From ac34a6ba0e5b2452c4e294d7cabab7196ef9b7de Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 20 Feb 2015 17:18:07 +0100 Subject: [PATCH 001/122] First draft of new implementation. Not all benchmarks have been converted yet. --- .gitignore | 2 + CalibVolDiff/Data/Large/input.data | 5 - CalibVolDiff/Data/Medium/input.data | 5 - CalibVolDiff/Data/Small/input.data | 5 - CalibVolDiff/HaskellLH/Makefile | 45 -- CalibVolDiff/includeC/ParseInput.h | 128 ---- CalibVolDiff/includeC/ParseInputOLD.h | 152 ----- GenericPricing/HaskellLH/Makefile | 43 -- benchmarks.hs | 171 ----- {CalibGA => benchmarks/CalibGA}/README.txt | 0 .../CalibGA/datasets}/Large/input.data | 0 .../CalibGA/datasets}/Large/output.data | 0 .../CalibGA/datasets}/Medium/input.data | 0 .../CalibGA/datasets}/Medium/output.data | 0 .../CalibGA/datasets}/Small/input.data | 0 .../CalibGA/datasets}/Small/output.data | 0 .../All_CppOpenCL/FindBestKer.h | 0 .../All_CppOpenCL/GenAlgFlat.h | 0 .../All_CppOpenCL/GenAlgKers.h | 0 .../implementations}/All_CppOpenCL/MainKer.h | 0 .../implementations}/All_CppOpenCL/Makefile | 0 .../All_CppOpenCL/SrcCL/BestIndValRedKer.cl | 0 .../All_CppOpenCL/SrcCL/CalibKers.cl | 0 .../All_CppOpenCL/SrcCL/Date.cl | 0 .../All_CppOpenCL/SrcCL/ExactYhat.cl | 0 .../All_CppOpenCL/SrcCL/G2ppUtil.cl | 0 .../All_CppOpenCL/SrcCL/GenAlg.cl | 0 .../All_CppOpenCL/SrcCL/Reductions.cl | 0 .../All_CppOpenCL/SwapCalib.cpp | 0 .../All_CppOpenCL/UtilGPGPU.h | 0 .../Outer_CppOpenMP/GenAlgFlat.h | 0 .../implementations}/Outer_CppOpenMP/Makefile | 0 .../implementations/Outer_CppOpenMP/SwapCalib | Bin 0 -> 80848 bytes .../Outer_CppOpenMP/SwapCalib.cpp | 0 .../Outer_CppOpenMP/UtilCPU.h | 0 .../CalibGA}/includeC/Candidate.h | 0 .../CalibGA}/includeC/Constants.h | 0 .../CalibGA}/includeC/Date.h | 0 .../CalibGA}/includeC/EvalGenomeInl.h | 0 .../CalibGA}/includeC/G2PP.h | 0 .../CalibGA}/includeC/G2ppUtil.h | 0 .../CalibGA}/includeC/GenAlgUtil.h | 0 .../CalibGA}/includeC/IrregShape.h | 0 .../CalibGA}/includeC/KerConsts.h | 0 .../CalibGA}/includeC/MathModule.h | 0 .../CalibGA}/includeC/ParseInput.h | 0 .../CalibGA}/includeC/tmp/Constants.h | 0 .../CalibGA}/includeC/tmp/DataStructConst.h | 0 .../CalibGA}/includeC/tmp/G2PP.h | 0 .../CalibVolDiff}/README.txt | 0 .../CalibVolDiff}/ToDo.txt | 0 .../CalibVolDiff/datasets/Large/input.json | 6 + .../CalibVolDiff/datasets/Large/output.json | 24 +- .../CalibVolDiff/datasets/Medium/input.json | 6 + .../CalibVolDiff/datasets/Medium/output.json | 5 +- .../CalibVolDiff/datasets/Small/input.json | 6 + .../CalibVolDiff/datasets/Small/output.json | 35 +- .../All_COpenCLMP/CrankNicolson.cl | 0 .../implementations}/All_COpenCLMP/Makefile | 10 - .../All_COpenCLMP/PrepareKernels.h | 0 .../implementations}/All_COpenCLMP/Vect_CPU.h | 2 +- .../implementations}/All_COpenCLMP/Vect_GPU.h | 2 +- .../All_COpenCLMP/VolCalibAll.cpp | 29 +- .../All_COpenCLMP/VolCalibInit.h | 2 +- .../implementations/All_COpenCLMP/instantiate | 17 + .../implementations/All_COpenCLMP/run | 3 + .../implementations}/HaskellLH/VolCalib.hs | 33 +- .../implementations/HaskellLH/instantiate | 11 + .../implementations/HaskellLH/run | 5 + .../implementations}/Orig_COpenMP/Makefile | 10 - .../Orig_COpenMP/VolCalibOrig.cpp | 16 +- .../implementations/Orig_COpenMP/instantiate | 14 + .../implementations/Orig_COpenMP/run | 3 + .../implementations}/Original/Makefile | 0 .../implementations/Original/VolCalib | Bin 0 -> 40968 bytes .../Original/VolCalibOrig.cpp | 640 +++++++++--------- .../implementations/Original/instantiate | 14 + .../CalibVolDiff/implementations/Original/run | 3 + .../Outer_COpenCLMP/CrankNicolson.cl | 0 .../implementations}/Outer_COpenCLMP/Makefile | 0 .../Outer_COpenCLMP/PrepareKernels.h | 0 .../Outer_COpenCLMP/Vect_CPU.h | 2 +- .../Outer_COpenCLMP/Vect_GPU.h | 0 .../Outer_COpenCLMP/VolCalibInit.h | 2 +- .../Outer_COpenCLMP/VolCalibOuter.cpp | 24 +- .../Outer_COpenCLMP/instantiate | 17 + .../implementations/Outer_COpenCLMP/run | 3 + .../CalibVolDiff/lib/include}/Constants.h | 0 .../lib/include}/DataStructConst.h | 0 .../CalibVolDiff/lib/include}/ParPrefixUtil.h | 0 .../CalibVolDiff/lib/include/ParseInput.h | 58 ++ .../GenericPricing/datasets}/Large/input.data | 0 .../datasets}/Large/output.data | 0 .../datasets}/Medium/input.data | 0 .../datasets}/Medium/output.data | 0 .../GenericPricing/datasets}/Small/input.data | 0 .../datasets}/Small/output.data | 0 .../CppOpenCL/ContractDefs/LargeContract.cl | 0 .../CppOpenCL/ContractDefs/MediumContract.cl | 0 .../CppOpenCL/ContractDefs/SmallContract.cl | 0 .../implementations}/CppOpenCL/GenPricing.cpp | 14 +- .../CppOpenCL/GenericPricingPrivOpt.cl | 0 .../CppOpenCL/GenericPricingVectOpt.cl | 0 .../GenericPricingVectUncoalesced.cl | 0 .../implementations}/CppOpenCL/Makefile | 20 +- .../implementations}/CppOpenCL/StructGPU.h | 0 .../implementations/CppOpenCL/instantiate | 16 + .../implementations/CppOpenCL/run | 3 + .../implementations}/HaskellLH/GenPricing.hs | 101 +-- .../implementations}/HaskellLH/Payoff3Cond.hs | 0 .../implementations/HaskellLH/instantiate | 11 + .../implementations/HaskellLH/run | 5 + .../implementations}/Orig_COpenMp/Contracts.h | 0 .../Orig_COpenMp/GenPricing.cpp | 22 +- .../implementations}/Orig_COpenMp/Makefile | 16 +- .../Orig_COpenMp/SobolGaussBB.h | 0 .../implementations/Orig_COpenMp/instantiate | 15 + .../implementations/Orig_COpenMp/run | 3 + .../GenericPricing/lib}/Constants.h | 0 .../GenericPricing/lib}/Optimizations.h | 0 .../GenericPricing/lib}/ParseInput.h | 28 - .../GenericPricing/lib}/TimeHelper.h | 0 {DOCS => docs}/Jepsen_Report.pdf | Bin {DOCS => docs}/TridagPres.pdf | Bin finpar | 247 +++++++ {include => lib/include}/ParserC.h | 42 +- {include => lib/include}/SDK_stub.h | 0 {include => lib/include}/Util.h | 0 {include => lib/include}/Utilities.cl | 0 lib/linearise_data.py | 20 + lib/platform.mk | 28 + lib/setup.mk | 20 + redesign.md | 114 ++++ setup.mk | 2 +- 134 files changed, 1134 insertions(+), 1151 deletions(-) delete mode 100644 CalibVolDiff/Data/Large/input.data delete mode 100644 CalibVolDiff/Data/Medium/input.data delete mode 100644 CalibVolDiff/Data/Small/input.data delete mode 100644 CalibVolDiff/HaskellLH/Makefile delete mode 100644 CalibVolDiff/includeC/ParseInput.h delete mode 100644 CalibVolDiff/includeC/ParseInputOLD.h delete mode 100644 GenericPricing/HaskellLH/Makefile delete mode 100644 benchmarks.hs rename {CalibGA => benchmarks/CalibGA}/README.txt (100%) rename {CalibGA/Data => benchmarks/CalibGA/datasets}/Large/input.data (100%) rename {CalibGA/Data => benchmarks/CalibGA/datasets}/Large/output.data (100%) rename {CalibGA/Data => benchmarks/CalibGA/datasets}/Medium/input.data (100%) rename {CalibGA/Data => benchmarks/CalibGA/datasets}/Medium/output.data (100%) rename {CalibGA/Data => benchmarks/CalibGA/datasets}/Small/input.data (100%) rename {CalibGA/Data => benchmarks/CalibGA/datasets}/Small/output.data (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/FindBestKer.h (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/GenAlgFlat.h (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/GenAlgKers.h (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/MainKer.h (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/Makefile (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/BestIndValRedKer.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/CalibKers.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/Date.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/ExactYhat.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/G2ppUtil.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/GenAlg.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SrcCL/Reductions.cl (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/SwapCalib.cpp (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/All_CppOpenCL/UtilGPGPU.h (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/Outer_CppOpenMP/GenAlgFlat.h (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/Outer_CppOpenMP/Makefile (100%) create mode 100755 benchmarks/CalibGA/implementations/Outer_CppOpenMP/SwapCalib rename {CalibGA => benchmarks/CalibGA/implementations}/Outer_CppOpenMP/SwapCalib.cpp (100%) rename {CalibGA => benchmarks/CalibGA/implementations}/Outer_CppOpenMP/UtilCPU.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/Candidate.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/Constants.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/Date.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/EvalGenomeInl.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/G2PP.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/G2ppUtil.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/GenAlgUtil.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/IrregShape.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/KerConsts.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/MathModule.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/ParseInput.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/tmp/Constants.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/tmp/DataStructConst.h (100%) rename {CalibGA => benchmarks/CalibGA}/includeC/tmp/G2PP.h (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff}/README.txt (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff}/ToDo.txt (100%) create mode 100644 benchmarks/CalibVolDiff/datasets/Large/input.json rename CalibVolDiff/Data/Large/output.data => benchmarks/CalibVolDiff/datasets/Large/output.json (72%) create mode 100644 benchmarks/CalibVolDiff/datasets/Medium/input.json rename CalibVolDiff/Data/Medium/output.data => benchmarks/CalibVolDiff/datasets/Medium/output.json (93%) create mode 100644 benchmarks/CalibVolDiff/datasets/Small/input.json rename CalibVolDiff/Data/Small/output.data => benchmarks/CalibVolDiff/datasets/Small/output.json (62%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/CrankNicolson.cl (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/Makefile (80%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/PrepareKernels.h (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/Vect_CPU.h (99%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/Vect_GPU.h (99%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/VolCalibAll.cpp (86%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/All_COpenCLMP/VolCalibInit.h (98%) create mode 100755 benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/All_COpenCLMP/run rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/HaskellLH/VolCalib.hs (94%) create mode 100755 benchmarks/CalibVolDiff/implementations/HaskellLH/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/HaskellLH/run rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Orig_COpenMP/Makefile (64%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Orig_COpenMP/VolCalibOrig.cpp (92%) create mode 100755 benchmarks/CalibVolDiff/implementations/Orig_COpenMP/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/Orig_COpenMP/run rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Original/Makefile (100%) create mode 100755 benchmarks/CalibVolDiff/implementations/Original/VolCalib rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Original/VolCalibOrig.cpp (88%) create mode 100755 benchmarks/CalibVolDiff/implementations/Original/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/Original/run rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/CrankNicolson.cl (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/Makefile (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/PrepareKernels.h (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/Vect_CPU.h (99%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/Vect_GPU.h (100%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/VolCalibInit.h (98%) rename {CalibVolDiff => benchmarks/CalibVolDiff/implementations}/Outer_COpenCLMP/VolCalibOuter.cpp (88%) create mode 100755 benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/run rename {CalibVolDiff/includeC => benchmarks/CalibVolDiff/lib/include}/Constants.h (100%) rename {CalibVolDiff/includeC => benchmarks/CalibVolDiff/lib/include}/DataStructConst.h (100%) rename {CalibVolDiff/includeC => benchmarks/CalibVolDiff/lib/include}/ParPrefixUtil.h (100%) create mode 100644 benchmarks/CalibVolDiff/lib/include/ParseInput.h rename {GenericPricing/Data => benchmarks/GenericPricing/datasets}/Large/input.data (100%) rename {GenericPricing/Data => benchmarks/GenericPricing/datasets}/Large/output.data (100%) rename {GenericPricing/Data => benchmarks/GenericPricing/datasets}/Medium/input.data (100%) rename {GenericPricing/Data => benchmarks/GenericPricing/datasets}/Medium/output.data (100%) rename {GenericPricing/Data => benchmarks/GenericPricing/datasets}/Small/input.data (100%) rename {GenericPricing/Data => benchmarks/GenericPricing/datasets}/Small/output.data (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/ContractDefs/LargeContract.cl (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/ContractDefs/MediumContract.cl (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/ContractDefs/SmallContract.cl (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/GenPricing.cpp (96%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/GenericPricingPrivOpt.cl (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/GenericPricingVectOpt.cl (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/GenericPricingVectUncoalesced.cl (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/Makefile (66%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/CppOpenCL/StructGPU.h (100%) create mode 100755 benchmarks/GenericPricing/implementations/CppOpenCL/instantiate create mode 100755 benchmarks/GenericPricing/implementations/CppOpenCL/run rename {GenericPricing => benchmarks/GenericPricing/implementations}/HaskellLH/GenPricing.hs (85%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/HaskellLH/Payoff3Cond.hs (100%) create mode 100755 benchmarks/GenericPricing/implementations/HaskellLH/instantiate create mode 100755 benchmarks/GenericPricing/implementations/HaskellLH/run rename {GenericPricing => benchmarks/GenericPricing/implementations}/Orig_COpenMp/Contracts.h (100%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/Orig_COpenMp/GenPricing.cpp (93%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/Orig_COpenMp/Makefile (64%) rename {GenericPricing => benchmarks/GenericPricing/implementations}/Orig_COpenMp/SobolGaussBB.h (100%) create mode 100755 benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate create mode 100755 benchmarks/GenericPricing/implementations/Orig_COpenMp/run rename {GenericPricing/includeC => benchmarks/GenericPricing/lib}/Constants.h (100%) rename {GenericPricing/includeC => benchmarks/GenericPricing/lib}/Optimizations.h (100%) rename {GenericPricing/includeC => benchmarks/GenericPricing/lib}/ParseInput.h (93%) rename {GenericPricing/includeC => benchmarks/GenericPricing/lib}/TimeHelper.h (100%) rename {DOCS => docs}/Jepsen_Report.pdf (100%) rename {DOCS => docs}/TridagPres.pdf (100%) create mode 100755 finpar rename {include => lib/include}/ParserC.h (82%) rename {include => lib/include}/SDK_stub.h (100%) rename {include => lib/include}/Util.h (100%) rename {include => lib/include}/Utilities.cl (100%) create mode 100755 lib/linearise_data.py create mode 100644 lib/platform.mk create mode 100644 lib/setup.mk create mode 100644 redesign.md diff --git a/.gitignore b/.gitignore index 0505c1b..d245830 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ CalibVolDiff/Original/CalibVol # emacs backups *~ +# For development, we instantiate in this directory. +instantiations/ \ No newline at end of file diff --git a/CalibVolDiff/Data/Large/input.data b/CalibVolDiff/Data/Large/input.data deleted file mode 100644 index 226cb57..0000000 --- a/CalibVolDiff/Data/Large/input.data +++ /dev/null @@ -1,5 +0,0 @@ -128 // OUTER -- no restrictions -256 // NUM_X -- 2^x, where x \in {5, ..., 9} -256 // NUM_Y -- 2^x, where x \in {5, ..., 9} -64 // NUM_T -- no restrictions - diff --git a/CalibVolDiff/Data/Medium/input.data b/CalibVolDiff/Data/Medium/input.data deleted file mode 100644 index ad615a3..0000000 --- a/CalibVolDiff/Data/Medium/input.data +++ /dev/null @@ -1,5 +0,0 @@ -128 // OUTER -- no restrictions -256 // NUM_X -- 2^x, where x \in {5, ..., 9} -32 // NUM_Y -- 2^x, where x \in {5, ..., 9} -64 // NUM_T -- no restrictions - diff --git a/CalibVolDiff/Data/Small/input.data b/CalibVolDiff/Data/Small/input.data deleted file mode 100644 index 370c268..0000000 --- a/CalibVolDiff/Data/Small/input.data +++ /dev/null @@ -1,5 +0,0 @@ -128 // OUTER -- no restrictions -32 // NUM_X -- 2^x, where x \in {5, ..., 9} -32 // NUM_Y -- 2^x, where x \in {5, ..., 9} -256 // NUM_T -- no restrictions - diff --git a/CalibVolDiff/HaskellLH/Makefile b/CalibVolDiff/HaskellLH/Makefile deleted file mode 100644 index 87ba8be..0000000 --- a/CalibVolDiff/HaskellLH/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# can be set using $>gmake GHC=/path/to/my/ghc -ifeq ($(strip $(GHC)),) - GHC=`which ghc` -endif - -# switch this on if llvm is enabled -#BACKEND=-fllvm - -OPTIMIZATION=-O2 -msse2 -rtsopts -EXECUTABLE=VolCalib - -all: $(EXECUTABLE) - -$(EXECUTABLE): % : %.hs - $(GHC) $(OPTIMIZATION) --make $< -o $@ - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) - -# the Large dataset runs out of memory on the current Haskell implementation! -run_large: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) -# cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) - - -#------------------------------------------------------------------------- -# clean -#------------------------------------------------------------------------- -.PHONY : clean_executables clean_obj clean_source_backup -.SILENT : clean_executables clean_obj clean_source_backup - -clean: clean_executables clean_obj clean_source_backup - -clean_executables: - rm -f $(EXECUTABLE) - -clean_obj : - rm -f *.o *.hi - -clean_source_backup: - rm -f *~ - diff --git a/CalibVolDiff/includeC/ParseInput.h b/CalibVolDiff/includeC/ParseInput.h deleted file mode 100644 index 3cde309..0000000 --- a/CalibVolDiff/includeC/ParseInput.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef PARSE_INPUT -#define PARSE_INPUT - -#include "ParserC.h" -#include -#include -#include - -using namespace std; - -#include -using std::cout; -using std::endl; - - -#if WITH_FLOATS - #define read_real read_float -#else - #define read_real read_double -#endif - -const float EPS = 0.00001; - -/***********************************/ -/********** READ DATA SET **********/ -/***********************************/ - -void readDataSet( unsigned int& outer, - unsigned int& num_X, - unsigned int& num_Y, - unsigned int& num_T -) { - if( read_int( static_cast( &outer ) ) || - read_int( static_cast( &num_X ) ) || - read_int( static_cast( &num_Y ) ) || - read_int( static_cast( &num_T ) ) ) { - - fprintf(stderr, "Syntax error when reading the dataset, i.e., four ints.\n"); - exit(1); - } - - { // check dataset invariants: - bool atr_ok = true; - - atr_ok = outer > 0; - assert(atr_ok && "Outer loop count less than 0!"); - - atr_ok = (num_X > 0) && (num_X <= WORKGROUP_SIZE) && is_pow2(num_X); - assert(atr_ok && "Illegal NUM_X value!"); - - atr_ok = (num_Y > 0) && (num_Y <= WORKGROUP_SIZE) && is_pow2(num_Y); - assert(atr_ok && "Illegal NUM_X value!"); - - atr_ok = num_T > 0; - assert(atr_ok && "NUM_T value less or equal to zero!!"); - } -} - -REAL* readOutput( const int& N ) { - REAL* result; - int64_t shape[3]; - - // reading the standard output - if (read_array(sizeof(REAL), read_real, (void**)&result, shape, 1) ) { - fprintf(stderr, "Syntax error when reading the output.\n"); - exit(1); - } - - bool ok = ( shape[0] == N ); - assert(ok && "Incorrect shape of the standard result!"); - - return result; -} - -bool validate( const REAL* res, const int& N ) { - bool is_valid = true; - - REAL* std_res = readOutput( N ); - - for ( int i = 0; i < N; i ++ ) { - float err = fabs(std_res[i] - res[i]); - if ( err > EPS ) { - is_valid = false; - fprintf(stderr, "Error[%d] = %f, EPS = %f!\n", i, err, EPS); - break; - } - } - - return is_valid; -} - -void writeStatsAndResult( const bool& valid, const REAL* data, - const int & outer, const int & num_X, - const int & num_Y, const int & num_T, - const bool& is_gpu,const int & P, - const unsigned long int& elapsed -) { - // print stats to stdout - fprintf(stdout, "// OUTER=%d, NUM_X=%d, NUM_Y=%d, NUM_T=%d.\n", - outer, num_X, num_Y, num_T ); - - if(valid) { fprintf(stdout, "1\t\t// VALID Result,\n"); } - else { fprintf(stdout, "0\t\t// INVALID Result,\n"); } - - fprintf(stdout, "%ld\t\t// Runtime in microseconds,\n", elapsed); - if(is_gpu) fprintf(stdout, "%d\t\t// GPU Threads,\n\n", P); - else fprintf(stdout, "%d\t\t// CPU Threads,\n\n", P); - - // write the result - write_1Darr( data, static_cast(outer), - "Volatility Calibration Result" ); -} - -#if 0 -void writeResult( const REAL* res, const unsigned int N, const char* msg ) { - //ofstream fout; - //fout.open ("output.data"); - cout << "\n[ " - for( int k=0; k -using std::cout; -using std::endl; - -#include -using std::ifstream; - -#include - -const int MAX_CHARS_PER_LINE = 512; -const int MAX_TOKENS_PER_LINE = 20; -const char* const DELIMITER = " :="; - -const float EPS = 0.00001; - -/***********************************/ -/********** READ DATA SET **********/ -/***********************************/ - -bool is_pow2(int atr_val) { - int x = 1; - - for(int i = 0; i < 31; i++) { - if(x == atr_val) return true; - x = (x << 1); - } - return false; -} -#if 0 -static bool is_pow2(unsigned int x) { - while(x > 1) { - if( x & 1 ) return false; - x = x >> 1; - } - return true; -} -#endif - -inline int parseIntAttribute(ifstream& fin, char* buf, const char* atr) { - int ret_val; - - assert( (!fin.eof()) && "incomplete input.data file!" ); - fin.getline(buf, MAX_CHARS_PER_LINE); - - { // reading the atribute name - char* token_atr = strtok(buf, DELIMITER); - bool ok = (token_atr != NULL) && (strcmp(token_atr, atr) == 0); - assert( ok && "illegal/missing attribute name in input.data file!"); - // the result of strtok is part of buf, - // i.e., no dealocation is necessary! - } - - { // reading the attribute value - char* token_val = strtok(NULL, DELIMITER); - assert( token_val && "missing attribute value in input.data file!"); - ret_val = atoi(token_val); - } - - return ret_val; -} - -void readDataSet( unsigned int& outer, - unsigned int& num_X, - unsigned int& num_Y, - unsigned int& num_T -) { - char buf[MAX_CHARS_PER_LINE]; - int atr_val; bool atr_ok; - - // create a file-reading object - ifstream fin; - fin.open("input.data"); - assert(fin.good() && "Error opening input.data file!"); - - { // seeting and checking legality of the outer loop count - atr_val = parseIntAttribute(fin, buf, "OUTER"); - atr_ok = atr_val > 0; - assert(atr_ok && "outer loop count less than 0!"); - outer = static_cast(atr_val); - } - - { // seeting and checking legality of NUM_X - atr_val = parseIntAttribute(fin, buf, "NUM_X"); - atr_ok = (atr_val > 0) && (atr_val <= 512) && is_pow2(atr_val); - assert(atr_ok && "illegal NUM_X value!"); - num_X = static_cast(atr_val); - } - - { // seeting and checking legality of NUM_Y - atr_val = parseIntAttribute(fin, buf, "NUM_Y"); - atr_ok = (atr_val > 0) && (atr_val <= 512) && is_pow2(atr_val); - assert(atr_ok && "illegal NUM_Y value!"); - num_Y = static_cast(atr_val); - } - - { // seeting and checking legality of NUM_T - atr_val = parseIntAttribute(fin, buf, "NUM_T"); - atr_ok = atr_val > 0; - assert(atr_ok && "NUM_T value less or equal to zero!"); - num_T = static_cast(atr_val); - } - - fin.close(); - - cout<<"Parameters: { OUTER = "< EPS ) { - is_valid = false; - cout<<"INVALID: error["< "<gmake GHC=/path/to/my/ghc -ifeq ($(strip $(GHC)),) - GHC=`which ghc` -endif - -# switch this on if llvm is enabled -#BACKEND=-fllvm - -OPTIMIZATION=-O2 -msse2 -rtsopts -EXECUTABLE=GenPricing - -all: $(EXECUTABLE) - -$(EXECUTABLE): % : %.hs - $(GHC) $(OPTIMIZATION) --make $< -o $@ - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) - - -#------------------------------------------------------------------------- -# clean -#------------------------------------------------------------------------- -.PHONY : clean_executables clean_obj clean_source_backup -.SILENT : clean_executables clean_obj clean_source_backup - -clean: clean_executables clean_obj clean_source_backup - -clean_executables: - rm -f $(EXECUTABLE) - -clean_obj : - rm -f *.o *.hi - -clean_source_backup: - rm -f *~ - diff --git a/benchmarks.hs b/benchmarks.hs deleted file mode 100644 index a41b878..0000000 --- a/benchmarks.hs +++ /dev/null @@ -1,171 +0,0 @@ -{-# LANGUAGE CPP,RecordWildCards #-} - --- running finpar benchmarks --- Usage: runhaskell benchmarks.hs - -import System.Environment -import System.IO -import System.Process -- run commands -import System.Exit -- exit codes -import System.Directory -import System.FilePath -import System.Console.GetOpt -import Control.Exception -import Text.ParserCombinators.ReadP -- (string, readP_to_S) -import Control.Monad -import Control.Applicative((<*), (<$>), (<*>), pure ) -import Data.Maybe - - -------------------------------- options of this script: ------------------------- -options = - [ Option ['v'] ["verbose"] (NoArg (\o -> o{optVerbose = True})) - "report activities on stderr" - -- , Option ['g'] ["graph"] (ReqArg (\f o -> o{optGraph = Just f}) "out.png") - -- "output a png graph to given filename" - , Option [] ["all"] (NoArg (\o -> o{optAll = True})) - "run all configured benchmarks" - , Option ['s'] ["small"] (NoArg (\o -> o{optSize = Small})) - "run on small data (default)" - , Option ['m'] ["medium"] (NoArg (\o -> o{optSize = Medium})) - "run on medium data" - , Option ['l'] ["large"] (NoArg (\o -> o{optSize = Large})) - "run on large data" - ] - -data Options = Options - { optVerbose :: Bool - , optGraph :: Maybe FilePath - , optAll :: Bool - , optSize :: BenchSize - } -instance Show Options where - show Options{..} = "// Options:" - ++ "Running with " ++ show optSize ++ " data size, " - ++ (if optVerbose then "verbose, " else "") - -- ++ (case optGraph of - -- Just f -> "output to " ++ f ++ ", " - -- Nothing -> "" - -- ) - ++ (if optAll then "(all benchmarks)" else "") - -defaults = Options { optVerbose = False, optGraph = Nothing - , optAll = False, optSize = Small } - -data BenchSize = Small | Medium | Large - deriving (Eq,Ord) -instance Show BenchSize where - show Small = "small" - show Medium = "medium" - show Large = "large" -instance Read BenchSize where - readsPrec _ = readP_to_S $ - (string "small" >> return Small) +++ - (string "medium" >> return Medium) +++ - (string "large" >> return Large) - ---------------------------------------------------------------------------------- - -usage = usageInfo "runhaskell benchmarks.hs [OPTIONS] benchmarkname" options - -main = do putStrLn "Please use make!" - args <- getArgs - let (opts,bs) = case getOpt Permute options args of - (o, [], []) -> - (foldl (flip ($)) defaults{optAll=True} o, []) - -- (flip id) :-] - (o, n, []) -> (foldl (flip ($)) defaults o, n) - (_,_,errs) -> error (concat errs ++ '\n':usage) - benches <- filterM doesDirectoryExist - (if optAll opts then dirnames else bs) - when (optVerbose opts) $ do hPutStrLn stderr usage - print benches - print opts - mapM_ (runBench opts) benches - - ---------------------------------------------------------------------------------- -runBench :: Options -> String -> IO () -runBench Options{..} dir = - do (e,msg) <- runMake optVerbose dir [] - (ret,out) <- if e /= ExitSuccess then return (e,msg) - else runMake optVerbose dir ["run_" ++ show optSize] - when (optVerbose || (ret /= ExitSuccess)) - (hPutStrLn stderr ("make returned " ++ show ret)) - -- parsing output - putStrLn out - -runMake :: Bool -> FilePath -> [String] -> IO (ExitCode,String) -runMake verbose dir targets = do - when verbose (putStrLn ("make " ++ unwords ("-C":dir:targets))) - dirOK <- doesDirectoryExist dir - if not dirOK then return (ExitFailure 1, dir ++ ": does not exist") - else do - let args = (if verbose then ["-C"] else ["--no-print-directory","-C"]) - (code, stdo, stde) <- readProcessWithExitCode "make" (args ++dir:targets) "" - when verbose $ hPutStrLn stderr ("Output from " ++ dir ++ "\nstdout:\n" - ++ stdo ++ "\nstderr:\n" ++ stde) - return (code,stdo) - --- every directory with source code must supply a makefile with --- default target compiling the program, and targets run_small, --- run_medium, run_large with test data in a relative path "../Data" - --- names of target directories (only those with code) -dirnames = ["CalibVolDiff" "Orig_COpenMP" - , "CalibVolDiff" "Original" - , "CalibVolDiff" "All_COpenMPCL" - , "CalibVolDiff" "Outer_COpenMPCL" - , "CalibVolDiff" "HaskellLH" --- , "CalibGA/CppAndGPU" --- , "CalibGA/python" --- , "CalibGA/OCaml" - , "GenericPricing" "Orig_COpenMp" - , "GenericPricing" "CppOpenCL" - , "GenericPricing" "HaskellLH" - ] - --- names of different benchmarks -benchnames = [ "CalibVolDiff" - , "GenericPricing" - -- , "CalibGA" - ] - --- code directories inside benchmark directories; kind-of ad-hoc standardised -codenames = ["Orig_COpenMP", "Original", "CppOpenCL" - , "All_COpenMPCL", "Outer_COpenMPCL" - , "HaskellLH" - ] - - ---------------------- --- parsing using ReadP (no external library required) - -signed p = (char '-' >> (('-':) <$> p)) +++ p - -whitespace :: ReadP () -whitespace = skipSpaces <* - optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) -anyChar = satisfy (const True) -digit = satisfy (`elem` ['0'..'9']) - -lexeme :: ReadP a -> ReadP a -lexeme p = p <* whitespace - --- token :: String -> Parser () -token = return () . lexeme . string - -readInt :: ReadP Int -readInt = lexeme $ read <$> signed (many1 digit) - -readDouble :: ReadP Double -readDouble = read <$> signed (s2 +++ s1) - where s1 = do bef <- many1 digit - aft <- option "" ((:) <$> char '.' <*> many1 digit) - return $ bef ++ aft - s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit - --- not ready: --- readArray :: ReadP a -> ReadP [a] --- readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") - diff --git a/CalibGA/README.txt b/benchmarks/CalibGA/README.txt similarity index 100% rename from CalibGA/README.txt rename to benchmarks/CalibGA/README.txt diff --git a/CalibGA/Data/Large/input.data b/benchmarks/CalibGA/datasets/Large/input.data similarity index 100% rename from CalibGA/Data/Large/input.data rename to benchmarks/CalibGA/datasets/Large/input.data diff --git a/CalibGA/Data/Large/output.data b/benchmarks/CalibGA/datasets/Large/output.data similarity index 100% rename from CalibGA/Data/Large/output.data rename to benchmarks/CalibGA/datasets/Large/output.data diff --git a/CalibGA/Data/Medium/input.data b/benchmarks/CalibGA/datasets/Medium/input.data similarity index 100% rename from CalibGA/Data/Medium/input.data rename to benchmarks/CalibGA/datasets/Medium/input.data diff --git a/CalibGA/Data/Medium/output.data b/benchmarks/CalibGA/datasets/Medium/output.data similarity index 100% rename from CalibGA/Data/Medium/output.data rename to benchmarks/CalibGA/datasets/Medium/output.data diff --git a/CalibGA/Data/Small/input.data b/benchmarks/CalibGA/datasets/Small/input.data similarity index 100% rename from CalibGA/Data/Small/input.data rename to benchmarks/CalibGA/datasets/Small/input.data diff --git a/CalibGA/Data/Small/output.data b/benchmarks/CalibGA/datasets/Small/output.data similarity index 100% rename from CalibGA/Data/Small/output.data rename to benchmarks/CalibGA/datasets/Small/output.data diff --git a/CalibGA/All_CppOpenCL/FindBestKer.h b/benchmarks/CalibGA/implementations/All_CppOpenCL/FindBestKer.h similarity index 100% rename from CalibGA/All_CppOpenCL/FindBestKer.h rename to benchmarks/CalibGA/implementations/All_CppOpenCL/FindBestKer.h diff --git a/CalibGA/All_CppOpenCL/GenAlgFlat.h b/benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgFlat.h similarity index 100% rename from CalibGA/All_CppOpenCL/GenAlgFlat.h rename to benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgFlat.h diff --git a/CalibGA/All_CppOpenCL/GenAlgKers.h b/benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgKers.h similarity index 100% rename from CalibGA/All_CppOpenCL/GenAlgKers.h rename to benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgKers.h diff --git a/CalibGA/All_CppOpenCL/MainKer.h b/benchmarks/CalibGA/implementations/All_CppOpenCL/MainKer.h similarity index 100% rename from CalibGA/All_CppOpenCL/MainKer.h rename to benchmarks/CalibGA/implementations/All_CppOpenCL/MainKer.h diff --git a/CalibGA/All_CppOpenCL/Makefile b/benchmarks/CalibGA/implementations/All_CppOpenCL/Makefile similarity index 100% rename from CalibGA/All_CppOpenCL/Makefile rename to benchmarks/CalibGA/implementations/All_CppOpenCL/Makefile diff --git a/CalibGA/All_CppOpenCL/SrcCL/BestIndValRedKer.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/BestIndValRedKer.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/BestIndValRedKer.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/BestIndValRedKer.cl diff --git a/CalibGA/All_CppOpenCL/SrcCL/CalibKers.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/CalibKers.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/CalibKers.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/CalibKers.cl diff --git a/CalibGA/All_CppOpenCL/SrcCL/Date.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Date.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/Date.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Date.cl diff --git a/CalibGA/All_CppOpenCL/SrcCL/ExactYhat.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/ExactYhat.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/ExactYhat.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/ExactYhat.cl diff --git a/CalibGA/All_CppOpenCL/SrcCL/G2ppUtil.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/G2ppUtil.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/G2ppUtil.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/G2ppUtil.cl diff --git a/CalibGA/All_CppOpenCL/SrcCL/GenAlg.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/GenAlg.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/GenAlg.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/GenAlg.cl diff --git a/CalibGA/All_CppOpenCL/SrcCL/Reductions.cl b/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Reductions.cl similarity index 100% rename from CalibGA/All_CppOpenCL/SrcCL/Reductions.cl rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Reductions.cl diff --git a/CalibGA/All_CppOpenCL/SwapCalib.cpp b/benchmarks/CalibGA/implementations/All_CppOpenCL/SwapCalib.cpp similarity index 100% rename from CalibGA/All_CppOpenCL/SwapCalib.cpp rename to benchmarks/CalibGA/implementations/All_CppOpenCL/SwapCalib.cpp diff --git a/CalibGA/All_CppOpenCL/UtilGPGPU.h b/benchmarks/CalibGA/implementations/All_CppOpenCL/UtilGPGPU.h similarity index 100% rename from CalibGA/All_CppOpenCL/UtilGPGPU.h rename to benchmarks/CalibGA/implementations/All_CppOpenCL/UtilGPGPU.h diff --git a/CalibGA/Outer_CppOpenMP/GenAlgFlat.h b/benchmarks/CalibGA/implementations/Outer_CppOpenMP/GenAlgFlat.h similarity index 100% rename from CalibGA/Outer_CppOpenMP/GenAlgFlat.h rename to benchmarks/CalibGA/implementations/Outer_CppOpenMP/GenAlgFlat.h diff --git a/CalibGA/Outer_CppOpenMP/Makefile b/benchmarks/CalibGA/implementations/Outer_CppOpenMP/Makefile similarity index 100% rename from CalibGA/Outer_CppOpenMP/Makefile rename to benchmarks/CalibGA/implementations/Outer_CppOpenMP/Makefile diff --git a/benchmarks/CalibGA/implementations/Outer_CppOpenMP/SwapCalib b/benchmarks/CalibGA/implementations/Outer_CppOpenMP/SwapCalib new file mode 100755 index 0000000000000000000000000000000000000000..9cc25976a5063b0509d9e19b065e77112a96db87 GIT binary patch literal 80848 zcmdqK4R}<=^*_FwWHDgYyHTQ1gT%UMq9KwBmQ>IzZgkVGiX})ALlAk9)Cd$dfEE?l z1h|H^v|?+kt$bT;t+i@fYJn=*gqI|!7(gY6F9A{S65de=pyc=YoVj+sn)GQa-+DephVWmiFvYiY{t@R?ZnXXXv#9uN|B{b6WOyg@3|P@|$lREj37G75GOS!k<0ew%qQDXI=*WU5S60 z{g$Ln9zEWbd$=a;{(^g7K~|6dy$D3-o}u({Zny8pMN2l)T$A-@9% z&P4Zk5Ab_?fWN2*{yTcWa~tra<6rmx!acx$2*5M(S=Iymv>xEAdw_qZhy3y$@(=Zp ze|``7f9QdqfA)|c=>gBvJ;49Ehy33FPqOVI+fr>jAmF#;ug&%oGk;#U{7q*5;%@n~ zP>=d=*78gY<^%p|W?uc0VEl~0xN){|KbSS{N0aU;pBb1m zUIk!tr-kOj2cME-9Hh{yy8dl8NI-&LWjL zbH+`dG-KwpspBik1NV=cHOK}|?o&)mnls%t^CvR`lWi5#?vXbZ-ZSmK=`7E&-F(|E zBga)tn>Kyiq^T3fO`SG-e0jiz(sB1p3XGdtdEdCelo^x8Pn@X$r;nd8zM^7MMHE7n z5-3FBrePQcc5g^p>FVS*(Cc$zt5{M3oI>6L+* zHZW9CF>Qhk$}XP@1yGkz@#OL46}AbgsB$X!pJ2Oh(tR^0p>AN}w90^OGHN4FL5v$$ zK6C2$sgqH^d}jI7$$Xg*xPSVjad(4DK|X254BO<{Gs**#Y`_*Mzi-mC$rH!luUHv8 z6!>P8PlaY@P7pi=w^3;mfCr*LENS=q#)HMlGbT;4-B?uQ8Bs7UC;J-P&HjQBNRGQE zd$7{aV8|;ik;503j{9!*ce95?-|6GxFnYz|e>INAVQ#^c^*_twFmAD&Z#LUmu<%%@ zMAT<_yoo2y)>{nMjy#yUjpN23{M-7{y_mN2w)F=R<^?i;fv)1PT}h<)&yM=f;mNW* z{A<4KaS)A6jls2q&M+kDaTINNPti1_*6 zdFAC!N>ga!Q}A(7`1Ete3mnJn*m;H3pE(EP_-*}X^=Ia1TA6rSeu4QM^R55#O#Ejd zgL<<5^Tp(wtV_|zn0#}pCiz7%`Kk>Srn_SDN!$8wN=$yNT+?InEg!}@b7JyU%PLIs zV)FY~$njhplYe$h{?eHIq?r6CV)D@-(f^jm%sclOH?2 zg=6y1i-B*9$>-e8`mZ@AKgG(#vn3|~{FwaKnEVT3@{O4M3uE#R#^hfVliwbbe{oE{ z%^W{yKh_$7#fdTb{bJx{=0*q*pV|E)}s!`tMA$D@6{TLdJmSnWmeJv`YH- zOtVWxnkD@krrDJuVM+gjX?CH=%aVSCX?C5+a!D^>nq4NcRMHPH&8`xeC+QhXvx`Kg zOZvx5r!sw)r0-^$T_rM7(j`o@i$wAy{UfH?H6nu~{R5`iB_ipP9>FxbLc}HM?=yV~ z(>6(emuZ@Q5#v$g(J$hO%gFZGP}6xOB#aP%mc za8ZNTEh845;*Id6YHWB)ug5dpOiOPuo&pcFeb1^!^bF6+R{Wh3#-CLN{;WQTKWm!t zr?v%u{GkeWp0ORu%Q@=T5BPv>D6tv81eT%_U#QgW_J#cJG+(IDo$3#Pm@gD?_w|M5 zx?Mh2F3`6d1%G3GpMIb~UuTq(e!1VBmp4MQ`O3ZSLGrSC$KY4CE%@-_8z*ZA!uZ$Z zi}$;IzIYJyW!CxhM&GeL{9D(4gRkzyxxUQ$!#?fGdSCe#sh+u+$)>|vvE$B0Wn+aR>SrUIx`TKL0A+=F|81^-q2JN65-Ez7IFC z*y}#0#?gYZ4PLiK&^#Zc%NXey&1e6SXoXRJNIsH6`>6vTb>OA=0G;c;-k5>m+&6#S zVo+X5_i*P}PpN0@+QV9DT_-2Ll_=qV^L#nLAGsSAHW~j#TfD*XV{ox}+Poh&IFj)8 z<{SR&8yvmx#{U`|HuZKxgX6@P=`vGjaD0w8U_{=2ywMe{&DmF=Z!YucyL`dj2S*kb zG=!(a#C#2PHhDBGb-~tJPj+;C-bq^P?*;3NUjZW%6iLG^Rp5V>dWXorI`I*3uu>wj)sG3*KO>bhJH&dQoJDSfQhNY~%r|G^)>0 zKK-OI27-e7_&e7wHSRsp(V^o_>pu^QVz<)2Vh1tq29Qs;@_jYKe*&t;Fy_{r?Vk`H zan$Rvr&oR&Y`;2iPFsJoez3hyU@L&V1l9l?Z11St(-y`faE`BLNEY(-2IFy1_38U_ z!nIXs0OJ)TgY9_H4{Omjd5-%|KTkx}jzz++VF8n-&eDLEC za70PU1z_dHy+y)8r-Muc>mR}^}08=?o^-5P4hSWY0Txe zP!bo`HoXyL$M)2n&@wlc*Z=MNaW;?M92(gx7>?I`^{YSF_3wYxwZ~;{@P=-+=a)Av z$1vk1(h;GgJ|0x9JKoou*;KyypBNuQBjT&KXa)7FFC5-@ktb;6NX_7e{@zg1EBW_^ zCwl63CZIO!9oyrz*VUa!^k#1KmT&wSMn{jnW%WHU%uWEkx$cC+leyVz-{e^p`F%~c z=UBvx%=Z49Pk8jr5cC31X5EdUgaWUOcP!BWArC*6;@oG>X|F|H*%#n ziVmc~==jkfnHxiWe`GZ^Teu-qb^T}8zSmJ6UJkJx&2VQ&v@63_KUkRt{vw+>N{YV- zM(m+E&PWg$l3slY%devkkhHHnPK`Y0$RmD4qAxo3_~LI(>|wOw*rQ(%9d4R^`pt(MmAPW;be&b%WR2e|_wf-VAh#e$DIzZ_Qbuo9Lcq zJ>Ur~X1k01mp4hT^u$*;X}-qb{47r4g?)2dRqS{) z%3IS*e3w@b!%OI4bkCbYNpa%9;5z!C&wE0;_^`ntXxwH>Lmzh7@?l#~_hEIRVte@x zdN92Oh(moZsyo>qy|J$+^F5F1vzA$#9;{6~SY5ELe`v6tfA5Zob)P1f#PaQ1=?-D= zaANva@m%?tjhRQvkIxF z&2MMV33=n=^qUg`IS_oczIgFsO9gj&?e#=f@6+4$F-iAs8Rp4s_UfYjdDH^(8*WbG zvZ3K-nQ?N&M7z|SThpt0%R`AFUq|rx*|U5(M}zHgf$_?h1Tx`Av}NJoiT)n#cj2mV zWok}SUe(b+@8F3v?RRzF-gSDT!V^4k2|?OEGVQzOd!a|Y?HwI!U{bdE$8W%6_8)+{ z@>$i7^K*c;U**d+H{>*V^y75;UVWo@*$c$WRz5qwqZ!L4{ZQaZz1{S+5D^aX-uj8T z4Ia(g*fxJD`o>x4BfXAjWsX7HF;n8~C1(B-Tkb+R;gSev@u}s6^|$Ie`s=6a_Fod} zn-km>pL@76%XDqW_DJv4->p04$UJrL(TTZ-DqZlwnI|k44D}pY+c`g}(G<25F#|?r zK@^(|7Mbm8thlV^d>JZ&C*lI%3-0@Wjy`xX&Tk{*#*!~(|zwOxGfT8QZH?}tf8#uPt{*T7? zw|W@c&p+eX9F$Z2)U*#AYx$&%43+KGtqpMkC@MDL>mx z+b?zAvxSpCXSyUynlSO(tSy*<`2aBgftVRCRG8Ou`S-8ATvR$2cO|-*M4w_&H=?#Y zWBqZ9Xupe0qDS!r(Z4jyY?DN{YYQG!M6=I8bc7;$URRe`irQNvDr6c3@JX)H`sHNwlvb zTK85|(ulTTlp^Xq1JNQyG?PW&ixRbc0;0oFM6dPLo^-aH;}D)`$sy|ncbOvulAz8; z{XJg`oj>fPdPrNqkr|?HLbdLVx@(V!`VSUe6{R|qR2xu4s*6xYsz1dOREOVYQoTR~ zEpwdLNj*bRe{)k*=HpthR;UjjDQHTWW z$)}g!!SWk0FtPklgj~j=H?C#*pD`w|eDmq$=d--8S^l@v%a2A-{;;C&{5i_IDNp$S zF8~pLIm$;F*C2&>PAL-lT0~IR8i*sc+}VBpILf$)fU$9;OjI#G2e_~1Jl}-Iquw7N zjPx19NN2UBGJdoJL=p(}7JyXzsFCp_?M@JEGeEE*QiviDTRO^DGdmSAE#Gys69eDz z)tu$iUYd#6>##u`qcW<)l~`upm}=)_U9IPQc0^)lCjx4=%U5%Q@xJge6DZ=_)?q&A z8RNObQw!U*G183a(}WKT^bf^1sK6K?Kk@|k+l>XRseiO4k&Uh=xQ(A6qd;GuuYYb_ zE@f*ACTu7OdDo-Z>rOP+-!;QCA%XGvXWt+{f!+d8jQotB?fs168>6NA@DGtP{wz>q zwJMk-0vB0dRD}g4xpe6vF z<_@mcs`rA?{Oa9-D?Guyb_%0v{t~9XAG`mrhR7SBCf+166rSKr zHMFiZu<~C@doIx5qA?ffUyUABpdYWT6lnF*O0S zu6}+u+{(T?FUh+dK3zNW9A2ZxQcaN8q0cnJ)3}7myErQUp2q`GovjD}ZN;caN&Mz^5Mp z^&l$dgx5p}-oV<`I|3K^^!HFS1x0K2q2SJ(aO5v2gCB)&mUZYD>fG``3%X(!GTz=@%dI6vM6oY^MM3l+|{kQZg_T;g2X z9iQqS$5j6~#s2a3E&7}29aG>i+M=g;R5{vt@;7_#o%0bYC_<`Re49iMm8#~ zIkgj!{76ZAi9 zPd^!v_M{@ZwdcbK{7ZXs)UOW1XKU57I@n|hZfP^Eng_;{y<~^fMWGwM(g=oTz>tKy{^`kp%q@ z^^-+LdeYChFDNAJU4}GML6uz-Ukyo2XUwciI_tgMUyf57W z(EqUgDv16J?KiJ)9{T4I3hQV4EpsmiMK)m{t$KzuA!d2vmohL>nG!PzQl9JzGAN#G z3jC{)0Nzx==xD(ly12IYtb$vk1vVCJi5BEX3mRd%#;Rz+_0fWnELa{bkX5=6Zz1tT zC@{wztdR=zFL7w#3yhi5je%5|9uv=p9p>&xSNxvV&N1t~z6AORc)Rt_FW-~)orDqz zMp!2Xssz*?7>5zF6)?5)Xn`Xr03D0*Im%TlZrqM>Kk6@JebeTJldS?67e;D*vkW+l zaTfhfc<_Hei@anYwjZ_q6P(Hlp;)n44?1MgWwE#u8Jy%*7o&NBCx>{xBvdROGIWOi zm_XpS1Va~pzIVImV>Ho#SYL}+KtMrk?>CqIA|< zLRBd``&ty8REtiMMW;&9DP{dDzM0No!gT zzm`zlmDg3CHwgEu)9I{0KKw*Klwb|0?^oweuD7VX@)hzim!jX)iK0+Qo$Y%9D=&4> zny5>*37BV$OOJ%qI8!`u4ESVF44m)0G``G`kzCAblDYt{<4Y1t{OUPbnz z1E9&x`9&|{rKZxxEhm1Lm(!H9h0(wURK{~4pI8v=ZcFX#&-Hd+ur3M5HLA9wGM5XJ zwTw+5S$cM&mhm=L3*N+p!&(_)h%RqpqLz&lX~l0I)=HXY_W>VkwG73|=2OLubC5(^-7aq zG3E(|wpY!0=!F(kMi;0O(fB&Jl~_8YD@!ZM?DSU>zmmoN=Um#pv!)fu&qFW-=fPu#&79J`8YJMyBpT?mXmr z=3S3I2fQ^dt@>$H08A=i*33e^oUl;}7_%Mh%;t(u<*4$>+aR9@q_W&Y zJ$GllCX~h0(@OGfhC@|*k=3TeRNMD9(IvP|l8;(d(X5KB@wz|^53uIan415Pe2Mdk z)r>m5>QYrTmsMBBRGnj1b(vICPp>*!RXw#8Ra;}K4mYc!0|?a*03fnuvBm_r({4DypOV zt*Bql`gA(d^tDS--xpk)Wc&p6O}1{b*iucWmE8Ebu>i%WeHCl7Q>ogIqqgzA&YDT5 z)oeF>s^+0Br`P;yOO)mo6nAO%8^1KpQ8oY7wdNC~xfV6yx1T~$Z5G%u;+T=!rd3}k zo!GemB{&T?vAd{G6og8vZAP$@a#456@y6qV-Fbai!XoSsIxF_?Uh&2R<4#pG;S4oh zoi#t%++Em2<5E>~BZ^`aEW*CKnZgc#2}N)uLst)iUC@zu#xnM~=1C|7p`2Dg)fP}W zf5cnlx-V7y|9;ZCOF)d*SWt=rYd!^6ljyB+h5+Ny+dZ2NPfmM2qZMh<1B>vNkcBc5vp*O*1KKY}4a2A7cvneS%XZ9s#b%q?m(?(e%sv|;CL$blAl&u^x1R{IZ1MbCY|Sa-tk~PeS!rIqWoxTP59eRn=*0;{nD*NAhRAmX#O!P@`tlu^oj9le zorGL*S|KMZ<}t03?MJj^OrkKW*$Qs9f&xsx7|#-RfqFou+>DCS6~-W05;n$w4Dw~_ zRqU)3{#_}z;EAr0iX&Y(?OU=DSfm4S3op7}LbVHIdX@oHWjJb4!mkXRV}-Ti@DZ)Z z;fU&^n7i(dT%oQy<6875OCI2HIiLC)=0$?baR_iqG@L#wC8sf>DX}OX#VUrVO0){p zj}>k1>#?H!M%Z$t%#deSu@t5v$MYrzrj1*md7`5pFo)&HwKoxbIzE3{bWfho(F(y_ z=|+X1%<&UJP;5Sn%x4L7!AYgC>lh9gh|mQ6I6skh(VLtUZU@Qu0jxQooMB z2@Sym^EfM{8WYyQSQ8fVZ8hH(@NE^}=F7}~CH^KS%#-(3@~-k%%liWC@6vvJ6KK7| zUVHgS9&Bf)mVs{N%6hF?k}YVOH<2FlM$4hKJp z#IC9u4jx5IGg-;8Q&Vbmp0_Kb9}ShO_Pjo`>gS8hm3D@AQ;gv*~e$!1Vh_6S$n9}r`P-HcBMlAh+EW%tVUmN9M#68 z^oaJ5xy5Pj%Roy5{6G=81hX4xv~4vVRHthKwL0VKMsZJz@vz2st}kw}_7mUae#yI7 zF=0y)4VB@WP~pA{t?P9s_^=V@3jKB-^a4@|FZt>|j`M|*`sc7Id;74qNHqBU*<_#g zP#9VL4nRc4#_&}lYRXci&VVc~EJ~QtvRkx;mtdlZ@x2zXvuR(Be~My~?Ld8rERT^{ z=uW`j-uRdBA_=*`QK>u4_#4*v7CEFzjC2z5Esmm-$Q0a#!snv(&i6kFO!4_&mE-;S;z zd8GdicF(fERvu{JW1CTqs;m@bDM#irY!Z7rikHq5n*?QPG*jAzPz8`OT^ zyR_doVfb5Uz22IM?kQaLQYJ(}Xv|puRK~-=V=Wn$oqD=CyNufr;IK44ARQu!h0&a8 zz?LfTrc}|YE#$}g(E7o@SX%!SZy;{>1iuuMhH?^K)T*uk9J#bCT>4L{(R!kj;J}wq zl>|x46*XxZxJ%16fC$#EEqqOx^g~gK0ig)HN&w9`(#Aiew5nf#C{3J%rNLiRW^Q)h zRAYP$`Qd}Uj(odCK3kDLD@y*W=cVNp`S@7!e*vhNxkVrL9kumyjNQjOW$*WIU^$c6 zswYEi^jj)=5#W@0KNw3lffm68fsAsP>Q=rXs}Pb?%^B2C)y~o zmwrsvNubl$9ciHlm$dRomK#D@Oj`|&q2Esf{jY1QMTNkrNV8d#`6=o@Mu|9Gx*vF2 zQW4J^HOWo*%E;=1!+-nSw~_R|GfO(3I?dQFx{jR>Tk$mn*AP^zaXeF>j?*cAH@t^4 z5AQrv;}W&=>_B?Hj?d4^v3%TI3#kK@F|D6Lg}OC3%QM4 zp1ikpmq&j)|I)X;xw|S2?==asKFMvA<;iYYKI?Tf+O4~wiXjjGiL<^dcR^`aHe=2( z;O~E=)s-M%TJ|>P3|qA9ceUU(AdEUYwCwk^MVBLis{Q7nDm1>83zaR`6}qQ;^le(z z2$bfB%Hurx9?zPG(SaZY)*N1aU{M|BK{9)YlzM6pt@FHBR1>xC@_nZ7Gb-$Z`>APNhz7p|X;|-Z* zqVFB#7w$x+VDD4w;CHL2^aOa&vQKD>4&j9guPJp;KjOtQ?B!?3T`LR#0q3G-)Cz|l znuKKvknw1RTZk#`X?d%i$A3ivgEvk z+#>Z3ST^v&wOr9VUM+j0w&>G%m=nVPJdEejS(n-zb+Mj-yVxc`ZNPEVL#pONL*H?aY z#^xMqiF9?WNNrst!7hR+$-+`df^h%9XUvf$88)S42!&9a{XkMiQ=wvi}2pW0( zS!iTP-$isZZ_*mJj28GO1d&wzn0Y}A+C@XrOf3|DcuVZ&d>h;S3 zjLa(fU4b_Wo$jyc>qgIy3O<&CdxCX|=YZLlwH%JDR0{Eyt?zNf5WZ|5GVCQ zaEN-;vkF9PZQcFrMflin>n?p8my;(d_gLXlj1Hfg){SND8JyMS!ZMn-pD8M*cIdG9 zL(^PO;n+``*-aPz45VS)Bmc{4-J9^nxl0D%lFw~Oz&6ml8!&wt8Z%Q@^MQQ*NaSuz z5K%oDm9$04SR6p3De*`}61Y;3c>~ATrkME*y+Y*Q9DMuF19kBdkrx1Nrdj*|=0ylF zOy`-YCcto%Lf~n@!Kdj?h00%-)AJ8}aWzIN8N8sCeIP%i2nCVFoWa2xLq%(`75wZj zb5F^*ew8eEe}xCjaiA0+^=%)h1Xk5Zh#&Xr?@B_#dR~3MBwjIb*0(($?T^+7T5FD= zR6$?GTr!!zei;Z_37aBd0td*kERw#%$`toi}K^kaypWWE(j8sxE`AYOm&#=sTi!4n#s z+J%qMFnjK?2O9~b9|u_FcD?b}$4=4)(ut{s%FkruG}-Gs_Ikb1n+cP?5|Uimh;LMH zfm@RJrOXT-|E-FVy(v%GGvDbsD&A0Fpv@PWlh`(d zr@v z>j{2*eSv41Ka`Z=!J!?G-q(+tCk9#M@mV-XZL$-5{!aD{I|-D;tN@9$Xymo0?) zW@fh74|y|NkdaUblzsix`vP;lp~8Wf9PiQ%SQ}<#O0B_ALuz;q(P|Wz*?oDmjZt$WbP=w7h zFU8lglSc%H-Dt1eS1{oah61~u^s={RvW)p!p0p#to8GoD=N5)A(s*yoM|n}j{`5cu4HcrUAQWyNfOXpqJ^2$G-} zn|XEGqImQ$iubWn03+%t4Zjv;;2XP)Jy1rWJKaX)TOWMNp`Z--E1c$QQ)ORAVrfh0HBh8V5^ zVU-EmMel1FC}TO7lEnl5tcp^el_$ZApp=r=VS3JI!7+O&P{bpEb}c}_Uek;m+7B`z zq%Z{d^~S-MWZHx!qYy6HOeMjnVQ?iFxN%SlepYR0MfbCUH(aV!A^u>)H5!;hG~ms1 z2kWT_?WWPAu(wcvb7cA#IXgt*%Kl}%=c?S5urRpRu8nd02rFpt!c9&b4Z@KOcmi}# zOy_yP4BKkAgFVQ?l=5OFO}S$MRm3O?_$+Ch{b#g+a|mP>Zp{M`!n76N04S%-B`(!r zi&CBhS;iV}lxHzQFU6EM41;kw?f@zgI4UpWM+N#RCEXixM2o|SbwCT1uw?YQ=V%!l z;Sor!22$16_d-d^*pdYYnZ;yttJuu+YZ zdl;Ilo<%Y`pH}>+hPU`BisdKT@Z3-6D-BWFt3BEF1ihvDp zumusGTlj<;+*1AyiEutM1NEp0X*RbNcZFC=Z$+Z;V#fbKS*?1ZN5L!j6dEE%Nw?EKJt3pSRB~i2mvfuIQ84tt-ZWLe;2QWvc z3U`)P=s5r9Xpn4U<^b?|)Dz0L3(a(Vy~|S@2es@|;3)tm7A=u62fYS|9HSP15HHHn zQI*A@vJ7y@>ADn_^TbiB5_85{v34b9m8jnr`YKU2ny3zh);=#@9f5UTRVwWb23Ze2 z6`*uF=s`t}%fUaKj&l<%3l0Y(9*U}+3?0S<5GO8J`?_VNI23LOHPL}Cb9D29xCGnQc^*djpN=m6 zu;o$FgdDFanJfNqnCd^u|Fk@JTL0R7@E?@k@mLMHyqL)q&0l3gv z&Ie9|FXXMkqzwSszgOsxnkZvh^5t6g2PUb)aHRSv$=KSNQNxUkT}ob55zK>u`7^l820U>@g=bNYAo+%t!CXu! zN-=9=6hk>wuHcG4)iMB6ieZFP#4^C{lybUWOs9)6kH8TPf&d-Dxmp>(ILR);td7Rj zhLHuV5Emyc;@mJGf+JF5To65jzC#>X)MsHo8NS2uB;<#mkU5m{GRzGj7suf1W+w|q zoZevPT6ld_g{G=8grScVJ0gGw9kjdjPxMEvYA1lBLm4NBKSP_U@k@>W*7#KfU5Y44 zbX_ujab>2?6JY!*diJ#b*JbgH_QgoiS1TM?2Y6wFZ5e>LR4K|J{N7p20~-8=Z^d6V>_N-)Xy^yo0G-Pc z4t4^IVXo9rJ*)yFQMN%Fd=SIC)sFx*kpq#r?t&RhZA6SR@G?=X+8W%@UpfajgoeRZ z#;o&1*vN${Xrkg9o&6VRfjl|2dk0nXZ|H-AOg}$_#?!G(gvTJmW4D+=W^6VG8JyfJ z<^Y0!B@y7O5L4oE6b59%Vf-p3945}iFgJF8l;BL0Y_n~SEWpVMbN(`KuKPNhR_#<1 zCBF!X!BLKYp&H&e4JvdF*3m?Tj)8c96qqSa*{}6Y@gD^?tGodB;#K04!9kqkupJ(2O(in zFgf&ir9Ms>O6f!Z5j3h!CjC+nARa?8u47X#|Q$&C% z05I16S4Rh&vI}mJQ{Qwx0g#CILcZfU(tP@H59|#{`>^{E#?uR9V0qr9c=|$K_t262 z>y7>`bytkyb==cO^Umr3@2sBAJF5YJkDmB>QU$+`nqrjU{D3I16jnco5topM0?#?~;2JbC0XskC2Odz)jX`4Q(IO znDD~Hl920{3#^XsB@^(Bj2{emU8t2ho)+ScQbn9b+&c5SwP$|}!i_{5Tvx;|ggWCx zIB5J4$f|?klK>JKhe@Sk>X)%Kc)&EeKBdYb_gOF;$LIf*4%y2bsUXc~UwJY>QS5jX zd>9>1)3M6wSst*LdrD<}+aa3}{Qk(NzYdgBfYL#|ac&2N&vlo=nPN=~!Ap(j{z!rG z>Syo5KYE9F{JVwL?&e^`cl=ez$*(d71P6THeU)d6oAJgN>t} zHN2u2^@gW_2b}vF7D|iW2njT}NoFn%|D5cDh8q5SHGbJddHkgLYk5&5IcP<0C<*a@ z(gNKCEUqxU{rZccdGGJq&=2kEMrd3JeE|1Bk}$6M#C@two}O=n#>$UXadBjt?y372 z7ecpqa1kpnoyBd?@0GvD`%|sUpmBjJi+JlZ?mpeRTCP!L(*Al~^zO&btDkY8Wv~ZV zZ{~**>?1-6aY*B?6~nK8Re4jPq4K=g>ptJrs=1sG9>=YW zI;L}aqjf9ey-4A<)Y|^glvXtssgS25_ap7Lll+Eu;R4hOE#&39<>7x~itY`KjIR!R zwSwkgByRo&Ub5SH0kmk>b8Iheuf*}2q;uuISn!25-9kxEyL>lPrJa5UW3$@n)Up_! z==&Vj4a1H_{=@6O_07?na^<>iAn}DBvX^)8qFgp>-|yq@RCP`6i8Ec38;r!<^PTp} zy-m30JEm1V_Kg@(vNT?kyG>p2o%xZs{3Et#=WLX|Q!tREK2FKx=c3#rn*_7{~x9P{MmJB7FuNtyy2*z-B(&{_$Qkw=S>58F+yoB27 zfl=Mp^_jncmrZ-iH(R7c$WIBdC8JE;O=r5vFjZ?LkK&HsAd1P10Yx^;M0l-ySE*6fI zN}4l&*YI=ai3=a*rn7(TVbh6omSy7K@t*X>8k{WMj} zSa)V4`NtD7^{8NrmkzuiRWVX&kbp4(LtT|J000GalFkYX;CYc(Uv2IES1vMpgIVJ)IQ&MZ0clMn!B7=Olcs}tp zJ}CHlsc*r75s1I==~zh>BVY=|4ZkAd13T!CQQ;OE@@}xtz9pZ7mvCbujDO~qUeO-N zgK4nKnIwF030u<2>i7q^65>W*E{R8%+ju8lc8ukslr^3QH=a_ki;bvaguYx(134CNz9$({=Wi!n~KlNeQBTj_16pZO_;@SU52ZsD%>LxH2rukgao^oB_<>K zjjjhT0NL7p$!2j4zXn9uEJfgun;`9!5n!0qK&SZ9Pd<=pMQw>j;o$HX$IpmUE9TTE zZ2aCtvS-05!HY``6ZY;~|qUlbSP2!+el#g~w&Zm;-bxSVcpR>r+XkaN~ z9=5=s8lDfLU8YF_M<`L3wvFKT31BFsKbK=#jJ#Yd+vla}(%M`rYNZ+4nBn(7K)qn$ zoCuEqO=VzJ$4CuqHz#7RK;(K2w_)Ofmv_;Xu@9&E@kx9$f!>hEPyu`*cykT^LNTCe84;YF zbJ=;IEs=7}!GSK?7te$u*fb2lgP1=Z1ThB$SPGI-mad27_HEFpNWQe){MX5 zfN8T^Dy5?cDkww6vJJ>Vqyv9>pdMPsxZDDA{0CoChCO~4LM!Z>h~12F4!ocImcgZR z$GS)?7^)(A49!ONW1`P~vj8?ZAF71r*m;4@6%WQrTF|*7bBKe!_AppQxCV;cu38*u zByfgdAB|OlmM`iTC!%r54cI}(>%R~`k9aB$>#|RZScn&;13$v733#|J^J-%T%m*Dc z1^|jedbP4`{KG@GMTi`(gKp6ui(A1Z(3h+;rUE&b!Zaflb->DGfP4%P_KylMjEYF2 zd=R8E@J2(%r-?Y-_&!pXf#FsFm0@~P+zMI0noS;PHS+x;;?kyQ$SD<}&jB;V+-Ei= z_`s0pBazK3>OdP(9c)x| zf;^0F#Sz*5h46?smww`vneqYObsCWS_Wj z*4Orli=W-){zrXczmSafiGTg<+xCh3K<7W~6D2_YzuG4vfp66(*au?! z1p7#t)hE_J`oGvGionqSv`-8ML;uY_(ItM=xxe=|4>#cB1&$R(FgM3`u*uMmpI^pc z+GNIm{Kj(_#n2Numy^IgHRT#|^wD%`a5Vq$h*Zk$6caI=ol?Nj17q4&{+3)lzR*J_ zJr4>_xff9Q&_*_h%TmTm9gMR>wW@d(?`fB4kEhlQ^6c}x#vl*p5Bv>G1bH&xw<EiNPhIT~rE#UMe&_3CpUjgIDpGMC1c9>57|;J%TqkGW|3z3QKNN_I>lV^+ zN2VjzV(ou1p0n?3<2g_Lx8gbXpBB&Ysg-==Y4IHVpb~#Z&2#L4#B=ytO89*xutl3W zLpTSgT}PZbpo4h_8aL}OS~Kapz@b|6c%RHe^XtC$7mxIJyM%G-fGEq0Xo&fnZTRK1 z5%_%#{s>Q92Y#{bt@3S*QFZyfqu~DN&mAG^qvNM=JaxMeo|BNou|0Nd&Sf2vAl(*k z`4$zW+id=1n+b!Xwi3wM5)ITfdhx4k(LjxTn-#0Gloj?^VVnceXdLX$9UI2kXh!5d#5DX&VVvu&h|9#U3FAan zZ-sGGAeEmk;>Yx2`(8d`sgZ|(s&l`9ZC{-bjpsCKw>E|r#fEdD*f;c<-yqQ(X;=%p z>dNfdhXwm3<~~vIfIWoY2T|Kwi0?3-^8=>@Xky|yfBJ@a&N*j}=isA5*YFefu|2wZ z`lV>d0bedoN7JpN9rT;3?BPOrM(v^3BAKwvm4+Yw2H@3HRn}%@j?V;jnd4)5Mr$=M zR91wxmWU0;K+OAxaZL2Vx@1`?{d6EGucD5EWGt`Q}`Zagg|n8Cv!QBKQ85h5515 zQNHgtkw#$YiYYLvj z@SKS1+@-s#&$d4>UCO7Yko$68{HkoJ+b6#$>-UGM+{*##3oUWalV_oOF8Ao>P@I7A z<3rdeR3M}vqPvknSd$dO4MJ*;Nh-i67q^szTY%q4B<1rck<8Mc-5^8;brPXmb4_Ac zr3o=1g8b4FI&Kv;f5*tG5HzEbmf4iK$V+_7-iG({sVbe4T9tk&E!(ZYMk>3qTlHvHM(G$m_ea21#~6Xr>{5eL;_v& zD83ScK2!3l(xD;@P7s7sROAgDggk3L#a_(DE+xl>fWdhPe4&JJ4!WgZ2$UMLu|Oq| zN*56nGw5XRZ;2WwW{f+yq{co(!c%B)$xFnQdkAurI&T0mDBp20_R0cu#D6rr6m z$8XJgzmBQrVZAEUqxS>LjBTVma}RAU#)qOd{G66?P}IYAa2ymQI3SV+qdE^2XxX$% z7H(688??u8Le=rb1rP_jA%x-`|Sr8)*7}*OQ|L6jfqF~?! zi6;T&k98^Mewg5>qOk!7c`tNK?E=)SfZ$SzBoXDeb}4_^Lb5oDgg}{HfNCrx6-1JR z^4?v_@3oNNK$OV|fp$+KgGyc6f}1QP(}@Jml=CxF5r@4)BiiAKVU4ULyKnOGv2~Q1vzf1X37Lq5TNC=b?12p5OpaOqR1hkCf z7^y5#XN(gLhy@2Xlq6}ix4}RF*f(QfVH_Kb(s?|M@R?DFC*1QvIyd7XeAkgPzR+V2x`58miCYHvh}=5Ade9sdIx!>HKVhXoM$T4r#$vqEd_rt-Gw_CB4XP8Mz&XH~i}Ra==)}+%c69 z#$(Q-K)u-7GTwR+r&9QPZJqN;ku*BW30#8lC&F#UaU=OY6+@Cl&r45g86Sb$;m?6R zoUrmJE)lcE%@GT30=OC`{><7xLXv!#=Uck@T2)CrqGK2a?1cr&_aL_HJl=LT9`9@$a^FIsdadKuE zUOP!!bhpfvWsbSl7=mVG?HXKu#3>?-2_L?~r~0dLt`$a*AP%hzyG_{`b+rYf?s$51QoA+B;$0eE-Zt6B`?5q{;!z*fs1#Yd zmkGqns=k~R%|o?8EM@%Mg_fyuhgER~>S0_hs>c)i1x4$5h&Xta9kdbQ#<)=2Z$G$1 z33m^-K`{su7rmopzpVv70Sb+uW^g3O#G%4K`$})&Ijt!d{A=@2JSPGda>wD*+P(ON zp@>gctz0C-&e+dUK}LE&$_#LN^lz1$?iES(b-+meAV4axafVohlFk|8tK$BQbe31gwi0EW5D0(msD{=_{ZFy&!H zjz8a@E*g0gG^v>;d8&EfPw;N6m_rgFMX|U!3{Q}O&^Y(-=zr-yv9ATS)00c}BB@TV zSd9GSCGJ+?g{J^uskA{rI~uN=HUTF5)tqw-(U6CXMDUN# zLG|@ZfiA4K_(ChB&(i$EfZiM5u3@?4G` zcd`s;uxF7!tbe3U%AA@!&2`kNfVinrcSi10BD)F;PIRZ!KcM;>vWVh9+)N~!1nF1_ z6UyLEf5w(^u9OmUB}I8@^ouT0z7Hcja5*L_Rve23w#-o_Pt}RC@NP^~?1&aihYSI@ zET%Afkj2zUvz|Yu-sdH#_dV33GX~R5W+NggHdETjD-Ns!MXDjPjLE2A0`huMpIn1* zdu*oqHb?SvJM(c)RI)Db%wqjHl9?Qv2?vOFl>Fl}yAT^GnY+7Y7D?t?%zQx_!Ur$Q ziA422t!hi3POCxF4rwlC)4GNSAUl6qFrB6(yVI~WG(OA_Grd=(lSNL(!Or=+Aeh6* zHWOL~N2>NF-lD_9z${%d43x4JQ}zqyvXnjYOkU=8!NO>;?}L@Dj-DkL_Fr(nj3R%H z-(A$*PvcigjQe(&;~?gu`xSZc0n&=-GP7%yr36gM(=Ezbq-?r#j&VX=5d}Ye74_4H z7gjTly(d(cxzmt><*B&|ywox`yFL1Jq1y-HIYmaK3c55cw0@>^7RRSWger6FlBcrJ zNAPaE`4eSns6sVDslX$jmlwM69UDJS6hO5sv1~!7#M$2cfK&jW?%@9|s}| z05S~W;%FET>?J>FGhUk^@j=uvQo#SiN6 zTm^B%ofs}CAKy_`U!BO-;V_9Z<4Ul^+zXLwb{@FT+z+&c=0~+*kN)9l4tAgYNC7V3 z$G9dR)LV0=*SP$H6aE~W!_k6pmAvD{3l4sVVlAURm&bBI9;S6%K3OSqt{~I!gD=Yy z<5iYcy%;+U&^+QhMb6!$W#ZZtnTbq)4LU7QptnK;ugZYME(t0aO?{!Kq+5*YP>VG@ zo&Y=M!-J{O3o>2u;A@a)q$hX^@p;G#?xASN(OlxSl6%axh9QG9@j-Yp98CaUXqlUr z@={9nBFw*xe;p#D5Vc*z=5bMJ9JEOWK%}UYb%N`B^aj%Vdf<+W(NW;++fg@$Dbff~ zff3NPC?bFa>i|ptM|9UoFaeEtSIv;dY3Y!$v{Cvb4pXtmz_hKY6$X+bOh?S@5_nB; zNfn}P8^wb2kU$0J&4r?@S7i>V48Mc{>m||xFb{wyzp6SMXDzgR=yYT?B@f8e)9ROM zur`~HrT_(yT8tOmp&KuL9L{38uO`JQECVsUFJ{?l-U8qjRcr790JTn~T*aHJIpbL& zD=#1%wm_IzE`a7Ylv60a5PLzgxyx6)#I06du!83#x76}OWhxHHeu-g6tMY(1B?0e? z!tew4X5Qzjx1a#vzED;*kYF4t@o@IguAWkw%+u2dCBOa}U2V8dobhrHG5@tE+S_URVyk>=y95oN-P-?8c zR|XqEplE;#5`i-{O&-`wQpJ0a15o@WW7(x_=^{j;T>~RR4W|o{#^pc2z<)epIdF?A zO4%e&f)`;owgf&M-i2NtULJQ*Ty07z_z{&FWMqONWMcZJh<3fl1gK?V#8Z@=uJw~2 zD<`^G%o+`rX#5^%=vOO|MTcrm5EosEg)wQO&78j!C1QM9f~Eyaj(lWL!C({sWU;u; zcml{(CX9S27*M-k+L$3_Bb6gki&#!ZWU6O*QAIj5%%~AG zV%`lxMdbE51=s0fKI$YV&o7Ux^XMgm}N%tF{&6INi;^% z4hyaah%1%2GNZU2Rk-c}E;F7K-7gOA9fW)EP)G1{S%*)}aq%U)eqa2>CKCQ4hND%r zqCqLXA2I7Bf2aaeYHTz2&DkM0pWs`V{&_GshX=@X9H8c0hNHbix8>s-SHjZJC_73d zMkuK`NoBz(SQam-LBX{Nk|C+VidAk04`uLt7=z~+o)KPV@I24>8#ZDElH23yLXB`) zgv%ftKIKBB*yz1o9GE%<(jp)8mNlb?!DfmW7s9u}&?z=pm;1$_c_VX5)-BTE&1aGM zvEnD|Se|85 zyT60D`-}8oZu_bu23c~%V36$o4`wqCVl!f!1S=Ufqt~c!BkRSE=OHn+M;1d!@W=K> z>lm@5n+-^Qyj8&EJ?5J9#7PkCJgh zMa^vi!b3O}=5q?4m{L~2zwVrXT3FTiA+fkgAHH7w5!`CA;}U5r*RZ9b+v!;6%3Lf9 zsdxr0!oY!CHEl;t_fm{}m=eRgkHp^!IT=tTc*#{Gz;U&?Qs9Jy`9vX7;BX?QxpvNO zp@TZ=Af1KtPysijqhN_l3e2($rj;fHb`aCc0gHLBz& z;kb6EPXpJ(tM5*ynPEc}fAMW5+@JGkXEP&JgWFql`886j?_p4j1}iZ_!@W6-$cB)B?1%6GUq_y zxy+dYdGcx1t`0OSZp1euYe2(T+IBM-@|FD8c@v75ns~E5D4E!bG1{fEyum%t+ay z5DRxq;QmK87COmSC_yBOgXXk+DF#}kI6G|x@H2wnxcDz*9aR%!`kHDY#BM@fscAOo zf#*d`bG`$`z}sN;k;E8+gywjehy?c1!H~ST`NHTy23{Du_!8_hc0v1L>_XPeFcOMD z4!CqMdcmu~-KKh0@x%bpvv}kbE5#`{uzpKyjZLtzF^;+$ak^L#Lf$GBJTU{3{}b#F z;Md21eFCrxUIuA6M57(eSR6v-x#QANTILul`Ydx4%Trm99q)#Btf+R0>AGdh3CBW9 z3~No702&=5NCV3)@(W@WJh6q{n6pqBeP`fp!ULvNXlMC+i2F^r=1{)K3}d&XMa$ly zJ(8Hj+6Xpqbikw#cBFa)0|2NDN{@G?1R8%RRW#b9B$ftHp+9w_q_&)@&lXD0SW-P> zlEj>wvu){y>+mvBh^C)LG+PmM&Qe4H#%L&H-mQqrY!r)gAS-@KMlT49Wj)3;8Xj^n zr$Z#R6@o&U5EN06-6A!{zYGCUce6GN1&o-qTz~qnf3F^!fRV#LQffc%1f>w1i5as6_aq(t159`6XWBOLC zCb2^1s>SSzyRp)V^{py?g;Mhc{n-cu2L2#F7iam=V2KbZA{W+`Ip6V+?K0O3SPc-S9PwH zZh(oY;soZ z^>XiRd%3;d%G+8mwH5+W!B$%ktN772D%Ooui(+ZC>c0PTW}f}Z2JHR)-UqVt%$b=p zXU?2CbLR6|y-H|&t`Xiaq5>a88d6MKswY@*Sj{cHMO$q^)~jjrB}AK4AsWOJQkt>I z;1Ce0lA{+Hh$BUH32hjJeQN;DHRS?aB`ccP>NvRs%V zqTHdQJ}g4XfrPf9VmTXUeTDu?4gL=@rJ+3ueK!V32ZO)AnIM7LKUY4&gux~SlMlUb z+mr+5zuJ^wIihR!xz?ubxb7Ye$GEu}6Hs(%f+(eE#@MrV1Bo5a@M8#8iB?NZ-o7#v z$ZWu0IsMh)hsBYlkc~b2%1U%`y%hCk63e^rMq=3ompVlXp-wTt?h|r?|7n)v;F~rXD-?*X6!MUe+id??ka#4Uyk7H`?127Eb07ymB!spcC!Ns9WTPkvDff~kKeD(lNJm0a1;-=#cK=APm zytQPiVDqfYfdfo@9XlVFauk{+;!7}wX(s5WfFT;T(7+^KjUZBrjpuL~Bv4?7fH8|s zPQxRo<1+w;)(Bo(&-KoG2v!x`CkVx+LQptsJ^Sd&bhLC{!NeQL0mWx2{1y?8uj9N+ zAinN^V)KOjEV~GuQN%8#X!r%;q zL0hK2G#Gl6c#rm-?64O2>Q&S`5|Thb^ie-F-q@U`ZH;pTy~u@@7(`!y(l~ z3-A%mG`)NbWumb$4ZH!P{qjXSKnW;jyt3h@n7Aa`siO4cEtHssKj0J=7O-ry`Vb~= zUR}sZf#$YpZlIz16K;ca$?zl7i^q@CESwcx=hBe!s>l|iNZH(m6{AKPQNiDklFqo~ z+~pG}hu|tS?n%&q6^u4o!Dz!vd$Kj<`Z{6{I7flT&4quZZiCLxyauL#U=e`jf(CFR zvRt5@YZAmYOxuRSAfM+(edqA`5ALmg282-}@ZB4EqAVFuWz>m@arAGaZJ)3(lEo=D z+?~EZm`<{ib#%1yZ$to$?d0GWf)>2Oyc%8eF=o|I14JJuJ$;rWi|^Oq^Hn%1jn4^e zr@6?~a%>>~7P6(U>ij#ht=yWKiEC$4O9$VnYCctQ@RTmRK3KlBB%_o*v2{u1)?2V^ zrLM4Q@XwW7mzyi~{&Lz?T)wqe-I_A3R)q*GPu+Sk?E=ok{SuE49~_xXo|#wi7UbEL zNyFts`J0ywE#6$YwFDC{C0P`Ztingz9!yi!ivGjN!C&KgLWh+;;Fmt>-ag(%jdBFv z2EEYJCXLnFeSq5evH0@+v__Qg5tNV0=0F*FpG`@5DSGBUfcXnrRIWmM|KTK*&0M+F zZ>t{4hG3S!meYzeb1N6>K~dDJZiHZf@aYf8LQYh$E#ZP~3H}XptPbltR4A;5egnJh zLZc{9XnSzVxN^nJANGfm_Cdgu9_&S>`wx?btw+{>Y8^A~pzDNee4mh*Riv}I6(!76zRJeZMbe9WXw7p)zh@0*lVZnL{g3Xeq_cbF6tL$;X|NcO%- zz!yBjq)dAV`8;I-fY*x-WSxN?`~iZtPCJ4Snon#L$|Ypq4{UTTb*bf)?Due7^iAB6 zbdzd)oag*O&g-DPNYMUbMgNhhn7*qR!e;|2hVYF=wAAd}{Y}UNZ<#twLpCC+V-VMy zU|hLs&ddVXZm50eo)@50_^#ZwAEQhdk*=Em1!nk-Ss&u{Ib(f+Ee}OP4SLb_HfZ~H zXiI&;rNDwFNw;#N_os_O(${|mB*7oNO^l2q zu!s6W;(K58btT9l8R2SG*esvgz1VKdnVQ*?W*@{pRFr=zmS~mSnxbZ4Kb2?kLDYHpG9A=>>Cd?JU*L&ThMB_?LK!%y41cft*x_$F$!=x>$O?4IG4$IWrua)5U* zGRt!WHf?+{kY^djHLa&7#zu0*%|~bAKFQpgIJUWaCsy$nKFpH1kf7!O4BZw zGT2FK2w)m4$r#i-zwmtJ4S=qeuM}CO$WsYDt}3E;XshxRQfZW-ji+&fBPa*c9qa)I z9b0D|Sf(mli_({?P@iO^&iXM5g%95S9dNWNQj(#;PfCY=(T4^@cKCzWDar|K96621 zGdzgA-7)w_`_L^($3Jjb{x->6yPz0=h7kLiTwK>CRbn_15BAR)>!cPM>lyoyA79`-iO)w;{_oo@C+$yzPYA=g7Bu7g721f!FCT?Mg9T4l zsLJV!Bke`fhwnv>5Pgo>hd|(arFq#Jf%Lt|VGLG49R>=qG+oOy?avS$3AN_U{}&$6 z^(%b04}8KGcY}7z85%b=q+Em8f)dy{;srL<;H+yvl5ya7=wd_>nEulS(O-&>bkg^Z z--`ZVYcNcq_}(#dZybGFbBJfRN7Hwkpf6<~f{1TJ{$!@{q@ZyKU_siLMk9`&4Hj%H zX9*b&*rI8S`5yECg1*!9iN1Tj62-r-!$S&hCI}fkYwv$11>8J%{Iun)An+8D2m&z= zB3>|ZaSYCSd#R-GhG+`WcWB>RX8MlVXPpcMdo?DX;7J8jNIf;7Te;1NNr}~nsz5niRR-mh62LEXOeyxO2pxlUz8RANG!Fd5 zNIaRp3?8cDVg8K!>2M7Xeo77GxPA7A4t)J`+!w0fk9-k)_{3ZI68L+lqj@y2n!jfr z$s7%`Zo}dPYnvOdCCOA~uwqI-Ux!XHN( zlEEc2HuKxT9`45P34?p_*8i#AIN(N-jkxjmvB{jWXfkrPykEJMrZ}L16?iLQ|HA;G z)z!+an8>5;y*Bu9Mr4#fFbq4IC_BpKICK=opsC;&@EGe48gKfo_}0t7wF;Cv^9;c= zvVj*2Fm1~wFuf&b2Or-6bE4dM&oE+On1#wz%V8$Lhm~gX;b_j6RwM+;JRSeKS9A865aDzQ9L*RPaF?eUvOP$`3+<#=nHT=b8`88 zpA!wnfguz}d>?ok7s#}Yg$5-|zBc$xobJ+u1Cj{7WJuw_8~O05DdXk<9W%^2GWq~q zvd>4`F%!U@G}I-!Vls_LbD}e*SIaP6J(sfbYtZ%uYOzq^qdU?0$ng@U;YJr>Afe5N zlYb91ezgD6IDbFUK;OdjLGMx{+xQ4xg1;z+J&xX-b|}un;V+tfp-XS+!wC9fN0$K7G$+tb{ge_ zyI9dvUva>;U+X|feeXp&s@x{oo4ilJeG=G4o?-GN=svh#I4NUtzc3;_<&;e8F}Rb^ zdJN3fC+IQWwNa0ubxhJy-zwM8q4OCpL?qm4;0u2=6ahBuO0O9Fd$`}=Oc4`(jqIl2 zLH8murDzTKT0!F~(vMj*f3UUSy(MJSF1BIw<3~efNyp!_d<4TZ-s%N@DgBtJ%LVqUJ)Mb1@ZM#t3Px z2niZ@WRq-Qv`m{0VSd~xR8Gp{h{ZzwDOFljE8aMY=5P-Es?j)*k;)T;t7&3zbrB5* zjT;{#%MRJh1(6klf3&=>?WyPQ4%4_e^@i}+*3?}_A8$(S0ht*0rVgH_>)fF*`j9KW zER9l;@L_epGmwo3Hulsi=K_hK#!T8OlSL{+qip5PtGDZjoza`oTcb{&^e*kVSwlf07%Y>p(#E2 zy3t)=Dbdrqo$Q0r0eJgAO)?Iwn+z*@=%-0g>X^saTcl#LXBajO*iJ%WDk=r>kZ}{8 zy-!(8B?0F%;cEJ;6c)>nFUfwK7B`1WEyuA%s^BX?6mX!izc0R39Y3Br+H-|t@HH}b zUMijayuoZefNEru?rqCGSZ0XP%o&ES}LTe{8+%Y((XR#mj&~ZZ(3yz3_m*gG`s*dfYyE!Z>gd$RZkz10nDo z-=Mb-t#kEPn?7=D%`1$Sb1;f6ktmKD2j1pndk=iNK&EFJEIIw|9sDPH)8; zg^QWM4>9aUUZ;2%dI}zjHTVIzlzjYyvt?)qkC0k8t)ege0D~6H3}G^edlB3# z1bHM!fs$wv#rLoyh|;aw_&#;cM_9)&ZhBHrfu-)8k-n(=L*&$bsIMya+JpN zS_66aOPBZQE2+HSgmR(soK^_RF&f&kf;lJeqT($$nU#H za1CQl4L9 zd0x+D67r0>t%g_e2WFV&>?bTaZ(~cQanpWmUCEZ9N2@^Evow0#TXxRO-7n;7JM*n zx(mUM!C#+vYw-88|7Lx!`&~!g%x|22Gdy2L_U(OSzsmD%5ErlC3oC#7h6^ z1z2YyJ3v_w?!{A$8yAsL4qL#~a}nDD_>SH?6n9+Y7ay0f&7lMaEV_Y+t1#eZ#7=nm%O~NfASK}Z?=k2%;2@)hm z>n0kgms8&r9DNiDhwLCRy!tVvhR)b_HQOn8OTId2S%)&mjK0SWuwefYB8(U~AsAo+Hr=DuP#AirUSI`+Tymk8Xd`VgR7#*h@DjklW|5Pqg&|Z zX(>@;6phiOFAbx9$5R=C3_X(}@{wfF_mGGT62xs^BMQWLAKv7z1z)6n?P2zwe_a1( zsVIARmRZg$c$kdv%mOxa3HvUvMGfr|pTgK%c(TuGyx@CVt*f8+asD>eJ1a_~J|%-{fy(DXNW#ocve)KDVpIpA9M{v?Laqc8jW{srboO74=pn?N($2a?=#Q zca66_Yfj5GOhb-Z+Up5;I@f}jtJPwkyEC8$-2MQSTP?Z)X~XHFqM`(#uV##%-J+5|CvbO{5r|L{gQ;Sg^RlwBRsycxT;-WNr zyHVVtBDG4LJ6FA`qO-^4Lm2{UtIN~wZc#m*>RNZ8F5vP7Dmq(cUqxx?>G1Zroq-Kq zZgqB%TD_vWl#^GjSXt_! z{FG0kc)5sYHRFkkx4{ijjYU_GXI?N4UtGKbpvzs5m!Dr4g|Nl7!S7t-4y<>(JF_}m zy-Z=&HQ5@mS=T`5id2hbLE*xMIr&yAG9q$Z%>ifLf`V|8Z~~5=mut?+wdCgIvdB;o zT>+oddwU!U{p(#_0gt!SuU4Y@s$QS!{(85oT@85E#?smqvsZV9`B=B1GvMk~-PA7C z^=l^PQo0qVi6YKYXYcYDzka?%p#*XH(hpyjx}M26?jFN{cS_PSd=%^tKt$~C5( z6`jpq=&|O2>L*PmWX7$=rqvQ_lKN%yUGMg+ZIgM%@%MuH%Cwwi;(8%{qptA;E?hAa z)5}UrZSfEXP{(QyT(3`X=|X&(AT21KIKS$fs+@H<+iRRR-n62=w2o`zLir?+9a#|* z=hGS10O6X{3WbW8I33fsqIgB6v$&#OBkw%%i8i0R)eZgL?1oY!{YXuOYNZ_tw%ya_ z^|r`jUI34`J3##!1XQ-c31lRapUdZSZ9x9iyAewqo>q+%D7$v=+R88q>J6$T$Gk{J zmSNEN*-_++1X>pgK8X%8svs&f?|R6G8x0zLQiPKAo+E4YzSXD4YUQD-9FnlBm8?^)Xs#(5rmo!wCg&lAtr=8Z%=PrSZT%@+5mR!wk5p{eE$Exvpn%&vO?XKqA#cPe**9?tGGIgt9kK$@s*X<9u z*0j4tzfJ~Vce~4{+F1~*y#du8jsk&%EmK>&qIQv5>_L?<6&>zCo3};nL{!vKkK4D_ z-I6VO3^t9(25Ess!cQbU+fQFQ?HbS89yXX%2+W=8!kog~!b0nUg1r2N?)mxX{c|kl zg$4OmOP)2xquwn#ais6)6$pyd`RFC{3Kp0bEX-eMwl1_r_45>OLsUGoC4XUVL4K}f zfi-VIZX{w_T0Kl9k~ZeA$_xf+3kvdcEcvf1^J6$rin+3?d}b@J6qf>POa;7 zdRxQq=-;bd)v5~}8wq|F)gRkDTI6UGRN!?rH+OeX8?HvrM>QNcD1w7n637Tz%^@R;*M?!>F8z?ll$4Y`~oN=tDH7(?}lda-eZPg zDsc%%qaaOz9&n>ruJ-l~YDK4%yo!#lc6Y}j6`Y~AEXp0r7%r!oxI!F)IJ|$d8B-a~Eq(~)*%CF$MBr&rT6c#R6h}uNuhpSVW zFdZedSk1XP)`bgl3oTYlzO^ta<;3YYVPU>Gr?9|k$%R!}Xtt7MiahQ=_=zEk zXn57c&sJ~%2E9KZOy@MUBH$Kk8mU18kE~)#m>p&zF^{5&GIP1nfuaxO{%nQMv)0pz z+_Grkit#d9kGuUERV(9stuVxtVwf#$9WLMPLO)FOTSeotdK#Dc-R)51J1*&1TPB#Qfhqgi3XTg-#(xoUcGS(Jyk25ReVy-s>Z| z3kZtl#gamBus1v+l_lsFv`42EMdN@d6pnC6VQwnR! z)v|(ZK$*YDo&qOG_hq@s^+V{%%Bph*vX~ahA=FNsm&u8Mi94|b073dHe{<@;?mBY4prL}|;hAo`bNY{$zIn%hjIY=jtc*ziD%%U!-`o1= z?sL+gD#MRy{^5OB;-jDY9z7t^Wl^}=*MDNkhiz|f`PtaVl4m0aj_-fsp|M*&qjbZ6 znA!m%T6uLxneiM73JY} z)rQ%K-AF}fPYqewC5hcLQ8IYssc3Zwx>MxA2&?eaQ_Vt{^vvc-#+uR zC2uQF9k}X^&7i06fU|4Rtk`CjJ>2u1d+_%KXt2G!sA^I6;h`n(6n}j`{+_1#n)$uI zFP=Miwd1zrP8%3dwwiO^8?ik#Ya0{`LI|g?P+zhOr zo`hQnH{%AxhnrOly5R093586UHP0#!g___7;r7AZR{{RP-GXy0!*JVhie&`u7~CYdhi7g3ezNs~6H)j#aePI|l<|YpAw!UD z#b7EkWGpjIS)bacEV=ypd3l*v5dy;Lz~6SX39PGPTY|yVud7Nkq!v#pH>5J278(A4 z4Bw=)8#4O!OAV^-PD6&nV6q!hDZg#_8v~y6#Upy3z~AmmLm{j!bAIFy{CWKSTLSng zz|B{LLQhdS+8OuR(YoL&Oik z=|C8@`K#mLEr4$a9HJh6DE?i5Zvp&p7%KR_18^I3#&WoVpZc#Pfrh3jwcx0DC_No8 zYEyAGOv1<^_)CDBplcvn;fLUV0Xze6t|u8naQeoP3V2yKw!kwJ@CLx|iG$|@J`8v~ zKPv%m%M67M!POq(XAAu5*FvFhK=%UsRXDsA_$#=^Dgir%aMQJ+&~M=?#Rk(ibj5~@ z2leF!btt*mkhLwvZZL0}WH%J{Pp&o8=-&XZ3jwklvWg8Vq9RGLCIKYN`6$Qs`H(;G zGYVg67@s4IuhP($r29V;;M3ihC?DX&L+yc1qLgEy?|kin;vGi3y%&f_eEJLGWngh} z5#9wKJHV%9#736;smahe2rmwY`w(6g4$nq-n-*S5^+e$n98P?$MEFjGThSL>fG^7o zyOZ?yOqzf(NS=?sUBE|uPAXi&w~h41COssmKY6KPdy@Vmy+L&tG9VJDAH=~!bi9Q4 zO^ZUI9$7!p>8cE7-AI~21tyWKe2T6S{*s6v_@U|~Qo@&sK63l@=*uM?Qhp#DQhuWA zyGuVa8O16aCqI=ek5mr<;2T~N3jG4_Xb&dc4zN)w7z*Ek@Fr}#IoHEe*Hd z?<2gcEEM`#Z2L{r-l_~u`Wk4L1noDX4?YII5!fdAvGth<-*Vu)J2AepFntcl`!U!q z50eZ=^h-oOBKpN)=+a*_IU#+byo-Ti2k@ykg+e!@y%N3$NnZ`=fp1$fl+vaY$Xov; zeUd)SkY$h3P^F+K8%bV5dK)$udhj0AZpx_L=x$EaWSb?9>Ngp5_aXiV6d$;CF9^Ll z6Yz#rusw+H22YeXtVyaKp*DFw|^OLxv2Z$aA{_aA& z;ObE5Z35gxI<%%|P}pZt+UKE=UqFlhEjRfVBs~l~+iwkp z{&C^@Tn7HXmsr0SPtm`aIK%)QoyQ+eSysl&QjS$iOFVo0kJo%7^5sVEkz961IO^AoecNg&N zyAygmmj8+5X&H5Q{~qQ)nsV4KA!eda!Qb=1SBNpmpU@r>>J4sBOARNJbhU;NNKO!c zXOeU-K#Bpd17IhB2Y|Au7#)UVN&186t;r^e)i}G5m18RGv#p`f3$gVSDMv((mKydZ z>8(1$z9gq%76aO{;BUL$ZrG`>FznXrnq>O;h{cFlEF;<}V(piW z_#_eVQDWs&F=Z8q*R2OGJEAf7pv&QAVk~R=mr&>i+5e8~k65l8h9;fU(1xOP6&rd{ zprkf*o_WxLBsJ*P!xBp!Pdo751-xUsL!oAgSLy@qryPa`Fs7-@&{k&XT5qUeH5vLOd_c5m$8LZQ1a1|T8_m0>$BBBwWkz4}ebsEGzJxWcdp ze|z;C;9miMsq}+FQB`4pozflB0o)apPPb0R(-7&_P`po*0Ioqi2k<$7-(lE?+8>5{ z6!{&)2>B!=VnnZNl<5;iL<8c8Xu*2j%@>GR42&G{AQ4bRmMRJzH_|~j#QGduQj+ed zspOf2$@*hPo1z!<38MebM0ghFFkXY3{L&OV@ieh)EJYuFXq@&S{0{t)EDQtBi*S=q zUI@=q3Gt9U@;r8THvB9UqP|FbD)Dj(@Fu{QN;w;6zeno50{zI0#P*&r(DQ*WA9|$e ze?p;0C=--<2r{3s4Yj6jBKxdAr4q%xmo+7Z8Hj+<3DMV%bVre{meT3aLBa{(Zvb%9 zzEH?}B|H(iOsqe5>-Aro1bHcjyyyaWAq}AaMT!QxLj#qhqjJ$h##OE;2HP{AA>W-T zu)oO8h?D~@N0!5ZM!W&G23iAj^A>at7|ou=3$zau_f7zI<9!d@y-Di~S)$E}0#jU| zrE<5Ry{VJIf4plC)%#t5Z~1*Fyq}Tbnv7FdPtV`J2zkkE(%JBY}L zvwM<_T^eH1vr}gyM}aBC&ux-vvb&@c1^meAMCnr$>e}haG6?!KUN^}As%Lu0l%WS( z()sC4v$3neGo)XmyNN>;1*RxJTK-?4IS`=XA{)a)(x1#e@Im^&NEP7{{QuvXD#{<9 z(WM4K$6VI|)jeo=c@WSGo(N zTPEF=(ruM)k90Rl_dC-4p>&^=?z7T;S-O9g?m6jBGRgd^CQ0o6C^^|?CS&bAh$ z)qFtO-0XDsHoLn5PTuq+a5#C_oxq{JuWLp^GBY7uuPjaoPY&ywXk>b5A5G81!Y3)3K8l4;RuZ*iy^s_)AK_&mq7G&+a%p4|DwS^|BA}MCE!`;yEVq zX#M@DglqDq_4BD9ED3Ve^pOoQ6lEd*!Ude@StsRFi(e<>_kC#Nm|vCg?~(CMGXz{) zv)Rq@FIVWxC-i9j>W?Iz?Po=N4gYHrZjP^w0&L z^jyQg;3wb|U$YA}8x_S(SdZ%%Pr7m}uAS04ew*1@XMDRp0(d%Z;yfnnSF^WX23%Ffx8FAbznHR)d;Tu*oQabYJp?9E{OJ?Gvlu>2 z*?!2zIq+BqZ)Fq2Z=3+WUgGI`Q{aIZ@UvOMk6bL^60AI^#lKd-ACLjNCERqkfb(1) z!VXKgk}cqiWc*jP__qo;&ut@&=A18v{EYlazvNdmS>_}(1?&U0Z1+dlyw+82_jeos#TPr(4=;spKU6ox}@ z-y!nlxmVDhJ-iWW@G=`{EK;~3Gf>*Fe3R; z^F@4K>qMHXB)o5xfPWzI_6XhI~@y$Q9F_h;H@peqY_ueGnyv7CiUjQdMPsY(h zYb}Z7&znFt7Lrh4I=(8WB^@{#PnwfxW@m*60XSp(JkZCsx8GI zmhrEa@J0#WzFOeX_}nGo=1u|UHA19$M8Zw79%oBDKalXgt3-U>>w~bLFS&63V?ndWl|SEb&YDd87kz(D1yX}2+i*G%#D6~Il9+q>fUd9{pxM&_&8 z!-as8oCjrmjh|&Q{)nu{beZq165i(!`EE%P0e%TTCgqd&a3N@$#J^ACPnLMTDdX2T z1s-0*M%ZD7%SchqD-*y^PXG@APJ9@P<3lo<5S4dJTzNA9XZe)&PqEBeZ4B&ZK!p(gG&TFE8?_)S#;-2RxfWHYim1`uf zTxTTy;UzZ4^qj<(Vvy}fwl58SxrBE$iukHdB$zMZeNsNPJ%CogNzcd2n~me6-!lq4 zGF!zZ@r+~(IPaN4V84X#wF)@zIRboG!jFAL!0P~`=M=-md-N||TA8Syy3$DexlHMe zlf$n8o+!R`0(b+%VfS|1I9p9l)=m)rE*ZaXx`_XPB=&&`;y)teE5#zd_*In0C46L_ zfM|I315Wk6J+9tgl<~KlM0{TBP!#1AhL4{Y`UAreA^vIh1^j_-e4(LPaXOck)H*9G z>gt_Nr3D9b*LwVzYjg%WoXzdtPPbo40CGB8yw0`l-ZeO4(n1HIov!X)1=DpnYK8-1 zISUpnumE#{NKTqc6w`oCOzrtLC}JwHrMshJ1Cm7foHPR&6P3>7l+Y2)oaU}B#o1`F zCOB2mlj8&(&eqNxGexmPol~h@zOKe!XLjav;Uzk{GeYh1R-%Xx%HaG}7w)A1vdV(`6%P9VuB)wSt#j5{_`kEZ#&e#8=E#Yf+U1_w)(N9lE?DctwF-VBlwLiZ^xBwf zPIQ{bQ@d_LL?AZmm=b?9gvj;O_|HSAC9lKf>0Ivib-LSeqNbM0C;x@39@5wNW#Z)$ z-PZ8&vYO?swdX1L(#jRZ_DZMI-@V3J;Y1D#=omGfvjQaG!*S4>g%W}~#eWENS*^XQ z)LB~XAOYgGCf_Bp6=h|0rS;BwdvRqc#fTC5mRJBzbov5{)3K`BUR6;NK87dGdMh+> z?vzoS9)G8+v(;u>it~jf&fJ{boC1Xo>z9|-R#nuODmcm-8`$N;8be%y^YT#XaChJY zdMp-ddDJGOPC40ZE2?UoI82YSpy@W_aBMeg0YxKLiY(McH;ziz^q@`(_^7aG8-kT_ zzf`~G^|+tK?W9AtHOoCU%c0B~a|^n)D`1>8PC6Z5+S^rzn(_L8t(B5ZEOMZ5E$%fD zbWwdR>v7gfg;>(=^829;>*yK@hsU?FIiTP)tUtE=&PJ?hNKiwAGcPBfXfnrKE#U0* z`Z`?gqHsh|A$X6o$kFFy&sTCcF3O3^)k(DZ0#3RwCN>C_K@#b0#hoazA+inxt9#Fv zVO2%7(_x3uI2#w>s4&)dJgih?qoX32MVXvkEv;cpfLlq=@r^Cv(iVWq?#@UgaH8GY z97mcE6qaQu8c%0jaAWQr&A>nz=c9nNuFjT<&OkNT+74J@!0YsT+k4zl_mCR2>AGBJ zEmR;iCcme%b-a|vYd&BpaQj+YEixBNhwFBC9l9u&Z^OD;Ye`o(pWuhqtEjJXMtaTq zsuJom>*>fpH@CX*-5BD&Bh+y#8V%B|fRy2?7iYKMjaJ@hCEe@9Y0-`vOD?aNISJzS zDczkYVmyNy7YLbQm5JmNs$M}w1;YGM%Sjv)(e<#v2uUHa@yE%Hhw1mN2y;P(`5n zxHZCX<@4#XapnsfH<#;*Zll2MRT_IIu#Q2@LXRKxtHDqXt!FZxH5=|LeXuLyO~ZPf1F%)4SfqrkK`GlHD4yZWI>L z{KDA!g1%tQ4Qm@+3WO&<7#fS!q_m}2sR-+!xy|K68b~g#zKTsoMv}r~2ZgAPvvA^v z|NpH23M8N@K{;)N7aM$dBtVJA_BaHSSYJP1WBArL4XPAE#g~%b^Y4l65a)*R#>9zez8CVyfr-^?f z`D^L5@(&=K@D|H>+PhxSLobWH@75xmt z6P-T1PYUyj^zfN*@yfp@`L4M;;EztP?Qf}(5w1EOl^CyDIt}{Wxb)h-tH7HghO7oH zI`b;*!OL#^QT`hLwf$LrGX0k62#k7cQSbD+2Y=D&wS8Qv=R`!>e-iz~^Y2LnMyJ>I zdmSAUsis~MojOu~8gv*h(do5)VJ}S~==k^o%0c||B7Ui=q?m;FkB!Lm@%+~0Ps8v> zykIIcoL<{!c4mV7`SKqE7FqeYU#uK)~1S*s*?Yjd~5k@GF2KSRP9^~C4@{{Upb74rZ9 literal 0 HcmV?d00001 diff --git a/CalibGA/Outer_CppOpenMP/SwapCalib.cpp b/benchmarks/CalibGA/implementations/Outer_CppOpenMP/SwapCalib.cpp similarity index 100% rename from CalibGA/Outer_CppOpenMP/SwapCalib.cpp rename to benchmarks/CalibGA/implementations/Outer_CppOpenMP/SwapCalib.cpp diff --git a/CalibGA/Outer_CppOpenMP/UtilCPU.h b/benchmarks/CalibGA/implementations/Outer_CppOpenMP/UtilCPU.h similarity index 100% rename from CalibGA/Outer_CppOpenMP/UtilCPU.h rename to benchmarks/CalibGA/implementations/Outer_CppOpenMP/UtilCPU.h diff --git a/CalibGA/includeC/Candidate.h b/benchmarks/CalibGA/includeC/Candidate.h similarity index 100% rename from CalibGA/includeC/Candidate.h rename to benchmarks/CalibGA/includeC/Candidate.h diff --git a/CalibGA/includeC/Constants.h b/benchmarks/CalibGA/includeC/Constants.h similarity index 100% rename from CalibGA/includeC/Constants.h rename to benchmarks/CalibGA/includeC/Constants.h diff --git a/CalibGA/includeC/Date.h b/benchmarks/CalibGA/includeC/Date.h similarity index 100% rename from CalibGA/includeC/Date.h rename to benchmarks/CalibGA/includeC/Date.h diff --git a/CalibGA/includeC/EvalGenomeInl.h b/benchmarks/CalibGA/includeC/EvalGenomeInl.h similarity index 100% rename from CalibGA/includeC/EvalGenomeInl.h rename to benchmarks/CalibGA/includeC/EvalGenomeInl.h diff --git a/CalibGA/includeC/G2PP.h b/benchmarks/CalibGA/includeC/G2PP.h similarity index 100% rename from CalibGA/includeC/G2PP.h rename to benchmarks/CalibGA/includeC/G2PP.h diff --git a/CalibGA/includeC/G2ppUtil.h b/benchmarks/CalibGA/includeC/G2ppUtil.h similarity index 100% rename from CalibGA/includeC/G2ppUtil.h rename to benchmarks/CalibGA/includeC/G2ppUtil.h diff --git a/CalibGA/includeC/GenAlgUtil.h b/benchmarks/CalibGA/includeC/GenAlgUtil.h similarity index 100% rename from CalibGA/includeC/GenAlgUtil.h rename to benchmarks/CalibGA/includeC/GenAlgUtil.h diff --git a/CalibGA/includeC/IrregShape.h b/benchmarks/CalibGA/includeC/IrregShape.h similarity index 100% rename from CalibGA/includeC/IrregShape.h rename to benchmarks/CalibGA/includeC/IrregShape.h diff --git a/CalibGA/includeC/KerConsts.h b/benchmarks/CalibGA/includeC/KerConsts.h similarity index 100% rename from CalibGA/includeC/KerConsts.h rename to benchmarks/CalibGA/includeC/KerConsts.h diff --git a/CalibGA/includeC/MathModule.h b/benchmarks/CalibGA/includeC/MathModule.h similarity index 100% rename from CalibGA/includeC/MathModule.h rename to benchmarks/CalibGA/includeC/MathModule.h diff --git a/CalibGA/includeC/ParseInput.h b/benchmarks/CalibGA/includeC/ParseInput.h similarity index 100% rename from CalibGA/includeC/ParseInput.h rename to benchmarks/CalibGA/includeC/ParseInput.h diff --git a/CalibGA/includeC/tmp/Constants.h b/benchmarks/CalibGA/includeC/tmp/Constants.h similarity index 100% rename from CalibGA/includeC/tmp/Constants.h rename to benchmarks/CalibGA/includeC/tmp/Constants.h diff --git a/CalibGA/includeC/tmp/DataStructConst.h b/benchmarks/CalibGA/includeC/tmp/DataStructConst.h similarity index 100% rename from CalibGA/includeC/tmp/DataStructConst.h rename to benchmarks/CalibGA/includeC/tmp/DataStructConst.h diff --git a/CalibGA/includeC/tmp/G2PP.h b/benchmarks/CalibGA/includeC/tmp/G2PP.h similarity index 100% rename from CalibGA/includeC/tmp/G2PP.h rename to benchmarks/CalibGA/includeC/tmp/G2PP.h diff --git a/CalibVolDiff/README.txt b/benchmarks/CalibVolDiff/README.txt similarity index 100% rename from CalibVolDiff/README.txt rename to benchmarks/CalibVolDiff/README.txt diff --git a/CalibVolDiff/ToDo.txt b/benchmarks/CalibVolDiff/ToDo.txt similarity index 100% rename from CalibVolDiff/ToDo.txt rename to benchmarks/CalibVolDiff/ToDo.txt diff --git a/benchmarks/CalibVolDiff/datasets/Large/input.json b/benchmarks/CalibVolDiff/datasets/Large/input.json new file mode 100644 index 0000000..0988c05 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/Large/input.json @@ -0,0 +1,6 @@ +{ + "outer" : 128, + "num_x" : 256, + "num_y" : 256, + "num_t" : 64 +} diff --git a/CalibVolDiff/Data/Large/output.data b/benchmarks/CalibVolDiff/datasets/Large/output.json similarity index 72% rename from CalibVolDiff/Data/Large/output.data rename to benchmarks/CalibVolDiff/datasets/Large/output.json index 53b14d7..5336d78 100644 --- a/CalibVolDiff/Data/Large/output.data +++ b/benchmarks/CalibVolDiff/datasets/Large/output.json @@ -1,17 +1,17 @@ [ 0.03, 0.029208, 0.0288064, 0.0284091, 0.0280168, 0.02763, 0.0272488, 0.0268733, - 0.0265035, 0.0261398, 0.0257819, 0.0254298, 0.0250835, 0.0247429, 0.0244079, 0.0240786, - 0.0237549, 0.0234366, 0.0231239, 0.0228165, 0.0225144, 0.0222177, 0.0219261, 0.0216397, - 0.0213582, 0.0210816, 0.0208095, 0.0205413, 0.0202763, 0.0200168, 0.0197942, 0.0195152, - 0.0192728, 0.019036, 0.0188019, 0.018571, 0.0183438, 0.0181204, 0.0179008, 0.0176849, - 0.0174728, 0.0172644, 0.0170595, 0.0168582, 0.0166602, 0.0164656, 0.0162743, 0.0160862, + 0.0265035, 0.0261398, 0.0257819, 0.0254298, 0.0250835, 0.0247429, 0.0244079, 0.0240786, + 0.0237549, 0.0234366, 0.0231239, 0.0228165, 0.0225144, 0.0222177, 0.0219261, 0.0216397, + 0.0213582, 0.0210816, 0.0208095, 0.0205413, 0.0202763, 0.0200168, 0.0197942, 0.0195152, + 0.0192728, 0.019036, 0.0188019, 0.018571, 0.0183438, 0.0181204, 0.0179008, 0.0176849, + 0.0174728, 0.0172644, 0.0170595, 0.0168582, 0.0166602, 0.0164656, 0.0162743, 0.0160862, 0.0159012, 0.0157192, 0.0155402, 0.0153642, 0.0151911, 0.0150208, 0.0148533, 0.0146884, - 0.0145262, 0.0143665, 0.0142093, 0.0140545, 0.0139021, 0.013752, 0.0136042, 0.0134586, - 0.0133152, 0.0131739, 0.0130346, 0.0128974, 0.0127622, 0.012629, 0.0124976, 0.0123681, + 0.0145262, 0.0143665, 0.0142093, 0.0140545, 0.0139021, 0.013752, 0.0136042, 0.0134586, + 0.0133152, 0.0131739, 0.0130346, 0.0128974, 0.0127622, 0.012629, 0.0124976, 0.0123681, 0.0122403, 0.0121144, 0.0119902, 0.0118678, 0.011747, 0.0116278, 0.0115102, 0.0113942, - 0.0112796, 0.0111666, 0.011055, 0.0109448, 0.010836, 0.0107285, 0.0106224, 0.0105175, - 0.010414, 0.0103117, 0.0102105, 0.0101106, 0.0100119, 0.00991426, 0.00981776, 0.00972235, - 0.00962805, 0.00953481, 0.00944259, 0.00935138, 0.00926115, 0.00917188, 0.00908355, 0.00899615, + 0.0112796, 0.0111666, 0.011055, 0.0109448, 0.010836, 0.0107285, 0.0106224, 0.0105175, + 0.010414, 0.0103117, 0.0102105, 0.0101106, 0.0100119, 0.00991426, 0.00981776, 0.00972235, + 0.00962805, 0.00953481, 0.00944259, 0.00935138, 0.00926115, 0.00917188, 0.00908355, 0.00899615, 0.00890965, 0.00882403, 0.00873928, 0.00865539, 0.00857232, 0.00849007, 0.00840863, 0.00832796, - 0.00824807, 0.00816892, 0.00809052, 0.00801284, 0.00793587, 0.0078596, 0.00778404, 0.00770914, + 0.00824807, 0.00816892, 0.00809052, 0.00801284, 0.00793587, 0.0078596, 0.00778404, 0.00770914, 0.00763491, 0.00756131, 0.00748835, 0.007416, 0.00734426, 0.00727311, 0.00720255, 0.00713255 -] // Standard Result for the Large dataset of Volatility Calibration. +] diff --git a/benchmarks/CalibVolDiff/datasets/Medium/input.json b/benchmarks/CalibVolDiff/datasets/Medium/input.json new file mode 100644 index 0000000..4b6f586 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/Medium/input.json @@ -0,0 +1,6 @@ +{ + "outer" : 128, + "num_x" : 256, + "num_y" : 32, + "num_t" : 64 +} diff --git a/CalibVolDiff/Data/Medium/output.data b/benchmarks/CalibVolDiff/datasets/Medium/output.json similarity index 93% rename from CalibVolDiff/Data/Medium/output.data rename to benchmarks/CalibVolDiff/datasets/Medium/output.json index a8fc75d..4d5f9c1 100644 --- a/CalibVolDiff/Data/Medium/output.data +++ b/benchmarks/CalibVolDiff/datasets/Medium/output.json @@ -1,7 +1,7 @@ [ 0.03, 0.0292079, 0.0288058, 0.028408, 0.0280152, 0.0276279, 0.0272462, 0.0268701, 0.0264998, 0.0261355, 0.025777, 0.0254243, 0.0250773, 0.024736, 0.0244004, 0.0240704, 0.0237459, 0.0234269, 0.0231134, 0.0228053, 0.0225025, 0.022205, 0.0219126, 0.0216253, - 0.0213431, 0.0210657, 0.0207928, 0.0205238, 0.0202581, 0.0199978, 0.0197739, 0.0194946, + 0.0213431, 0.0210657, 0.0207928, 0.0205238, 0.0202581, 0.0199978, 0.0197739, 0.0194946, 0.0192514, 0.0190136, 0.0187787, 0.018547, 0.0183189, 0.0180947, 0.0178743, 0.0176577, 0.0174448, 0.0172356, 0.0170299, 0.0168278, 0.016629, 0.0164336, 0.0162415, 0.0160526, 0.0158668, 0.0156841, 0.0155044, 0.0153276, 0.0151536, 0.0149826, 0.0148144, 0.0146488, @@ -14,5 +14,4 @@ 0.00884636, 0.00876059, 0.00867569, 0.00859167, 0.00850848, 0.00842613, 0.00834459, 0.00826384, 0.00818388, 0.00810468, 0.00802623, 0.00794852, 0.00787153, 0.00779524, 0.00771969, 0.00764481, 0.0075706, 0.00749704, 0.00742412, 0.00735183, 0.00728016, 0.00720909, 0.00713861, 0.00706872 -] // Standard Result for the Medium dataset of Volatility Calibration. - +] diff --git a/benchmarks/CalibVolDiff/datasets/Small/input.json b/benchmarks/CalibVolDiff/datasets/Small/input.json new file mode 100644 index 0000000..9003d1a --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/Small/input.json @@ -0,0 +1,6 @@ +{ + "outer" : 128, + "num_x" : 32, + "num_y" : 32, + "num_t" : 256 +} diff --git a/CalibVolDiff/Data/Small/output.data b/benchmarks/CalibVolDiff/datasets/Small/output.json similarity index 62% rename from CalibVolDiff/Data/Small/output.data rename to benchmarks/CalibVolDiff/datasets/Small/output.json index 93b61a0..dae8dac 100644 --- a/CalibVolDiff/Data/Small/output.data +++ b/benchmarks/CalibVolDiff/datasets/Small/output.json @@ -1,18 +1,17 @@ -[ 0.0300001, 0.0290001, 0.0280001, 0.0270001, 0.026, 0.0251064, 0.0247889, 0.0244714, - 0.0241539, 0.0238364, 0.0235189, 0.0232014, 0.0228839, 0.0225664, 0.0222744, 0.02199, - 0.0217056, 0.0214212, 0.0211368, 0.0208524, 0.020568, 0.0202836, 0.0200131, 0.0197647, - 0.0195162, 0.0192678, 0.0190194, 0.018771, 0.0185225, 0.0182741, 0.0180257, 0.0178105, - 0.0175953, 0.0173801, 0.0171649, 0.0169497, 0.0167345, 0.0165193, 0.0163041, 0.0161067, - 0.0159203, 0.0157339, 0.0155476, 0.0153612, 0.0151749, 0.0149885, 0.0148022, 0.0146214, - 0.0144594, 0.0142974, 0.0141353, 0.0139733, 0.0138113, 0.0136492, 0.0134872, 0.0133252, - 0.0131803, 0.0130385, 0.0128967, 0.012755, 0.0126132, 0.0124714, 0.0123297, 0.0121879, - 0.0120539, 0.0119289, 0.011804, 0.011679, 0.0115541, 0.0114291, 0.0113042, 0.0111792, - 0.0110553, 0.0109443, 0.0108333, 0.0107223, 0.0106113, 0.0105003, 0.0103893, 0.0102783, - 0.0101672, 0.0100642, 0.00996481, 0.00986541, 0.009766, 0.00966658, 0.0095672, 0.00946778, - 0.00936839, 0.0092719, 0.00918218, 0.00909245, 0.00900272, 0.00891302, 0.00882328, 0.00873356, - 0.00864382, 0.00855409, 0.00847181, 0.0083902, 0.00830859, 0.00822697, 0.00814538, 0.00806375, - 0.00798213, 0.00790052, 0.00782254, 0.00774774, 0.00767295, 0.00759818, 0.00752339, 0.0074486, - 0.00737381, 0.00729902, 0.00722509, 0.00715607, 0.00708704, 0.00701801, 0.00694899, 0.00687997, - 0.00681095, 0.00674192, 0.0066729, 0.0066076, 0.00654346, 0.00647933, 0.00641519, 0.00635106 -] // Standard Result for the Small dataset of Volatility Calibration. - +[ 0.0300001, 0.0290001, 0.0280001, 0.0270001, 0.026, 0.0251064, 0.0247889, 0.0244714, + 0.0241539, 0.0238364, 0.0235189, 0.0232014, 0.0228839, 0.0225664, 0.0222744, 0.02199, + 0.0217056, 0.0214212, 0.0211368, 0.0208524, 0.020568, 0.0202836, 0.0200131, 0.0197647, + 0.0195162, 0.0192678, 0.0190194, 0.018771, 0.0185225, 0.0182741, 0.0180257, 0.0178105, + 0.0175953, 0.0173801, 0.0171649, 0.0169497, 0.0167345, 0.0165193, 0.0163041, 0.0161067, + 0.0159203, 0.0157339, 0.0155476, 0.0153612, 0.0151749, 0.0149885, 0.0148022, 0.0146214, + 0.0144594, 0.0142974, 0.0141353, 0.0139733, 0.0138113, 0.0136492, 0.0134872, 0.0133252, + 0.0131803, 0.0130385, 0.0128967, 0.012755, 0.0126132, 0.0124714, 0.0123297, 0.0121879, + 0.0120539, 0.0119289, 0.011804, 0.011679, 0.0115541, 0.0114291, 0.0113042, 0.0111792, + 0.0110553, 0.0109443, 0.0108333, 0.0107223, 0.0106113, 0.0105003, 0.0103893, 0.0102783, + 0.0101672, 0.0100642, 0.00996481, 0.00986541, 0.009766, 0.00966658, 0.0095672, 0.00946778, + 0.00936839, 0.0092719, 0.00918218, 0.00909245, 0.00900272, 0.00891302, 0.00882328, 0.00873356, + 0.00864382, 0.00855409, 0.00847181, 0.0083902, 0.00830859, 0.00822697, 0.00814538, 0.00806375, + 0.00798213, 0.00790052, 0.00782254, 0.00774774, 0.00767295, 0.00759818, 0.00752339, 0.0074486, + 0.00737381, 0.00729902, 0.00722509, 0.00715607, 0.00708704, 0.00701801, 0.00694899, 0.00687997, + 0.00681095, 0.00674192, 0.0066729, 0.0066076, 0.00654346, 0.00647933, 0.00641519, 0.00635106 +] diff --git a/CalibVolDiff/All_COpenCLMP/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/CrankNicolson.cl similarity index 100% rename from CalibVolDiff/All_COpenCLMP/CrankNicolson.cl rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/CrankNicolson.cl diff --git a/CalibVolDiff/All_COpenCLMP/Makefile b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile similarity index 80% rename from CalibVolDiff/All_COpenCLMP/Makefile rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile index 74a911e..aa5e0ed 100644 --- a/CalibVolDiff/All_COpenCLMP/Makefile +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile @@ -34,16 +34,6 @@ cpu: gpu: $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) - -run_small: - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt @# clean nVidia compiler cache diff --git a/CalibVolDiff/All_COpenCLMP/PrepareKernels.h b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/PrepareKernels.h similarity index 100% rename from CalibVolDiff/All_COpenCLMP/PrepareKernels.h rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/PrepareKernels.h diff --git a/CalibVolDiff/All_COpenCLMP/Vect_CPU.h b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_CPU.h similarity index 99% rename from CalibVolDiff/All_COpenCLMP/Vect_CPU.h rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_CPU.h index b483d79..ddce703 100644 --- a/CalibVolDiff/All_COpenCLMP/Vect_CPU.h +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_CPU.h @@ -1,7 +1,7 @@ #ifndef NORDEA_CPU #define NORDEA_CPU -#include "../includeC/ParPrefixUtil.h" +#include "ParPrefixUtil.h" //////////////////////////////////////////////////////////// //// FINALLY THE MEAT: The CPU Version of the Main Loop! diff --git a/CalibVolDiff/All_COpenCLMP/Vect_GPU.h b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_GPU.h similarity index 99% rename from CalibVolDiff/All_COpenCLMP/Vect_GPU.h rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_GPU.h index 385881a..91ca5d2 100644 --- a/CalibVolDiff/All_COpenCLMP/Vect_GPU.h +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_GPU.h @@ -1,7 +1,7 @@ #ifndef NORDEA_GPU #define NORDEA_GPU -#include "../../include/SDK_stub.h" +#include "SDK_stub.h" #include "PrepareKernels.h" diff --git a/CalibVolDiff/All_COpenCLMP/VolCalibAll.cpp b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibAll.cpp similarity index 86% rename from CalibVolDiff/All_COpenCLMP/VolCalibAll.cpp rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibAll.cpp index 1b969b5..19df6b0 100644 --- a/CalibVolDiff/All_COpenCLMP/VolCalibAll.cpp +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibAll.cpp @@ -1,11 +1,12 @@ -#include "../../include/Util.h" -#include "../includeC/Constants.h" -#include "../includeC/DataStructConst.h" -#include "../includeC/ParseInput.h" +#include "Constants.h" +#include "DataStructConst.h" +#include "ParseInput.h" #include "VolCalibInit.h" #include "Vect_CPU.h" #include "Vect_GPU.h" +#include "Util.h" +#include "ParseInput.h" void whole_loop_nest ( REAL* res, @@ -128,7 +129,7 @@ int main() { strikes[i] = 0.001*i; } - unsigned long int elapsed = 0; + unsigned long int elapsed_usec = 0; { // Instrumenting Runtime and Validation! struct timeval t_start, t_end, t_diff; gettimeofday(&t_start, NULL); @@ -137,17 +138,15 @@ int main() { gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; } - - { // validation & write back of the result - bool is_valid = validate ( res, OUTER_LOOP_COUNT ); - int num_threads = (IS_GPU) ? GPU_CORES : get_CPU_num_threads() ; - - writeStatsAndResult( is_valid, res, OUTER_LOOP_COUNT, - NUM_X, NUM_Y, NUM_T, - (IS_GPU!=0), num_threads, elapsed ); - //writeResult( res, OUTER_LOOP_COUNT ); + + { FILE* runtime = fopen("runtime.txt", "w"); + FILE* result = fopen("result.json", "w"); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + write_1Darr(result, res, OUTER_LOOP_COUNT); + fclose(result); } delete[] strikes; diff --git a/CalibVolDiff/All_COpenCLMP/VolCalibInit.h b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibInit.h similarity index 98% rename from CalibVolDiff/All_COpenCLMP/VolCalibInit.h rename to benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibInit.h index a944ba5..8d6a638 100644 --- a/CalibVolDiff/All_COpenCLMP/VolCalibInit.h +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibInit.h @@ -1,7 +1,7 @@ #ifndef NORDEA_INIT #define NORDEA_INIT -#include "../includeC/DataStructConst.h" +#include "DataStructConst.h" /////////////////////////////////////////////////////// //// INITIALISATION ! diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate new file mode 100755 index 0000000..c349e59 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/platform.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_LIB_DIR/include/SDK_stub.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/DataStructConst.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParPrefixUtil.h . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data + +make diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/run b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/run new file mode 100755 index 0000000..c409dcd --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat input.data | ./VolCalib diff --git a/CalibVolDiff/HaskellLH/VolCalib.hs b/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs similarity index 94% rename from CalibVolDiff/HaskellLH/VolCalib.hs rename to benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs index efb347c..734f004 100644 --- a/CalibVolDiff/HaskellLH/VolCalib.hs +++ b/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs @@ -4,6 +4,7 @@ import Control.DeepSeq import Control.Applicative import Control.Monad import Data.Maybe +import System.CPUTime ------------------------------------ --- Requires the installation of --- @@ -18,8 +19,6 @@ import Data.Bits import Data.List import Prelude -import Debug.Trace - ------------------------------ --- Parser-related Helpers --- ------------------------------ @@ -373,33 +372,25 @@ validate res_ref res info= --- e.g., parsing Dataset from StdIn --- ----------------------------------------- main :: IO () -main = do s <- getContents +main = do s <- getContents case parse run "input" s of Left e -> error $ show e - Right (p,pr,i) -> do let msg_lst = validate pr p i - putStrLn (msg_lst !! 0) - putStrLn (msg_lst !! 1) - putStrLn (msg_lst !! 2) - putStrLn (msg_lst !! 3) - putStrLn (msg_lst !! 4) - putStrLn (msg_lst !! 5) - -- print $ validate pr p i --- either (error . show) print $ parse run "input" s - where run = do outer <- readInt + Right m -> do (v,runtime) <- m + writeFile "result.json" $ show v + writeFile "runtime.txt" $ show runtime + where run = do whitespace + outer <- readInt num_x <- readInt num_y <- readInt num_t <- readInt let params = (0.03, 5.0, 0.2, 0.6, 0.5) --(s0, t, alpha, nu, beta) - let v = compute (outer, num_x, num_y, num_t) params - r <- readDouble1d - return (v, r, (outer, num_x, num_y, num_t)) - - readInt2d = readArray $ readArray readInt - readDouble1d = readArray readDouble - readDouble2d = readArray $ readArray readDouble - readDouble3d = readArray $ readArray $ readArray readDouble + return $ do + start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + let v = compute (outer, num_x, num_y, num_t) params + end <- v `seq` getCPUTime + return (v, (end - start) `div` 1000000000) -- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs -- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data diff --git a/benchmarks/CalibVolDiff/implementations/HaskellLH/instantiate b/benchmarks/CalibVolDiff/implementations/HaskellLH/instantiate new file mode 100755 index 0000000..4d2f324 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/HaskellLH/instantiate @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e # Die on error. + +impl_dir=$FINPAR_IMPLEMENTATION +input=$FINPAR_INPUT + +cp $impl_dir/*hs . +cp $impl_dir/run . +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data +ghc -Wall -O2 -msse2 -rtsopts VolCalib.hs -o VolCalib diff --git a/benchmarks/CalibVolDiff/implementations/HaskellLH/run b/benchmarks/CalibVolDiff/implementations/HaskellLH/run new file mode 100755 index 0000000..baa6480 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/HaskellLH/run @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +./VolCalib +RTS -K128m -RTS < input.data diff --git a/CalibVolDiff/Orig_COpenMP/Makefile b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/Makefile similarity index 64% rename from CalibVolDiff/Orig_COpenMP/Makefile rename to benchmarks/CalibVolDiff/implementations/Orig_COpenMP/Makefile index 88daa45..490461d 100644 --- a/CalibVolDiff/Orig_COpenMP/Makefile +++ b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/Makefile @@ -24,16 +24,6 @@ cpu: $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) diff --git a/CalibVolDiff/Orig_COpenMP/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/VolCalibOrig.cpp similarity index 92% rename from CalibVolDiff/Orig_COpenMP/VolCalibOrig.cpp rename to benchmarks/CalibVolDiff/implementations/Orig_COpenMP/VolCalibOrig.cpp index 63c62ce..c9f6938 100644 --- a/CalibVolDiff/Orig_COpenMP/VolCalibOrig.cpp +++ b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/VolCalibOrig.cpp @@ -5,7 +5,7 @@ typedef double REAL; #define WORKGROUP_SIZE 512 #include "Util.h" -#include "../includeC/ParseInput.h" +#include "ParseInput.h" using namespace std; @@ -324,7 +324,7 @@ int main() const int Ps = get_CPU_num_threads(); - unsigned long int elapsed = 0; + unsigned long int elapsed_usec = 0; { // Main Computational Kernel struct timeval t_start, t_end, t_diff; gettimeofday(&t_start, NULL); @@ -333,13 +333,15 @@ int main() gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; } - { // validation and writeback of the result - bool is_valid = validate ( res.data(), OUTER_LOOP_COUNT ); - writeStatsAndResult( is_valid, res.data(), OUTER_LOOP_COUNT, - NUM_X, NUM_Y, NUM_T, false, Ps, elapsed ); + { FILE* runtime = fopen("runtime.txt", "w"); + FILE* result = fopen("result.json", "w"); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + write_1Darr(result, res.data(), OUTER_LOOP_COUNT); + fclose(result); } return 0; diff --git a/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/instantiate b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/instantiate new file mode 100755 index 0000000..f20c373 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/instantiate @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/platform.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data + +make diff --git a/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/run b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/run new file mode 100755 index 0000000..c409dcd --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat input.data | ./VolCalib diff --git a/CalibVolDiff/Original/Makefile b/benchmarks/CalibVolDiff/implementations/Original/Makefile similarity index 100% rename from CalibVolDiff/Original/Makefile rename to benchmarks/CalibVolDiff/implementations/Original/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/Original/VolCalib b/benchmarks/CalibVolDiff/implementations/Original/VolCalib new file mode 100755 index 0000000000000000000000000000000000000000..c2bf4ac7ae98011bd2b9b94e86d8fd4292c84c06 GIT binary patch literal 40968 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 literal 0 HcmV?d00001 diff --git a/CalibVolDiff/Original/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/Original/VolCalibOrig.cpp similarity index 88% rename from CalibVolDiff/Original/VolCalibOrig.cpp rename to benchmarks/CalibVolDiff/implementations/Original/VolCalibOrig.cpp index ee50ef5..cd6fcbd 100644 --- a/CalibVolDiff/Original/VolCalibOrig.cpp +++ b/benchmarks/CalibVolDiff/implementations/Original/VolCalibOrig.cpp @@ -1,322 +1,318 @@ -#include -#include - -#define WITH_FLOATS 0 -#define WORKGROUP_SIZE 512 - -typedef double REAL; - -#include "Util.h" -#include "../includeC/ParseInput.h" - -using namespace std; - -// grid -vector myX, myY, myTimeline; -unsigned myXindex, myYindex; - -// variable -vector > myResult; - -// coeffs -vector > myMuX, myVarX, myMuY, myVarY; - -// operators -vector > myDx, myDxx, myDy, myDyy; - - - - -/***********************************/ - -void updateParams(const unsigned g, const double alpha, const double beta, const double nu) -{ - for(unsigned i=0;i(s0/dx); - - for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) -{ - const unsigned n = x.size(); - - Dx.resize(n); - Dxx.resize(n); - - for(unsigned i=0;i& a, - const vector& b, - const vector& c, - const vector& r, - const int n, - vector& u, - vector& uu) -{ - int i, offset; - REAL beta; - - u[0] = r[0]; - uu[0] = b[0]; - - for(i=1; i=0; i--) { - u[i] = (u[i] - c[i]*u[i+1]) / uu[i]; - } -} - -void -rollback(const unsigned g) -{ - unsigned numX = myX.size(), - numY = myY.size(); - - unsigned numZ = max(numX,numY); - - int k, l; - unsigned i, j; - - int kl, ku, ll, lu; - - double dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]); - - vector > u(numY,vector(numX)), v(numX,vector(numY)); - - vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); - - // explicit x - for(i=0;i=0;--i) - { - updateParams(i,alpha,beta,nu); - rollback(i); - } - - return myResult[myXindex][myYindex]; -} - -int main() -{ - unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; - const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; - - fprintf(stdout, "\n// Original (Sequential) Volatility Calibration Benchmark:\n"); - readDataSet( OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T ); - - vector strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); - - for(unsigned i=0;i4) -//get_tot_num_threads() - +#include +#include + +#define WITH_FLOATS 0 +#define WORKGROUP_SIZE 512 + +typedef double REAL; + +#include "Util.h" +#include "ParseInput.h" + +using namespace std; + +// grid +vector myX, myY, myTimeline; +unsigned myXindex, myYindex; + +// variable +vector > myResult; + +// coeffs +vector > myMuX, myVarX, myMuY, myVarY; + +// operators +vector > myDx, myDxx, myDy, myDyy; + + + + +/***********************************/ + +void updateParams(const unsigned g, const double alpha, const double beta, const double nu) +{ + for(unsigned i=0;i(s0/dx); + + for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) +{ + const unsigned n = x.size(); + + Dx.resize(n); + Dxx.resize(n); + + for(unsigned i=0;i& a, + const vector& b, + const vector& c, + const vector& r, + const int n, + vector& u, + vector& uu) +{ + int i, offset; + REAL beta; + + u[0] = r[0]; + uu[0] = b[0]; + + for(i=1; i=0; i--) { + u[i] = (u[i] - c[i]*u[i+1]) / uu[i]; + } +} + +void +rollback(const unsigned g) +{ + unsigned numX = myX.size(), + numY = myY.size(); + + unsigned numZ = max(numX,numY); + + int k, l; + unsigned i, j; + + int kl, ku, ll, lu; + + double dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]); + + vector > u(numY,vector(numX)), v(numX,vector(numY)); + + vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); + + // explicit x + for(i=0;i=0;--i) + { + updateParams(i,alpha,beta,nu); + rollback(i); + } + + return myResult[myXindex][myYindex]; +} + +int main() +{ + unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; + const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; + + fprintf(stdout, "\n// Original (Sequential) Volatility Calibration Benchmark:\n"); + readDataSet( OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T ); + + vector strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); + + for(unsigned i=0;i input.data + +make diff --git a/benchmarks/CalibVolDiff/implementations/Original/run b/benchmarks/CalibVolDiff/implementations/Original/run new file mode 100755 index 0000000..c409dcd --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/Original/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat input.data | ./VolCalib diff --git a/CalibVolDiff/Outer_COpenCLMP/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/CrankNicolson.cl similarity index 100% rename from CalibVolDiff/Outer_COpenCLMP/CrankNicolson.cl rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/CrankNicolson.cl diff --git a/CalibVolDiff/Outer_COpenCLMP/Makefile b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Makefile similarity index 100% rename from CalibVolDiff/Outer_COpenCLMP/Makefile rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Makefile diff --git a/CalibVolDiff/Outer_COpenCLMP/PrepareKernels.h b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/PrepareKernels.h similarity index 100% rename from CalibVolDiff/Outer_COpenCLMP/PrepareKernels.h rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/PrepareKernels.h diff --git a/CalibVolDiff/Outer_COpenCLMP/Vect_CPU.h b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_CPU.h similarity index 99% rename from CalibVolDiff/Outer_COpenCLMP/Vect_CPU.h rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_CPU.h index 26d522c..e584cb1 100644 --- a/CalibVolDiff/Outer_COpenCLMP/Vect_CPU.h +++ b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_CPU.h @@ -1,7 +1,7 @@ #ifndef NORDEA_CPU #define NORDEA_CPU -#include "../includeC/ParPrefixUtil.h" +#include "ParPrefixUtil.h" //////////////////////////////////////////////////////////// //// FINALLY THE MEAT: The CPU Version of the Main Loop! diff --git a/CalibVolDiff/Outer_COpenCLMP/Vect_GPU.h b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_GPU.h similarity index 100% rename from CalibVolDiff/Outer_COpenCLMP/Vect_GPU.h rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_GPU.h diff --git a/CalibVolDiff/Outer_COpenCLMP/VolCalibInit.h b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibInit.h similarity index 98% rename from CalibVolDiff/Outer_COpenCLMP/VolCalibInit.h rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibInit.h index fc47818..e6aa566 100644 --- a/CalibVolDiff/Outer_COpenCLMP/VolCalibInit.h +++ b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibInit.h @@ -1,7 +1,7 @@ #ifndef NORDEA_INIT #define NORDEA_INIT -#include "../includeC/DataStructConst.h" +#include "DataStructConst.h" /////////////////////////////////////////////////////// //// INITIALISATION ! diff --git a/CalibVolDiff/Outer_COpenCLMP/VolCalibOuter.cpp b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibOuter.cpp similarity index 88% rename from CalibVolDiff/Outer_COpenCLMP/VolCalibOuter.cpp rename to benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibOuter.cpp index 046310f..20ba82d 100644 --- a/CalibVolDiff/Outer_COpenCLMP/VolCalibOuter.cpp +++ b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibOuter.cpp @@ -1,10 +1,10 @@ -#include "../../include/Util.h" -#include "../includeC/Constants.h" -#include "../includeC/DataStructConst.h" +#include "Util.h" +#include "Constants.h" +#include "DataStructConst.h" #include "VolCalibInit.h" #include "Vect_CPU.h" #include "Vect_GPU.h" -#include "../includeC/ParseInput.h" +#include "ParseInput.h" void whole_loop_nest ( @@ -132,7 +132,7 @@ int main() { strikes[i] = 0.001*i; } - + unsigned long int elapsed_usec = 0; { // Instrumenting Runtime and Validation! struct timeval t_start, t_end, t_diff; gettimeofday(&t_start, NULL); @@ -142,15 +142,15 @@ int main() { gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; } - { // validation & write back of the result - bool is_valid = validate ( res, OUTER_LOOP_COUNT ); - int num_threads = (IS_GPU) ? GPU_CORES : get_CPU_num_threads() ; - writeStatsAndResult( is_valid, res, OUTER_LOOP_COUNT, - NUM_X, NUM_Y, NUM_T, - (IS_GPU!=0), num_threads, elapsed ); - //writeResult( res.data(), OUTER_LOOP_COUNT ); + { FILE* runtime = fopen("runtime.txt", "w"); + FILE* result = fopen("result.json", "w"); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + write_1Darr(result, res, OUTER_LOOP_COUNT); + fclose(result); } delete[] strikes; diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/instantiate b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/instantiate new file mode 100755 index 0000000..c349e59 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/instantiate @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/platform.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_LIB_DIR/include/SDK_stub.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/DataStructConst.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParPrefixUtil.h . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data + +make diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/run b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/run new file mode 100755 index 0000000..c409dcd --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat input.data | ./VolCalib diff --git a/CalibVolDiff/includeC/Constants.h b/benchmarks/CalibVolDiff/lib/include/Constants.h similarity index 100% rename from CalibVolDiff/includeC/Constants.h rename to benchmarks/CalibVolDiff/lib/include/Constants.h diff --git a/CalibVolDiff/includeC/DataStructConst.h b/benchmarks/CalibVolDiff/lib/include/DataStructConst.h similarity index 100% rename from CalibVolDiff/includeC/DataStructConst.h rename to benchmarks/CalibVolDiff/lib/include/DataStructConst.h diff --git a/CalibVolDiff/includeC/ParPrefixUtil.h b/benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h similarity index 100% rename from CalibVolDiff/includeC/ParPrefixUtil.h rename to benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h diff --git a/benchmarks/CalibVolDiff/lib/include/ParseInput.h b/benchmarks/CalibVolDiff/lib/include/ParseInput.h new file mode 100644 index 0000000..8453724 --- /dev/null +++ b/benchmarks/CalibVolDiff/lib/include/ParseInput.h @@ -0,0 +1,58 @@ +#ifndef PARSE_INPUT +#define PARSE_INPUT + +#include "ParserC.h" +#include "Util.h" +#include +#include +#include + +using namespace std; + +#include + +#if WITH_FLOATS + #define read_real read_float +#else + #define read_real read_double +#endif + +const float EPS = 0.00001; + +/***********************************/ +/********** READ DATA SET **********/ +/***********************************/ + +void readDataSet( unsigned int& outer, + unsigned int& num_X, + unsigned int& num_Y, + unsigned int& num_T +) { + if( read_int( static_cast( &outer ) ) || + read_int( static_cast( &num_X ) ) || + read_int( static_cast( &num_Y ) ) || + read_int( static_cast( &num_T ) ) ) { + + fprintf(stderr, "Syntax error when reading the dataset, i.e., four ints.\n"); + exit(1); + } + + { // check dataset invariants: + bool atr_ok = true; + + atr_ok = outer > 0; + assert(atr_ok && "Outer loop count less than 0!"); + + atr_ok = (num_X > 0) && (num_X <= WORKGROUP_SIZE) && is_pow2(num_X); + assert(atr_ok && "Illegal NUM_X value!"); + + atr_ok = (num_Y > 0) && (num_Y <= WORKGROUP_SIZE) && is_pow2(num_Y); + assert(atr_ok && "Illegal NUM_X value!"); + + atr_ok = num_T > 0; + assert(atr_ok && "NUM_T value less or equal to zero!!"); + } +} + +#endif // PARSE_INPUT + diff --git a/GenericPricing/Data/Large/input.data b/benchmarks/GenericPricing/datasets/Large/input.data similarity index 100% rename from GenericPricing/Data/Large/input.data rename to benchmarks/GenericPricing/datasets/Large/input.data diff --git a/GenericPricing/Data/Large/output.data b/benchmarks/GenericPricing/datasets/Large/output.data similarity index 100% rename from GenericPricing/Data/Large/output.data rename to benchmarks/GenericPricing/datasets/Large/output.data diff --git a/GenericPricing/Data/Medium/input.data b/benchmarks/GenericPricing/datasets/Medium/input.data similarity index 100% rename from GenericPricing/Data/Medium/input.data rename to benchmarks/GenericPricing/datasets/Medium/input.data diff --git a/GenericPricing/Data/Medium/output.data b/benchmarks/GenericPricing/datasets/Medium/output.data similarity index 100% rename from GenericPricing/Data/Medium/output.data rename to benchmarks/GenericPricing/datasets/Medium/output.data diff --git a/GenericPricing/Data/Small/input.data b/benchmarks/GenericPricing/datasets/Small/input.data similarity index 100% rename from GenericPricing/Data/Small/input.data rename to benchmarks/GenericPricing/datasets/Small/input.data diff --git a/GenericPricing/Data/Small/output.data b/benchmarks/GenericPricing/datasets/Small/output.data similarity index 100% rename from GenericPricing/Data/Small/output.data rename to benchmarks/GenericPricing/datasets/Small/output.data diff --git a/GenericPricing/CppOpenCL/ContractDefs/LargeContract.cl b/benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/LargeContract.cl similarity index 100% rename from GenericPricing/CppOpenCL/ContractDefs/LargeContract.cl rename to benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/LargeContract.cl diff --git a/GenericPricing/CppOpenCL/ContractDefs/MediumContract.cl b/benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/MediumContract.cl similarity index 100% rename from GenericPricing/CppOpenCL/ContractDefs/MediumContract.cl rename to benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/MediumContract.cl diff --git a/GenericPricing/CppOpenCL/ContractDefs/SmallContract.cl b/benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/SmallContract.cl similarity index 100% rename from GenericPricing/CppOpenCL/ContractDefs/SmallContract.cl rename to benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/SmallContract.cl diff --git a/GenericPricing/CppOpenCL/GenPricing.cpp b/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp similarity index 96% rename from GenericPricing/CppOpenCL/GenPricing.cpp rename to benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp index a67d8db..db0ee96 100644 --- a/GenericPricing/CppOpenCL/GenPricing.cpp +++ b/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp @@ -3,6 +3,9 @@ //#include "Contracts.h" //#include +#include +#include + /*****************************************************/ /*****************************************************/ /*****************************************************/ @@ -158,7 +161,7 @@ int main() { int num_cores; double* prices; - unsigned long int elapsed; + unsigned long int elapsed_usec; { // run kernel prices = run_GPUkernel( scals, sob_arrs, md_arrs, bb_arrs, num_cores, elapsed ); @@ -167,9 +170,12 @@ int main() { bb_arrs.cleanup(); } - { // validation and writeback of the result - bool is_valid = validate ( scals.num_models, prices ); - writeStatsAndResult( is_valid, scals.num_models, prices, true, num_cores, elapsed ); + { + std::ofstream runtime("runtime.txt"); + runtime << elapsed_usec / 1000; + std::ofstream result("result.data"); + result << *prices; + free(prices); } } diff --git a/GenericPricing/CppOpenCL/GenericPricingPrivOpt.cl b/benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingPrivOpt.cl similarity index 100% rename from GenericPricing/CppOpenCL/GenericPricingPrivOpt.cl rename to benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingPrivOpt.cl diff --git a/GenericPricing/CppOpenCL/GenericPricingVectOpt.cl b/benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectOpt.cl similarity index 100% rename from GenericPricing/CppOpenCL/GenericPricingVectOpt.cl rename to benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectOpt.cl diff --git a/GenericPricing/CppOpenCL/GenericPricingVectUncoalesced.cl b/benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectUncoalesced.cl similarity index 100% rename from GenericPricing/CppOpenCL/GenericPricingVectUncoalesced.cl rename to benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectUncoalesced.cl diff --git a/GenericPricing/CppOpenCL/Makefile b/benchmarks/GenericPricing/implementations/CppOpenCL/Makefile similarity index 66% rename from GenericPricing/CppOpenCL/Makefile rename to benchmarks/GenericPricing/implementations/CppOpenCL/Makefile index 5159537..c1c5d4c 100644 --- a/GenericPricing/CppOpenCL/Makefile +++ b/benchmarks/GenericPricing/implementations/CppOpenCL/Makefile @@ -1,17 +1,16 @@ -include ../../setup.mk +include setup.mk ifndef ($(HAVE_GPU)) -include ../../platform.mk +include platform.mk endif -INCLUDES += -I../includeC GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) SOURCES_CPP =GenPricing.cpp -HELPERS =StructGPU.h ../includeC/Constants.h ../includeC/Optimizations.h ../includeC/ParseInput.h +HELPERS =StructGPU.h Constants.h Optimizations.h ParseInput.h OBJECTS =GenPricing.o EXECUTABLE =GenPricing @@ -35,19 +34,6 @@ gpu: $(OBJECTS) $(SOURCES_CPP) $(HELPERS) cpu: $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) -run_small: - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - - -#default: $(OBJECTS) -# $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) - clean: rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt @# clean nVidia compiler cache diff --git a/GenericPricing/CppOpenCL/StructGPU.h b/benchmarks/GenericPricing/implementations/CppOpenCL/StructGPU.h similarity index 100% rename from GenericPricing/CppOpenCL/StructGPU.h rename to benchmarks/GenericPricing/implementations/CppOpenCL/StructGPU.h diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate b/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate new file mode 100755 index 0000000..f1ba6ec --- /dev/null +++ b/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/platform.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_LIB_DIR/include/SDK_stub.h . +cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . +cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . +cp -r $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run $FINPAR_IMPLEMENTATION/ContractDefs . +cp $FINPAR_INPUT input.data + +make diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/run b/benchmarks/GenericPricing/implementations/CppOpenCL/run new file mode 100755 index 0000000..e494a24 --- /dev/null +++ b/benchmarks/GenericPricing/implementations/CppOpenCL/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat input.data | ./GenPricing diff --git a/GenericPricing/HaskellLH/GenPricing.hs b/benchmarks/GenericPricing/implementations/HaskellLH/GenPricing.hs similarity index 85% rename from GenericPricing/HaskellLH/GenPricing.hs rename to benchmarks/GenericPricing/implementations/HaskellLH/GenPricing.hs index d12942a..9ea379c 100644 --- a/GenericPricing/HaskellLH/GenPricing.hs +++ b/benchmarks/GenericPricing/implementations/HaskellLH/GenPricing.hs @@ -3,6 +3,7 @@ module Main where import Control.Applicative import Control.Monad import Data.Maybe +import System.CPUTime ------------------------------------ --- Requires the installation of --- @@ -17,8 +18,6 @@ import Data.Bits import Data.List hiding (tail) import Prelude hiding (tail) -import Debug.Trace - import Data.Vector.Unboxed(Vector) -- for gaussian approx import qualified Data.Vector.Unboxed as V @@ -93,6 +92,7 @@ sobolIndR bits_num dir_vs n = divisor = 2.0 ** fromIntegral bits_num +lsb0 :: (Bits a, Num b, Num a) => a -> b lsb0 n = lsb0_help 0 n where lsb0_help ell c | (c .&. 1 == 0) = ell | otherwise = lsb0_help (ell+1) (c `shiftR` 1) @@ -462,25 +462,6 @@ tiledSkeleton sob_dim num_mc_its chunk fun = extra = if (divides) then [] else [num_mc_its] iv = zip [1,chunk+1..] ([chunk, 2*chunk .. num_mc_its] ++ extra ) in (reduce (zipWith (+)) (replicate sob_dim 0.0) . map fun) iv ----------------------------------------------- ---- Formatting the Output of the Benchmark --- ----------------------------------------------- -validate :: [Double] -> [Double] -> (Int,Int,Int,Int) -> [String] -validate prices_ref prices info= - let errs = map abs $ zipWith (-) prices_ref prices - err = reduce max 0.0 errs - (contract,num_mc_it, num_dates, num_under) = info - in ["// Generic Pricing Haskell Benchmark (List-Homomorphism Style):", - "// Contract: " ++ show contract ++ ", MC Its#: " ++ show num_mc_it ++ - ", #Underlyings: " ++ show num_under ++ ", #Path Dates: " ++ - show num_dates, - ( if err <= 0.0005 - then "1\t\t// VALID Result," - else "0\t\t// INVALID Result," ), - "0\t\t// Runtime in microseconds,", - "1\t\t// CPU Threads,", - show prices ++ "\t// Generic Pricing Result."] - ----------------------------------------- --- Entry point for Generic Pricing --- @@ -488,50 +469,42 @@ validate prices_ref prices info= --- e.g., parsing Dataset from StdIn --- ----------------------------------------- main :: IO () -main = do s <- getContents +main = do s <- getContents case parse run "input" s of - Left e -> error $ show e - Right (p,pr,i) -> do let msg_lst = validate pr p i - putStrLn (msg_lst !! 0) - putStrLn (msg_lst !! 1) - putStrLn (msg_lst !! 2) - putStrLn (msg_lst !! 3) - putStrLn (msg_lst !! 4) - putStrLn (msg_lst !! 5) - -- print $ validate pr p i --- either (error . show) print $ parse run "input" s - where run = do contract <- readInt - num_mc_it <- readInt - num_dates <- readInt - num_under <- readInt --- v <- compute contract num_mc_it num_dates num_under <$> --- readInt <*> readInt <*> readInt2d <*> --- readDouble3d <*> readDouble3d <*> readDouble3d <*> --- readDouble2d <*> readDouble2d <*> readDouble2d <*> --- readInt2d <*> readDouble2d - - num_models<- readInt - num_bits <- readInt - sob_dirvs <- readInt2d - md_cs <- readDouble3d - md_vols <- readDouble3d - md_drifts <- readDouble3d - md_starts <- readDouble2d - md_detvals<- readDouble2d - md_discts <- readDouble2d - bb_inds <- readInt2d - bb_data <- readDouble2d - - let tiled_skel = tiledSkeleton (num_under*num_dates) num_mc_it 128 - let v = tiled_skel $ - compute_chunk - contract num_mc_it num_dates num_under num_models num_bits - sob_dirvs md_cs md_vols md_drifts md_starts md_detvals - md_discts bb_inds bb_data - - - r <- readDouble1d - return (v, r, (contract,num_mc_it, num_dates, num_under)) + Left e -> error $ show e + Right m -> do + (v,runtime) <- m + writeFile "result.data" $ show v + writeFile "runtime.txt" $ show runtime + where run = do + contract <- readInt + num_mc_it <- readInt + num_dates <- readInt + num_under <- readInt + + num_models<- readInt + num_bits <- readInt + sob_dirvs <- readInt2d + md_cs <- readDouble3d + md_vols <- readDouble3d + md_drifts <- readDouble3d + md_starts <- readDouble2d + md_detvals<- readDouble2d + md_discts <- readDouble2d + bb_inds <- readInt2d + bb_data <- readDouble2d + + let tiled_skel = tiledSkeleton (num_under*num_dates) num_mc_it 128 + + return $ do + start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + let v = tiled_skel $ + compute_chunk + contract num_mc_it num_dates num_under num_models num_bits + sob_dirvs md_cs md_vols md_drifts md_starts md_detvals + md_discts bb_inds bb_data + end <- v `seq` getCPUTime + return (v, (end - start) `div` 1000000000) readInt2d = readArray $ readArray readInt readDouble1d = readArray readDouble diff --git a/GenericPricing/HaskellLH/Payoff3Cond.hs b/benchmarks/GenericPricing/implementations/HaskellLH/Payoff3Cond.hs similarity index 100% rename from GenericPricing/HaskellLH/Payoff3Cond.hs rename to benchmarks/GenericPricing/implementations/HaskellLH/Payoff3Cond.hs diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/instantiate b/benchmarks/GenericPricing/implementations/HaskellLH/instantiate new file mode 100755 index 0000000..267d65b --- /dev/null +++ b/benchmarks/GenericPricing/implementations/HaskellLH/instantiate @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e # Die on error. + +impl_dir=$FINPAR_IMPLEMENTATION +input=$FINPAR_INPUT + +cp $impl_dir/*hs . +cp $impl_dir/run . +cp $input input.data +ghc -Wall -O2 -msse2 -rtsopts GenPricing.hs -o GenPricing diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/run b/benchmarks/GenericPricing/implementations/HaskellLH/run new file mode 100755 index 0000000..eb51132 --- /dev/null +++ b/benchmarks/GenericPricing/implementations/HaskellLH/run @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +./GenPricing +RTS -K128m -RTS < input.data diff --git a/GenericPricing/Orig_COpenMp/Contracts.h b/benchmarks/GenericPricing/implementations/Orig_COpenMp/Contracts.h similarity index 100% rename from GenericPricing/Orig_COpenMp/Contracts.h rename to benchmarks/GenericPricing/implementations/Orig_COpenMp/Contracts.h diff --git a/GenericPricing/Orig_COpenMp/GenPricing.cpp b/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp similarity index 93% rename from GenericPricing/Orig_COpenMp/GenPricing.cpp rename to benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp index 74a7b27..54ceb50 100644 --- a/GenericPricing/Orig_COpenMp/GenPricing.cpp +++ b/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp @@ -1,5 +1,8 @@ #define FAST_BB +#include +#include + #include "ParseInput.h" #include "SobolGaussBB.h" #include "Contracts.h" @@ -152,7 +155,7 @@ int main() { const int Ps = get_CPU_num_threads(); double* prices; - unsigned long int elapsed; + unsigned long int elapsed_usec; { // run kernel struct timeval t_start, t_end, t_diff; gettimeofday(&t_start, NULL); @@ -164,21 +167,18 @@ int main() { gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; + std::ofstream runtime("runtime.txt"); + runtime << elapsed_usec / 1000; + std::ofstream result("result.data"); + result << *prices; md_arrs .cleanup(); bb_arrs .cleanup(); sob_arrs.cleanup(); } - { // validation and writeback of the result - bool is_valid = validate ( scals.num_models, prices ); - writeStatsAndResult( is_valid, scals.num_models, prices, false, Ps, elapsed ); - free(prices); - } + free(prices); - return 0; // XXX this was "1" before, why? + return 0; } - - -// cat ../Data/Medium/input.data ../Data/Medium/output.data | ./GenPricing 2> Debug.txt diff --git a/GenericPricing/Orig_COpenMp/Makefile b/benchmarks/GenericPricing/implementations/Orig_COpenMp/Makefile similarity index 64% rename from GenericPricing/Orig_COpenMp/Makefile rename to benchmarks/GenericPricing/implementations/Orig_COpenMp/Makefile index f4b87c0..e690441 100644 --- a/GenericPricing/Orig_COpenMp/Makefile +++ b/benchmarks/GenericPricing/implementations/Orig_COpenMp/Makefile @@ -1,7 +1,7 @@ -include ../../setup.mk +include setup.mk ifndef ($(HAVE_GPU)) -include ../../platform.mk +include platform.mk endif INCLUDES += -I../includeC @@ -28,15 +28,5 @@ gpu: $(OBJECTS) cpu: $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: - rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) - + rm -f $(EXECUTABLE) $(OBJECTS) diff --git a/GenericPricing/Orig_COpenMp/SobolGaussBB.h b/benchmarks/GenericPricing/implementations/Orig_COpenMp/SobolGaussBB.h similarity index 100% rename from GenericPricing/Orig_COpenMp/SobolGaussBB.h rename to benchmarks/GenericPricing/implementations/Orig_COpenMp/SobolGaussBB.h diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate b/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate new file mode 100755 index 0000000..84ff1e1 --- /dev/null +++ b/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/platform.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . +cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . +cp $FINPAR_INPUT input.data + +make diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/run b/benchmarks/GenericPricing/implementations/Orig_COpenMp/run new file mode 100755 index 0000000..e494a24 --- /dev/null +++ b/benchmarks/GenericPricing/implementations/Orig_COpenMp/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat input.data | ./GenPricing diff --git a/GenericPricing/includeC/Constants.h b/benchmarks/GenericPricing/lib/Constants.h similarity index 100% rename from GenericPricing/includeC/Constants.h rename to benchmarks/GenericPricing/lib/Constants.h diff --git a/GenericPricing/includeC/Optimizations.h b/benchmarks/GenericPricing/lib/Optimizations.h similarity index 100% rename from GenericPricing/includeC/Optimizations.h rename to benchmarks/GenericPricing/lib/Optimizations.h diff --git a/GenericPricing/includeC/ParseInput.h b/benchmarks/GenericPricing/lib/ParseInput.h similarity index 93% rename from GenericPricing/includeC/ParseInput.h rename to benchmarks/GenericPricing/lib/ParseInput.h index 6cc73fa..190b69a 100644 --- a/GenericPricing/includeC/ParseInput.h +++ b/benchmarks/GenericPricing/lib/ParseInput.h @@ -278,34 +278,6 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, } } -/****************************************/ -/*** Validate w.r.t. Reference Result ***/ -/****************************************/ -bool validate( const int num_models, const double* prices ) { - bool is_valid = true; - double* std_prices; - int64_t shape[3]; - - if (read_array(sizeof(double), read_double, (void**)&std_prices, shape, 1) ) { - fprintf(stderr, "Syntax error when reading reference prices.\n"); - exit(1); - } - assert( (shape[0] == num_models) && "Incorrect shape of reference-price array!"); - - double err = 0.0; - for( int i = 0; i < num_models; i++ ) { - err = std::max( err, fabs(std_prices[i] - prices[i]) ); - } - - if ( err > EPS ) { - is_valid = false; - fprintf(stderr, "Error = %f, EPS = %f!\n", err, EPS); - } - - free(std_prices); - return is_valid; -} - /**************************************/ /*** Format the Result & Other Info ***/ /**************************************/ diff --git a/GenericPricing/includeC/TimeHelper.h b/benchmarks/GenericPricing/lib/TimeHelper.h similarity index 100% rename from GenericPricing/includeC/TimeHelper.h rename to benchmarks/GenericPricing/lib/TimeHelper.h diff --git a/DOCS/Jepsen_Report.pdf b/docs/Jepsen_Report.pdf similarity index 100% rename from DOCS/Jepsen_Report.pdf rename to docs/Jepsen_Report.pdf diff --git a/DOCS/TridagPres.pdf b/docs/TridagPres.pdf similarity index 100% rename from DOCS/TridagPres.pdf rename to docs/TridagPres.pdf diff --git a/finpar b/finpar new file mode 100755 index 0000000..668c624 --- /dev/null +++ b/finpar @@ -0,0 +1,247 @@ +#!/usr/bin/env python + +import os +import subprocess +import json + +def executable(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + +class Implementation: + def __init__(self, finpar_lib_dir, benchmark_lib_dir, name, directory): + if os.path.isdir(directory): + self.directory = directory + else: + if os.path.isfile(directory): + raise Exception("File %s exists, but should be an implementation directory" % directory) + else: + raise Exception("Implementation directory %s does not exist " % directory) + + self.directory = directory + self.name = name + self.finpar_lib_dir = finpar_lib_dir + self.benchmark_lib_dir = benchmark_lib_dir + + runfile = os.path.join(self.directory, "run") + instantiatefile = os.path.join(self.directory, "instantiate") + if not executable(runfile): + raise Exception("%s is not an executable file" % runfile) + if not executable(instantiatefile): + raise Exception("%s is not an executable file" % instantiatefile) + + def instantiate(self, where, input_data): + if not os.path.isdir(where): + os.mkdir(where) + + # We use the current environment as a template, and then + # extend it with some new variables. + instantiate_env = os.environ.copy() + instantiate_env["FINPAR_LIB_DIR"] = self.finpar_lib_dir + instantiate_env["FINPAR_BENCHMARK_LIB_DIR"] = self.benchmark_lib_dir + instantiate_env["FINPAR_IMPLEMENTATION"] = self.directory + instantiate_env["FINPAR_INPUT"] = input_data + + proc = subprocess.Popen(os.path.join(self.directory, "instantiate"), + env=instantiate_env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + close_fds=True, + cwd=where) + (stdoutdata, stderrdata) = proc.communicate(input=None) + return (proc.returncode, stdoutdata, stderrdata) + +class Benchmark: + # In the constructor, we do some basic sanity-checking. The + # primary purpose here is to provide better error messages than if + # we fail to read files later down the line. + def __init__(self, finpardir, name, directory): + self.finpardir = finpardir + self.name = name + + if os.path.isdir(directory): + self.directory = directory + else: + raise Exception("Benchmark directory %s does not exist" % directory) + dircontents = os.listdir(self.directory) + + # The lib directories do not have to exist. + self.benchmark_lib_dir = os.path.join(self.directory, "lib") + self.finpar_lib_dir = os.path.join(self.finpardir, "lib") + + if "implementations" in dircontents: + self.__gather_implementations() + else: + raise Exception("No implementation directory in %s" % directory) + + if "datasets" in dircontents: + self.datasets = os.path.join(self.directory, "datasets") + self.__gather_datasets() + else: + raise Exception("No datasets directory in %s" % directory) + + def __gather_implementations(self): + self.implementations = [] + for impl in os.listdir(os.path.join(self.directory, "implementations")): + implpath = os.path.join(self.directory, "implementations", impl) + if os.path.isdir(implpath): + self.implementations.append(Implementation(self.finpar_lib_dir, + self.benchmark_lib_dir, + impl, + os.path.join(self.directory, "implementations", impl))) + + def __gather_datasets(self): + self.datasets = {} + for dataset in os.listdir(os.path.join(self.directory, "datasets")): + datasetpath = os.path.join(self.directory, "datasets", dataset) + if os.path.isdir(datasetpath): + inputfile = os.path.join(self.directory, "datasets", dataset, "input.json") + outputfile = os.path.join(self.directory, "datasets", dataset, "output.json") + if not os.path.isfile(inputfile): + raise Exception("File %s missing or not a file." % inputfile) + if not os.path.isfile(outputfile): + raise Exception("File %s missing or not a file." % outputfile) + + self.datasets[dataset] = { 'input_file' : inputfile, + 'expected_output' : read_json_file(outputfile) + } + +def note_result(results, benchmark, implementation, dataset, runtime): + if type(runtime) is int: + status = str(runtime) + "ms" + else: + status = runtime + print("Benchmark %s, implementation %s, dataset %s: %s" % + (benchmark, implementation, dataset, status)) + results[(benchmark,implementation,dataset)] = runtime + +def run_all_benchmark_implementations(finpar_dir, workdir, benchmarkdir): + b = Benchmark(finpar_dir, os.path.basename(benchmarkdir), benchmarkdir) + insts = [] + results = {} + + for impl in b.implementations: + for dataset in b.datasets: + instdir = os.path.join(workdir, + "%s-%s-%s" % (b.name, impl.name, dataset)) + print("Instantiating in %s" % instdir) + (retcode, stdout, stderr) = impl.instantiate(instdir, b.datasets[dataset]['input_file']) + if retcode != 0: + print("Instantiation failed with exit code %d.\nStdout:\n%s\nStderr:\n%s" % + (retcode, stdout, stderr)) + else: + insts.append({ 'benchmark' : b.name, + 'implementation' : impl.name, + 'dataset' : dataset, + 'instantiation_directory' : instdir, + 'expected_output' : b.datasets[dataset]['expected_output'] + }) + + for inst in insts: + instdir = inst['instantiation_directory'] + print("\nRunning %s" % instdir) + stdoutpath = os.path.join(instdir, "stdout.log") + stderrpath = os.path.join(instdir, "stderr.log") + with open(stdoutpath, "w") as stdout: + with open(stderrpath, "w") as stderr: + print("Output can be found in %s and %s" % (stdoutpath, stderrpath)) + proc = subprocess.Popen(os.path.join(instdir, "run"), + stdout=stdout, + stderr=stderr, + stdin=subprocess.PIPE, + close_fds=True, + cwd=instdir) + proc.stdin.close() # Make sure stdin EOFs. + proc.wait() + + if proc.returncode == 0: + success = "success" + else: + success = "failure" + + try: + runtime = read_runtime(instdir) + except IOError: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "no runtime measurement") + continue + except ValueError: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "non-integer runtime measurement") + continue + + try: + result = read_json_file(os.path.join(instdir, "result.json")) + expected = inst['expected_output'] + if compare_json(result, expected): + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + runtime) + else: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "invalid result") + except (IOError, ValueError): + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "cannot read result") + + return results + +def read_runtime(instdir): + with open(os.path.join(instdir, "runtime.txt"), "r") as file: + return int(file.read()) + +def read_json_file(filename): + with open(filename, "r") as file: + return json.loads(file.read()) + +epsilon = 0.001 + +# Generic comparison function using epsilon for comparing floats. +def compare_json(json1, json2): + if type(json1) != type(json2): + return False + + if type(json1) is float: + return abs(json1-json2) < epsilon + + if type(json1) is list: + if len(json1) != len(json2): + return False + for x,y in zip(json1, json2): + if not compare_json(x,y): + return False + return True + + if type(json1) is dict: + keys1 = json1.keys() + keys2 = json2.keys() + keys1.sort() + keys2.sort() + if keys1 == keys2: + for key in keys1: + if not compare_json(json1[key], json2[key]): + return False + return True + else: + return False + + return json1 == json2 + +def test(): + run_all_benchmark_implementations('/home/athas/repos/finpar', + '/home/athas/repos/finpar/instantiations', + '/home/athas/repos/finpar/benchmarks/CalibVolDiff') diff --git a/include/ParserC.h b/lib/include/ParserC.h similarity index 82% rename from include/ParserC.h rename to lib/include/ParserC.h index ed3b2c4..a6019ae 100644 --- a/include/ParserC.h +++ b/lib/include/ParserC.h @@ -7,7 +7,6 @@ #include #include - struct array_reader { char* elems; int64_t n_elems_space; @@ -216,41 +215,36 @@ int read_double(void* dest) { /////////////////////// /// Writing Dataset /// /////////////////////// -void write_scal( const int * i, const char* msg ) { - fprintf(stdout, "%d ", *i); - if( msg ) fprintf(stdout, "\t// %s\n", msg); +void write_scal( FILE* out, const int * i ) { + fprintf(out, "%d ", *i); } -void write_scal( const double* r, const char* msg ) { - fprintf(stdout, "%lf ", *r); - if( msg ) fprintf(stdout, "\t// %s\n", msg); +void write_scal( FILE* out, const double* r ) { + fprintf(out, "%lf ", *r); } -void write_scal( const float * r, const char* msg ) { - fprintf(stdout, "%f ", *r); - if( msg ) fprintf(stdout, "\t// %s\n", msg); +void write_scal( FILE* out, const float * r ) { + fprintf(out, "%f ", *r); } template -void write_1Darr( const T* ptr, const int& N, const char* msg ) { - fprintf(stdout, "\n [ "); +void write_1Darr( FILE* out, const T* ptr, const int& N ) { + fprintf(out, "\n [ "); for( int i = 0; i < N-1; i ++ ) { - write_scal(&ptr[i], NULL); - fprintf(stdout, ", "); + write_scal(out, &ptr[i]); + fprintf(out, ", "); } - write_scal(&ptr[N-1], NULL); - if (msg) fprintf(stdout, " ]\t//%s\n\n", msg); - else fprintf(stdout, " ]"); + write_scal(out, &ptr[N-1]); + fprintf(out, " ]"); } template -void write_2Darr( const T* ptr, const int& Nouter, const int& Ninner, const char* msg ) { - fprintf(stdout, "\n[ "); +void write_2Darr( FILE* out, const T* ptr, const int& Nouter, const int& Ninner ) { + fprintf(out, "\n[ "); for( int i = 0; i < Nouter-1; i ++ ) { - write_1Darr( ptr + i*Ninner, Ninner, NULL ); - fprintf(stdout, ","); + write_1Darr( stdout, ptr + i*Ninner, Ninner ); + fprintf(out, ","); } - write_1Darr( ptr + (Nouter-1)*Ninner, Ninner, NULL ); - if (msg) fprintf(stdout, "\n]\t//%s\n\n", msg); - else fprintf(stdout, "\n]\n"); + write_1Darr( out, ptr + (Nouter-1)*Ninner, Ninner ); + fprintf(out, "\n]\n"); } #endif // DATASET_PARSER diff --git a/include/SDK_stub.h b/lib/include/SDK_stub.h similarity index 100% rename from include/SDK_stub.h rename to lib/include/SDK_stub.h diff --git a/include/Util.h b/lib/include/Util.h similarity index 100% rename from include/Util.h rename to lib/include/Util.h diff --git a/include/Utilities.cl b/lib/include/Utilities.cl similarity index 100% rename from include/Utilities.cl rename to lib/include/Utilities.cl diff --git a/lib/linearise_data.py b/lib/linearise_data.py new file mode 100755 index 0000000..46d5831 --- /dev/null +++ b/lib/linearise_data.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +import json +import sys + +def read_json_file(filename): + with open(filename, "r") as file: + return json.loads(file.read()) + +if __name__ == '__main__': + if len(sys.argv) < 3: + exit("Usage: %s [fields...]" % sys.argv[0]) + else: + data = read_json_file(sys.argv[1]) + for field in sys.argv[2:]: + try: + print ("// " + field) + print(data[field]) + except KeyError: + exit("Key %s not found in JSON file." % field) diff --git a/lib/platform.mk b/lib/platform.mk new file mode 100644 index 0000000..c9889b1 --- /dev/null +++ b/lib/platform.mk @@ -0,0 +1,28 @@ +# platform specification for benchmarks. Edit as appropriate for your +# platform before running + +# 1 = platform has a GPU +HAVE_GPU = 1 +GPU_DEVICE_ID = 0 + +# GPU warp size. Keep consistent if you use the non-log variant +#GPU_WARP = 32 +GPU_LG_WARP = 5 + +# GPU memory sizes in kilobyte +GPU_LOCAL_MEM = 48 +GPU_CONST_MEM = 64 +GPU_REG_MEM = 64 +# device memory in gigabyte +GPU_DEVICE_MEM= 2 +# ``Optimal'' Amount of Local/Fast Memory Per Thread +GPU_LOCAL_MEM_PER_TH=8 +# Number of GPU cores +GPU_NUM_CORES = 192 + +# CPU and memory spec. +NCORES = 4 +# in gigabyte +MEMORY = 4 + +export diff --git a/lib/setup.mk b/lib/setup.mk new file mode 100644 index 0000000..f69bc95 --- /dev/null +++ b/lib/setup.mk @@ -0,0 +1,20 @@ +OS=$(shell uname -s) + +ifeq ($(OS),Darwin) + OPENCL_ROOTDIR ?= /System/Library/Frameworks/OpenCL.framework + OPENCL_LIBDIR := $(OPENCL_ROOTDIR)/Libraries + OPENCL_INCDIR ?= $(OPENCL_ROOTDIR)/Headers + CXX = g++-4.9 + CXXFLAGS = + LIB = -framework OpenCL -L$(OPENCL_LIBDIR) -Wl,-x -m64 + CXXFLAGS = -fopenmp -O3 -fno-rtti +else + OPENCL_ROOTDIR ?= /usr/local/cuda + OPENCL_LIBDIR ?= $(OPENCL_ROOTDIR)/lib64 + OPENCL_INCDIR ?= $(OPENCL_ROOTDIR)/include + CXX = g++ + LIB = -L$(OPENCL_LIBDIR) -lOpenCL + CXXFLAGS = -fopenmp -O3 +endif + +INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include diff --git a/redesign.md b/redesign.md new file mode 100644 index 0000000..4d20296 --- /dev/null +++ b/redesign.md @@ -0,0 +1,114 @@ +(To eliminate ambiguity, here is the nomenclature: we have a number of +*benchmarks* (currently CalibGA, CalibVolDiff, and GenericPricer), +each of which have several *data sets* (typically Small, Medium, and +Large), and several *implementations* (right now mostly different +versions of C) each of which may have several *configurations*. +Running a benchmark consists of selecting a data set and an +implementation, and possibly specifying a specific configuration of +the implementation. + +Recently, a Martin, Frederik, and myself have been implementing the +finpar bechmarks in more diverse programming languages - (streaming) +NESL, APL and Futhark, at least. Unfortunately, the current finpar +infrastructure is not very easy to work with, and so their work has +not been integrated. I have identified the following problems: + + * Implementations are not cleanly separated from data sets and + ancillary code. + + **Solution**: for each benchmark, have a directory that contains + only implementations. + + * Building an implementation modifies the implementation + directory, and more importantly, configuring an implementation + often involves manually modifying files in the directory (see + CalibGA/includeC/KerConsts.h for an example). This is really + bad and makes structured and reproducible benchmarking almost + impossible. + + **Solution**: when "compiling" an implementation, put everything + in a new, separate directory, I will call the *instantiation + directory*. All configuration must be done via passing options to + the compilation step, and will be reflected in the files put in + the instantiation directory. + + * Adding new implementations is a mess, because you have to modify + the global build system. + + **Solution**: define a setup/run-protocol that each benchmark + implementation must follow, and which can be used by a generic + controller script. + + * Validation is done by the benchmark implementations. There is no + reason to do this. + + **Solution**: have the implementation produce + their results in some well-defined format, and have the controller + script validate it. + + * Everything is done with Makefiles. Nobody likes modifying + Makefiles, and we don't need incremental rebuilds anyway. + + + **Solution**: write as much as possible in Python or simple shell + script. + +I propose the following rough protocol: + + * Each benchmark implementation must include one executable file, + called `instantiate`. This can be written in whatever language + one prefers. + + * When the `instantiate` program for an implementation is invoked, + the following environment variables must be set: + + * `FINPAR_IMPLEMENTATION`, which must point at the + implementation directory. This is to get around the fact that + it's not always easy to find the location of the running + program. + + * `FINPAR_DATASET`, which must point at a directory containint + `.input` and `.output` files. + + * The `instantiate` program will instantiate the implementation in + the *current directory*, which will become the instantiation + directory. + + * The `instantiate` program can be passed command-line options to + futher configure the implementation. These are defined on a + per-implementation basis, and not standardised. + + * After instantiation, the instantiation directory must contain a + program `run`, which, when executed, will run the benchmark + implementation. The result will be two files in the + instantiation directory: + + * `runtime.txt`, which contains the runtime in milliseconds as + an integer. + + * `result.data`, which contains the result in ou well-defined + data format. + + I have decided that the runtime should be measured by the + implementation itself, as it is not possible to black-box + measure this without possibly measuring the wrong things (like + kernel compilation, exotic hardware setup, parsing of input + data, or IO). + +The following questions have yet to be answered: + + * What data format should we use? Currently, finpar uses the + Futhark value format, which is pretty simple. We can possibly + make life even simpler by using JSON, but it is incredibly + annoying that JSON does not support comments. + + * Should we use environment variables at all? It was mostly to + avoid having the instantiate-script do command-line parsing unless + it wants to. + +Yet, I think this is a good protocol. It will allow us to build an +easy-to-use controller program on top of it, that can automatically +generate a bunch of different instantiations with different +configurations and data sets, and maybe draw graphs of the results, +etc. I estimate that the above could be implemented fairly quickly, +and sanity-checked with the extant benchmark implementations. diff --git a/setup.mk b/setup.mk index f85a816..fe4c4b2 100644 --- a/setup.mk +++ b/setup.mk @@ -17,4 +17,4 @@ else CXXFLAGS = -fopenmp -O3 endif -INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include +INCLUDES = -I$(OPENCL_INCDIR) -I. From 49feee8e813e8981138e97d7a08c29f4a2b7fd8c Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 20 Feb 2015 17:23:12 +0100 Subject: [PATCH 002/122] Standalone benchmark runner example. --- finpar | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/finpar b/finpar index 668c624..6f11400 100755 --- a/finpar +++ b/finpar @@ -110,7 +110,7 @@ def note_result(results, benchmark, implementation, dataset, runtime): if type(runtime) is int: status = str(runtime) + "ms" else: - status = runtime + status = "failed, " + runtime print("Benchmark %s, implementation %s, dataset %s: %s" % (benchmark, implementation, dataset, status)) results[(benchmark,implementation,dataset)] = runtime @@ -154,10 +154,13 @@ def run_all_benchmark_implementations(finpar_dir, workdir, benchmarkdir): proc.stdin.close() # Make sure stdin EOFs. proc.wait() - if proc.returncode == 0: - success = "success" - else: - success = "failure" + if proc.returncode != 0: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "non-zero exit code") + continue try: runtime = read_runtime(instdir) @@ -245,3 +248,12 @@ def test(): run_all_benchmark_implementations('/home/athas/repos/finpar', '/home/athas/repos/finpar/instantiations', '/home/athas/repos/finpar/benchmarks/CalibVolDiff') + +if __name__ == '__main__': + print "Assuming I am being run from finpar directory." + print "Will read benchmark benchmarks/CalibVolDiff." + print "Will instantiate in instantiations/." + finpar_dir = os.getcwd() + run_all_benchmark_implementations(finpar_dir, + os.path.join(finpar_dir, 'instantiations'), + os.path.join(finpar_dir, 'benchmarks/CalibVolDiff')) From 6668d7ac67a3be684f32cdcfb5f09e90ef93f609 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 20 Feb 2015 17:57:41 +0100 Subject: [PATCH 003/122] Fix test runner. --- finpar | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/finpar b/finpar index 6f11400..6861d01 100755 --- a/finpar +++ b/finpar @@ -106,13 +106,16 @@ class Benchmark: 'expected_output' : read_json_file(outputfile) } +def desc_triple(benchmark, implementation, dataset): + return "Benchmark %s, implementation %s, dataset %s" % (benchmark, implementation, dataset) + def note_result(results, benchmark, implementation, dataset, runtime): if type(runtime) is int: status = str(runtime) + "ms" else: status = "failed, " + runtime - print("Benchmark %s, implementation %s, dataset %s: %s" % - (benchmark, implementation, dataset, status)) + print("%s: %s" % + (desc_triple(benchmark, implementation, dataset), status)) results[(benchmark,implementation,dataset)] = runtime def run_all_benchmark_implementations(finpar_dir, workdir, benchmarkdir): @@ -244,16 +247,32 @@ def compare_json(json1, json2): return json1 == json2 -def test(): - run_all_benchmark_implementations('/home/athas/repos/finpar', - '/home/athas/repos/finpar/instantiations', - '/home/athas/repos/finpar/benchmarks/CalibVolDiff') - if __name__ == '__main__': print "Assuming I am being run from finpar directory." print "Will read benchmark benchmarks/CalibVolDiff." print "Will instantiate in instantiations/." finpar_dir = os.getcwd() - run_all_benchmark_implementations(finpar_dir, - os.path.join(finpar_dir, 'instantiations'), - os.path.join(finpar_dir, 'benchmarks/CalibVolDiff')) + results = run_all_benchmark_implementations(finpar_dir, + os.path.join(finpar_dir, 'instantiations'), + os.path.join(finpar_dir, 'benchmarks/CalibVolDiff')) + successful = {} + failed = {} + + for result in results: + if type(results[result]) is int: + successful[result] = int(results[result]) + else: + failed[result] = results[result] + + print "\nFailed" + for f in failed: + (benchmark, implementation, dataset) = f + print("%s: %s" % + (desc_triple(benchmark, implementation, dataset), + failed[f])) + + print "\nSucceeded" + for s in successful: + (benchmark, implementation, dataset) = f + print("%s: %s", (desc_triple(benchmark, implementation, dataset), + successful[s])) From 160f21d6cc5b0fa74f2505fef80d5f8ea7eebbc5 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 20 Feb 2015 18:01:00 +0100 Subject: [PATCH 004/122] This file is not needed. --- redesign.md | 114 ---------------------------------------------------- 1 file changed, 114 deletions(-) delete mode 100644 redesign.md diff --git a/redesign.md b/redesign.md deleted file mode 100644 index 4d20296..0000000 --- a/redesign.md +++ /dev/null @@ -1,114 +0,0 @@ -(To eliminate ambiguity, here is the nomenclature: we have a number of -*benchmarks* (currently CalibGA, CalibVolDiff, and GenericPricer), -each of which have several *data sets* (typically Small, Medium, and -Large), and several *implementations* (right now mostly different -versions of C) each of which may have several *configurations*. -Running a benchmark consists of selecting a data set and an -implementation, and possibly specifying a specific configuration of -the implementation. - -Recently, a Martin, Frederik, and myself have been implementing the -finpar bechmarks in more diverse programming languages - (streaming) -NESL, APL and Futhark, at least. Unfortunately, the current finpar -infrastructure is not very easy to work with, and so their work has -not been integrated. I have identified the following problems: - - * Implementations are not cleanly separated from data sets and - ancillary code. - - **Solution**: for each benchmark, have a directory that contains - only implementations. - - * Building an implementation modifies the implementation - directory, and more importantly, configuring an implementation - often involves manually modifying files in the directory (see - CalibGA/includeC/KerConsts.h for an example). This is really - bad and makes structured and reproducible benchmarking almost - impossible. - - **Solution**: when "compiling" an implementation, put everything - in a new, separate directory, I will call the *instantiation - directory*. All configuration must be done via passing options to - the compilation step, and will be reflected in the files put in - the instantiation directory. - - * Adding new implementations is a mess, because you have to modify - the global build system. - - **Solution**: define a setup/run-protocol that each benchmark - implementation must follow, and which can be used by a generic - controller script. - - * Validation is done by the benchmark implementations. There is no - reason to do this. - - **Solution**: have the implementation produce - their results in some well-defined format, and have the controller - script validate it. - - * Everything is done with Makefiles. Nobody likes modifying - Makefiles, and we don't need incremental rebuilds anyway. - - - **Solution**: write as much as possible in Python or simple shell - script. - -I propose the following rough protocol: - - * Each benchmark implementation must include one executable file, - called `instantiate`. This can be written in whatever language - one prefers. - - * When the `instantiate` program for an implementation is invoked, - the following environment variables must be set: - - * `FINPAR_IMPLEMENTATION`, which must point at the - implementation directory. This is to get around the fact that - it's not always easy to find the location of the running - program. - - * `FINPAR_DATASET`, which must point at a directory containint - `.input` and `.output` files. - - * The `instantiate` program will instantiate the implementation in - the *current directory*, which will become the instantiation - directory. - - * The `instantiate` program can be passed command-line options to - futher configure the implementation. These are defined on a - per-implementation basis, and not standardised. - - * After instantiation, the instantiation directory must contain a - program `run`, which, when executed, will run the benchmark - implementation. The result will be two files in the - instantiation directory: - - * `runtime.txt`, which contains the runtime in milliseconds as - an integer. - - * `result.data`, which contains the result in ou well-defined - data format. - - I have decided that the runtime should be measured by the - implementation itself, as it is not possible to black-box - measure this without possibly measuring the wrong things (like - kernel compilation, exotic hardware setup, parsing of input - data, or IO). - -The following questions have yet to be answered: - - * What data format should we use? Currently, finpar uses the - Futhark value format, which is pretty simple. We can possibly - make life even simpler by using JSON, but it is incredibly - annoying that JSON does not support comments. - - * Should we use environment variables at all? It was mostly to - avoid having the instantiate-script do command-line parsing unless - it wants to. - -Yet, I think this is a good protocol. It will allow us to build an -easy-to-use controller program on top of it, that can automatically -generate a bunch of different instantiations with different -configurations and data sets, and maybe draw graphs of the results, -etc. I estimate that the above could be implemented fairly quickly, -and sanity-checked with the extant benchmark implementations. From eeba233fdf1bb9f7ecde883cd0b452d87d3a369a Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 20 Feb 2015 23:11:46 +0100 Subject: [PATCH 005/122] Support platform-specific configuration. --- .../implementations/All_COpenCLMP/Makefile | 5 +- .../implementations/All_COpenCLMP/instantiate | 13 +- .../implementations/All_COpenCLMP/run | 3 - .../implementations/Orig_COpenMP/Makefile | 12 +- .../implementations/Orig_COpenMP/instantiate | 13 +- .../implementations/Orig_COpenMP/run | 3 - .../implementations/Original/Makefile | 4 +- .../implementations/Outer_COpenCLMP/Makefile | 4 +- .../Outer_COpenCLMP/instantiate | 14 +- .../implementations/Outer_COpenCLMP/run | 3 - config/platform_example.json | 14 ++ finpar | 145 ++++++++++-------- lib/generate_platform_mk.py | 36 +++++ lib/json_get.py | 16 ++ setup.mk | 20 --- 15 files changed, 191 insertions(+), 114 deletions(-) delete mode 100755 benchmarks/CalibVolDiff/implementations/All_COpenCLMP/run delete mode 100755 benchmarks/CalibVolDiff/implementations/Orig_COpenMP/run delete mode 100755 benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/run create mode 100644 config/platform_example.json create mode 100755 lib/generate_platform_mk.py create mode 100755 lib/json_get.py delete mode 100644 setup.mk diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile index aa5e0ed..e07480b 100644 --- a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile @@ -1,7 +1,7 @@ -include ../../setup.mk +include setup.mk ifndef ($(HAVE_GPU)) -include ../../platform.mk +include platform.mk endif INCLUDES += -I../includeC @@ -22,6 +22,7 @@ else # cannot build this one... no-gpu: @echo "\n*** No GPU configured, cannot build `pwd` ***\n" + exit 1 endif #.cpp.o: $(SOURCES_CPP) $(HELPERS) diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate index c349e59..c302f3b 100755 --- a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate +++ b/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate @@ -11,7 +11,18 @@ cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/DataStructConst.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParPrefixUtil.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile . + $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run < input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run < input.data +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run <" % sys.argv[0]) + else: + data = read_json_file(sys.argv[1]) + generate_platform_mk(data) + diff --git a/lib/json_get.py b/lib/json_get.py new file mode 100755 index 0000000..cca3191 --- /dev/null +++ b/lib/json_get.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import json +import sys +import math + +def read_json_file(filename): + with open(filename, "r") as file: + return json.loads(file.read()) + +if __name__ == '__main__': + if len(sys.argv) != 3: + exit("Usage: %s " % sys.argv[0]) + else: + data = read_json_file(sys.argv[1]) + print(data[sys.argv[2]]) diff --git a/setup.mk b/setup.mk deleted file mode 100644 index fe4c4b2..0000000 --- a/setup.mk +++ /dev/null @@ -1,20 +0,0 @@ -OS=$(shell uname -s) - -ifeq ($(OS),Darwin) - OPENCL_ROOTDIR ?= /System/Library/Frameworks/OpenCL.framework - OPENCL_LIBDIR := $(OPENCL_ROOTDIR)/Libraries - OPENCL_INCDIR ?= $(OPENCL_ROOTDIR)/Headers - CXX = g++-4.9 - CXXFLAGS = - LIB = -framework OpenCL -L$(OPENCL_LIBDIR) -Wl,-x -m64 - CXXFLAGS = -fopenmp -O3 -fno-rtti -else - OPENCL_ROOTDIR ?= /usr/local/cuda - OPENCL_LIBDIR := $(OPENCL_ROOTDIR)/lib64 - OPENCL_INCDIR ?= $(OPENCL_ROOTDIR)/include - CXX = g++ - LIB = -L$(OPENCL_LIBDIR) -lOpenCL - CXXFLAGS = -fopenmp -O3 -endif - -INCLUDES = -I$(OPENCL_INCDIR) -I. From 304d2e8a2a601aab2595adbaca72d57ff20ea7ed Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 20 Feb 2015 23:16:04 +0100 Subject: [PATCH 006/122] Lowercase filenames are preferable on Unix. --- benchmarks/CalibGA/datasets/{Large => large}/input.data | 0 benchmarks/CalibGA/datasets/{Large => large}/output.data | 0 benchmarks/CalibGA/datasets/{Medium => medium}/input.data | 0 benchmarks/CalibGA/datasets/{Medium => medium}/output.data | 0 benchmarks/CalibGA/datasets/{Small => small}/input.data | 0 benchmarks/CalibGA/datasets/{Small => small}/output.data | 0 benchmarks/CalibVolDiff/datasets/{Large => large}/input.json | 0 benchmarks/CalibVolDiff/datasets/{Large => large}/output.json | 0 benchmarks/CalibVolDiff/datasets/{Medium => medium}/input.json | 0 benchmarks/CalibVolDiff/datasets/{Medium => medium}/output.json | 0 benchmarks/CalibVolDiff/datasets/{Small => small}/input.json | 0 benchmarks/CalibVolDiff/datasets/{Small => small}/output.json | 0 benchmarks/GenericPricing/datasets/{Large => large}/input.data | 0 benchmarks/GenericPricing/datasets/{Large => large}/output.data | 0 benchmarks/GenericPricing/datasets/{Medium => medium}/input.data | 0 benchmarks/GenericPricing/datasets/{Medium => medium}/output.data | 0 benchmarks/GenericPricing/datasets/{Small => small}/input.data | 0 benchmarks/GenericPricing/datasets/{Small => small}/output.data | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename benchmarks/CalibGA/datasets/{Large => large}/input.data (100%) rename benchmarks/CalibGA/datasets/{Large => large}/output.data (100%) rename benchmarks/CalibGA/datasets/{Medium => medium}/input.data (100%) rename benchmarks/CalibGA/datasets/{Medium => medium}/output.data (100%) rename benchmarks/CalibGA/datasets/{Small => small}/input.data (100%) rename benchmarks/CalibGA/datasets/{Small => small}/output.data (100%) rename benchmarks/CalibVolDiff/datasets/{Large => large}/input.json (100%) rename benchmarks/CalibVolDiff/datasets/{Large => large}/output.json (100%) rename benchmarks/CalibVolDiff/datasets/{Medium => medium}/input.json (100%) rename benchmarks/CalibVolDiff/datasets/{Medium => medium}/output.json (100%) rename benchmarks/CalibVolDiff/datasets/{Small => small}/input.json (100%) rename benchmarks/CalibVolDiff/datasets/{Small => small}/output.json (100%) rename benchmarks/GenericPricing/datasets/{Large => large}/input.data (100%) rename benchmarks/GenericPricing/datasets/{Large => large}/output.data (100%) rename benchmarks/GenericPricing/datasets/{Medium => medium}/input.data (100%) rename benchmarks/GenericPricing/datasets/{Medium => medium}/output.data (100%) rename benchmarks/GenericPricing/datasets/{Small => small}/input.data (100%) rename benchmarks/GenericPricing/datasets/{Small => small}/output.data (100%) diff --git a/benchmarks/CalibGA/datasets/Large/input.data b/benchmarks/CalibGA/datasets/large/input.data similarity index 100% rename from benchmarks/CalibGA/datasets/Large/input.data rename to benchmarks/CalibGA/datasets/large/input.data diff --git a/benchmarks/CalibGA/datasets/Large/output.data b/benchmarks/CalibGA/datasets/large/output.data similarity index 100% rename from benchmarks/CalibGA/datasets/Large/output.data rename to benchmarks/CalibGA/datasets/large/output.data diff --git a/benchmarks/CalibGA/datasets/Medium/input.data b/benchmarks/CalibGA/datasets/medium/input.data similarity index 100% rename from benchmarks/CalibGA/datasets/Medium/input.data rename to benchmarks/CalibGA/datasets/medium/input.data diff --git a/benchmarks/CalibGA/datasets/Medium/output.data b/benchmarks/CalibGA/datasets/medium/output.data similarity index 100% rename from benchmarks/CalibGA/datasets/Medium/output.data rename to benchmarks/CalibGA/datasets/medium/output.data diff --git a/benchmarks/CalibGA/datasets/Small/input.data b/benchmarks/CalibGA/datasets/small/input.data similarity index 100% rename from benchmarks/CalibGA/datasets/Small/input.data rename to benchmarks/CalibGA/datasets/small/input.data diff --git a/benchmarks/CalibGA/datasets/Small/output.data b/benchmarks/CalibGA/datasets/small/output.data similarity index 100% rename from benchmarks/CalibGA/datasets/Small/output.data rename to benchmarks/CalibGA/datasets/small/output.data diff --git a/benchmarks/CalibVolDiff/datasets/Large/input.json b/benchmarks/CalibVolDiff/datasets/large/input.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/Large/input.json rename to benchmarks/CalibVolDiff/datasets/large/input.json diff --git a/benchmarks/CalibVolDiff/datasets/Large/output.json b/benchmarks/CalibVolDiff/datasets/large/output.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/Large/output.json rename to benchmarks/CalibVolDiff/datasets/large/output.json diff --git a/benchmarks/CalibVolDiff/datasets/Medium/input.json b/benchmarks/CalibVolDiff/datasets/medium/input.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/Medium/input.json rename to benchmarks/CalibVolDiff/datasets/medium/input.json diff --git a/benchmarks/CalibVolDiff/datasets/Medium/output.json b/benchmarks/CalibVolDiff/datasets/medium/output.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/Medium/output.json rename to benchmarks/CalibVolDiff/datasets/medium/output.json diff --git a/benchmarks/CalibVolDiff/datasets/Small/input.json b/benchmarks/CalibVolDiff/datasets/small/input.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/Small/input.json rename to benchmarks/CalibVolDiff/datasets/small/input.json diff --git a/benchmarks/CalibVolDiff/datasets/Small/output.json b/benchmarks/CalibVolDiff/datasets/small/output.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/Small/output.json rename to benchmarks/CalibVolDiff/datasets/small/output.json diff --git a/benchmarks/GenericPricing/datasets/Large/input.data b/benchmarks/GenericPricing/datasets/large/input.data similarity index 100% rename from benchmarks/GenericPricing/datasets/Large/input.data rename to benchmarks/GenericPricing/datasets/large/input.data diff --git a/benchmarks/GenericPricing/datasets/Large/output.data b/benchmarks/GenericPricing/datasets/large/output.data similarity index 100% rename from benchmarks/GenericPricing/datasets/Large/output.data rename to benchmarks/GenericPricing/datasets/large/output.data diff --git a/benchmarks/GenericPricing/datasets/Medium/input.data b/benchmarks/GenericPricing/datasets/medium/input.data similarity index 100% rename from benchmarks/GenericPricing/datasets/Medium/input.data rename to benchmarks/GenericPricing/datasets/medium/input.data diff --git a/benchmarks/GenericPricing/datasets/Medium/output.data b/benchmarks/GenericPricing/datasets/medium/output.data similarity index 100% rename from benchmarks/GenericPricing/datasets/Medium/output.data rename to benchmarks/GenericPricing/datasets/medium/output.data diff --git a/benchmarks/GenericPricing/datasets/Small/input.data b/benchmarks/GenericPricing/datasets/small/input.data similarity index 100% rename from benchmarks/GenericPricing/datasets/Small/input.data rename to benchmarks/GenericPricing/datasets/small/input.data diff --git a/benchmarks/GenericPricing/datasets/Small/output.data b/benchmarks/GenericPricing/datasets/small/output.data similarity index 100% rename from benchmarks/GenericPricing/datasets/Small/output.data rename to benchmarks/GenericPricing/datasets/small/output.data From e98929f66f8249331f72c567e7a21cd492630b70 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 21 Feb 2015 12:48:02 +0100 Subject: [PATCH 007/122] Accept some command line parameters. --- finpar | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/finpar b/finpar index 15d1877..414fb77 100755 --- a/finpar +++ b/finpar @@ -3,6 +3,7 @@ import os import subprocess import json +import sys def executable(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -117,13 +118,22 @@ def note_result(results, benchmark, implementation, dataset, runtime): (desc_triple(benchmark, implementation, dataset), status)) results[(benchmark,implementation,dataset)] = runtime -def run_all_benchmark_implementations(finpar_dir, workdir, benchmarkdir, platform): +def run_some_benchmark_implementations(finpar_dir, + workdir, + benchmarkdir, + platform, + run_implementation_fn, + use_dataset_fn): b = Benchmark(finpar_dir, os.path.basename(benchmarkdir), benchmarkdir) insts = [] results = {} for impl in b.implementations: + if not run_implementation_fn(impl): + continue for dataset in b.datasets: + if not use_dataset_fn(dataset): + continue instdir = os.path.join(workdir, "%s-%s-%s" % (b.name, impl.name, dataset)) print("Instantiating in %s" % instdir) @@ -252,19 +262,59 @@ def compare_json(json1, json2): return json1 == json2 +def what_to_run(): + if len(sys.argv) == 1: + return ("benchmarks/CalibVolDiff", None, None) + elif len(sys.argv) == 2: + return (sys.argv[1], None, None) + elif len(sys.argv) == 3: + return (sys.argv[1], sys.argv[2].split(','), None) + elif len(sys.argv) == 4: + return (sys.argv[1], sys.argv[2].split(','), sys.argv[3].split(',')) + else: + exit("Usage: %s [benchmark] [implementation1,implementation2,...] [dataset1,dataset2,...]" % + sys.argv[0]) + if __name__ == '__main__': - benchmark="benchmarks/CalibVolDiff" + (benchmark, implementations, datasets) = what_to_run() instantiations_dir = "instantiations" platform_file = "config/platform_example.json" + print("Assuming I am being run from main finpar directory.") - print("Will run implementations of benchmark %s." % benchmark) + print("Will run benchmark %s." % benchmark) + + if implementations is None: + print("Will run all implementations.") + else: + print("Will run these implementations: %s" % implementations) + + if datasets is None: + print("Will use all datasets.") + else: + print("Will use these datasets: %s" % datasets) + print("Will instantiate in %s." % instantiations_dir) print("Will use platform configuration %s." % platform_file) finpar_dir = os.getcwd() - results = run_all_benchmark_implementations(finpar_dir, - os.path.join(finpar_dir, instantiations_dir), - os.path.join(finpar_dir, benchmark), - os.path.join(finpar_dir, platform_file)) + + def run_implementation_fn(impl): + if implementations is None: + return True + else: + return impl.name in implementations + + def use_dataset_fn(dataset): + if datasets is None: + return True + else: + return dataset in datasets + + results = run_some_benchmark_implementations(finpar_dir, + os.path.join(finpar_dir, instantiations_dir), + os.path.join(finpar_dir, benchmark), + os.path.join(finpar_dir, platform_file), + run_implementation_fn, + use_dataset_fn) successful = {} failed = {} @@ -274,14 +324,14 @@ if __name__ == '__main__': else: failed[result] = results[result] - print "\nFailed" + print "\nFailed:" for f in failed: (benchmark, implementation, dataset) = f print("%s: %s" % (desc_triple(benchmark, implementation, dataset), failed[f])) - print "\nSucceeded" + print "\nSucceeded:" for s in successful: (benchmark, implementation, dataset) = s print("%s: %s" % From aad4aa2e120517c19c816a31c0c705986566d304 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 21 Feb 2015 13:27:20 +0100 Subject: [PATCH 008/122] Report failed instantiations in a vaguely usable format. --- finpar | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/finpar b/finpar index 414fb77..e4f78cb 100755 --- a/finpar +++ b/finpar @@ -110,12 +110,6 @@ def desc_triple(benchmark, implementation, dataset): return "Benchmark %s, implementation %s, dataset %s" % (benchmark, implementation, dataset) def note_result(results, benchmark, implementation, dataset, runtime): - if type(runtime) is int: - status = str(runtime) + "ms" - else: - status = "failed, " + runtime - print("%s: %s" % - (desc_triple(benchmark, implementation, dataset), status)) results[(benchmark,implementation,dataset)] = runtime def run_some_benchmark_implementations(finpar_dir, @@ -126,6 +120,7 @@ def run_some_benchmark_implementations(finpar_dir, use_dataset_fn): b = Benchmark(finpar_dir, os.path.basename(benchmarkdir), benchmarkdir) insts = [] + failed_insts = [] results = {} for impl in b.implementations: @@ -139,8 +134,14 @@ def run_some_benchmark_implementations(finpar_dir, print("Instantiating in %s" % instdir) (retcode, stdout, stderr) = impl.instantiate(instdir, b.datasets[dataset]['input_file'], platform) if retcode != 0: - print("Instantiation failed with exit code %d.\nStdout:\n%s\nStderr:\n%s" % - (retcode, stdout, stderr)) + failed_insts.append({ 'benchmark' : b.name, + 'implementation' : impl.name, + 'dataset' : dataset, + 'instantiation_directory' : instdir, + 'retcode' : retcode, + 'stdout' : stdout, + 'stderr' : stderr}) + print("Spoiler: failed") else: insts.append({ 'benchmark' : b.name, 'implementation' : impl.name, @@ -219,7 +220,7 @@ def run_some_benchmark_implementations(finpar_dir, inst['implementation'], inst['dataset'], "cannot read result") - return results + return (results, failed_insts) def read_runtime(instdir): with open(os.path.join(instdir, "runtime.txt"), "r") as file: @@ -309,15 +310,26 @@ if __name__ == '__main__': else: return dataset in datasets - results = run_some_benchmark_implementations(finpar_dir, - os.path.join(finpar_dir, instantiations_dir), - os.path.join(finpar_dir, benchmark), - os.path.join(finpar_dir, platform_file), - run_implementation_fn, - use_dataset_fn) + (results, failed_to_instantiate) = ( + run_some_benchmark_implementations(finpar_dir, + os.path.join(finpar_dir, instantiations_dir), + os.path.join(finpar_dir, benchmark), + os.path.join(finpar_dir, platform_file), + run_implementation_fn, + use_dataset_fn) + ) successful = {} failed = {} + for failed in failed_to_instantiate: + print("Failed to instantiate implementation %s with dataset %s; exit code %d." % + (failed['implementation'], failed['dataset'], failed['retcode'])) + print("Stdout\n") + print(failed['stdout']) + print("Stderr\n") + print(failed['stderr']) + print("") + for result in results: if type(results[result]) is int: successful[result] = results[result] From 32dacda40a0905bc1ed75ee9f540f02093f85e46 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 21 Feb 2015 13:52:02 +0100 Subject: [PATCH 009/122] Fix error caused by variable shadowing. Python is a bad language. --- finpar | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/finpar b/finpar index e4f78cb..42e7c40 100755 --- a/finpar +++ b/finpar @@ -318,8 +318,6 @@ if __name__ == '__main__': run_implementation_fn, use_dataset_fn) ) - successful = {} - failed = {} for failed in failed_to_instantiate: print("Failed to instantiate implementation %s with dataset %s; exit code %d." % @@ -330,6 +328,9 @@ if __name__ == '__main__': print(failed['stderr']) print("") + successful = {} + failed = {} + for result in results: if type(results[result]) is int: successful[result] = results[result] From de3c0f91542e3701878e3a2b9e836dd2800ce6e1 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 21 Feb 2015 13:54:22 +0100 Subject: [PATCH 010/122] This one is obsolete. --- lib/platform.mk | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 lib/platform.mk diff --git a/lib/platform.mk b/lib/platform.mk deleted file mode 100644 index c9889b1..0000000 --- a/lib/platform.mk +++ /dev/null @@ -1,28 +0,0 @@ -# platform specification for benchmarks. Edit as appropriate for your -# platform before running - -# 1 = platform has a GPU -HAVE_GPU = 1 -GPU_DEVICE_ID = 0 - -# GPU warp size. Keep consistent if you use the non-log variant -#GPU_WARP = 32 -GPU_LG_WARP = 5 - -# GPU memory sizes in kilobyte -GPU_LOCAL_MEM = 48 -GPU_CONST_MEM = 64 -GPU_REG_MEM = 64 -# device memory in gigabyte -GPU_DEVICE_MEM= 2 -# ``Optimal'' Amount of Local/Fast Memory Per Thread -GPU_LOCAL_MEM_PER_TH=8 -# Number of GPU cores -GPU_NUM_CORES = 192 - -# CPU and memory spec. -NCORES = 4 -# in gigabyte -MEMORY = 4 - -export From 177bc0b8ca09750d72ccc36b904ebcd9f2ca9860 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 21 Feb 2015 14:22:42 +0100 Subject: [PATCH 011/122] Use deepseq for proper timing. --- benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs b/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs index 734f004..364bb6c 100644 --- a/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs +++ b/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs @@ -389,7 +389,7 @@ main = do s <- getContents return $ do start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. let v = compute (outer, num_x, num_y, num_t) params - end <- v `seq` getCPUTime + end <- v `deepseq` getCPUTime return (v, (end - start) `div` 1000000000) -- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs From 39b43de76b4e6935ce0c96743cdb7489beaba1fc Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 21 Feb 2015 14:23:08 +0100 Subject: [PATCH 012/122] Move GenericPricing to the brave new world. --- .../GenericPricing/datasets/large/input.data | 4090 ----------------- .../GenericPricing/datasets/large/input.json | 4088 ++++++++++++++++ .../GenericPricing/datasets/large/output.data | 1 - .../GenericPricing/datasets/large/output.json | 1 + .../GenericPricing/datasets/medium/input.data | 108 - .../GenericPricing/datasets/medium/input.json | 106 + .../datasets/medium/output.data | 1 - .../datasets/medium/output.json | 1 + .../GenericPricing/datasets/small/input.data | 56 - .../GenericPricing/datasets/small/input.json | 39 + .../GenericPricing/datasets/small/output.data | 1 - .../GenericPricing/datasets/small/output.json | 1 + .../implementations/CppOpenCL/GenPricing.cpp | 22 +- .../implementations/CppOpenCL/instantiate | 16 +- .../implementations/CppOpenCL/run | 3 - .../implementations/HaskellLH/GenPricing.hs | 13 +- .../implementations/HaskellLH/instantiate | 4 +- .../Orig_COpenMp/GenPricing.cpp | 12 +- .../implementations/Orig_COpenMp/instantiate | 16 +- .../implementations/Orig_COpenMp/run | 3 - benchmarks/GenericPricing/lib/ParseInput.h | 19 - 21 files changed, 4292 insertions(+), 4309 deletions(-) delete mode 100644 benchmarks/GenericPricing/datasets/large/input.data create mode 100644 benchmarks/GenericPricing/datasets/large/input.json delete mode 100644 benchmarks/GenericPricing/datasets/large/output.data create mode 100644 benchmarks/GenericPricing/datasets/large/output.json delete mode 100644 benchmarks/GenericPricing/datasets/medium/input.data create mode 100644 benchmarks/GenericPricing/datasets/medium/input.json delete mode 100644 benchmarks/GenericPricing/datasets/medium/output.data create mode 100644 benchmarks/GenericPricing/datasets/medium/output.json delete mode 100644 benchmarks/GenericPricing/datasets/small/input.data create mode 100644 benchmarks/GenericPricing/datasets/small/input.json delete mode 100644 benchmarks/GenericPricing/datasets/small/output.data create mode 100644 benchmarks/GenericPricing/datasets/small/output.json delete mode 100755 benchmarks/GenericPricing/implementations/CppOpenCL/run delete mode 100755 benchmarks/GenericPricing/implementations/Orig_COpenMp/run diff --git a/benchmarks/GenericPricing/datasets/large/input.data b/benchmarks/GenericPricing/datasets/large/input.data deleted file mode 100644 index 979fe1f..0000000 --- a/benchmarks/GenericPricing/datasets/large/input.data +++ /dev/null @@ -1,4090 +0,0 @@ -3 // contract number -131072 // number of Monte-Carlo Iterations -367 // number of path dates -3 // number of underlyings -1 // number of models -30 // integer bit-length representation for Sobol - -// Begin Direction vectors [3*367][30] -[ - [ - 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 570425344, 855638016, 713031680, 1069547520, 538968064, 808452096, 673710080, 1010565120, 572653568, 858980352, 715816960, 1073725440, 536879104, 805318656, 671098880, 1006648320, 570434048, 855651072, 713042560, 1069563840, 538976288, 808464432, 673720360, 1010580540, 572662306, 858993459 - ], - [ - 536870912, 805306368, 402653184, 603979776, 973078528, 385875968, 595591168, 826277888, 438304768, 657457152, 999817216, 358875136, 538574848, 807862272, 406552576, 605372416, 975183872, 389033984, 597170176, 828646400, 437926400, 656873216, 1002152832, 357921088, 536885792, 805312304, 402662296, 603992420, 973085210, 385885991 - ], - [ - 536870912, 805306368, 939524096, 335544320, 234881024, 721420288, 411041792, 616562688, 920649728, 1062207488, 381157376, 258736128, 771883008, 453181440, 545488896, 817971200, 954261504, 340963328, 238651392, 732843008, 417426944, 609285376, 909831040, 1068349120, 383778848, 256901168, 783810616, 460062740, 537001998, 805503019 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 167772160, 285212672, 713031680, 566231040, 853540864, 489684992, 952631296, 208928768, 316801024, 758317056, 550076416, 813154304, 417505280, 1009913856, 172697600, 297131008, 704744960, 553894656, 847291520, 499194688, 954376224, 204607536, 306915352, 766893116, 536972810, 805552913 - ], - [ - 536870912, 805306368, 402653184, 469762048, 301989888, 721420288, 92274688, 264241152, 941621248, 741343232, 169345024, 924581888, 395444224, 619380736, 1034256384, 603963392, 838868992, 452997120, 494934016, 331357184, 706744832, 120597248, 261621120, 953946048, 800208928, 148581424, 935168536, 350484252, 630339474, 1072370923 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 503316480, 754974720, 629145600, 440401920, 94371840, 711983104, 229113856, 374079488, 330694656, 996212736, 907247616, 557531136, 867573760, 190918656, 1041467392, 490437632, 766918144, 643898624, 462663040, 125527616, 672545696, 202454896, 373006376, 288845836, 1000351766, 930090001 - ], - [ - 536870912, 268435456, 402653184, 872415232, 838860800, 956301312, 612368384, 717225984, 211812352, 386924544, 302514176, 688128000, 1015414784, 516751360, 1051492352, 773734400, 914432000, 63877120, 807741440, 165200896, 748683776, 118489344, 168296832, 486802240, 243663648, 667747216, 439124552, 81674924, 975249610, 350138737 - ], - [ - 536870912, 268435456, 671088640, 469762048, 973078528, 1023410176, 713031680, 339738624, 912261120, 797966336, 176685056, 71565312, 510263296, 865533952, 814120960, 961232896, 887136256, 668078080, 116070400, 382772224, 1047134720, 597098752, 411468416, 625689024, 249602976, 449975248, 745216680, 43033924, 134873446, 201786361 - ], - [ - 536870912, 268435456, 402653184, 67108864, 704643072, 385875968, 696254464, 205520896, 920649728, 946864128, 359137280, 859045888, 302907392, 50659328, 462192640, 524599296, 895541248, 590794752, 168810496, 118033408, 831447552, 138662144, 485185920, 796511296, 1021313184, 1064304752, 619184920, 997458052, 250479054, 745865975 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 838860800, 889192448, 645922816, 46137344, 476053504, 584056832, 210239488, 465829888, 820903936, 689897472, 73695232, 249118720, 110075904, 315338752, 610637824, 517665792, 1049494016, 785318144, 376210304, 735921088, 402760480, 738505552, 168368744, 151499820, 344957894, 936096557 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 503316480, 922746880, 41943040, 423624704, 228589568, 651165696, 195559424, 500957184, 791019520, 261292032, 1040285696, 118407168, 982065152, 625250304, 329533440, 298984448, 153690624, 76845824, 579619712, 692987840, 900670432, 450334832, 363187112, 719119956, 765461306, 382730781 - ], - [ - 536870912, 805306368, 402653184, 603979776, 838860800, 117440512, 478150656, 658505728, 752877568, 1060110336, 141033472, 209453056, 244187136, 272957440, 678068224, 1014546432, 377724928, 876875776, 443160576, 998185984, 168665600, 318837504, 914397568, 71818816, 40763680, 527762288, 939688008, 335855668, 705536494, 587273091 - ], - [ - 536870912, 268435456, 671088640, 738197504, 637534208, 150994944, 813694976, 943718400, 77594624, 179306496, 798490624, 967049216, 134348800, 1006698496, 235044864, 620937216, 377643008, 826314752, 874711040, 854819840, 725109248, 856992512, 664336768, 94804544, 100663328, 419430416, 411041832, 339738668, 580911142, 61865993 - ], - [ - 536870912, 805306368, 939524096, 603979776, 100663296, 452984832, 998244352, 188743680, 866123776, 389021696, 287834112, 172228608, 824836096, 977731584, 153714688, 507854848, 254402560, 88403968, 883578880, 235160576, 118055424, 422917888, 371224704, 326210368, 654926368, 691353392, 773877944, 930190180, 554263078, 842348331 - ], - [ - 536870912, 268435456, 134217728, 872415232, 771751936, 486539264, 629145600, 163577856, 467664896, 472907776, 168296448, 993787904, 201981952, 37552128, 260734976, 587087872, 535322624, 705662976, 729954304, 79891456, 912360960, 569626368, 1072277120, 974077120, 595691040, 818138896, 409052808, 1022573812, 443254286, 869191437 - ], - [ - 536870912, 805306368, 134217728, 67108864, 369098752, 654311424, 562036736, 1044381696, 333447168, 1068498944, 487063552, 614727680, 652869632, 790036480, 635600896, 682835968, 881451008, 518402048, 587823104, 933663744, 426354176, 844586752, 25366144, 239108416, 467682848, 1001484080, 185235080, 61216068, 124379190, 290861079 - ], - [ - 536870912, 805306368, 134217728, 603979776, 436207616, 1023410176, 830472192, 1061158912, 274726912, 946864128, 752353280, 1040973824, 660209664, 206503936, 247103488, 796737536, 671293440, 335712256, 302135296, 419587072, 730054144, 37987072, 568382336, 120820672, 1018805792, 108831536, 193090440, 843240420, 702586426, 590426893 - ], - [ - 536870912, 805306368, 402653184, 335544320, 637534208, 452984832, 578813952, 364904448, 903872512, 84934656, 498597888, 152829952, 794951680, 886243328, 374964224, 51200000, 911761408, 856600576, 777627648, 655301632, 140164608, 1007657216, 718934912, 701382080, 523919392, 752726064, 41953304, 633494548, 769842726, 286331163 - ], - [ - 536870912, 805306368, 134217728, 67108864, 1040187392, 721420288, 696254464, 272629760, 945815552, 202375168, 973602816, 360448000, 47579136, 965935104, 671121408, 872464384, 905977856, 788533248, 394328064, 994094080, 299935232, 475021568, 40427904, 426520640, 954132512, 753882608, 718703448, 227747404, 503316482, 452984835 - ], - [ - 536870912, 268435456, 134217728, 335544320, 167772160, 822083584, 343932928, 884998144, 618659840, 753926144, 953679872, 852230144, 61734912, 386334720, 598638592, 117915648, 732864512, 319229952, 565086208, 570938368, 892262912, 382142208, 298731904, 976729280, 689351392, 150700016, 716743768, 536617964, 152480482, 419135473 - ], - [ - 536870912, 268435456, 402653184, 603979776, 33554432, 486539264, 679477248, 155189248, 580911104, 678428672, 745013248, 1043595264, 997326848, 936706048, 1021870080, 57950208, 64118784, 648384512, 973113344, 687879168, 847299072, 809547008, 136348288, 1009833408, 642257824, 520412624, 901408584, 563183252, 737329666, 177583361 - ], - [ - 536870912, 805306368, 134217728, 738197504, 234881024, 687865856, 176160768, 750780416, 429916160, 355467264, 1017643008, 563347456, 825622528, 514523136, 110526464, 312197120, 952016896, 869232640, 505976832, 290771968, 781595136, 245081856, 1052701824, 919569344, 447225376, 345248144, 1035356408, 929807420, 464961058, 40591763 - ], - [ - 536870912, 805306368, 671088640, 335544320, 436207616, 486539264, 511705088, 742391808, 375390208, 995098624, 229113856, 905183232, 966393856, 533528576, 209747968, 356564992, 987799552, 504385536, 524838912, 1071936512, 1020426752, 1026142464, 785570176, 69807424, 38934176, 560547792, 280145512, 729389876, 368705538, 161284099 - ], - [ - 536870912, 805306368, 134217728, 335544320, 100663296, 721420288, 713031680, 666894336, 371195904, 326107136, 918028288, 904134656, 997851136, 317915136, 1004699648, 73908224, 1042325504, 930123776, 951597056, 182778880, 402305536, 506671872, 121795200, 819401408, 515383904, 300157520, 897191688, 770924636, 392310882, 145205587 - ], - [ - 536870912, 268435456, 939524096, 201326592, 1040187392, 385875968, 713031680, 398458880, 140509184, 609222656, 174587904, 627310592, 64094208, 708509696, 895123456, 1003438080, 637558784, 184578048, 746592256, 213937152, 484463104, 613417728, 680037248, 385142336, 31066144, 722404560, 1021355752, 881884540, 277363234, 452229073 - ], - [ - 536870912, 268435456, 134217728, 603979776, 905969664, 721420288, 109051904, 20971520, 664797184, 919601152, 422051840, 198967296, 617480192, 71892992, 638091264, 592199680, 583409664, 923111424, 214849536, 810150912, 403225088, 743232768, 306603648, 491120448, 770582176, 131712624, 645969848, 289415012, 799054338, 315639041 - ], - [ - 536870912, 805306368, 939524096, 469762048, 570425344, 1056964608, 58720256, 557842432, 786432000, 632291328, 270008320, 139722752, 607518720, 1048248320, 494436352, 1017430016, 583983104, 262107136, 190187520, 898317312, 402681344, 738211072, 436261760, 587209408, 562087520, 507533392, 761275736, 82897452, 1056476674, 769934595 - ], - [ - 536870912, 268435456, 671088640, 67108864, 33554432, 486539264, 310378496, 239075328, 186646528, 634388480, 96993280, 367263744, 1032454144, 966590464, 1000374272, 646987776, 879271936, 980684800, 828508160, 346649600, 291686912, 78215424, 962727040, 11126592, 996294432, 497644432, 702714920, 334101364, 583180290, 909709313 - ], - [ - 536870912, 268435456, 402653184, 335544320, 503316480, 117440512, 746586112, 876609536, 236978176, 523239424, 950534144, 712769536, 154009600, 870907904, 209747968, 608190464, 371220480, 187715584, 648574976, 763108352, 632205824, 128569600, 44087424, 997211328, 780698272, 558692848, 797334712, 513135524, 690880514, 602472449 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 100663296, 218103808, 746586112, 641728512, 1029701632, 883949568, 439877632, 996933632, 967442432, 920715264, 492863488, 78692352, 37249024, 124579840, 1068111872, 1004614656, 836776448, 586176768, 1062770048, 870064832, 630354144, 9296304, 139121832, 336691844, 574119938, 929886211 - ], - [ - 536870912, 805306368, 939524096, 335544320, 570425344, 553648128, 981467136, 62914560, 488636416, 76546048, 748158976, 818675712, 1054212096, 701431808, 273580032, 134463488, 739794944, 906792960, 58091520, 463459328, 964092416, 513755904, 435617408, 677350720, 475410144, 235914608, 393104184, 965967628, 402705634, 604016243 - ], - [ - 536870912, 805306368, 671088640, 67108864, 973078528, 285212672, 343932928, 692060160, 148897792, 1058013184, 669515776, 14942208, 185204736, 904724480, 367558656, 635748352, 227188736, 162336768, 864577536, 582255616, 906162688, 521778432, 394939264, 682457152, 252243360, 267679376, 81938344, 822706164, 618852866, 17413379 - ], - [ - 536870912, 805306368, 939524096, 201326592, 704643072, 754974720, 897581056, 1019215872, 656408576, 680525824, 824705024, 397148160, 633208832, 881393664, 320241664, 249937920, 906518528, 255651840, 748046336, 790987776, 480837120, 392988416, 278833792, 1025073472, 1035890720, 143231216, 18277464, 803573652, 696815138, 519835635 - ], - [ - 536870912, 268435456, 134217728, 469762048, 637534208, 587202560, 25165824, 1019215872, 442499072, 355467264, 715653120, 557056000, 11141120, 739573760, 1046642688, 923877376, 1004576768, 972042240, 952678400, 671415296, 201498112, 773947136, 1061744512, 667215808, 534962976, 466722832, 696299528, 817952900, 878763298, 707850001 - ], - [ - 536870912, 805306368, 402653184, 67108864, 167772160, 721420288, 612368384, 817889280, 312475648, 630194176, 253231104, 516685824, 62521344, 841154560, 523927552, 920895488, 530243584, 1014222848, 1040369664, 964656128, 194533888, 504151808, 152735872, 330557760, 438455520, 53428848, 950012424, 1049638652, 865619170, 705446515 - ], - [ - 536870912, 805306368, 671088640, 335544320, 1040187392, 452984832, 260046848, 566231040, 580911104, 292552704, 446169088, 490995712, 411172864, 742719488, 841121792, 422952960, 1052385280, 191991808, 397989888, 502594560, 146433536, 879868672, 238603392, 859074240, 463109856, 532801488, 964754152, 515911108, 991977186, 1068529619 - ], - [ - 536870912, 805306368, 402653184, 603979776, 973078528, 620756992, 679477248, 239075328, 639631360, 187695104, 798490624, 669253632, 987365376, 108331008, 706772992, 218251264, 346038272, 275787776, 959977472, 110371840, 157432320, 262219008, 400730240, 584273472, 578455072, 272071472, 673224600, 1006793700, 505428186, 523253621 - ], - [ - 536870912, 805306368, 671088640, 469762048, 503316480, 922746880, 1048576000, 750780416, 933232640, 359661568, 231211008, 302776320, 822476800, 1031995392, 276594688, 845529088, 728637440, 184496128, 78817280, 32168960, 336903680, 840550144, 18888320, 363856064, 208142752, 746339952, 474885448, 877595084, 677034022, 911655987 - ], - [ - 536870912, 268435456, 939524096, 872415232, 436207616, 419430400, 729808896, 943718400, 648019968, 433061888, 1071120384, 549715968, 72482816, 547684352, 384663552, 592920576, 805969920, 673255424, 203405312, 774009856, 54508032, 850544896, 331854720, 518413376, 1064150176, 639067344, 522851928, 615589252, 619162482, 913730613 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 1040187392, 754974720, 629145600, 775946240, 689963008, 397410304, 626524160, 496762880, 575537152, 253034496, 111771648, 1053310976, 517480448, 786182144, 921573376, 182795264, 886160896, 434400512, 1011746176, 303373888, 992588064, 747137968, 167263064, 342622364, 909516750, 960044373 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 234881024, 687865856, 427819008, 457179136, 333447168, 890241024, 664272896, 441712640, 911343616, 544669696, 491290624, 918994944, 176332800, 702935040, 504891392, 823397376, 229778944, 694621440, 886085504, 93516352, 626043488, 315809360, 280018040, 851632964, 547919818, 450289443 - ], - [ - 536870912, 805306368, 402653184, 67108864, 503316480, 318767104, 763363328, 708837376, 199229440, 328204288, 157810688, 1048313856, 1036648448, 478478336, 1053982720, 421904384, 144220160, 148959232, 371865600, 1058354176, 800753152, 593090304, 726832000, 124111168, 91790944, 208719312, 750920840, 942213868, 873504546, 101507001 - ], - [ - 536870912, 268435456, 402653184, 603979776, 771751936, 452984832, 947912704, 146800640, 253755392, 512753664, 802684928, 1032060928, 595460096, 56819712, 325877760, 189710336, 794304512, 21237760, 442374144, 586359808, 708095488, 621468416, 998643840, 343349440, 701142816, 178911888, 164274648, 447346308, 298492926, 1051328419 - ], - [ - 536870912, 268435456, 134217728, 603979776, 369098752, 620756992, 595591168, 616562688, 98566144, 544210944, 699924480, 737935360, 962199552, 807862272, 403210240, 739131392, 842047488, 858935296, 109750272, 124089344, 557465088, 630657280, 164674944, 37905856, 313692256, 156856752, 671098840, 872422220, 503319298, 16792235 - ], - [ - 536870912, 805306368, 939524096, 738197504, 369098752, 452984832, 243269632, 960495616, 228589568, 737148928, 450363392, 293339136, 700317696, 704577536, 1005355008, 315113472, 90578944, 327364608, 617789440, 779578368, 623556096, 834366208, 904697472, 365454656, 635831200, 499330288, 837991000, 667377468, 1020435614, 846680143 - ], - [ - 536870912, 268435456, 134217728, 469762048, 1040187392, 956301312, 276824064, 868220928, 614465536, 30408704, 732430336, 877395968, 919994368, 437583872, 53903360, 60735488, 945168384, 13963264, 1058441216, 764337152, 157163008, 206121216, 854104192, 806875072, 404667040, 336783568, 572527400, 118492044, 696788086, 593247941 - ], - [ - 536870912, 805306368, 402653184, 67108864, 100663296, 989855744, 377487360, 767557632, 1033895936, 326107136, 209190912, 752091136, 571342848, 219611136, 898400256, 1062518784, 376840192, 365113344, 159553536, 222544896, 863675904, 1012386560, 886353536, 640735680, 186647456, 246422640, 702022904, 1000619540, 678825774, 448989351 - ], - [ - 536870912, 805306368, 939524096, 201326592, 973078528, 922746880, 41943040, 171966464, 509607936, 407896064, 761790464, 350486528, 639500288, 84475904, 29065216, 1053409280, 423337984, 864677888, 1037801472, 765066240, 886284800, 372099840, 1025876096, 226541888, 81805024, 772806928, 822621064, 934559220, 871771542, 749548797 - ], - [ - 536870912, 805306368, 134217728, 67108864, 838860800, 922746880, 931135488, 868220928, 429916160, 183500800, 656932864, 263454720, 1073348608, 798162944, 267747328, 665632768, 198844416, 363016192, 1023248384, 573096960, 254284288, 1001654016, 100286336, 479410112, 175483808, 594345456, 637153448, 747834484, 41266778, 661447011 - ], - [ - 536870912, 805306368, 134217728, 469762048, 33554432, 83886080, 1048576000, 750780416, 1029701632, 101711872, 590872576, 764674048, 157155328, 673644544, 738951168, 169492480, 420323328, 1018785792, 702556160, 63974400, 718801408, 507779328, 730217600, 711141824, 93160416, 628714192, 570441304, 889199492, 914367078, 817895859 - ], - [ - 536870912, 268435456, 402653184, 738197504, 33554432, 922746880, 394264576, 1044381696, 434110464, 800063488, 38273024, 64225280, 882769920, 402456576, 179601408, 987217920, 103456768, 288018432, 379467776, 821902336, 87333376, 681040640, 499824000, 161143104, 55981664, 224996848, 675971496, 282785636, 355861334, 815336809 - ], - [ - 536870912, 805306368, 134217728, 67108864, 838860800, 385875968, 1015021568, 784334848, 920649728, 181403648, 886571008, 366739456, 208535552, 154730496, 765820928, 1065041920, 933601280, 477851648, 824551424, 565933056, 155556352, 313221888, 939370112, 593972672, 967544928, 894584592, 750265528, 382472908, 987105494, 1022700533 - ], - [ - 536870912, 268435456, 402653184, 603979776, 503316480, 50331648, 360710144, 213909504, 190840832, 1041235968, 319291392, 227278848, 684851200, 359596032, 1024557056, 109232128, 21651456, 599240704, 727713792, 772801536, 185075200, 697043200, 919734144, 376373440, 680625504, 172147504, 170549976, 497532804, 946343106, 597428067 - ], - [ - 536870912, 268435456, 939524096, 469762048, 234881024, 922746880, 377487360, 1010827264, 996147200, 386924544, 109576192, 73138176, 661520384, 420937728, 831750144, 316096512, 456138752, 577417216, 646449152, 341574656, 527306240, 85395200, 1066632064, 634867136, 229647776, 506117904, 501745368, 55312836, 434507682, 21693975 - ], - [ - 536870912, 805306368, 671088640, 67108864, 838860800, 184549376, 545259520, 666894336, 52428800, 915406848, 785907712, 11796480, 902955008, 941686784, 1040285696, 218775552, 832495616, 138809344, 913442816, 426839040, 1006209536, 1059995904, 412413056, 1003688640, 488734752, 194659824, 927394504, 217193636, 832573238, 709889773 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 973078528, 285212672, 662700032, 725614592, 576716800, 714080256, 114819072, 270794752, 325976064, 1024786432, 630489088, 239714304, 66494464, 718581760, 305530880, 913378304, 479887872, 634179328, 448409216, 632910912, 623813088, 183547600, 156762776, 929302948, 51252534, 981798729 - ], - [ - 536870912, 805306368, 939524096, 738197504, 1040187392, 318767104, 595591168, 423624704, 228589568, 11534336, 2621440, 49545216, 973209600, 151846912, 446464000, 1003569152, 443277312, 616706048, 937682944, 377895936, 902424064, 830420736, 727148928, 279147456, 136315232, 384828816, 671615496, 604244412, 705299458, 17367553 - ], - [ - 536870912, 268435456, 134217728, 201326592, 1040187392, 620756992, 796917760, 482344960, 526385152, 722468864, 310902784, 927203328, 832962560, 795803648, 856326144, 379305984, 88891392, 716615680, 635963392, 5506048, 355336704, 824902400, 321687424, 3459392, 111602656, 201160496, 759984088, 917946052, 333975202, 693373649 - ], - [ - 536870912, 268435456, 671088640, 335544320, 100663296, 50331648, 58720256, 465567744, 522190848, 691011584, 305659904, 766246912, 610664448, 1044709376, 401899520, 495796224, 885825536, 649408512, 602712064, 193278976, 534028800, 824783104, 1043506048, 397160896, 895886176, 953251632, 213025960, 452480380, 419440678, 43282967 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 436207616, 654311424, 192937984, 583008256, 27262976, 917504000, 623378432, 335282176, 876740608, 1073676288, 910458880, 217923584, 466493440, 320991232, 921053184, 215874560, 816062976, 673379072, 392209536, 555727552, 110003808, 642663024, 350268936, 266318812, 892241218, 201212963 - ], - [ - 536870912, 268435456, 671088640, 738197504, 503316480, 486539264, 729808896, 574619648, 652214272, 957349888, 159907840, 156499968, 1014366208, 786366464, 270958592, 1026670592, 784277504, 149975040, 470288384, 638845952, 420874752, 428804864, 558794624, 276154176, 817965792, 222001296, 381190584, 216713796, 772253794, 622508373 - ], - [ - 536870912, 805306368, 939524096, 469762048, 234881024, 486539264, 713031680, 977272832, 283115520, 1053818880, 129499136, 1017905152, 522584064, 636682240, 5537792, 402145280, 592879616, 409120768, 798132224, 1021004800, 481963520, 792131328, 501361536, 474676032, 435956896, 1045820816, 854499768, 365868020, 741641934, 577261051 - ], - [ - 536870912, 268435456, 134217728, 872415232, 973078528, 352321536, 964689920, 415236096, 694157312, 781189120, 407371776, 237240320, 69861376, 153419776, 213286912, 444252160, 471293952, 504705024, 654444544, 412156928, 458523136, 616287488, 1047260800, 773518656, 1057744480, 613085744, 356769880, 196014756, 317317778, 256638921 - ], - [ - 536870912, 268435456, 939524096, 603979776, 704643072, 16777216, 931135488, 331350016, 295698432, 762314752, 811073536, 7602176, 568197120, 615448576, 150568960, 110182400, 206774272, 510636032, 852666368, 909833216, 111642112, 100551936, 118137984, 277805376, 324636512, 987840688, 864757640, 702265004, 682404606, 1055260417 - ], - [ - 536870912, 805306368, 939524096, 201326592, 704643072, 1023410176, 494927872, 734003200, 517996544, 510656512, 405274624, 353632256, 427950080, 902758400, 99450880, 351617024, 325951488, 1033916416, 851945472, 763059200, 380118528, 4267776, 707267712, 336855104, 369230816, 789513904, 747473496, 474300972, 136685266, 486823977 - ], - [ - 536870912, 805306368, 939524096, 201326592, 771751936, 956301312, 276824064, 339738624, 228589568, 839909376, 521666560, 496762880, 650510336, 251068416, 372015104, 700465152, 460201984, 82628608, 85985280, 441453568, 79171072, 445383424, 123603840, 1043009088, 768246816, 23545104, 536519528, 44080260, 663760838, 232250215 - ], - [ - 536870912, 805306368, 402653184, 67108864, 771751936, 218103808, 159383552, 457179136, 782237696, 684720128, 1056440320, 519831552, 787087360, 921894912, 853573632, 485867520, 301604864, 409210880, 53118976, 764857344, 88253952, 1002295552, 625124224, 196992832, 1027779680, 264100816, 323137064, 45995124, 448964702, 436068143 - ], - [ - 536870912, 805306368, 402653184, 201326592, 301989888, 184549376, 629145600, 868220928, 929038336, 770703360, 363331584, 268697600, 672268288, 335740928, 504004608, 421412864, 781099008, 374378496, 78948352, 446143488, 944516608, 96132864, 939526784, 1006636480, 167775200, 117443888, 931135544, 952108364, 316670418, 506463117 - ], - [ - 536870912, 268435456, 671088640, 603979776, 301989888, 150994944, 192937984, 767557632, 757071872, 149946368, 299368448, 591134720, 536215552, 625147904, 510754816, 496451584, 650125312, 129626112, 179415040, 53392384, 267485696, 223825152, 979381888, 260700992, 801746528, 203603248, 662670248, 773342284, 119513534, 479310259 - ], - [ - 536870912, 268435456, 671088640, 872415232, 167772160, 218103808, 159383552, 180355072, 522190848, 315621376, 321388544, 79953920, 540147712, 172032000, 779386880, 371572736, 692183040, 150097920, 745834496, 1059439616, 46262784, 993156352, 819235456, 708167488, 122284128, 669409200, 485395784, 912311284, 438791338, 1061592705 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 33554432, 822083584, 796917760, 801112064, 98566144, 682622976, 1058537472, 614203392, 625606656, 1002373120, 831094784, 214384640, 863248384, 351997952, 388999168, 954160128, 494404096, 267127552, 900860544, 982713152, 106662752, 220481456, 232237720, 619925980, 791283390, 751765259 - ], - [ - 536870912, 268435456, 134217728, 738197504, 570425344, 788529152, 629145600, 46137344, 1033895936, 328204288, 1002962944, 824442880, 365297664, 741933056, 390299648, 661438464, 170156032, 642207744, 132515840, 778634240, 514556416, 68733696, 503998592, 84564928, 646676832, 88655024, 274885992, 197025764, 713395826, 928367497 - ], - [ - 536870912, 268435456, 402653184, 201326592, 704643072, 117440512, 75497472, 20971520, 597688320, 292552704, 1058537472, 411303936, 860487680, 682819584, 1072070656, 962183168, 1067900928, 594243584, 873621504, 906343424, 890768896, 260310784, 801770624, 636682944, 910592928, 791265680, 71231944, 984577036, 620261166, 264681085 - ], - [ - 536870912, 268435456, 671088640, 872415232, 838860800, 1056964608, 310378496, 759169024, 631242752, 1001390080, 985137152, 959184896, 1073086464, 680460288, 910196736, 757186560, 502489088, 1066643456, 282290176, 845394944, 122380800, 381663488, 119893632, 787265216, 51112480, 77495696, 139854664, 1010762620, 913868262, 223201591 - ], - [ - 536870912, 268435456, 671088640, 469762048, 637534208, 1056964608, 847249408, 943718400, 652214272, 447741952, 1045954560, 167510016, 2752512, 436535296, 152076288, 631029760, 383279104, 950259712, 55109632, 377426944, 267420160, 791462656, 8414080, 761256128, 627240224, 863638992, 878708504, 854592444, 817366446, 256642067 - ], - [ - 536870912, 268435456, 939524096, 469762048, 234881024, 956301312, 1015021568, 532676608, 1008730112, 393216000, 9961472, 30670848, 1026686976, 939065344, 289636352, 83279872, 382967808, 682684416, 748824576, 784282624, 565315072, 943260416, 358845824, 260491584, 407612576, 275052976, 756033576, 109458988, 215058734, 733988521 - ], - [ - 536870912, 805306368, 402653184, 738197504, 771751936, 922746880, 528482304, 314572800, 908066816, 581959680, 703070208, 235143168, 117571584, 126681088, 1054507008, 404963328, 363667456, 913682432, 482813952, 826063872, 624930304, 388167424, 371197312, 313526976, 837290592, 570688112, 687997416, 814547420, 559579154, 182669213 - ], - [ - 536870912, 268435456, 671088640, 872415232, 33554432, 1056964608, 377487360, 926941184, 157286400, 435159040, 733478912, 390856704, 426115072, 838795264, 532447232, 358203392, 644440064, 661344256, 686778368, 472142848, 1066131968, 214014208, 1069318784, 89769664, 241790752, 325803792, 720334712, 589582444, 688647958, 998348671 - ], - [ - 536870912, 805306368, 939524096, 469762048, 838860800, 520093696, 8388608, 683671552, 287309824, 730857472, 240648192, 821821440, 188612608, 546373632, 415989760, 691159040, 932405248, 1011224576, 803604480, 195890176, 139824640, 166938368, 44100736, 970479552, 213084192, 618010160, 725484104, 277938660, 550207766, 892488959 - ], - [ - 536870912, 268435456, 134217728, 469762048, 905969664, 318767104, 209715200, 432013312, 547356672, 1072693248, 865599488, 994836480, 1047134208, 969211904, 817528832, 939245568, 798793728, 223064064, 762062848, 893744128, 695339520, 390660864, 275812224, 1053737920, 373173920, 188510896, 280658696, 670813580, 664577742, 290174511 - ], - [ - 536870912, 268435456, 939524096, 67108864, 436207616, 922746880, 612368384, 1044381696, 367001600, 321912832, 915931136, 626262016, 394133504, 75431936, 720273408, 464371712, 785080320, 430886912, 232515584, 524030976, 10356224, 877593856, 452364416, 867814592, 315977632, 128045648, 550331480, 213245788, 441675486, 536533145 - ], - [ - 536870912, 805306368, 939524096, 469762048, 838860800, 385875968, 360710144, 432013312, 85983232, 944766976, 989331456, 1013710848, 774242304, 801964032, 203522048, 819052544, 1034444800, 118935552, 495421440, 1037880320, 724168192, 492246784, 947381376, 808851904, 852517728, 314236272, 243370952, 910278868, 804284766, 116054955 - ], - [ - 536870912, 268435456, 939524096, 201326592, 973078528, 150994944, 343932928, 54525952, 1021313024, 728760320, 498597888, 42205184, 542244864, 426180608, 816807936, 403423232, 471556096, 34574336, 85026816, 782013440, 173336064, 678713088, 674367616, 559351104, 704087456, 1040171408, 468804760, 283940940, 23913846, 749756077 - ], - [ - 536870912, 268435456, 134217728, 603979776, 838860800, 318767104, 159383552, 952107008, 85983232, 808452096, 12058624, 251396096, 747503616, 4653056, 795246592, 542523392, 1063264256, 675786752, 460859392, 441168896, 141437440, 331398400, 817800832, 384694720, 9831648, 374015984, 242257320, 987582460, 238071686, 363525443 - ], - [ - 536870912, 268435456, 671088640, 738197504, 838860800, 251658240, 461373440, 448790528, 807403520, 762314752, 228065280, 467402752, 1050804224, 255787008, 249987072, 323371008, 904568832, 786329600, 372123648, 342307840, 117572096, 663686912, 14583424, 321538240, 82881120, 407729520, 812819176, 151157228, 848047470, 945304235 - ], - [ - 536870912, 805306368, 939524096, 469762048, 771751936, 117440512, 293601280, 272629760, 140509184, 770703360, 128450560, 47448064, 195690496, 617938944, 681738240, 122699776, 301293568, 432001024, 1038051328, 103472128, 446555648, 667589376, 991989120, 101796544, 320725472, 462066384, 624985592, 820069036, 724953490, 236886233 - ], - [ - 536870912, 268435456, 402653184, 335544320, 503316480, 285212672, 494927872, 490733568, 564133888, 1049624576, 197656576, 913047552, 452591616, 171376640, 786202624, 635486208, 246915072, 570773504, 319948800, 512427008, 466519552, 778814720, 251209600, 338596928, 1070280544, 947229520, 334341736, 60972708, 763792242, 357026011 - ], - [ - 536870912, 268435456, 671088640, 872415232, 301989888, 452984832, 411041792, 884998144, 195035136, 827326464, 1055391744, 631504896, 474087424, 125108224, 653492224, 698826752, 307421184, 979505152, 930711552, 518407168, 900426240, 876895488, 863169664, 888279744, 850494496, 181552176, 245460072, 1019565972, 799761690, 189027993 - ], - [ - 536870912, 805306368, 134217728, 67108864, 704643072, 754974720, 226492416, 834666496, 908066816, 141557760, 378011648, 123469824, 23461888, 17235968, 328957952, 1054097408, 314318848, 505868288, 1013032960, 881179648, 776866304, 652938496, 500533376, 675236416, 124365280, 840546096, 285738728, 731644524, 851839530, 1018626763 - ], - [ - 536870912, 805306368, 402653184, 201326592, 369098752, 83886080, 629145600, 12582912, 291504128, 30408704, 116916224, 102498304, 756940800, 830930944, 449085440, 41533440, 559079424, 597848064, 398231552, 1034275840, 917300736, 439710464, 694160768, 1037045056, 150474592, 253494064, 513671640, 877068596, 774146270, 57262519 - ], - [ - 536870912, 268435456, 134217728, 201326592, 838860800, 486539264, 998244352, 46137344, 769654784, 416284672, 753401856, 424935424, 1059979264, 1026359296, 942702592, 129548288, 997580800, 965226496, 131106816, 308855808, 605938176, 773600000, 656311424, 714457920, 189099232, 842068912, 245723128, 920712564, 407728090, 1052045797 - ], - [ - 536870912, 268435456, 134217728, 469762048, 570425344, 956301312, 327155712, 524288000, 618659840, 240123904, 996671488, 991166464, 981860352, 81068032, 666009600, 145276928, 204152832, 333950976, 517638144, 448578560, 757932544, 343062272, 1065877632, 625216064, 166594272, 599851216, 1060405688, 897437140, 941206074, 68122901 - ], - [ - 536870912, 805306368, 134217728, 738197504, 503316480, 50331648, 847249408, 465567744, 597688320, 47185920, 272105472, 1049886720, 902692864, 682295296, 474447872, 367935488, 507011072, 93753344, 593463296, 23743488, 586048000, 649698048, 659427200, 57347264, 937922208, 993938928, 268463976, 939692148, 605126830, 838944085 - ], - [ - 536870912, 268435456, 671088640, 201326592, 704643072, 687865856, 293601280, 583008256, 136314880, 944766976, 241696768, 19136512, 970850304, 78184448, 85360640, 731103232, 600104960, 364793856, 813729792, 793691136, 686057984, 358650624, 229433984, 77225536, 559842912, 669503408, 133358216, 401823572, 1072170362, 870581945 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 167772160, 184549376, 142606336, 968884224, 622854144, 426770432, 337117184, 638320640, 152698880, 1067122688, 994082816, 400670720, 885563392, 883322880, 388638720, 912307200, 578816512, 583011072, 631242880, 481299904, 993525920, 880544944, 360844136, 542574636, 393907278, 822792159 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 973078528, 83886080, 494927872, 859832320, 778043392, 418381824, 1027080192, 647233536, 1037697024, 665780224, 558989312, 528039936, 459923456, 224808960, 711714816, 250434560, 439905792, 35592960, 687997056, 1066076736, 173248480, 166871696, 783966840, 248781740, 221350838, 780748617 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 436207616, 754974720, 511705088, 750780416, 622854144, 389021696, 372768768, 448528384, 660733952, 114229248, 271155200, 1035911168, 484745216, 143405056, 63219712, 582759424, 58501632, 683686656, 457092224, 339685440, 61811488, 536738672, 487162472, 110022332, 417116134, 53492755 - ], - [ - 536870912, 805306368, 939524096, 67108864, 704643072, 788529152, 260046848, 826277888, 174063616, 240123904, 234356736, 51118080, 697958400, 139001856, 83197952, 897761280, 374808576, 973008896, 286099456, 42912768, 768421376, 448262400, 813171328, 692848576, 1048186336, 475598160, 653101080, 647940180, 936714398, 229375123 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 234881024, 486539264, 545259520, 633339904, 1025507328, 1053818880, 347602944, 295436288, 591790080, 569049088, 291536896, 482295808, 93872128, 155504640, 251168768, 586370048, 82208256, 1039392512, 796789632, 431426368, 419860000, 579094128, 784395464, 1017616628, 898032910, 290230551 - ], - [ - 536870912, 805306368, 402653184, 67108864, 1040187392, 654311424, 612368384, 926941184, 882900992, 586153984, 566755328, 921960448, 937295872, 233111552, 693141504, 599506944, 510320640, 311980032, 1012033536, 841464832, 145657344, 686738688, 550660480, 828881088, 437161632, 689883152, 463102472, 399750252, 1039172314, 827048129 - ], - [ - 536870912, 805306368, 939524096, 872415232, 100663296, 184549376, 109051904, 675282944, 681574400, 426770432, 336068608, 906756096, 856555520, 848101376, 776044544, 597868544, 535928832, 1010962432, 514205696, 712530944, 645923328, 406848256, 278922112, 762315584, 302514272, 1024196784, 898498664, 449643140, 115442314, 986890647 - ], - [ - 536870912, 268435456, 939524096, 469762048, 503316480, 285212672, 780140544, 910163968, 799014912, 36700160, 373817344, 1067712512, 977141760, 172949504, 564363264, 725237760, 616865792, 401477632, 76654592, 653536256, 27492864, 993673472, 482648960, 200151488, 445753824, 938749200, 790855912, 226116196, 862232954, 165548515 - ], - [ - 536870912, 805306368, 134217728, 335544320, 503316480, 385875968, 427819008, 20971520, 572522496, 198180864, 505937920, 836501504, 522846208, 727252992, 434995200, 524075008, 698081280, 193236992, 608659456, 782263296, 236708352, 767857408, 401041536, 808478016, 739501024, 13144688, 258304280, 737502548, 150233538, 1065177805 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 704643072, 117440512, 645922816, 1010827264, 106954752, 934281216, 841482240, 500432896, 127008768, 351469568, 382500864, 673234944, 584458240, 890458112, 1052735488, 1034722304, 1041932800, 171151616, 317282944, 150982592, 751163552, 120524144, 945552104, 592993540, 1071546950, 747880907 - ], - [ - 536870912, 268435456, 134217728, 335544320, 100663296, 251658240, 260046848, 658505728, 899678208, 34603008, 578289664, 604766208, 503709696, 319225856, 495222784, 776093696, 891297792, 718942208, 815577088, 330427392, 1046878720, 359832832, 662700672, 591396928, 1000341728, 420479408, 737673368, 206307972, 606471074, 911671893 - ], - [ - 536870912, 268435456, 671088640, 469762048, 704643072, 83886080, 578813952, 272629760, 35651584, 238026752, 432537600, 1004797952, 635043840, 337575936, 871792640, 1009205248, 758226944, 1011585024, 271075328, 1060826112, 222593536, 78397696, 7676544, 686281152, 945646240, 199048272, 521791528, 175209476, 1038928034, 852929571 - ], - [ - 536870912, 268435456, 939524096, 201326592, 436207616, 16777216, 528482304, 121634816, 1054867456, 663748608, 445120512, 650379264, 380502016, 301137920, 1054769152, 460079104, 836624384, 65327104, 169752576, 684270592, 296092160, 762773760, 722502528, 659505344, 787177888, 530354192, 377870840, 1019933812, 396409326, 242575225 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 33554432, 452984832, 327155712, 171966464, 891289600, 686817280, 781713408, 197394432, 208273408, 710475776, 841449472, 159006720, 668737536, 292384768, 752179200, 719369216, 43448832, 566462208, 862815104, 131285184, 560177568, 886256240, 384006424, 9749780, 985931882, 552169771 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 369098752, 83886080, 343932928, 843055104, 861929472, 309329920, 26738688, 464257024, 308150272, 906821632, 353271808, 1015988224, 239820800, 627847168, 393283584, 353723392, 702835200, 557077760, 612098176, 346026688, 657255392, 471570320, 325059112, 40895092, 697827582, 665584067 - ], - [ - 536870912, 268435456, 671088640, 738197504, 436207616, 251658240, 679477248, 717225984, 996147200, 554696704, 329777152, 24379392, 70385664, 18284544, 60850176, 695648256, 674603008, 454619136, 212318208, 33428480, 49619456, 545140992, 767171200, 307422912, 58760096, 608642544, 749189640, 301864300, 720708246, 209596705 - ], - [ - 536870912, 268435456, 402653184, 603979776, 436207616, 318767104, 880803840, 759169024, 790626304, 445644800, 736624640, 762576896, 681443328, 350552064, 1072988160, 684965888, 105816064, 799739904, 903686144, 868701184, 426516992, 1027199232, 573639040, 549357120, 956115872, 240604208, 67379400, 168677780, 185535186, 277579481 - ], - [ - 536870912, 268435456, 939524096, 872415232, 369098752, 989855744, 427819008, 46137344, 794820608, 250609664, 347602944, 698089472, 104988672, 656867328, 920027136, 367935488, 834215936, 387846144, 118228992, 327635968, 599820800, 803345664, 951396736, 463029824, 323780832, 832913904, 999662456, 55267548, 161589774, 261097331 - ], - [ - 536870912, 268435456, 939524096, 872415232, 301989888, 1056964608, 411041792, 1044381696, 748683264, 972029952, 369623040, 84148224, 730726400, 13434880, 1071939584, 853524480, 155066368, 31690752, 1003563008, 79002624, 740295168, 598737152, 279446400, 938738496, 923140384, 76088304, 541753736, 899859428, 208839370, 264786847 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 234881024, 251658240, 243269632, 113246208, 526385152, 1020264448, 345505792, 490471424, 915275776, 583598080, 627998720, 31408128, 454811648, 444452864, 564905984, 128998400, 306924032, 883301632, 608053888, 319065792, 277742176, 29950512, 770605192, 874464092, 83616254, 795726673 - ], - [ - 536870912, 268435456, 402653184, 738197504, 436207616, 50331648, 981467136, 784334848, 123731968, 946864128, 879230976, 183762944, 783155200, 1000275968, 265846784, 913817600, 291643392, 829583360, 367851520, 851241984, 487203328, 126251264, 960690560, 639889088, 844276640, 473018672, 364960296, 31562796, 347495382, 470376119 - ], - [ - 536870912, 268435456, 134217728, 469762048, 369098752, 385875968, 343932928, 801112064, 731906048, 254803968, 808976384, 683409408, 427687936, 970522624, 879525888, 1016152064, 721969152, 311267328, 818313216, 589640704, 922647040, 211367168, 855669376, 109065408, 986512352, 572618160, 897358504, 936437580, 929357842, 572314559 - ], - [ - 536870912, 268435456, 671088640, 469762048, 301989888, 318767104, 947912704, 901775360, 379584512, 254803968, 933756928, 884211712, 316801024, 198377472, 427196416, 542097408, 585408512, 869576704, 762316800, 776141824, 602710528, 407941376, 540674688, 220593600, 980951840, 550268976, 589834504, 729714332, 592218698, 845823171 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 234881024, 687865856, 595591168, 935329792, 559939584, 1009778688, 42467328, 407633920, 816447488, 140443648, 322666496, 68042752, 705617920, 856223744, 948230144, 860277760, 471990784, 152240896, 672236160, 126960576, 374694112, 574010000, 864172600, 801259388, 896325654, 238734531 - ], - [ - 536870912, 805306368, 134217728, 738197504, 167772160, 1023410176, 142606336, 1069547520, 761266176, 485490688, 116916224, 66322432, 796262400, 918355968, 752844800, 94420992, 874176512, 625020928, 1001146368, 387871744, 1053575680, 401504000, 976505472, 85620160, 398608928, 828864016, 519948968, 402109932, 25110654, 766682147 - ], - [ - 536870912, 268435456, 671088640, 335544320, 704643072, 150994944, 478150656, 448790528, 748683264, 141557760, 620232704, 104595456, 378929152, 551747584, 655458304, 883933184, 612294656, 855330816, 825358336, 689185792, 799537664, 234300672, 179730560, 609805376, 407411232, 90420432, 425288680, 1053266300, 1051106082, 1031582971 - ], - [ - 536870912, 805306368, 134217728, 469762048, 1040187392, 956301312, 75497472, 1035993088, 18874368, 588251136, 263716864, 769916928, 180224000, 661454848, 108298240, 1053540352, 648306688, 156487680, 752777216, 831663104, 662444544, 508100352, 828957312, 326898368, 205790048, 1047330384, 855040424, 184619852, 998807770, 339950637 - ], - [ - 536870912, 268435456, 134217728, 603979776, 301989888, 956301312, 226492416, 440401920, 622854144, 592445440, 811073536, 953942016, 287178752, 561446912, 25395200, 1011204096, 102932480, 869675008, 899577856, 1052126208, 451312128, 674901248, 740326016, 919678784, 102628256, 737406160, 423943032, 632036724, 782106922, 305595201 - ], - [ - 536870912, 268435456, 402653184, 469762048, 1040187392, 419430400, 25165824, 264241152, 954204160, 544210944, 396886016, 450101248, 654180352, 283836416, 880640000, 766459904, 568123392, 7614464, 128129024, 47582208, 989291008, 786723072, 763132288, 740720064, 773134816, 949554320, 668787608, 359936060, 539171310, 135663191 - ], - [ - 536870912, 268435456, 402653184, 335544320, 973078528, 553648128, 25165824, 809500672, 673185792, 357564416, 522715136, 198443008, 770572288, 657522688, 458260480, 337723392, 861724672, 137318400, 89516032, 119636992, 534045184, 401297664, 104065408, 450135360, 610427296, 461312784, 494504344, 444569156, 217443106, 842106437 - ], - [ - 536870912, 805306368, 939524096, 872415232, 167772160, 50331648, 964689920, 272629760, 354418688, 479199232, 187170816, 630980608, 161873920, 944832512, 113541120, 853655552, 687005696, 202493952, 300787712, 561116160, 609411584, 818008832, 937798528, 746452800, 752673440, 772592432, 17246232, 915224132, 399148018, 208454393 - ], - [ - 536870912, 268435456, 671088640, 335544320, 570425344, 788529152, 411041792, 734003200, 568328192, 667942912, 994574336, 237240320, 205127680, 664600576, 266633216, 114671616, 314646528, 610496512, 328284160, 1038685184, 31359488, 508084480, 765829760, 494317888, 45095456, 291137264, 830978952, 105240508, 27337374, 57897533 - ], - [ - 536870912, 805306368, 939524096, 201326592, 704643072, 352321536, 679477248, 725614592, 589299712, 944766976, 198705152, 856948736, 419037184, 860422144, 522944512, 710066176, 316596224, 832253952, 649558016, 955198464, 204831232, 44183296, 429717888, 582873024, 652974880, 1060707984, 355172776, 257081380, 39772570, 383463585 - ], - [ - 536870912, 805306368, 134217728, 335544320, 905969664, 16777216, 679477248, 759169024, 320864256, 9437184, 829947904, 503578624, 621674496, 377946112, 944275456, 229490688, 752508928, 182022144, 870029312, 122874880, 136280576, 741695232, 85983872, 831521344, 301466592, 658768208, 3015144, 387384004, 565216186, 1055507165 - ], - [ - 536870912, 268435456, 134217728, 603979776, 570425344, 989855744, 394264576, 96468992, 538968064, 435159040, 609746944, 929824768, 244711424, 985858048, 94732288, 791953408, 939139072, 156241920, 837400576, 64263168, 715495936, 45581568, 624009856, 955994944, 886577824, 724551152, 377323864, 228082412, 290202618, 241374083 - ], - [ - 536870912, 268435456, 402653184, 335544320, 973078528, 654311424, 8388608, 297795584, 1042284544, 225443840, 749207552, 666107904, 604897280, 838926336, 721977344, 780976128, 214867968, 430813184, 473933824, 55520256, 350265856, 98349312, 958343552, 683142464, 947913120, 364905328, 471859592, 1047527516, 371720258, 292815527 - ], - [ - 536870912, 268435456, 134217728, 603979776, 301989888, 754974720, 578813952, 725614592, 778043392, 1018167296, 422051840, 1020526592, 916062208, 477429760, 1015709696, 541343744, 1005002752, 1014763520, 746911744, 675421184, 535667200, 779636992, 25417856, 181276224, 882989856, 1986512, 1027373224, 333929972, 142213446, 914686555 - ], - [ - 536870912, 268435456, 134217728, 738197504, 503316480, 654311424, 1048576000, 633339904, 895483904, 1032847360, 691535872, 63700992, 644218880, 957939712, 435453952, 824328192, 665870336, 1040699392, 923576320, 915307520, 164121088, 728493312, 445940352, 397558720, 638083424, 319541424, 76196360, 818379820, 853854910, 30780549 - ], - [ - 536870912, 268435456, 671088640, 738197504, 503316480, 889192448, 729808896, 549453824, 698351616, 357564416, 469237760, 506200064, 329121792, 56164352, 317751296, 61652992, 710057984, 528240640, 309303296, 443620352, 31799808, 1051806976, 441229440, 15029184, 524229472, 361618832, 97491288, 706813020, 429734050, 744311961 - ], - [ - 536870912, 805306368, 939524096, 67108864, 570425344, 486539264, 1065353216, 557842432, 413138944, 745537536, 734527488, 174850048, 194904064, 605618176, 224165888, 704462848, 595910656, 927191040, 531032064, 184171520, 386564608, 780681984, 13001600, 48730176, 878610976, 74755536, 666929656, 342732052, 815532042, 613477767 - ], - [ - 536870912, 268435456, 402653184, 201326592, 905969664, 452984832, 578813952, 666894336, 954204160, 953155584, 999817216, 935067648, 17432576, 528547840, 105414656, 833110016, 301195264, 548376576, 377186304, 719846400, 299493888, 538885376, 335186816, 296054208, 33030368, 950796400, 443678920, 485294860, 182092486, 43335745 - ], - [ - 536870912, 805306368, 402653184, 201326592, 436207616, 1056964608, 578813952, 935329792, 668991488, 540016640, 79167488, 1047789568, 269615104, 861995008, 50298880, 651444224, 117891072, 512102400, 902195200, 350299136, 414476800, 208676608, 991161216, 132147136, 272566816, 481522736, 846520328, 169284428, 207743094, 544302671 - ], - [ - 536870912, 805306368, 671088640, 603979776, 100663296, 989855744, 729808896, 893386752, 308281344, 1039138816, 1008205824, 144965632, 752222208, 9109504, 113541120, 723861504, 228401152, 1022242816, 607848448, 984810496, 191900160, 701904640, 739221632, 302018880, 352496352, 881358320, 416153816, 472843236, 68321566, 883835595 - ], - [ - 536870912, 805306368, 134217728, 67108864, 100663296, 184549376, 343932928, 415236096, 266338304, 1022361600, 756547584, 652476416, 360579072, 576389120, 558137344, 950878208, 928309248, 46895104, 1055557632, 695804928, 677276160, 675460864, 556589696, 807375680, 23890144, 355869936, 930933544, 525399612, 918717238, 820134147 - ], - [ - 536870912, 268435456, 939524096, 201326592, 637534208, 956301312, 645922816, 482344960, 253755392, 974127104, 1073217536, 466354176, 212467712, 509411328, 420642816, 779862016, 746971136, 331845632, 681605120, 207195136, 169286144, 401988864, 801800576, 648528320, 22536672, 110531408, 339277832, 1064259164, 653818010, 759533421 - ], - [ - 536870912, 268435456, 134217728, 738197504, 369098752, 486539264, 679477248, 79691776, 387973120, 747634688, 270008320, 920387584, 251527168, 769982464, 448299008, 168017920, 319283200, 294375424, 373463040, 417364992, 238852608, 281378048, 891558528, 60211136, 530316256, 294743568, 681533800, 974656092, 903707162, 393719189 - ], - [ - 536870912, 268435456, 939524096, 67108864, 436207616, 50331648, 562036736, 62914560, 509607936, 974127104, 875036672, 196345856, 911605760, 411893760, 827097088, 70238208, 599777280, 173977600, 109262848, 676074496, 648372736, 33321216, 401628032, 587031616, 645512096, 423548208, 1008599960, 958988668, 187859910, 320259025 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 234881024, 721420288, 763363328, 566231040, 559939584, 326107136, 941096960, 40108032, 721027072, 869335040, 973635584, 822296576, 747151360, 357535744, 136931328, 358425600, 104974848, 698529536, 579904384, 808161472, 424896864, 273425776, 1051281464, 17954732, 987759438, 363856875 - ], - [ - 536870912, 805306368, 134217728, 335544320, 637534208, 520093696, 696254464, 406847488, 6291456, 1051721728, 264765440, 724303872, 760348672, 71106560, 873299968, 369737728, 386752512, 1032491008, 1045321728, 526519296, 390038016, 394576640, 726196352, 334451008, 200358496, 522558960, 995383448, 322113156, 159384198, 675283371 - ], - [ - 536870912, 268435456, 671088640, 335544320, 301989888, 721420288, 209715200, 71303168, 991952896, 651165696, 930611200, 1022099456, 1061027840, 969342976, 484802560, 791953408, 298115072, 149073920, 1027545088, 986274816, 73792000, 964488448, 31940736, 582873152, 234912672, 1023979504, 495158248, 936330228, 568812026, 851309417 - ], - [ - 536870912, 268435456, 402653184, 335544320, 704643072, 251658240, 964689920, 549453824, 463470592, 395313152, 710410240, 58458112, 1068105728, 899088384, 693207040, 82853888, 980230144, 414355456, 662779904, 365132800, 891861504, 450837760, 993500032, 4631616, 1005396256, 1014141104, 237058232, 424902588, 217102978, 912473733 - ], - [ - 536870912, 268435456, 671088640, 335544320, 436207616, 1056964608, 629145600, 146800640, 379584512, 103809024, 673710080, 158597120, 893517824, 845217792, 916226048, 521322496, 567533568, 779874304, 1020250112, 481180672, 289006080, 430895360, 464603776, 485358912, 299795360, 376685296, 13590744, 313078220, 876357834, 52809619 - ], - [ - 536870912, 268435456, 671088640, 603979776, 905969664, 721420288, 427819008, 423624704, 39845888, 1072693248, 117964800, 461635584, 743047168, 350814208, 155025408, 925024256, 1066557440, 234115072, 168138752, 17595392, 143131136, 969146624, 531235456, 374932032, 978682720, 945210032, 223371672, 467227028, 756160550, 490192895 - ], - [ - 536870912, 268435456, 402653184, 738197504, 1040187392, 687865856, 729808896, 876609536, 287309824, 1047527424, 745013248, 349437952, 1046347776, 93782016, 720732160, 1051410432, 272392192, 508416000, 975464448, 452701184, 916578816, 607293696, 205916544, 757169856, 409995744, 694321040, 22776120, 589184132, 1060268402, 550022839 - ], - [ - 536870912, 805306368, 939524096, 872415232, 100663296, 754974720, 293601280, 356515840, 90177536, 158334976, 446169088, 941883392, 806486016, 434831360, 1034977280, 851230720, 3547136, 637186048, 374884352, 604103680, 235170304, 553932544, 596025728, 1044803648, 971926496, 230380944, 180102008, 875933828, 603638478, 995501699 - ], - [ - 536870912, 268435456, 134217728, 201326592, 167772160, 452984832, 276824064, 557842432, 933232640, 829423616, 795344896, 940834816, 377094144, 770637824, 106201088, 929021952, 752459776, 353505280, 267520000, 53455872, 104800768, 29806848, 250423424, 47807680, 404359840, 108768432, 635773832, 173659092, 1028762458, 936558183 - ], - [ - 536870912, 805306368, 402653184, 67108864, 369098752, 117440512, 629145600, 633339904, 1004535808, 800063488, 1060634624, 510918656, 986841088, 717422592, 846102528, 7553024, 299114496, 88100864, 44378112, 252838912, 959392256, 30738176, 759933824, 513886016, 488311520, 673535792, 592871608, 755450220, 8790278, 155406487 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 637534208, 1056964608, 964689920, 432013312, 836763648, 407896064, 692584448, 380370944, 1039269888, 53936128, 257785856, 482983936, 560947200, 252899328, 82655232, 13775872, 34046464, 486720256, 344514688, 88093632, 145611360, 922617840, 548952472, 261867164, 732248478, 427701573 - ], - [ - 536870912, 268435456, 939524096, 738197504, 234881024, 721420288, 964689920, 926941184, 10485760, 103809024, 587726848, 1032060928, 760086528, 162201600, 447971328, 113426432, 870998016, 479449088, 741550080, 34475008, 889717248, 713294080, 583926656, 971702976, 764641504, 481477296, 700605336, 275239796, 584394762, 806423651 - ], - [ - 536870912, 268435456, 671088640, 603979776, 436207616, 251658240, 109051904, 180355072, 1059061760, 923795456, 657981440, 111935488, 56492032, 517668864, 814972928, 108216320, 919429120, 958566400, 773535744, 280488960, 535714304, 1060732160, 447438976, 357929792, 802601760, 589278896, 87079880, 94940508, 1004354330, 17886365 - ], - [ - 536870912, 268435456, 402653184, 469762048, 503316480, 117440512, 511705088, 490733568, 547356672, 1051721728, 414711808, 331087872, 188350464, 226295808, 760905728, 162217984, 791994368, 528461824, 743806976, 204157952, 854956544, 630928640, 751672192, 929510592, 425171552, 61486256, 842341256, 83719524, 916191618, 676316815 - ], - [ - 536870912, 268435456, 134217728, 872415232, 33554432, 117440512, 511705088, 289406976, 492830720, 433061888, 870842368, 278134784, 311033856, 1061748736, 610435072, 912048128, 959389696, 87134208, 435877888, 424879104, 61153792, 511217920, 932739200, 470804288, 638190112, 218694000, 763527528, 231522900, 187113974, 439718381 - ], - [ - 536870912, 268435456, 134217728, 738197504, 100663296, 385875968, 914358272, 767557632, 429916160, 686817280, 565706752, 819724288, 34471936, 755826688, 797474816, 542064640, 82436096, 194187264, 644397056, 340993024, 181287424, 924935424, 557275776, 303118272, 153092832, 36700848, 110625672, 434897260, 1008075410, 572588323 - ], - [ - 536870912, 268435456, 134217728, 469762048, 369098752, 654311424, 713031680, 71303168, 673185792, 883949568, 139984896, 965476352, 885391360, 358940672, 219316224, 69484544, 985096192, 995209216, 419436544, 25469952, 818149888, 392451328, 538837632, 531169472, 863273440, 1035027376, 31318984, 357167668, 900298794, 310122255 - ], - [ - 536870912, 805306368, 671088640, 738197504, 369098752, 587202560, 343932928, 121634816, 895483904, 435159040, 314048512, 30670848, 321781760, 958201856, 697073664, 751452160, 413294592, 618082304, 1017391104, 786314240, 564701696, 894727936, 610977920, 611534272, 477553120, 679048176, 980437672, 594543748, 49676670, 842596571 - ], - [ - 536870912, 268435456, 402653184, 335544320, 771751936, 16777216, 595591168, 792723456, 429916160, 118489088, 189267968, 1067712512, 169213952, 315424768, 1072660480, 825638912, 420864000, 38555648, 270804992, 526001152, 611287552, 443957504, 917889408, 274485568, 384576224, 247342096, 341409848, 552289268, 464674842, 433983793 - ], - [ - 536870912, 805306368, 134217728, 738197504, 704643072, 687865856, 25165824, 1027604480, 954204160, 110100480, 732430336, 671350784, 470155264, 570490880, 84246528, 730152960, 340074496, 962605056, 1003988992, 323951616, 781505024, 933983488, 167772288, 419430592, 159383584, 289407152, 316670120, 797966500, 707264518, 356778229 - ], - [ - 536870912, 805306368, 134217728, 67108864, 570425344, 989855744, 427819008, 1027604480, 564133888, 854589440, 391643136, 317980672, 660471808, 452263936, 593395712, 955334656, 408543232, 561147904, 622741504, 14042112, 401085952, 395095808, 85870720, 819348672, 535303712, 327986960, 656295944, 198591532, 107484742, 785166309 - ], - [ - 536870912, 268435456, 402653184, 67108864, 905969664, 553648128, 830472192, 901775360, 773849088, 401604608, 680001536, 925106176, 846331904, 860553216, 1006927872, 570736640, 252125184, 344371200, 843085824, 987882496, 139775488, 180070656, 831463552, 312651840, 699562080, 946529296, 745557720, 508520836, 662700102, 79691927 - ], - [ - 536870912, 268435456, 134217728, 603979776, 100663296, 285212672, 243269632, 12582912, 106954752, 26214400, 284688384, 185860096, 104464384, 343212032, 758022144, 38649856, 827891712, 191238144, 890615808, 725376000, 821185024, 518775552, 498055296, 797531200, 331139616, 959849360, 974067864, 1056656388, 773026330, 113213331 - ], - [ - 536870912, 268435456, 671088640, 67108864, 234881024, 922746880, 394264576, 171966464, 60817408, 600834048, 978845696, 105119744, 430047232, 852819968, 517505024, 361086976, 658825216, 86503424, 219269120, 708424704, 460757504, 336575232, 660111488, 952483904, 459595936, 683143184, 988399672, 950908124, 789355102, 719239977 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 167772160, 352321536, 209715200, 767557632, 463470592, 458227712, 566755328, 720633856, 530448384, 532611072, 615350272, 293617664, 893394944, 409227264, 603052032, 689505280, 1064952320, 260662528, 756152448, 439178432, 624966240, 811885040, 133569192, 521875860, 545014482, 369718663 - ], - [ - 536870912, 268435456, 134217728, 872415232, 436207616, 822083584, 411041792, 994050048, 174063616, 30408704, 375914496, 755236864, 646053888, 406913024, 400982016, 940785664, 374218752, 1043795968, 175990784, 692866048, 498121216, 280661248, 887619712, 927203392, 1013055520, 382795984, 300843112, 633815236, 1042554978, 808587501 - ], - [ - 536870912, 268435456, 402653184, 872415232, 973078528, 721420288, 746586112, 205520896, 1059061760, 986710016, 815267840, 158597120, 369754112, 516882432, 296255488, 39469056, 756473856, 696078336, 1036134400, 719639552, 741499392, 179179264, 652134528, 223773760, 408472160, 370187216, 502942312, 92658668, 801385042, 1038273441 - ], - [ - 536870912, 268435456, 402653184, 603979776, 704643072, 419430400, 276824064, 390070272, 593494016, 279969792, 142082048, 343670784, 176029696, 561840128, 217677824, 557629440, 203415552, 793636864, 549918720, 531067904, 286745088, 846032128, 194470528, 741174592, 544695008, 266169808, 560947784, 303132084, 870933002, 810577385 - ], - [ - 536870912, 268435456, 671088640, 603979776, 301989888, 117440512, 562036736, 918552576, 127926272, 424673280, 171442176, 787742720, 728367104, 684261376, 865763328, 379666432, 1037262848, 847245312, 437581824, 291267584, 989864448, 797301504, 801609856, 388207680, 454351520, 500809616, 659012296, 157699932, 317932198, 627714827 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 771751936, 16777216, 645922816, 188743680, 622854144, 657457152, 182976512, 83623936, 1059454976, 607584256, 728399872, 339623936, 432267264, 744747008, 85407744, 912231424, 231842304, 347818752, 1065712256, 700921664, 342089760, 286519472, 610220056, 584289524, 859808290, 306203433 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 771751936, 654311424, 1031798784, 356515840, 543162368, 860880896, 322437120, 660340736, 235536384, 271908864, 1072594944, 270614528, 800104448, 732532736, 784496640, 639816704, 78851584, 2633984, 545492608, 365011392, 94500448, 250836272, 566941912, 681002156, 26957486, 741336377 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 436207616, 553648128, 998244352, 289406976, 773849088, 942669824, 35127296, 176422912, 46530560, 459472896, 806846464, 19611648, 303570944, 579170304, 650586112, 1029784576, 185845248, 464462592, 954073216, 501678272, 819036256, 122175728, 59744360, 334377092, 561973486, 915682373 - ], - [ - 536870912, 268435456, 134217728, 67108864, 234881024, 1056964608, 343932928, 616562688, 920649728, 691011584, 492306432, 383516672, 916324352, 750714880, 930054144, 218513408, 965058560, 222638080, 866166784, 513209344, 231346688, 605182208, 101454464, 242309440, 268276384, 734533968, 253211288, 344680876, 296925898, 597208383 - ], - [ - 536870912, 268435456, 671088640, 335544320, 637534208, 956301312, 830472192, 1010827264, 966787072, 1064304640, 434634752, 656670720, 867303424, 294453248, 800489472, 864993280, 414588928, 789491712, 863127552, 334009344, 69475840, 154342656, 55320704, 584560704, 949930144, 1003443280, 387366552, 25060836, 253675590, 781145265 - ], - [ - 536870912, 805306368, 939524096, 67108864, 838860800, 721420288, 729808896, 247463936, 262144000, 577765376, 232259584, 664535040, 259653632, 1064108032, 820346880, 68665344, 93102080, 468897792, 404326400, 1002126336, 667652608, 253139200, 504107648, 758143424, 331297376, 734546384, 18324136, 51012988, 531832838, 502796359 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 771751936, 318767104, 511705088, 482344960, 207618048, 529530880, 220725248, 520355840, 142737408, 465895424, 15171584, 1045807104, 214589440, 47697920, 352950272, 389057536, 450785792, 935159040, 463995008, 801374272, 48365728, 726991088, 1028620472, 781303884, 380133498, 440586355 - ], - [ - 536870912, 805306368, 939524096, 469762048, 167772160, 1056964608, 461373440, 322961408, 903872512, 84934656, 878182400, 977010688, 476708864, 634716160, 117080064, 617201664, 69672960, 87347200, 392853504, 542204928, 79484416, 598672640, 1022490240, 860804544, 358682208, 735474096, 536541256, 843949132, 803305126, 840046017 - ], - [ - 536870912, 268435456, 939524096, 201326592, 838860800, 318767104, 260046848, 79691776, 39845888, 456130560, 436731904, 422838272, 554303488, 582156288, 466321408, 30752768, 477749248, 278704128, 65894400, 684129280, 543497728, 808598784, 428701824, 804715584, 812457696, 906378544, 84375624, 444988428, 642162398, 673414435 - ], - [ - 536870912, 805306368, 671088640, 469762048, 234881024, 318767104, 645922816, 1002438656, 127926272, 829423616, 1048051712, 230424576, 639238144, 829358080, 1343488, 623460352, 737222656, 1002106880, 823724032, 770227200, 986952192, 420252928, 348598912, 522571200, 834015776, 56573360, 151984664, 214401532, 723822722, 599198739 - ], - [ - 536870912, 805306368, 134217728, 469762048, 973078528, 251658240, 729808896, 272629760, 241172480, 519045120, 26738688, 718536704, 638451712, 171769856, 989954048, 1031815168, 759390208, 920760320, 523544576, 280845312, 297838080, 690353920, 789989504, 690793664, 271543840, 917314416, 376194664, 97060860, 806879246, 93585649 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 436207616, 754974720, 411041792, 759169024, 870318080, 640679936, 761790464, 774635520, 114163712, 662372352, 785678336, 484163584, 260071424, 146829312, 774199296, 76735488, 582959616, 141762304, 487309952, 584638272, 1015259680, 860139440, 283179592, 900811524, 799881258, 84841649 - ], - [ - 536870912, 805306368, 402653184, 335544320, 637534208, 956301312, 696254464, 826277888, 400556032, 384827392, 717750272, 1029963776, 758513664, 921370624, 800489472, 19578880, 26222592, 217690112, 1024321536, 591748096, 954609152, 511037696, 638460032, 1036431552, 354773088, 592485456, 157191832, 110731748, 213608486, 1064279045 - ], - [ - 536870912, 268435456, 402653184, 67108864, 905969664, 251658240, 125829120, 88080384, 228589568, 344981504, 196608000, 994836480, 218497024, 914423808, 298024960, 1030111232, 628563968, 436801536, 648304640, 890444800, 435693056, 896492800, 718724736, 1067329856, 966263008, 1050411088, 622723256, 308084780, 654147782, 988495913 - ], - [ - 536870912, 268435456, 402653184, 738197504, 771751936, 553648128, 729808896, 524288000, 157286400, 1048576, 180879360, 663486464, 703463424, 394067968, 728793088, 366559232, 1069768704, 379785216, 112490496, 343806976, 536245760, 404602624, 778499712, 781516608, 604870368, 313257968, 69201496, 140835700, 999758070, 227345417 - ], - [ - 536870912, 268435456, 134217728, 335544320, 234881024, 385875968, 998244352, 96468992, 232783872, 646971392, 921174016, 13369344, 616431616, 323420160, 983662592, 171065344, 937009152, 378556416, 787425280, 483095552, 1052333568, 172323584, 371291776, 880239424, 1073741472, 1038108432, 1050116248, 719929420, 449716470, 1035538459 - ], - [ - 536870912, 805306368, 134217728, 201326592, 369098752, 654311424, 780140544, 121634816, 710934528, 781189120, 916979712, 915144704, 368705536, 117637120, 512131072, 256000000, 644325376, 949219328, 296343552, 403469312, 314209792, 761613056, 806573696, 971570112, 284110496, 761823216, 380109048, 109838444, 502923458, 184746161 - ], - [ - 536870912, 805306368, 939524096, 67108864, 503316480, 50331648, 981467136, 88080384, 52428800, 554696704, 314048512, 610009088, 371851264, 589627392, 286359552, 716980224, 543105024, 137293824, 539138048, 731257856, 804826624, 595144960, 691801728, 849248704, 264779360, 970337744, 6234136, 942600412, 404920434, 798366729 - ], - [ - 536870912, 805306368, 134217728, 469762048, 503316480, 184549376, 880803840, 113246208, 719323136, 877658112, 586678272, 174850048, 863109120, 953090048, 302415872, 755384320, 730046464, 809791488, 958760960, 557114368, 619529728, 79039744, 665734784, 487893440, 39364768, 102421680, 221867608, 822712668, 912261162, 512753911 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 771751936, 620756992, 444596224, 448790528, 400556032, 753926144, 554172416, 115081216, 230817792, 912326656, 833650688, 178929664, 151871488, 853405696, 667224064, 23536640, 540156416, 804216576, 514509440, 319802304, 1037598816, 172376112, 170352728, 311488612, 348096722, 510682367 - ], - [ - 536870912, 805306368, 939524096, 738197504, 905969664, 16777216, 176160768, 742391808, 736100352, 986710016, 36175872, 473694208, 850526208, 976814080, 1001816064, 616382464, 234217472, 945483776, 1017190400, 481514496, 658159104, 1060321024, 637480576, 445916096, 802093152, 535602288, 371142200, 1011098548, 602339442, 785425525 - ], - [ - 536870912, 805306368, 134217728, 872415232, 503316480, 553648128, 142606336, 138412032, 383778816, 667942912, 1006108672, 510918656, 793640960, 547160064, 526680064, 387235840, 760979456, 457199616, 761325568, 605481984, 651846144, 277048064, 71813248, 887520448, 752298528, 209508304, 1069007608, 963263300, 435003522, 363417649 - ], - [ - 536870912, 805306368, 671088640, 335544320, 771751936, 352321536, 109051904, 641728512, 513802240, 1034944512, 628621312, 270794752, 1073086464, 1037893632, 748060672, 839630848, 515612672, 188764160, 337774592, 167179264, 349709824, 269682432, 793616512, 329076928, 372541600, 163394640, 985892536, 870537044, 412592282, 739222617 - ], - [ - 536870912, 268435456, 402653184, 201326592, 905969664, 687865856, 528482304, 817889280, 966787072, 384827392, 198705152, 334757888, 844759040, 305594368, 410746880, 33669120, 50765824, 411447296, 172144640, 551683072, 915531264, 990756608, 1041938560, 332792896, 627828320, 868925232, 465123416, 723764452, 196560414, 163287027 - ], - [ - 536870912, 805306368, 671088640, 335544320, 838860800, 352321536, 226492416, 482344960, 853540864, 464519168, 285736960, 351535104, 338558976, 723582976, 1020559360, 712720384, 287055872, 1013837824, 914765824, 306605056, 748760576, 957488384, 454867072, 627846336, 889294496, 1031843152, 885039176, 652390548, 699668630, 67804195 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 771751936, 50331648, 780140544, 205520896, 312475648, 558891008, 620232704, 776732672, 952500224, 669319168, 879788032, 912932864, 399613952, 79671296, 720328704, 647126016, 60734976, 360469760, 847824512, 489158976, 110526560, 329203888, 762912856, 243921148, 857798658, 93645885 - ], - [ - 536870912, 805306368, 134217728, 872415232, 704643072, 385875968, 713031680, 826277888, 1033895936, 789577728, 943194112, 861143040, 1966080, 998572032, 717258752, 660881408, 7626752, 206049280, 353945600, 33612800, 319080960, 143078144, 306202752, 1025549504, 156674592, 790504400, 755367976, 92340380, 667320458, 317014037 - ], - [ - 536870912, 805306368, 939524096, 335544320, 503316480, 50331648, 528482304, 348127232, 480247808, 533725184, 609746944, 689700864, 108658688, 1015873536, 80183296, 346046464, 869670912, 777703424, 874432512, 452500480, 936117760, 211942656, 399607424, 140295616, 588785248, 460991888, 537579032, 260399516, 482836582, 815808719 - ], - [ - 536870912, 805306368, 134217728, 469762048, 503316480, 922746880, 998244352, 675282944, 819986432, 430964736, 333971456, 57933824, 936247296, 837091328, 959807488, 371900416, 819027968, 991604736, 620685312, 583592960, 325516800, 368443648, 688744576, 801320128, 916725280, 374829424, 769220856, 652128284, 861464782, 605678801 - ], - [ - 536870912, 805306368, 939524096, 738197504, 369098752, 486539264, 226492416, 281018368, 65011712, 617611264, 941096960, 239337472, 530972672, 343343104, 1055752192, 183418880, 15310848, 871149568, 258643968, 69876736, 168655360, 549409536, 749961344, 420331712, 742007008, 535916720, 992524376, 277826676, 251380278, 51584835 - ], - [ - 536870912, 805306368, 671088640, 67108864, 973078528, 352321536, 713031680, 188743680, 778043392, 124780544, 176685056, 653524992, 877527040, 340852736, 949911552, 109985792, 686825472, 860426240, 802310144, 593058816, 917333504, 727837952, 905201792, 768367808, 915793568, 473607440, 559736936, 1068371092, 401018378, 364224829 - ], - [ - 536870912, 805306368, 134217728, 469762048, 1040187392, 83886080, 109051904, 415236096, 929038336, 783286272, 608698368, 69468160, 731250688, 324599808, 549421056, 500023296, 90415104, 766791680, 869160960, 946211840, 1060398592, 151970048, 872554624, 302289088, 855930912, 528915568, 541466360, 715226388, 525581978, 305933731 - ], - [ - 536870912, 268435456, 402653184, 335544320, 1040187392, 822083584, 612368384, 339738624, 1012924416, 705691648, 601358336, 167510016, 210632704, 583335936, 589529088, 636895232, 470507520, 411136000, 910309376, 1063425024, 361940480, 471430400, 878323328, 708724032, 53182176, 527540496, 692944920, 409157844, 470867978, 517681349 - ], - [ - 536870912, 805306368, 402653184, 67108864, 973078528, 117440512, 595591168, 658505728, 887095296, 785383424, 778567680, 1025245184, 474087424, 426049536, 747864064, 974110720, 755736576, 646877184, 499750912, 388756480, 83723776, 236336896, 936132224, 942445504, 997949664, 391364816, 1042915464, 846958604, 298981478, 971519105 - ], - [ - 536870912, 268435456, 939524096, 872415232, 771751936, 218103808, 260046848, 968884224, 689963008, 45088768, 364380160, 1066139648, 393609216, 916258816, 641564672, 877477888, 290807808, 749457408, 650545152, 430111744, 469230080, 500893952, 23030400, 303625536, 24840288, 154123408, 335708760, 1040243172, 889315846, 998640019 - ], - [ - 536870912, 805306368, 134217728, 603979776, 503316480, 822083584, 880803840, 272629760, 320864256, 1001390080, 162004992, 390856704, 119144448, 73596928, 957579264, 14565376, 142958592, 306540544, 270776320, 70417408, 40688128, 296617728, 189282944, 890910656, 258433696, 579894096, 354345176, 1063727252, 714397834, 823659541 - ], - [ - 536870912, 268435456, 134217728, 872415232, 570425344, 150994944, 931135488, 247463936, 375390208, 74448896, 260571136, 1062469632, 559546368, 600637440, 376471552, 512704512, 886218752, 966668288, 514439168, 746953728, 675341824, 321144064, 181508224, 916057152, 170622496, 683715024, 627205640, 116524388, 550090878, 217423019 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 301989888, 553648128, 763363328, 423624704, 362807296, 420478976, 781713408, 581173248, 194379776, 828047360, 516128768, 568606720, 725032960, 868888576, 639461376, 140809216, 745771520, 225082112, 261038208, 4075712, 590571616, 667653360, 270406216, 123812740, 854949942, 414138533 - ], - [ - 536870912, 805306368, 671088640, 201326592, 369098752, 1056964608, 1048576000, 171966464, 958398464, 311427072, 752353280, 785645568, 452853760, 717291520, 812089344, 725073920, 118382592, 329846784, 335325184, 457700352, 748788224, 341114624, 985344128, 316683456, 796392096, 623505200, 632914136, 476495932, 221372506, 269144089 - ], - [ - 536870912, 268435456, 402653184, 201326592, 503316480, 721420288, 562036736, 809500672, 916455424, 649068544, 954728448, 373555200, 27394048, 20119552, 799637504, 526893056, 1012359168, 788475904, 790333440, 277550080, 227849728, 941337856, 654934144, 47693888, 1027563616, 83570736, 102336632, 470291628, 995440262, 24669633 - ], - [ - 536870912, 268435456, 134217728, 603979776, 838860800, 117440512, 528482304, 490733568, 916455424, 347078656, 145227776, 845938688, 630063104, 429850624, 344162304, 79806464, 383983616, 512872448, 752809984, 371354624, 712382976, 1028652800, 24877696, 319897408, 647707296, 922824656, 126280296, 826446796, 547749910, 565379257 - ], - [ - 536870912, 805306368, 402653184, 469762048, 771751936, 83886080, 75497472, 297795584, 945815552, 969932800, 789053440, 769392640, 726794240, 399310848, 658276352, 440680448, 706764800, 670085120, 586999808, 941904896, 1022756352, 997946112, 828567168, 995305408, 1070524640, 590959792, 675448536, 19084132, 644910634, 935237523 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 503316480, 553648128, 394264576, 1069547520, 849346560, 210763776, 501743616, 1043070976, 42860544, 387514368, 561414144, 1050230784, 800284672, 599298048, 551675904, 317914112, 861801984, 437527296, 631803520, 189621056, 12316256, 409334704, 598869528, 364580660, 98699334, 662056139 - ], - [ - 536870912, 268435456, 402653184, 872415232, 301989888, 855638016, 629145600, 549453824, 987758592, 9437184, 864550912, 417595392, 999424000, 973799424, 505577472, 544227328, 740122624, 686698496, 581982208, 771243008, 570237440, 402172160, 788357248, 209596480, 456677472, 840711376, 770646600, 1043573196, 801103894, 207515843 - ], - [ - 536870912, 805306368, 671088640, 603979776, 637534208, 989855744, 746586112, 532676608, 387973120, 938475520, 675807232, 278134784, 131989504, 768147456, 651591680, 348110848, 1012588544, 747622400, 456611840, 133141504, 916575744, 666187008, 2963584, 763528384, 306507424, 895725968, 714593816, 651703596, 273528978, 747652143 - ], - [ - 536870912, 268435456, 134217728, 469762048, 838860800, 452984832, 8388608, 37748736, 346030080, 66060288, 246939648, 281804800, 968228864, 505085952, 893288448, 34324480, 659693568, 357298176, 175151104, 125729792, 246077952, 816255232, 905200256, 868117824, 625875104, 309705776, 326695656, 548200732, 430234186, 779096357 - ], - [ - 536870912, 805306368, 671088640, 738197504, 234881024, 117440512, 125829120, 549453824, 44040192, 1007681536, 515375104, 925106176, 232128512, 412942336, 242319360, 940556288, 294248448, 105869312, 728422400, 465187840, 161755648, 93351680, 293593216, 503476416, 520312992, 58848432, 46387768, 195436316, 1016248478, 972719171 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 637534208, 989855744, 8388608, 390070272, 509607936, 999292928, 760741888, 58458112, 805961728, 579272704, 776241152, 400965632, 223617024, 972795904, 172595200, 795030528, 1041585664, 362517760, 282982016, 532309440, 296373792, 741728560, 15335608, 962003164, 335315002, 1061830721 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 167772160, 553648128, 125829120, 29360128, 262144000, 240123904, 133693440, 121896960, 434241536, 674562048, 974094336, 82657280, 945430528, 823390208, 169392128, 427176960, 149498368, 173829888, 68518016, 1000095808, 867672224, 566997232, 38606888, 227050628, 1026273822, 603564807 - ], - [ - 536870912, 268435456, 671088640, 603979776, 100663296, 922746880, 310378496, 851443712, 488636416, 34603008, 22544384, 58982400, 121765888, 358940672, 167018496, 409518080, 936042496, 387731456, 593844224, 116401152, 115933696, 655264512, 993656960, 82903104, 669941920, 713670800, 1065115672, 756125916, 266025034, 994358475 - ], - [ - 536870912, 268435456, 134217728, 469762048, 1040187392, 251658240, 847249408, 633339904, 249561088, 808452096, 525860864, 989593600, 267255808, 694616064, 309362688, 603799552, 1047109632, 136736768, 709888000, 296334336, 1002643968, 299897088, 179569280, 647766336, 169683616, 819897648, 79667288, 223178764, 586582034, 658502875 - ], - [ - 536870912, 805306368, 671088640, 872415232, 704643072, 251658240, 1015021568, 146800640, 836763648, 999292928, 910688256, 820248576, 974520320, 286064640, 725778432, 497238016, 515170304, 574164992, 406345728, 255712256, 801104384, 964579584, 765255808, 630001856, 663115936, 776264912, 505635496, 49549628, 790397042, 944390371 - ], - [ - 536870912, 268435456, 939524096, 201326592, 234881024, 1056964608, 142606336, 138412032, 375390208, 506462208, 271056896, 213647360, 243662848, 323289088, 619085824, 728776704, 1070473216, 759885824, 135141376, 535479296, 840534528, 982549248, 154743424, 390461248, 249954400, 779419760, 172916952, 478953676, 564666394, 394260701 - ], - [ - 536870912, 268435456, 939524096, 738197504, 1040187392, 285212672, 780140544, 482344960, 375390208, 309329920, 273154048, 252968960, 129630208, 370868224, 797671424, 150388736, 243965952, 242520064, 105510912, 168950784, 993633792, 635063552, 107698304, 683764800, 341991136, 91533744, 63667832, 55763204, 471475930, 1015582083 - ], - [ - 536870912, 268435456, 402653184, 201326592, 973078528, 553648128, 41943040, 155189248, 576716800, 340787200, 486014976, 104595456, 664666112, 216858624, 270827520, 95928320, 459923456, 1038528512, 764418048, 47846400, 76168704, 1031090432, 399031936, 773058880, 421256928, 934248816, 122070536, 627369460, 366305282, 977105105 - ], - [ - 536870912, 268435456, 671088640, 335544320, 33554432, 285212672, 461373440, 213909504, 698351616, 529530880, 915931136, 236716032, 811466752, 851116032, 508133376, 232898560, 544727040, 1072599040, 376834048, 1022344192, 888606208, 1068137728, 328273536, 412974400, 555650592, 752598288, 922676776, 833613140, 748062278, 740229479 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 100663296, 285212672, 8388608, 12582912, 979369984, 519045120, 444071936, 884736000, 735969280, 397213696, 638746624, 1062092800, 455237632, 752316416, 438953984, 811000832, 216947200, 53667072, 782031488, 529311040, 826718944, 707253680, 1011962616, 49033716, 909478138, 337417463 - ], - [ - 536870912, 805306368, 939524096, 469762048, 234881024, 218103808, 327155712, 994050048, 849346560, 131072000, 768081920, 257687552, 355598336, 708378624, 998277120, 793001984, 413622272, 416305152, 1028446208, 714906624, 257351168, 604711680, 591038080, 168032192, 788740192, 679775408, 969369304, 342026052, 53608694, 188284953 - ], - [ - 536870912, 805306368, 134217728, 738197504, 234881024, 452984832, 729808896, 4194304, 564133888, 11534336, 590872576, 645660672, 257556480, 2818048, 553025536, 849035264, 784998400, 6311936, 676386816, 883862528, 422648320, 243068160, 325032576, 103525824, 402111136, 387775856, 898359960, 172101916, 681990198, 909503517 - ], - [ - 536870912, 805306368, 134217728, 67108864, 33554432, 956301312, 1031798784, 700448768, 920649728, 688914432, 163053568, 268173312, 299499520, 1068171264, 818118656, 996655104, 148299776, 995643392, 619309056, 560034816, 232158720, 148795648, 842004096, 285389248, 159553184, 599859664, 199728808, 378733876, 427524190, 77316243 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 33554432, 285212672, 192937984, 197132288, 962592768, 743440384, 135790592, 26476544, 242876416, 222494720, 723877888, 938950656, 716021760, 740110336, 798316544, 628841472, 734032384, 694415104, 340842624, 874257472, 60150496, 528146416, 113737864, 551567364, 244457678, 117010655 - ], - [ - 536870912, 268435456, 402653184, 872415232, 1040187392, 620756992, 679477248, 784334848, 559939584, 206569472, 427294720, 99876864, 894042112, 509542400, 369131520, 419872768, 981540864, 29642752, 317110272, 789945344, 1046036992, 101112576, 17242240, 243731520, 1069996640, 937629648, 127066744, 278612948, 660602946, 223346731 - ], - [ - 536870912, 805306368, 402653184, 201326592, 234881024, 1023410176, 1065353216, 926941184, 719323136, 663748608, 948436992, 402391040, 199360512, 1041563648, 650805248, 10240000, 674521088, 788353024, 510105600, 777384960, 212651520, 483275520, 262092416, 1018599360, 389832928, 843141360, 694523992, 114357444, 594431686, 32404265 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 973078528, 285212672, 562036736, 171966464, 379584512, 844103680, 129499136, 954466304, 452067328, 183304192, 165380096, 584138752, 1014833152, 201502720, 33785856, 84063232, 663214592, 558026496, 640065664, 429125696, 459188384, 470811888, 790385384, 901020484, 734755334, 851984233 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 100663296, 117440512, 343932928, 817889280, 564133888, 17825792, 756547584, 532414464, 2752512, 351469568, 90734592, 638730240, 161062912, 662679552, 495577088, 333675520, 796028416, 757949696, 963890816, 305059264, 435168928, 418294064, 961726648, 176000044, 806004330, 77850927 - ], - [ - 536870912, 805306368, 671088640, 67108864, 570425344, 385875968, 310378496, 289406976, 996147200, 867172352, 285736960, 240386048, 167641088, 523829248, 10125312, 596328448, 789929984, 446533632, 680331264, 865147904, 987475456, 879645952, 350644352, 326470848, 598484640, 79956240, 547399176, 898779548, 1071203946, 434739605 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 838860800, 855638016, 947912704, 557842432, 1042284544, 70254592, 616038400, 1047789568, 371064832, 755171328, 830570496, 784416768, 702668800, 441536512, 355092480, 121426944, 330739200, 1064981248, 705939584, 680105152, 516509408, 644350960, 974651464, 386138124, 109445122, 407306357 - ], - [ - 536870912, 268435456, 402653184, 469762048, 234881024, 956301312, 461373440, 222298112, 383778816, 403701760, 175636480, 1072431104, 232128512, 693698560, 349995008, 882655232, 872144896, 229298176, 1035311104, 898569216, 838913536, 654832896, 981685888, 180478272, 363272416, 938890288, 166309464, 953443732, 618639062, 1016948113 - ], - [ - 536870912, 268435456, 671088640, 335544320, 33554432, 553648128, 1048576000, 37748736, 354418688, 972029952, 221773824, 280231936, 60424192, 1065418752, 750813184, 1063600128, 953589760, 919572480, 1015572480, 766211072, 1046246912, 107119360, 709945472, 176829504, 514381472, 165155664, 782368904, 1060438212, 123371610, 350503001 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 905969664, 721420288, 1031798784, 264241152, 119537664, 214958080, 676855808, 9699328, 666501120, 685834240, 469073920, 210485248, 349102080, 288321536, 610244608, 244569088, 415113728, 526438144, 154146944, 489231424, 710754976, 831553520, 792420440, 228897004, 412186710, 599565519 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 905969664, 654311424, 293601280, 138412032, 396361728, 625999872, 817364992, 392429568, 406192128, 160104448, 812351488, 228376576, 771088384, 141078528, 27215872, 66409472, 325696000, 639192832, 749756544, 357265600, 185542752, 195962096, 662606552, 595815324, 356577990, 254221281 - ], - [ - 536870912, 805306368, 134217728, 469762048, 1040187392, 184549376, 360710144, 960495616, 685768704, 617611264, 301465600, 283901952, 3276800, 858718208, 504791040, 660226048, 1062969344, 458903552, 827938816, 408671232, 953972224, 522169600, 456765056, 776812992, 864221344, 373392560, 392507096, 882145628, 429774894, 335451145 - ], - [ - 536870912, 805306368, 134217728, 738197504, 503316480, 352321536, 427819008, 851443712, 73400320, 116391936, 1012400128, 676593664, 718143488, 687669248, 432504832, 954515456, 632692736, 654143488, 885209088, 90643456, 628405760, 698146560, 1051891840, 310291648, 998354464, 29799344, 753211128, 531984276, 33521862, 641777851 - ], - [ - 536870912, 805306368, 134217728, 469762048, 704643072, 352321536, 109051904, 197132288, 425721856, 179306496, 297271296, 84672512, 129105920, 859766784, 818839552, 1037352960, 581632, 959770624, 754542592, 531149824, 140610048, 36735232, 830005888, 971521472, 1061251232, 597996720, 726895240, 869239076, 878076466, 273481147 - ], - [ - 536870912, 805306368, 134217728, 335544320, 771751936, 754974720, 830472192, 29360128, 392167424, 680525824, 171442176, 111411200, 133562368, 1051262976, 916357120, 39305216, 635084800, 946974720, 577337344, 411012096, 1057358336, 377851648, 994320512, 505835712, 565434400, 420363344, 49248952, 574227380, 581050950, 569638855 - ], - [ - 536870912, 805306368, 402653184, 335544320, 838860800, 989855744, 1031798784, 843055104, 341835776, 1060110336, 887619584, 854327296, 199884800, 359202816, 246120448, 445497344, 182099968, 1015353344, 147281920, 631493632, 68628992, 725298944, 234304128, 374026176, 897528544, 261566352, 947728936, 319958908, 12366558, 783740853 - ], - [ - 536870912, 268435456, 134217728, 738197504, 33554432, 822083584, 964689920, 163577856, 127926272, 458227712, 639107072, 188481536, 19791872, 416743424, 719224832, 320389120, 213770240, 871256064, 1005758464, 63454208, 174343680, 586255616, 105883264, 161799488, 945131168, 647963120, 394045608, 223296564, 891471566, 773147987 - ], - [ - 536870912, 268435456, 134217728, 67108864, 33554432, 83886080, 629145600, 826277888, 467664896, 904921088, 857210880, 633602048, 354549760, 374407168, 1049133056, 359415808, 949919744, 126070784, 608544768, 912440320, 11984384, 721040128, 355631232, 62472256, 47456288, 810479632, 919308296, 889801748, 925882006, 167395269 - ], - [ - 536870912, 805306368, 134217728, 335544320, 503316480, 419430400, 159383552, 524288000, 660602880, 632291328, 794296320, 460062720, 124911616, 964624384, 146767872, 270221312, 202104832, 717459456, 35952640, 232023040, 241895936, 1022846208, 1027445376, 895222208, 610867360, 200287376, 633301592, 933213492, 38464222, 271054297 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 436207616, 654311424, 276824064, 641728512, 1012924416, 791674880, 145227776, 949747712, 78774272, 342556672, 767459328, 996589568, 263495680, 116158464, 956176384, 830923776, 1002936832, 94415616, 428966528, 666521536, 73668640, 187819056, 111876808, 966617964, 691249834, 95223749 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 838860800, 721420288, 964689920, 457179136, 836763648, 212860928, 911736832, 837550080, 238157824, 1016922112, 1061715968, 1029947392, 527835136, 712953856, 544839680, 125596672, 352123392, 415073536, 584934016, 506327488, 538155232, 101545008, 260471464, 239289692, 157532846, 963698945 - ], - [ - 536870912, 805306368, 671088640, 201326592, 704643072, 889192448, 998244352, 775946240, 929038336, 347078656, 876085248, 58982400, 977666048, 962920448, 129073152, 280838144, 591568896, 417427456, 888195072, 274689024, 867423744, 784213760, 407240832, 811925696, 1043431584, 134037552, 94544040, 387018964, 203999470, 690711737 - ], - [ - 536870912, 805306368, 671088640, 335544320, 838860800, 385875968, 8388608, 406847488, 694157312, 600834048, 722993152, 994312192, 736493568, 76873728, 385515520, 852639744, 1050468352, 478220288, 239568896, 610692096, 542382592, 31142656, 492994688, 567689408, 337305760, 801378384, 27592904, 988818524, 900659714, 26157921 - ], - [ - 536870912, 805306368, 402653184, 872415232, 33554432, 150994944, 427819008, 322961408, 329252864, 812646400, 1011351552, 673447936, 439746560, 778764288, 1058177024, 937312256, 1061036032, 15708160, 584263680, 163107840, 690814464, 514851072, 380117120, 787787968, 965322848, 574788816, 237297160, 959754532, 317294822, 64103565 - ], - [ - 536870912, 805306368, 671088640, 872415232, 637534208, 687865856, 327155712, 373293056, 492830720, 590348288, 735576064, 454295552, 219021312, 825819136, 946110464, 985120768, 782147584, 787755008, 620570624, 726006784, 417619456, 880140032, 289343616, 140643520, 313644704, 446239696, 150273560, 234418020, 952541294, 245379145 - ], - [ - 536870912, 805306368, 134217728, 738197504, 838860800, 419430400, 41943040, 37748736, 878706688, 967835648, 866648064, 991166464, 188612608, 619511808, 267878400, 566837248, 228827136, 1024823296, 876357632, 694975488, 137588224, 1047302400, 431360128, 61713600, 856909344, 657997232, 384626248, 384946596, 592160938, 266681465 - ], - [ - 536870912, 268435456, 134217728, 738197504, 838860800, 553648128, 58720256, 180355072, 950009856, 158334976, 964165632, 209977344, 37879808, 887160832, 647331840, 292438016, 648552448, 932081664, 826169344, 761631744, 827452928, 273272576, 672792704, 131399744, 521109536, 763052208, 176660680, 893726852, 140638222, 1020568619 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 1040187392, 553648128, 1048576000, 4194304, 1067450368, 560988160, 127401984, 133955584, 938344448, 115539968, 609255424, 212680704, 482369536, 820391936, 693565440, 607104000, 25170432, 264571136, 694612608, 579959104, 659483168, 1484208, 151576792, 917991476, 720935074, 258645109 - ], - [ - 536870912, 805306368, 939524096, 201326592, 301989888, 486539264, 478150656, 809500672, 102760448, 219152384, 941096960, 48496640, 1064697856, 355401728, 887980032, 369639424, 427728896, 878120960, 213698560, 145990656, 214716928, 605584128, 417669248, 376459456, 397404384, 195884080, 296630856, 950849396, 976075506, 91197185 - ], - [ - 536870912, 268435456, 134217728, 872415232, 100663296, 285212672, 125829120, 146800640, 383778816, 753926144, 4718592, 800849920, 796262400, 378208256, 341540864, 905986048, 151117824, 998592512, 986163200, 31532032, 980783616, 252477184, 832191104, 358701888, 976332960, 1001006224, 919474744, 821837716, 961796742, 412617511 - ], - [ - 536870912, 268435456, 134217728, 738197504, 436207616, 419430400, 595591168, 88080384, 383778816, 68157440, 677904384, 569638912, 251265024, 190644224, 179011584, 341065728, 386768896, 833073152, 1073170432, 838847488, 601815552, 426658048, 1047718016, 431782976, 683389472, 926451120, 545100520, 60519716, 1041201710, 170330597 - ], - [ - 536870912, 268435456, 134217728, 738197504, 1040187392, 654311424, 159383552, 213909504, 866123776, 361758720, 629669888, 617349120, 430833664, 782172160, 469925888, 637616128, 50831360, 461869056, 365135872, 488782848, 282357248, 451538688, 49868416, 699903808, 803065504, 560037872, 288482904, 832099180, 562036862, 817889375 - ], - [ - 536870912, 805306368, 939524096, 603979776, 234881024, 1056964608, 243269632, 390070272, 60817408, 846200832, 1018691584, 722731008, 246284288, 943390720, 1029079040, 76070912, 931684352, 453939200, 558483456, 963625984, 601699840, 973253376, 956377216, 763794624, 868490976, 635453328, 5453496, 386509628, 55552090, 342512653 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 1040187392, 788529152, 645922816, 37748736, 127926272, 854589440, 448266240, 114556928, 831127552, 906952704, 902397952, 850051072, 129982464, 961646592, 508356608, 393118720, 333014528, 348134144, 232884352, 290722880, 709758560, 225402864, 1054609016, 591683580, 103255674, 842375097 - ], - [ - 536870912, 805306368, 671088640, 738197504, 301989888, 989855744, 159383552, 281018368, 207618048, 814743552, 1065877504, 774635520, 777650176, 956760064, 713457664, 490913792, 580952064, 368316416, 1033652224, 149332992, 483624448, 732786432, 480093824, 644333504, 1066618400, 537791344, 1005060200, 45875356, 735183054, 2818079 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 1040187392, 721420288, 1048576000, 1002438656, 924844032, 691011584, 385351680, 156499968, 1043202048, 3735552, 267747328, 945602560, 857989120, 858886144, 402184192, 517460992, 778849792, 425665280, 346077312, 192120000, 849016480, 998352880, 910282360, 644342636, 668293338, 502207711 - ], - [ - 536870912, 805306368, 402653184, 738197504, 973078528, 452984832, 998244352, 37748736, 685768704, 827326464, 105381888, 314310656, 281149440, 237305856, 779517952, 280674304, 398467072, 396496896, 456407040, 970511360, 1070626304, 42697472, 983232128, 129468352, 303857888, 980664432, 918331528, 784453852, 455120902, 418710629 - ], - [ - 536870912, 268435456, 939524096, 201326592, 771751936, 654311424, 847249408, 163577856, 320864256, 472907776, 860356608, 395575296, 196739072, 947585024, 1046446080, 569163776, 48521216, 320278528, 964597760, 265851904, 11259392, 486966528, 662763648, 172262464, 56809184, 441897264, 312301112, 424284636, 982595242, 70844759 - ], - [ - 536870912, 805306368, 134217728, 469762048, 234881024, 721420288, 293601280, 20971520, 962592768, 110100480, 606601216, 477364224, 922615808, 868024320, 551124992, 390774784, 468049920, 844591104, 101582848, 445004800, 549480960, 807784704, 603318400, 750537920, 325050912, 990719344, 67527352, 705162604, 822313702, 679517621 - ], - [ - 536870912, 268435456, 939524096, 201326592, 167772160, 989855744, 360710144, 398458880, 56623104, 376438784, 355991552, 1000603648, 378667008, 495910912, 259883008, 856113152, 830627840, 700723200, 1046624256, 855002112, 746528256, 981921536, 340254848, 497512512, 932337888, 185433136, 20489768, 765715436, 529571542, 1057926943 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 369098752, 922746880, 394264576, 406847488, 929038336, 26214400, 746061824, 850132992, 909508608, 961085440, 1046511616, 353845248, 297738240, 9408512, 910505984, 744621056, 403746304, 1060893952, 72160896, 417509696, 903125216, 354407600, 943470136, 466100524, 614932614, 682856701 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 167772160, 889192448, 1065353216, 985661440, 106954752, 258998272, 930611200, 452722688, 289275904, 920322048, 7110656, 838189056, 339697664, 828280832, 783206400, 26510336, 609200640, 211854592, 823241344, 738960704, 461711904, 885155248, 761547272, 871888228, 222167798, 752529807 - ], - [ - 536870912, 268435456, 939524096, 469762048, 167772160, 855638016, 796917760, 725614592, 262144000, 1007681536, 547880960, 308019200, 575012864, 992280576, 483688448, 306888704, 418062336, 578654208, 219256832, 136977408, 949990912, 597767936, 504467072, 934050624, 735871072, 805748784, 671424712, 604278972, 369301654, 956685409 - ], - [ - 536870912, 268435456, 134217728, 738197504, 973078528, 754974720, 830472192, 46137344, 765460480, 590348288, 58195968, 751042560, 245497856, 565248000, 188579840, 623067136, 511156224, 522137600, 684840960, 178844672, 1038927360, 344841984, 85819520, 366166080, 858759200, 321597616, 53205224, 187561140, 657147590, 489398027 - ], - [ - 536870912, 268435456, 671088640, 201326592, 301989888, 889192448, 243269632, 750780416, 165675008, 948961280, 816316416, 29097984, 911605760, 877592576, 329809920, 876462080, 454549504, 652865536, 312379392, 740803584, 368320000, 905932544, 678729344, 79407936, 14026784, 1015678064, 72089320, 732602340, 272375538, 85159719 - ], - [ - 536870912, 805306368, 939524096, 603979776, 1040187392, 587202560, 662700032, 390070272, 39845888, 80740352, 15204352, 1002700800, 514195456, 871825408, 1063026688, 91996160, 911106048, 607252480, 67069952, 260574208, 865450496, 848186624, 118653056, 977846464, 909435104, 50147472, 286099704, 508705932, 590131870, 828617053 - ], - [ - 536870912, 268435456, 939524096, 872415232, 234881024, 922746880, 461373440, 1027604480, 702545920, 70254592, 592969728, 354680832, 965869568, 437190656, 545947648, 357548032, 745529344, 1073541120, 619833344, 486120448, 561075712, 784012032, 655843456, 432812096, 447514848, 324971728, 1025859128, 898990044, 537878254, 428769205 - ], - [ - 536870912, 268435456, 939524096, 335544320, 301989888, 855638016, 595591168, 171966464, 1054867456, 87031808, 430440448, 564396032, 693239808, 1046413312, 992903168, 727990272, 108224512, 466219008, 190154752, 626654208, 883537408, 656575744, 429252736, 242856000, 993847520, 811273296, 640204360, 98841036, 447985166, 770280809 - ], - [ - 536870912, 805306368, 134217728, 469762048, 234881024, 822083584, 562036736, 566231040, 534773760, 254803968, 996671488, 316932096, 280363008, 598278144, 814186496, 810008576, 908533760, 215461888, 979236864, 411687936, 601347584, 316429568, 214900864, 267628736, 1024194592, 672193648, 641226296, 25138628, 199098374, 21823559 - ], - [ - 536870912, 805306368, 402653184, 201326592, 570425344, 16777216, 763363328, 88080384, 1021313024, 449839104, 745013248, 1029963776, 227934208, 160104448, 104169472, 112869376, 151986176, 1022767104, 639232000, 247020544, 755575296, 183518464, 152641664, 4010176, 80504928, 517176368, 711854728, 174224644, 253151286, 38735061 - ], - [ - 536870912, 805306368, 671088640, 201326592, 503316480, 385875968, 713031680, 440401920, 2097152, 737148928, 16252928, 157024256, 409600000, 804716544, 586842112, 677068800, 703242240, 20148224, 798914560, 688741376, 413438464, 145888512, 358363776, 510289344, 485673504, 444299760, 991852632, 340614316, 436507250, 889328901 - ], - [ - 536870912, 805306368, 402653184, 603979776, 369098752, 822083584, 864026624, 406847488, 618659840, 644874240, 81264640, 818675712, 128057344, 34930688, 913276928, 775045120, 138076160, 717180928, 830208000, 366760960, 860615168, 132474112, 49343104, 102719936, 468541664, 191959120, 895162424, 394921044, 96832150, 430076325 - ], - [ - 536870912, 268435456, 671088640, 335544320, 100663296, 822083584, 125829120, 742391808, 874512384, 760217600, 112721920, 218890240, 1023803392, 763822080, 658997248, 279068672, 831971328, 677302272, 1069119488, 244124672, 1061170688, 1017183488, 194393728, 190472512, 255328288, 340525072, 547750072, 160891028, 341803014, 767443061 - ], - [ - 536870912, 805306368, 402653184, 738197504, 570425344, 553648128, 578813952, 952107008, 794820608, 927989760, 1027080192, 852754432, 545128448, 821493760, 218857472, 213598208, 563322880, 559747072, 503429120, 721845248, 931303936, 340245248, 346536064, 464878784, 271520352, 407894960, 177838088, 450899012, 839944938, 320657235 - ], - [ - 536870912, 268435456, 939524096, 872415232, 838860800, 721420288, 612368384, 624951296, 782237696, 831520768, 491257856, 287047680, 699793408, 849149952, 1047887872, 410697728, 448798720, 124088320, 913405952, 75144192, 616904192, 711348992, 200789632, 784011072, 195516512, 269675664, 160026152, 326766460, 776263898, 438643833 - ], - [ - 536870912, 805306368, 134217728, 738197504, 167772160, 922746880, 813694976, 994050048, 90177536, 13631488, 554172416, 29097984, 870449152, 915865600, 736919552, 648593408, 651010048, 94105600, 156760064, 197919744, 975148544, 647105280, 334352000, 44695488, 13607072, 949809264, 248739848, 574572, 70792938, 589495089 - ], - [ - 536870912, 268435456, 939524096, 335544320, 167772160, 754974720, 41943040, 29360128, 463470592, 938475520, 462946304, 775159808, 70909952, 734199808, 648052736, 225853440, 241115136, 1066733568, 516921344, 853025792, 156386816, 317474560, 309270656, 44983360, 1032677088, 951670608, 486572200, 713441524, 768024810, 94441559 - ], - [ - 536870912, 805306368, 671088640, 469762048, 570425344, 754974720, 696254464, 583008256, 371195904, 581959680, 108527616, 146014208, 125698048, 724631552, 347963392, 915750912, 969416704, 256405504, 822638592, 409777152, 809053696, 232258304, 623409280, 668775616, 935407264, 1000602480, 376862728, 56472692, 210021894, 658684923 - ], - [ - 536870912, 268435456, 671088640, 201326592, 33554432, 587202560, 864026624, 339738624, 308281344, 1028653056, 968359936, 149159936, 630325248, 639434752, 479559680, 43663360, 492134400, 700313600, 551798784, 697674752, 605854208, 1066688256, 824139904, 152367168, 1004292256, 498527280, 271481352, 754904972, 436488270, 386067473 - ], - [ - 536870912, 805306368, 671088640, 872415232, 637534208, 352321536, 1065353216, 163577856, 954204160, 699400192, 821559296, 519307264, 677249024, 996212736, 40927232, 320454656, 700456960, 149237760, 28743680, 83782656, 955567616, 1029546752, 81795200, 196259008, 737832608, 7361488, 941498392, 524562580, 749082718, 60271863 - ], - [ - 536870912, 268435456, 402653184, 335544320, 905969664, 218103808, 25165824, 524288000, 853540864, 1064304640, 992477184, 336330752, 241041408, 136642560, 752058368, 935280640, 869392384, 87904256, 739604480, 186450944, 96705024, 824702720, 190315136, 1039984448, 347529952, 319484688, 685531192, 568791076, 804722878, 535761945 - ], - [ - 536870912, 805306368, 134217728, 201326592, 33554432, 419430400, 964689920, 163577856, 576716800, 131072000, 214433792, 815005696, 1039007744, 946143232, 718766080, 860438528, 777428992, 1024028672, 385292288, 876411904, 799834624, 986019072, 1055299712, 1033157824, 845914656, 782517552, 641114248, 534343844, 700389574, 409533463 - ], - [ - 536870912, 805306368, 402653184, 738197504, 301989888, 117440512, 830472192, 281018368, 568328192, 63963136, 936902656, 577503232, 262275072, 125108224, 590249984, 243515392, 1027907584, 992333824, 154249216, 395076608, 40936960, 1034858752, 466071168, 845284800, 202383584, 197070960, 595167272, 513766572, 390803086, 194299231 - ], - [ - 536870912, 805306368, 134217728, 67108864, 234881024, 150994944, 729808896, 1010827264, 52428800, 227540992, 109576192, 670302208, 297664512, 464322560, 459440128, 817283072, 169385984, 251146240, 67987456, 3617792, 652003840, 287014144, 511658112, 416138432, 399966752, 950630672, 132410040, 645090788, 452599822, 839839777 - ], - [ - 536870912, 268435456, 939524096, 335544320, 100663296, 318767104, 1031798784, 272629760, 815792128, 806354944, 434634752, 400818176, 322043904, 113180672, 288260096, 830914560, 306667520, 497168384, 177227776, 841790464, 604492288, 772048128, 1057087616, 796979264, 88418528, 505513040, 500242968, 957018444, 391336566, 986268929 - ], - [ - 536870912, 268435456, 671088640, 738197504, 1040187392, 620756992, 427819008, 163577856, 115343360, 674234368, 438829056, 927727616, 498991104, 368246784, 919240704, 8077312, 688971776, 704598016, 416425984, 723162112, 585531904, 708218624, 690512512, 667606848, 871942688, 1071057904, 26781912, 1000461412, 43409982, 725212931 - ], - [ - 536870912, 268435456, 939524096, 469762048, 503316480, 721420288, 545259520, 499122176, 975175680, 1003487232, 264765440, 1039400960, 974782464, 557514752, 997031936, 417513472, 192143360, 953896960, 26908672, 880538624, 948744704, 454268160, 174684288, 23110720, 993405664, 146301296, 590203640, 210186732, 734352098, 891536711 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 503316480, 385875968, 142606336, 826277888, 425721856, 363855872, 756547584, 761528320, 665976832, 203227136, 249790464, 7454720, 859824128, 179474432, 161474560, 706792448, 366355968, 254626560, 96460928, 1022529600, 813688992, 852544752, 1068377720, 553208668, 127262882, 751538309 - ], - [ - 536870912, 268435456, 402653184, 67108864, 570425344, 989855744, 243269632, 759169024, 782237696, 661651456, 80216064, 72613888, 343539712, 964624384, 654213120, 574177280, 156950528, 885526528, 206768128, 142517248, 528233984, 1073517824, 398190720, 714978368, 925613664, 92565776, 734248456, 534802860, 802275034, 985362917 - ], - [ - 536870912, 805306368, 939524096, 603979776, 503316480, 352321536, 947912704, 46137344, 983564288, 550502400, 292028416, 827588608, 556662784, 976420864, 853180416, 801685504, 1065623552, 491114496, 400652288, 255263744, 979182080, 353159424, 556234880, 596640960, 327787232, 115804560, 431085816, 362353812, 858454530, 489872795 - ], - [ - 536870912, 805306368, 939524096, 603979776, 1040187392, 587202560, 276824064, 1010827264, 106954752, 328204288, 307757056, 304873472, 136445952, 619773952, 273383424, 364331008, 766353408, 921006080, 534190080, 742360064, 633232896, 612362496, 366929536, 149429696, 218505312, 998387792, 818067480, 539423772, 150161082, 843935101 - ], - [ - 536870912, 268435456, 939524096, 67108864, 503316480, 956301312, 880803840, 843055104, 824180736, 326107136, 728236032, 548667392, 780795904, 732102656, 808615936, 315408384, 461611008, 331829248, 367421440, 856699904, 448783872, 661154048, 313976960, 898364480, 1009043168, 301005072, 472490232, 1058295972, 683468850, 1013511385 - ], - [ - 536870912, 268435456, 939524096, 201326592, 838860800, 721420288, 796917760, 901775360, 652214272, 17825792, 396886016, 97255424, 916324352, 101777408, 439123968, 588038144, 872194048, 13094912, 6465536, 139940864, 654894592, 637328128, 767706752, 988154688, 185757280, 816619376, 407546024, 677074140, 259450518, 788388683 - ], - [ - 536870912, 805306368, 402653184, 201326592, 973078528, 50331648, 343932928, 423624704, 509607936, 164626432, 553123840, 729546752, 884604928, 614006784, 296255488, 415744000, 446930944, 24588288, 915347456, 1064391680, 730672640, 116412672, 323956352, 743788992, 171814624, 383488496, 256806408, 1045914108, 490223194, 878183833 - ], - [ - 536870912, 268435456, 402653184, 738197504, 167772160, 889192448, 209715200, 62914560, 618659840, 313524224, 491257856, 697565184, 689569792, 661585920, 927170560, 455098368, 609230848, 385699840, 844863488, 911059968, 639024640, 22793472, 365443200, 72399936, 117245536, 710619568, 441261736, 739433876, 878280914, 424624383 - ], - [ - 536870912, 805306368, 939524096, 469762048, 704643072, 318767104, 1031798784, 683671552, 572522496, 519045120, 861405184, 1065091072, 881459200, 995426304, 510296064, 931512320, 197304320, 665292800, 708003840, 997960704, 848093696, 978600192, 753812096, 147050944, 304417376, 653557168, 794552520, 360267004, 663562942, 114699679 - ], - [ - 536870912, 268435456, 134217728, 335544320, 704643072, 419430400, 1065353216, 708837376, 996147200, 386924544, 271056896, 875298816, 103677952, 53411840, 44924928, 468238336, 101441536, 81530880, 97605632, 495596544, 480171520, 1001902848, 186570368, 368563008, 310302368, 266851088, 399955464, 143381364, 353949430, 922014685 - ], - [ - 536870912, 805306368, 939524096, 469762048, 33554432, 822083584, 209715200, 138412032, 119537664, 1045430272, 45613056, 362545152, 600440832, 91553792, 250249216, 505462784, 651419648, 754511872, 1035548672, 572144640, 839714304, 412117248, 215934592, 409508288, 191356512, 393389488, 938137704, 916638836, 815021786, 416961941 - ], - [ - 536870912, 268435456, 671088640, 469762048, 369098752, 889192448, 192937984, 239075328, 421527552, 529530880, 1042808832, 467402752, 214302720, 451346432, 368476160, 790183936, 572547072, 85315584, 435009536, 868051968, 586421760, 194877184, 753356416, 821062464, 211320864, 811745328, 170975480, 863735972, 101931126, 929955053 - ], - [ - 536870912, 268435456, 671088640, 67108864, 838860800, 855638016, 595591168, 876609536, 1050673152, 521142272, 631767040, 926679040, 467009536, 483328000, 180977664, 466141184, 592125952, 814321664, 141506560, 450558976, 65267200, 624037632, 930799232, 796390208, 483964960, 987839568, 431441512, 381444060, 613893830, 770465629 - ], - [ - 536870912, 268435456, 671088640, 201326592, 637534208, 419430400, 897581056, 641728512, 2097152, 829423616, 211288064, 557580288, 34471936, 213057536, 805208064, 736903168, 211836928, 850808832, 50190336, 476789760, 434307584, 940910848, 961372800, 51411264, 802044448, 131532144, 690837688, 54819860, 732291822, 708000205 - ], - [ - 536870912, 268435456, 671088640, 469762048, 838860800, 117440512, 343932928, 926941184, 1050673152, 768606208, 697827328, 793509888, 408289280, 861863936, 791314432, 870563840, 410099712, 181202944, 714455040, 792566784, 916004352, 533295360, 689219200, 620293440, 595310624, 1052679216, 710778472, 917090668, 589399578, 722787713 - ], - [ - 536870912, 805306368, 134217728, 603979776, 570425344, 788529152, 125829120, 826277888, 295698432, 976224256, 988282880, 619446272, 904527872, 325779456, 212828160, 650887168, 345907200, 858181632, 938801152, 931712000, 893028864, 18306816, 689605248, 828856256, 802327200, 368793424, 351308328, 101472236, 24971830, 472946473 - ], - [ - 536870912, 805306368, 671088640, 872415232, 436207616, 822083584, 998244352, 432013312, 111149056, 93323264, 1055391744, 874250240, 297926656, 44236800, 932413440, 1005436928, 362373120, 956518400, 1065830400, 734030848, 61187584, 605163264, 371723904, 154989504, 227770400, 988659728, 102326472, 348344340, 589777030, 525364387 - ], - [ - 536870912, 805306368, 671088640, 67108864, 838860800, 520093696, 847249408, 767557632, 882900992, 791674880, 410517504, 353107968, 563216384, 474677248, 636583936, 39370752, 167550976, 609169408, 972204032, 475745280, 553312768, 1003254016, 968084096, 934870464, 380504096, 941915344, 468732520, 458964332, 1048258690, 537889803 - ], - [ - 536870912, 805306368, 939524096, 469762048, 301989888, 218103808, 528482304, 549453824, 752877568, 691011584, 148373504, 10223616, 171573248, 112001024, 677806080, 628146176, 1014980608, 722440192, 712378368, 653972480, 810537472, 676755712, 1009472128, 52935104, 525382240, 984213936, 174414376, 275869060, 1073569878, 432967687 - ], - [ - 536870912, 268435456, 134217728, 469762048, 503316480, 318767104, 528482304, 926941184, 828375040, 630194176, 78118912, 914096128, 330694656, 140181504, 54951936, 593641472, 546349056, 338300928, 12244992, 110404608, 53112320, 356273920, 550909568, 550153024, 191690912, 1037890608, 889198168, 142801724, 583434374, 388120785 - ], - [ - 536870912, 805306368, 939524096, 201326592, 838860800, 721420288, 1065353216, 364904448, 908066816, 907018240, 445120512, 436469760, 788922368, 965148672, 12681216, 279330816, 928342016, 116387840, 267827200, 901301248, 253608448, 793301248, 471859328, 554696896, 789053664, 683933744, 346423496, 827785388, 334070014, 695353431 - ], - [ - 536870912, 268435456, 134217728, 872415232, 838860800, 50331648, 1048576000, 373293056, 681574400, 986710016, 144179200, 285999104, 649461760, 447414272, 853770240, 208846848, 1062150144, 571813888, 779704320, 1065008128, 318578176, 842907904, 954189440, 413777216, 702806176, 251022480, 789112552, 1001426396, 690790578, 522711061 - ], - [ - 536870912, 268435456, 671088640, 469762048, 771751936, 520093696, 41943040, 20971520, 551550976, 516947968, 586678272, 937164800, 867041280, 937623552, 273973248, 633028608, 339320832, 33058816, 190355456, 99410944, 159559168, 566311168, 950111872, 1068566848, 300693024, 729996592, 952213656, 958689356, 309762066, 793764873 - ], - [ - 536870912, 268435456, 402653184, 67108864, 301989888, 251658240, 1031798784, 381681664, 715128832, 466616320, 845676544, 173801472, 411435008, 809566208, 199458816, 749912064, 748396544, 975327232, 932669440, 797740032, 1005235712, 110720768, 556000896, 1338176, 843972832, 1053622352, 76382248, 74432556, 123609278, 838963303 - ], - [ - 536870912, 805306368, 671088640, 335544320, 369098752, 385875968, 360710144, 289406976, 23068672, 588251136, 43515904, 1054605312, 658112512, 1039073280, 802521088, 918241280, 581672960, 95555584, 36419584, 812766208, 948606464, 46601472, 522655360, 200299968, 852407840, 1008813456, 947031672, 478728652, 1019492398, 472224905 - ], - [ - 536870912, 268435456, 134217728, 738197504, 838860800, 687865856, 847249408, 826277888, 425721856, 825229312, 798490624, 154402816, 463077376, 523567104, 748650496, 917716992, 106602496, 739577856, 525109248, 735984640, 148286976, 384683776, 88901760, 1054751808, 5680672, 581816240, 481069128, 397294820, 70168298, 736743285 - ], - [ - 536870912, 268435456, 671088640, 335544320, 1040187392, 251658240, 964689920, 859832320, 631242752, 30408704, 631767040, 746323968, 232128512, 934215680, 561741824, 290668544, 208216064, 18698240, 1071781888, 1056177152, 750640640, 976525056, 224380544, 466053952, 811735072, 112458768, 647880280, 329553772, 181913246, 170617777 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 637534208, 150994944, 461373440, 792723456, 710934528, 881852416, 153616384, 22806528, 36044800, 946929664, 192708608, 509034496, 688906240, 976048128, 635377664, 669082624, 450133504, 483165952, 9078400, 242070336, 523985120, 884347056, 576649464, 1050752212, 565307126, 266052505 - ], - [ - 536870912, 268435456, 134217728, 603979776, 100663296, 654311424, 796917760, 289406976, 484442112, 279969792, 765984768, 416546816, 970588160, 903675904, 131760128, 786415616, 39804928, 983478272, 272467968, 870960128, 531787264, 908742912, 126937216, 641629248, 217015840, 472997264, 91186840, 980508124, 1041196574, 528571797 - ], - [ - 536870912, 805306368, 939524096, 201326592, 33554432, 989855744, 394264576, 440401920, 195035136, 328204288, 538443776, 54788096, 388366336, 643235840, 1039761408, 427048960, 531193856, 311029760, 869844992, 597963776, 395678208, 370684672, 910262400, 966803648, 278356192, 1000009776, 453462024, 663188716, 574976606, 128287593 - ], - [ - 536870912, 805306368, 939524096, 469762048, 234881024, 620756992, 713031680, 633339904, 115343360, 61865984, 698875904, 558104576, 908460032, 399966208, 333152256, 901120, 836149248, 584863744, 9189376, 588291072, 633083392, 696009984, 52265088, 610975936, 866459872, 529895536, 159160376, 857459860, 476819114, 799086999 - ], - [ - 536870912, 805306368, 939524096, 738197504, 771751936, 452984832, 159383552, 415236096, 488636416, 422576128, 426246144, 927727616, 66715648, 945094656, 188514304, 762527744, 101523456, 907841536, 71747584, 660950016, 760379904, 700112640, 70736512, 803884992, 470520416, 521798512, 12937432, 19110940, 255267454, 778650559 - ], - [ - 536870912, 268435456, 939524096, 67108864, 973078528, 855638016, 58720256, 4194304, 195035136, 175112192, 120061952, 987496448, 800456704, 298647552, 160137216, 371834880, 509091840, 779587584, 757774336, 836492288, 674753024, 730723072, 824922752, 534458176, 423049312, 521083984, 149703176, 658482140, 459786854, 303457165 - ], - [ - 536870912, 268435456, 134217728, 335544320, 905969664, 553648128, 645922816, 675282944, 807403520, 785383424, 242745344, 156499968, 280625152, 422903808, 440958976, 261865472, 1012965376, 821104640, 497723392, 61510656, 648819200, 1042823936, 594061440, 63673408, 610185760, 1015479120, 859867224, 497108164, 588561082, 664633329 - ], - [ - 536870912, 805306368, 939524096, 872415232, 704643072, 587202560, 914358272, 29360128, 836763648, 353370112, 329777152, 226754560, 860225536, 572981248, 871792640, 440221696, 1021861888, 967102464, 95500288, 866106368, 828203520, 104420608, 720240768, 1017315520, 238059744, 232407248, 352247976, 361336972, 477190362, 109014023 - ], - [ - 536870912, 805306368, 939524096, 67108864, 234881024, 16777216, 41943040, 297795584, 639631360, 495976448, 580386816, 908853248, 983695360, 89194496, 977240064, 813514752, 823910400, 762146816, 826796032, 887536640, 170989056, 659476736, 785718912, 628694464, 899276896, 28078288, 534800600, 934804500, 218691122, 531800387 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 704643072, 83886080, 864026624, 1019215872, 199229440, 36700160, 446169088, 189005824, 958529536, 315686912, 942637056, 832126976, 868655104, 761622528, 91297792, 297516032, 680633856, 613384960, 814579840, 914899008, 294199328, 453783792, 1045412008, 208325652, 909819598, 307314675 - ], - [ - 536870912, 805306368, 939524096, 469762048, 503316480, 855638016, 125829120, 1027604480, 1038090240, 858783744, 484966400, 829685760, 814612480, 671285248, 335904768, 973389824, 822468608, 713240576, 163694592, 120015872, 865193472, 305930496, 514607232, 488082624, 704261856, 210506096, 100663544, 520093708, 562036990, 306184325 - ], - [ - 536870912, 805306368, 939524096, 738197504, 100663296, 419430400, 260046848, 1052770304, 165675008, 705691648, 212336640, 348913664, 85590016, 836042752, 80510976, 220086272, 634675200, 785059840, 303794176, 860902400, 529090048, 624540416, 279389824, 959949760, 1029189216, 24493936, 234817656, 138548244, 145172166, 624405295 - ], - [ - 536870912, 805306368, 134217728, 738197504, 637534208, 520093696, 1015021568, 1027604480, 257949696, 258998272, 268959744, 819200000, 176291840, 440598528, 400588800, 942850048, 644505600, 472248320, 457820160, 414503936, 494040576, 1024014080, 290971776, 507657536, 769785888, 154337328, 703102984, 1004978220, 912810022, 606531615 - ], - [ - 536870912, 805306368, 939524096, 603979776, 369098752, 486539264, 729808896, 641728512, 983564288, 460324864, 102236160, 596377600, 313393152, 530382848, 455507968, 131645440, 91201536, 612331520, 108349440, 947055616, 479749632, 609116416, 558688384, 516901952, 378357920, 355286128, 870219928, 243732564, 1009337998, 330694985 - ], - [ - 536870912, 268435456, 939524096, 469762048, 704643072, 754974720, 142606336, 96468992, 924844032, 179306496, 663224320, 914096128, 724434944, 230096896, 489717760, 197869568, 505208832, 578793472, 892336128, 783713280, 246605312, 25847040, 159355264, 313429056, 720636320, 47249488, 1054603160, 920955212, 78247986, 583894049 - ], - [ - 536870912, 805306368, 671088640, 335544320, 905969664, 419430400, 1065353216, 994050048, 845152256, 877658112, 527958016, 659816448, 678297600, 903413760, 136675328, 908443648, 187113472, 715485184, 484747264, 654699520, 823435776, 596617984, 197840512, 247388352, 677637280, 391164912, 871891464, 412490532, 835503774, 774603981 - ], - [ - 536870912, 268435456, 671088640, 67108864, 33554432, 452984832, 411041792, 725614592, 455081984, 890241024, 138936320, 915668992, 192806912, 45809664, 892305408, 30457856, 514416640, 115806208, 679901184, 599006208, 862926336, 594717440, 796557696, 541921216, 40032160, 221492432, 165260808, 329148180, 1070280618, 1062693087 - ], - [ - 536870912, 268435456, 134217728, 201326592, 369098752, 352321536, 260046848, 205520896, 597688320, 862978048, 992477184, 823918592, 5111808, 89587712, 826507264, 807485440, 556867584, 25751552, 468502528, 573008896, 409536000, 238831872, 771555200, 303903808, 181344160, 244688976, 312564136, 921947484, 1013678142, 71122953 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 704643072, 150994944, 92274688, 968884224, 656408576, 124780544, 395837440, 175374336, 485359616, 119078912, 741769216, 319569920, 516448256, 790409216, 549488640, 178365440, 447897088, 649661696, 772041344, 133603520, 825111712, 775663088, 876895800, 571739404, 570223282, 680780021 - ], - [ - 536870912, 805306368, 134217728, 67108864, 100663296, 620756992, 109051904, 448790528, 530579456, 781189120, 603455488, 967049216, 413007872, 43581440, 1050116096, 955695104, 440737792, 57651200, 408156160, 240804864, 1010214400, 484903680, 561914496, 107629504, 232719520, 863731952, 1046742568, 230587188, 885586574, 567255009 - ], - [ - 536870912, 805306368, 671088640, 872415232, 771751936, 50331648, 260046848, 331350016, 10485760, 552599552, 892862464, 446431232, 485621760, 523960320, 530481152, 611401728, 762961920, 268349440, 195147776, 728816640, 553302528, 759019264, 495095680, 985830336, 169981984, 196140080, 131775016, 705541940, 102404014, 61772739 - ], - [ - 536870912, 268435456, 402653184, 335544320, 1040187392, 1023410176, 880803840, 314572800, 341835776, 380633088, 642252800, 3932160, 83492864, 141885440, 566722560, 739131392, 91316224, 615124992, 189556736, 357719040, 1002126848, 206921472, 14026368, 370533056, 611800608, 466027280, 923613336, 418430420, 1021923486, 820961773 - ], - [ - 536870912, 805306368, 134217728, 201326592, 436207616, 218103808, 897581056, 272629760, 559939584, 948961280, 653787136, 221511680, 985006080, 334823424, 420839424, 717570048, 266133504, 314060800, 173369344, 488991744, 26016256, 736310016, 743586944, 811114432, 92552352, 708681712, 501857448, 478994428, 644046002, 940699633 - ], - [ - 536870912, 805306368, 134217728, 872415232, 637534208, 989855744, 595591168, 121634816, 1025507328, 233832448, 9961472, 797704192, 565575680, 1015611392, 478642176, 275890176, 819601408, 724389888, 33867776, 1068575744, 557553152, 683603200, 340755072, 643167040, 202912928, 491738736, 685047336, 467290372, 816676014, 960936527 - ], - [ - 536870912, 268435456, 939524096, 335544320, 234881024, 184549376, 41943040, 188743680, 912261120, 516947968, 181927936, 117702656, 254672896, 96665600, 925007872, 364036096, 160014336, 169627648, 1040881664, 551394304, 766136832, 422497024, 180363392, 60829120, 32754336, 862579408, 344752152, 3260420, 843784246, 507416607 - ], - [ - 536870912, 268435456, 402653184, 469762048, 369098752, 16777216, 461373440, 415236096, 333447168, 101711872, 563609600, 529793024, 832962560, 491716608, 890404864, 555302912, 332734464, 1007071232, 503302144, 414884864, 291785216, 45085440, 1023473280, 495176128, 29400736, 342007248, 147864760, 863664844, 34064430, 150905869 - ], - [ - 536870912, 805306368, 671088640, 872415232, 167772160, 83886080, 1048576000, 641728512, 694157312, 896532480, 8912896, 255590400, 622460928, 587661312, 957120512, 41041920, 386473984, 33394688, 289015808, 244683776, 288730624, 1013226240, 125819520, 460956352, 838108704, 524787504, 225377448, 360836596, 264327850, 681735925 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 838860800, 855638016, 92274688, 113246208, 710934528, 9437184, 591921152, 205783040, 1013579776, 762773504, 693338112, 245940224, 555130880, 214102016, 358643712, 789765120, 713637376, 296174848, 154772096, 568300864, 591797792, 1005221168, 11860632, 984840572, 989591570, 457055235 - ], - [ - 536870912, 268435456, 134217728, 603979776, 33554432, 419430400, 545259520, 759169024, 551550976, 378535936, 16252928, 165937152, 733347840, 376373248, 213614592, 898088960, 1046798336, 158658560, 676083712, 168332288, 214774272, 893960960, 1026527360, 660214976, 311830688, 392059088, 254966440, 747285492, 713994794, 606798637 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 503316480, 1023410176, 494927872, 222298112, 748683264, 846200832, 543686656, 293339136, 566362112, 711000064, 177307648, 20692992, 757456896, 485871616, 946788352, 12211200, 778406400, 357992192, 731707008, 865107904, 784039968, 459718672, 752246808, 81727548, 1009956894, 1011369021 - ], - [ - 536870912, 805306368, 134217728, 201326592, 33554432, 721420288, 243269632, 88080384, 668991488, 1045430272, 277348352, 752091136, 629538816, 26017792, 119111680, 100614144, 375545856, 59854848, 522909696, 518441984, 698147328, 988970752, 473693056, 764163264, 890831776, 654244080, 350478760, 80840700, 331979306, 775353111 - ], - [ - 536870912, 805306368, 939524096, 603979776, 301989888, 520093696, 830472192, 666894336, 702545920, 567279616, 429391872, 504102912, 740163584, 107282432, 985300992, 146718720, 974577664, 735285248, 312166400, 93148160, 819894784, 201797376, 598307456, 155566144, 570997408, 934696048, 723566744, 179497812, 537590282, 548830987 - ], - [ - 536870912, 805306368, 402653184, 201326592, 301989888, 184549376, 427819008, 465567744, 455081984, 344981504, 592969728, 79429632, 583925760, 891617280, 131104768, 356139008, 256663552, 15159296, 502335488, 522851328, 1012192768, 263890688, 688676480, 101031744, 121747104, 677550960, 317720760, 816412796, 714573866, 404313143 - ], - [ - 536870912, 805306368, 939524096, 872415232, 704643072, 587202560, 981467136, 1052770304, 392167424, 78643200, 1057488896, 823394304, 979501056, 1060306944, 340492288, 1010253824, 510697472, 174665728, 446965760, 569027584, 971298304, 550238976, 66328704, 479452480, 345546784, 84750384, 447621176, 1014869044, 944068138, 253475619 - ], - [ - 536870912, 268435456, 939524096, 335544320, 637534208, 251658240, 947912704, 843055104, 106954752, 154140672, 837287936, 902037504, 808845312, 721354752, 283672576, 1044889600, 821469184, 601673728, 238655488, 56597504, 947546624, 456982784, 709587840, 877972928, 583822240, 981701072, 859840920, 501317828, 837970494, 751370507 - ], - [ - 536870912, 805306368, 939524096, 67108864, 973078528, 855638016, 494927872, 675282944, 1033895936, 972029952, 873988096, 803995648, 119668736, 1043529728, 788234240, 138166272, 730439680, 920924160, 168056832, 282575872, 285145600, 451571456, 209058176, 193800896, 489922592, 997929008, 478009400, 673743876, 102029882, 278798131 - ], - [ - 536870912, 805306368, 134217728, 872415232, 1040187392, 285212672, 276824064, 591396864, 677380096, 315621376, 490209280, 1039400960, 380764160, 1038811136, 869040128, 549797888, 932896768, 75927552, 444123136, 328569856, 694351360, 978416896, 41521024, 529874240, 727853088, 559088688, 1039810056, 1028972852, 818117054, 950028369 - ], - [ - 536870912, 268435456, 671088640, 67108864, 838860800, 352321536, 595591168, 541065216, 601882624, 30408704, 634912768, 600571904, 298188800, 550699008, 207323136, 982433792, 665149440, 641822720, 1021372416, 458423296, 270227968, 124539648, 91695232, 119233856, 166501024, 716567120, 850978824, 215940116, 943544858, 930042641 - ], - [ - 536870912, 805306368, 671088640, 738197504, 1040187392, 654311424, 998244352, 1027604480, 253755392, 1028653056, 1050148864, 885260288, 1063911424, 374276096, 739540992, 733200384, 1042964480, 1064185856, 843356160, 1017857024, 783071744, 329644288, 530116480, 474250048, 61358624, 288329008, 1021595048, 163120748, 1033271198, 1005600599 - ], - [ - 536870912, 805306368, 939524096, 469762048, 1040187392, 16777216, 494927872, 650117120, 673185792, 1062207488, 285736960, 878444544, 915013632, 27197440, 69828608, 412008448, 943874048, 476237824, 355579904, 557562880, 719632896, 95389952, 814959232, 816471232, 936294944, 748718384, 672320184, 434674908, 1043257886, 995186993 - ], - [ - 536870912, 268435456, 402653184, 201326592, 301989888, 855638016, 914358272, 801112064, 60817408, 1039138816, 310902784, 939261952, 364511232, 760545280, 1073184768, 260554752, 273653760, 366047232, 523896832, 412462080, 458719744, 452418304, 201668224, 604982976, 775031328, 187250448, 755963032, 800089548, 342406322, 745346531 - ], - [ - 536870912, 805306368, 134217728, 67108864, 570425344, 520093696, 914358272, 339738624, 467664896, 550502400, 284688384, 323747840, 210370560, 403111936, 246317056, 559497216, 696098816, 992161792, 7473152, 357176320, 858220032, 920387840, 940639616, 1012559808, 821972512, 299918640, 198429576, 209210052, 470590850, 65626095 - ], - [ - 536870912, 805306368, 939524096, 872415232, 570425344, 352321536, 713031680, 641728512, 65011712, 462422016, 366477312, 975962112, 997326848, 600506368, 238518272, 981286912, 76226560, 894816256, 715941888, 204604416, 279694848, 317096192, 617017728, 376932544, 849299488, 245093424, 793617976, 681805108, 921747362, 839600597 - ], - [ - 536870912, 268435456, 671088640, 738197504, 905969664, 1056964608, 864026624, 188743680, 10485760, 217055232, 167247872, 744751104, 1024589824, 480837632, 233734144, 206356480, 809263104, 520515584, 729839616, 524456960, 849402368, 703702784, 863732608, 732344384, 91396128, 465052688, 138723880, 622936876, 682697142, 316179327 - ], - [ - 536870912, 805306368, 671088640, 469762048, 637534208, 654311424, 159383552, 230686720, 748683264, 512753664, 956825600, 120324096, 837156864, 526974976, 211648512, 868040704, 300851200, 46632960, 54044672, 213279744, 29574656, 312568576, 227585408, 176872512, 200174496, 868677488, 95970824, 351779628, 111191438, 127019131 - ], - [ - 536870912, 268435456, 671088640, 335544320, 1040187392, 486539264, 696254464, 1002438656, 98566144, 193986560, 829947904, 431226880, 599654400, 90374144, 936607744, 979091456, 709271552, 479473664, 894191616, 801678336, 373105152, 77776640, 959569536, 289973440, 931009696, 637728720, 822124552, 730017796, 214026262, 257975305 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 570425344, 150994944, 813694976, 985661440, 123731968, 87031808, 382205952, 516161536, 891944960, 255262720, 125992960, 289456128, 203595776, 873680896, 207169536, 56572928, 144014848, 148045568, 607820416, 703528768, 52289056, 808890160, 268513928, 939590524, 872546306, 503513145 - ], - [ - 536870912, 268435456, 134217728, 201326592, 33554432, 385875968, 243269632, 490733568, 488636416, 927989760, 849870848, 1025245184, 561643520, 435486720, 96894976, 161464320, 1060872192, 206843904, 920029184, 1033323520, 834136576, 291797248, 621585536, 32682688, 423322144, 89537808, 626380424, 894766028, 1029072546, 827703239 - ], - [ - 536870912, 805306368, 671088640, 872415232, 1040187392, 654311424, 494927872, 373293056, 983564288, 208666624, 361234432, 443809792, 415891456, 123142144, 871923712, 654065664, 272588800, 542912512, 642627584, 81253376, 851005952, 702477056, 1041070720, 829819968, 390713888, 337031984, 970463912, 944585844, 332720670, 121186071 - ], - [ - 536870912, 805306368, 402653184, 67108864, 637534208, 150994944, 998244352, 641728512, 824180736, 242221056, 894959616, 898891776, 745144320, 1047461888, 265256960, 461193216, 398909440, 583028736, 232986624, 1049711616, 239737344, 278907648, 274140032, 252211264, 1061061152, 971497264, 103936408, 561572676, 979702150, 343128953 - ], - [ - 536870912, 268435456, 939524096, 67108864, 100663296, 83886080, 880803840, 1002438656, 723517440, 126877696, 35127296, 151257088, 458358784, 247005184, 1020755968, 959070208, 382558208, 204328960, 261883904, 26696704, 46801408, 939364608, 82210176, 392305216, 250841120, 501816336, 510476856, 1073561860, 686286214, 761398853 - ], - [ - 536870912, 805306368, 402653184, 335544320, 100663296, 721420288, 327155712, 876609536, 119537664, 651165696, 3670016, 1027866624, 179437568, 72024064, 485326848, 930037760, 657285120, 1041117184, 668792832, 845603840, 274948608, 242369792, 413691776, 56511040, 799283232, 33788976, 83950104, 880906516, 901936518, 509717355 - ], - [ - 536870912, 805306368, 134217728, 67108864, 503316480, 587202560, 58720256, 767557632, 870318080, 860880896, 812122112, 28049408, 1058406400, 806420480, 919306240, 593281024, 940548096, 1013370880, 734758912, 870130688, 508477952, 642161408, 897211264, 333711424, 738791840, 893302640, 161351720, 644670516, 167043606, 801213223 - ], - [ - 536870912, 805306368, 671088640, 872415232, 905969664, 788529152, 327155712, 549453824, 291504128, 491782144, 45613056, 590086144, 249692160, 663945216, 383418368, 16728064, 639197184, 161345536, 659142656, 153504768, 493286912, 994403584, 162919296, 473829056, 91971616, 634318896, 762525736, 793316404, 220698166, 56923439 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 234881024, 654311424, 75497472, 952107008, 463470592, 753926144, 868745216, 73138176, 983433216, 305987584, 273448960, 239550464, 1010540544, 823644160, 922916864, 746689536, 482438656, 698417408, 99839360, 273281088, 941616544, 436121712, 627854776, 259350604, 969987510, 49935467 - ], - [ - 536870912, 805306368, 939524096, 335544320, 838860800, 318767104, 998244352, 381681664, 274726912, 338690048, 628621312, 621019136, 320733184, 296288256, 487358464, 532725760, 618749952, 661753856, 383502336, 1003877376, 471292416, 754384128, 965015680, 1012842944, 1007338144, 920497392, 172749336, 671062308, 1054534282, 668207303 - ], - [ - 536870912, 805306368, 134217728, 335544320, 167772160, 150994944, 411041792, 62914560, 979369984, 617611264, 804782080, 200015872, 997851136, 774832128, 505053184, 92160000, 698490880, 649252864, 388605952, 974515200, 865373696, 81256704, 729108864, 583405504, 846106144, 70836528, 361746824, 497569748, 483700266, 125186361 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 503316480, 587202560, 713031680, 96468992, 761266176, 904921088, 594018304, 1055653888, 452329472, 783482880, 30048256, 528236544, 669786112, 561303552, 82843648, 485209088, 917449216, 987207936, 249762176, 867408960, 407511968, 138195280, 860657688, 669316140, 829000230, 737085727 - ], - [ - 536870912, 268435456, 671088640, 67108864, 704643072, 117440512, 109051904, 406847488, 811597824, 951058432, 526909440, 159121408, 704512000, 146735104, 995983360, 506314752, 99049472, 453709824, 600668160, 496499712, 692288000, 669004032, 661792640, 415948864, 845948832, 663085136, 146384776, 337911892, 564709282, 828125267 - ], - [ - 536870912, 805306368, 402653184, 67108864, 637534208, 486539264, 1031798784, 692060160, 203423744, 63963136, 961019904, 660340736, 456785920, 478609408, 353337344, 20004864, 284745728, 258215936, 188741632, 659039232, 240929280, 414888192, 751100544, 45005504, 916541984, 403801392, 44617880, 627929028, 524360326, 958504685 - ], - [ - 536870912, 805306368, 402653184, 201326592, 369098752, 788529152, 159383552, 650117120, 127926272, 198180864, 141033472, 6553600, 75890688, 137691136, 992772096, 1030766592, 20652032, 625922048, 276940800, 809657344, 820116992, 649261824, 303779200, 752793536, 84602272, 706029552, 809272760, 96064508, 252679086, 425956563 - ], - [ - 536870912, 268435456, 939524096, 603979776, 234881024, 1023410176, 377487360, 692060160, 1000341504, 766509056, 515375104, 530317312, 942800896, 880345088, 134184960, 761282560, 265412608, 15224832, 733423616, 249852928, 491743744, 106640128, 714063744, 414802880, 782051360, 1018262544, 171633208, 434008868, 34856846, 352875517 - ], - [ - 536870912, 805306368, 939524096, 201326592, 167772160, 956301312, 578813952, 817889280, 106954752, 1072693248, 582483968, 319553536, 432668672, 41353216, 790986752, 973979648, 860495872, 112709632, 793233408, 922614784, 175373824, 133761792, 2918784, 219698624, 941504032, 205780784, 966981560, 269524684, 973774762, 798454473 - ], - [ - 536870912, 268435456, 671088640, 201326592, 369098752, 1023410176, 914358272, 834666496, 333447168, 179306496, 820510720, 593231872, 735182848, 26804224, 56000512, 96387072, 199385088, 1051742208, 48834560, 73317376, 911314432, 1004081920, 401996416, 758044608, 576276512, 666364944, 982394408, 222916364, 525210774, 1017877757 - ], - [ - 536870912, 268435456, 939524096, 201326592, 838860800, 184549376, 880803840, 1035993088, 740294656, 328204288, 814219264, 1011089408, 107872256, 259719168, 423526400, 139542528, 967499776, 441716736, 950351872, 610055168, 371273216, 1016263424, 34180480, 881155776, 667698080, 514375120, 215381528, 912529180, 822082442, 175196615 - ], - [ - 536870912, 268435456, 939524096, 469762048, 436207616, 150994944, 209715200, 4194304, 1042284544, 594542592, 275251200, 122421248, 547487744, 506527744, 483098624, 729661440, 292265984, 1070436352, 518080512, 789627904, 540656128, 1054304000, 616984192, 41935040, 233414688, 126652432, 1019398200, 375456796, 961569306, 891025161 - ], - [ - 536870912, 805306368, 134217728, 738197504, 905969664, 184549376, 226492416, 1010827264, 891289600, 774897664, 73924608, 320077824, 168165376, 157089792, 178356224, 863059968, 164175872, 736432128, 1015875584, 907717632, 308268544, 1059206400, 724785024, 652788928, 953647008, 1046968560, 349026728, 289137116, 762257438, 197660695 - ], - [ - 536870912, 805306368, 402653184, 738197504, 973078528, 352321536, 696254464, 406847488, 555745280, 384827392, 608698368, 661913600, 854458368, 539033600, 426934272, 185286656, 383082496, 803008512, 671795200, 542481408, 320787968, 350952704, 902257536, 361151424, 681977248, 475319024, 18702392, 904458268, 172279842, 583310393 - ], - [ - 536870912, 805306368, 134217728, 201326592, 704643072, 956301312, 192937984, 29360128, 899678208, 709885952, 67633152, 444858368, 252313600, 470220800, 726302720, 929546240, 741875712, 712790016, 223647744, 566381568, 94552576, 575760640, 134857344, 814096704, 906674720, 394619184, 713802376, 46473548, 107627018, 779462921 - ], - [ - 536870912, 805306368, 134217728, 738197504, 167772160, 520093696, 75497472, 692060160, 161480704, 537919488, 616038400, 871104512, 532021248, 434700288, 16220160, 1028145152, 526737408, 305385472, 426276864, 1068956672, 703282688, 150303488, 290041472, 358901568, 221278368, 501908592, 385140264, 541839132, 686289026, 905102451 - ], - [ - 536870912, 268435456, 939524096, 603979776, 369098752, 285212672, 998244352, 650117120, 60817408, 326107136, 236453888, 619970560, 748290048, 901054464, 66682880, 107429888, 571531264, 550129664, 882726912, 267860992, 471458304, 871680768, 1041802112, 217527360, 815522336, 129354512, 83567544, 753235044, 1062371894, 94952193 - ], - [ - 536870912, 268435456, 134217728, 201326592, 301989888, 452984832, 394264576, 457179136, 627048448, 288358400, 421003264, 141295616, 901120000, 536543232, 69042176, 80625664, 338092032, 762515456, 570001408, 488483840, 5091840, 350596352, 22183552, 246074688, 45370528, 175775824, 207442472, 976076060, 206993050, 168370519 - ], - [ - 536870912, 268435456, 402653184, 67108864, 570425344, 285212672, 1031798784, 499122176, 727711744, 779091968, 206045184, 509870080, 960888832, 261554176, 701399040, 521322496, 658169856, 363786240, 803383296, 36713472, 82321920, 745936128, 368929152, 754672576, 97454496, 823153616, 138002872, 522999764, 1017228186, 403736261 - ], - [ - 536870912, 805306368, 939524096, 67108864, 167772160, 184549376, 176160768, 364904448, 123731968, 619708416, 311951360, 915668992, 461242368, 590413824, 720928768, 719831040, 321314816, 306515968, 196515840, 380580864, 1048267264, 908519680, 700849792, 670491840, 177065120, 36321776, 204347416, 599323700, 222669362, 53999887 - ], - [ - 536870912, 268435456, 402653184, 335544320, 100663296, 50331648, 679477248, 884998144, 832569344, 407896064, 434634752, 613679104, 150339584, 143065088, 142508032, 266584064, 271687680, 395874304, 728733696, 904631296, 647491072, 368368384, 923143552, 306161856, 159460768, 289470672, 585176504, 665910468, 31056830, 1057977287 - ], - [ - 536870912, 805306368, 671088640, 67108864, 704643072, 150994944, 461373440, 834666496, 513802240, 865075200, 875036672, 826015744, 467271680, 581369856, 723288064, 1024016384, 762257408, 978341888, 914905088, 78621696, 150110720, 723008768, 327656576, 726546624, 444693024, 507674928, 761290408, 540211652, 909804682, 1037396217 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 33554432, 419430400, 545259520, 650117120, 585105408, 68157440, 876085248, 440139776, 253886464, 661848064, 40402944, 338149376, 686694400, 569937920, 224233472, 124988416, 845860352, 472215808, 351083392, 603514816, 341745696, 670257200, 346662920, 1053080636, 285066754, 398630169 - ], - [ - 536870912, 805306368, 134217728, 201326592, 838860800, 1023410176, 679477248, 734003200, 249561088, 309329920, 554172416, 825491456, 991297536, 33882112, 977108992, 52510720, 663773184, 284733440, 276740096, 142787584, 465570304, 115440896, 510764416, 319548096, 204752288, 328604400, 700751272, 886927100, 290566042, 110794689 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 301989888, 50331648, 528482304, 1002438656, 962592768, 271581184, 1060634624, 813957120, 608043008, 293273600, 891781120, 351223808, 682745856, 226136064, 925140992, 1072604160, 187841024, 616094976, 222688384, 811348416, 264883872, 761261264, 961264136, 505191724, 174822586, 495837695 - ], - [ - 536870912, 268435456, 939524096, 335544320, 167772160, 788529152, 494927872, 574619648, 1038090240, 122683392, 379060224, 422838272, 71958528, 300744704, 110985216, 603340800, 963125248, 748498944, 485865472, 485110784, 450811392, 722843904, 884714368, 298110016, 274820640, 219319568, 125369784, 6763860, 936568234, 979071359 - ], - [ - 536870912, 268435456, 134217728, 603979776, 570425344, 721420288, 25165824, 901775360, 828375040, 533725184, 421003264, 420741120, 1071251456, 368377856, 466255872, 277823488, 361537536, 688910336, 474855424, 376187904, 782036480, 133689600, 684445568, 1024227392, 642674208, 292335888, 689794952, 993429604, 858347010, 379575611 - ], - [ - 536870912, 268435456, 402653184, 872415232, 838860800, 754974720, 41943040, 440401920, 828375040, 556793856, 818413568, 714342400, 354287616, 678100992, 738492416, 482656256, 199712768, 95907840, 1062156288, 949185536, 853049856, 638459136, 678437760, 942395328, 342106528, 359994064, 946692664, 784510244, 1008925610, 332403673 - ], - [ - 536870912, 268435456, 939524096, 67108864, 167772160, 352321536, 142606336, 641728512, 178257920, 523239424, 2621440, 743702528, 481165312, 650313728, 14843904, 596885504, 68739072, 1006497792, 188471296, 504359936, 368266752, 919083264, 348574080, 255186880, 654059424, 800592592, 239894552, 72400916, 1048207410, 791556113 - ], - [ - 536870912, 805306368, 402653184, 469762048, 167772160, 150994944, 931135488, 910163968, 543162368, 617611264, 374865920, 794558464, 866779136, 1027014656, 683638784, 154714112, 252583936, 892522496, 801708032, 602330112, 803614208, 233304320, 14948224, 560236224, 338073120, 180827440, 802619800, 799831004, 71317418, 90265337 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 167772160, 318767104, 931135488, 759169024, 627048448, 393216000, 661127168, 424411136, 948043776, 549650432, 589529088, 965984256, 391684096, 138752000, 20805632, 309056512, 1070519808, 893597440, 694294144, 628327616, 141164576, 617545776, 113344568, 841007164, 420683786, 1000009747 - ], - [ - 536870912, 268435456, 134217728, 335544320, 167772160, 1023410176, 511705088, 314572800, 383778816, 263192576, 258473984, 626262016, 603062272, 457768960, 872710144, 925581312, 997564416, 262230016, 286369792, 116984832, 443547136, 318747392, 1027934848, 562647872, 652683296, 983256080, 488562184, 1047896852, 488702602, 366022525 - ], - [ - 536870912, 268435456, 939524096, 469762048, 570425344, 889192448, 981467136, 247463936, 769654784, 458227712, 967311360, 655622144, 674627584, 344391680, 662470656, 1027686400, 731996160, 896741376, 698030080, 690893824, 778619392, 980758272, 749051264, 72106176, 49839520, 247345360, 924976536, 548615372, 301586362, 792473593 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 369098752, 721420288, 796917760, 792723456, 484442112, 1039138816, 443023360, 444858368, 175505408, 211615744, 47939584, 286146560, 25305088, 541265920, 828614656, 330398720, 336110080, 213275904, 205475712, 407381440, 869590944, 546134512, 163726728, 757206220, 886082078, 750348583 - ], - [ - 536870912, 268435456, 402653184, 67108864, 704643072, 184549376, 545259520, 255852544, 555745280, 196083712, 695730176, 810287104, 26345472, 306774016, 242581504, 352206848, 845783040, 1044656128, 172345344, 675615744, 1061585408, 834978560, 528747392, 354759360, 827615264, 911025168, 747719192, 264820484, 79104426, 991932875 - ], - [ - 536870912, 805306368, 134217728, 738197504, 1040187392, 889192448, 142606336, 247463936, 85983232, 349175808, 755499008, 760479744, 1019346944, 1042481152, 558923776, 122339328, 414703616, 405884928, 259753984, 801926144, 335319552, 243772672, 709361792, 70720832, 217088032, 760922160, 950001672, 229986348, 548505662, 163277877 - ], - [ - 536870912, 268435456, 402653184, 67108864, 100663296, 452984832, 293601280, 977272832, 65011712, 439353344, 1061683200, 356777984, 230817792, 849412096, 273776640, 456671232, 804020224, 431468544, 296359936, 234300416, 88866304, 474252032, 423732352, 107002944, 1047756832, 598294544, 418766872, 332132356, 897873926, 1038193691 - ], - [ - 536870912, 805306368, 402653184, 738197504, 973078528, 385875968, 612368384, 113246208, 765460480, 846200832, 543686656, 760479744, 1042415616, 540213248, 319389696, 512147456, 372875264, 974024704, 620611584, 106408960, 144833024, 99751680, 203992704, 121022784, 678666272, 124350512, 299255832, 350383148, 932305466, 914007831 - ], - [ - 536870912, 805306368, 939524096, 201326592, 436207616, 117440512, 159383552, 775946240, 429916160, 219152384, 856162304, 189005824, 940703744, 965410816, 42434560, 519225344, 968531968, 476049408, 417224704, 807289856, 981428736, 378407168, 741749888, 401260096, 813062176, 222970928, 451242552, 16845068, 478393498, 348356167 - ], - [ - 536870912, 268435456, 939524096, 872415232, 704643072, 587202560, 327155712, 46137344, 526385152, 498073600, 283639808, 734265344, 848166912, 563806208, 89030656, 947568640, 213704704, 464588800, 1038698496, 155464704, 885959168, 95991040, 643582336, 968998080, 685802400, 225630672, 411656728, 267796772, 61211538, 112990679 - ], - [ - 536870912, 805306368, 671088640, 603979776, 704643072, 251658240, 343932928, 910163968, 23068672, 602931200, 405274624, 765722624, 851836928, 741670912, 597655552, 586792960, 35479552, 389582848, 767449088, 233372672, 839354880, 1451264, 395280256, 73472448, 141696928, 317295088, 1048856456, 978679252, 418237858, 43143387 - ], - [ - 536870912, 805306368, 402653184, 469762048, 1040187392, 956301312, 1048576000, 4194304, 161480704, 36700160, 980942848, 633602048, 5636096, 689766400, 203456512, 200491008, 740007936, 211136512, 268277760, 70351872, 796521984, 1027931392, 622280320, 540846272, 928056992, 111699184, 195913912, 1058661868, 18194438, 842838037 - ], - [ - 536870912, 268435456, 402653184, 201326592, 771751936, 285212672, 192937984, 339738624, 505413632, 783286272, 651689984, 611057664, 171573248, 758972416, 221478912, 916045824, 5201920, 395038720, 1063737344, 664785920, 1027774976, 161599232, 217309056, 637154752, 794589728, 698539792, 485648280, 1039856076, 593319950, 128111617 - ], - [ - 536870912, 805306368, 671088640, 872415232, 771751936, 889192448, 713031680, 448790528, 677380096, 451936256, 129499136, 994312192, 49676288, 745340928, 335249408, 1072087040, 426057728, 27783168, 784635904, 833917952, 491758080, 187430144, 185502336, 143332544, 354390688, 234897648, 83923080, 42173892, 784474662, 106968369 - ], - [ - 536870912, 805306368, 134217728, 67108864, 637534208, 587202560, 142606336, 381681664, 580911104, 1060110336, 931659776, 14417920, 672792576, 1030160384, 1020166144, 266420224, 1003610112, 819654656, 147236864, 629095424, 162107904, 925734656, 305331840, 671675584, 815716896, 997743408, 242599048, 28729284, 311932550, 988166355 - ], - [ - 536870912, 805306368, 939524096, 738197504, 704643072, 318767104, 494927872, 1044381696, 501219328, 923795456, 227016704, 983302144, 888274944, 530251776, 731348992, 313311232, 1061920768, 868069376, 63084544, 329286656, 317836800, 379148544, 487867520, 493790144, 921253920, 172831792, 618354232, 452320556, 25135786, 182516435 - ], - [ - 536870912, 268435456, 402653184, 603979776, 436207616, 318767104, 25165824, 910163968, 417333248, 680525824, 125304832, 578551808, 189923328, 1004077056, 1024294912, 456671232, 563912704, 507686912, 887314432, 244532224, 712703488, 721367296, 797975424, 351973824, 993843232, 741475344, 738975256, 806732068, 639097754, 51856851 - ], - [ - 536870912, 268435456, 939524096, 603979776, 503316480, 687865856, 897581056, 1027604480, 346030080, 628097024, 411566080, 1038876672, 1966080, 509018112, 458784768, 991215616, 1006247936, 946089984, 779200512, 772365312, 976201216, 293476608, 960966016, 641844544, 438338976, 112433488, 401187736, 872300660, 142880262, 35878173 - ], - [ - 536870912, 805306368, 134217728, 738197504, 905969664, 553648128, 226492416, 499122176, 702545920, 955252736, 571998208, 30146560, 755630080, 640090112, 1029603328, 438550528, 605085696, 90722304, 85293056, 531016704, 43865600, 12782336, 710943616, 540028352, 477679136, 872281904, 175115656, 257526508, 107985814, 752472529 - ], - [ - 536870912, 268435456, 939524096, 67108864, 637534208, 822083584, 629145600, 364904448, 786432000, 684720128, 655884288, 648282112, 872022016, 225771520, 509706240, 781271040, 356114432, 18305024, 267532288, 321604608, 107951616, 583373056, 241827712, 718108480, 506910240, 1069728016, 367249336, 642923332, 73129990, 788942881 - ], - [ - 536870912, 268435456, 402653184, 603979776, 1040187392, 687865856, 243269632, 1010827264, 467664896, 617611264, 449314816, 659816448, 597557248, 1036713984, 148144128, 761118720, 6987776, 551940096, 885504000, 255167488, 59607552, 362892032, 70380928, 463147968, 1012688800, 988436688, 983927352, 572869428, 459795878, 201593805 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 234881024, 553648128, 595591168, 859832320, 987758592, 53477376, 251133952, 452198400, 585236480, 120651776, 351961088, 167231488, 778231808, 921899008, 1054390272, 56947712, 424234496, 567223040, 137779072, 1010981696, 677568544, 1005785104, 995670056, 757396540, 237587982, 817832737 - ], - [ - 536870912, 268435456, 402653184, 335544320, 570425344, 855638016, 478150656, 666894336, 471859200, 472907776, 702021632, 11272192, 793116672, 825425920, 945324032, 653049856, 220553216, 459411456, 433223680, 885748736, 751099392, 745738496, 179873408, 494707520, 562954400, 989120080, 715814968, 949449732, 284876346, 18616615 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 369098752, 218103808, 411041792, 46137344, 165675008, 569376768, 955777024, 1021575168, 354025472, 253165568, 48398336, 208715776, 381280256, 499585024, 638248960, 60816384, 482317824, 783086336, 614986112, 154878272, 747009568, 816571184, 231545224, 412401020, 262266934, 215158845 - ], - [ - 536870912, 805306368, 939524096, 603979776, 234881024, 318767104, 75497472, 356515840, 157286400, 963641344, 881328128, 528220160, 548274176, 712310784, 689078272, 612024320, 288694272, 57774080, 562731008, 352300032, 460179968, 727168256, 243530112, 943956032, 652263840, 213015664, 648557464, 1013781844, 702003222, 348273671 - ], - [ - 536870912, 268435456, 402653184, 201326592, 1040187392, 285212672, 864026624, 130023424, 379584512, 498073600, 913833984, 983826432, 210108416, 41353216, 334397440, 605700096, 1027055616, 437104640, 541722624, 387789824, 109084160, 239195392, 710990464, 462591168, 814316192, 1060906192, 158593720, 878203100, 374647942, 706573773 - ], - [ - 536870912, 805306368, 402653184, 67108864, 503316480, 16777216, 1031798784, 297795584, 316669952, 389021696, 718798848, 833880064, 382861312, 862650368, 875397120, 46546944, 321445888, 84840448, 68425728, 138525696, 757227008, 483621632, 74041728, 347003200, 881129504, 252390448, 1012680216, 364758788, 269227934, 261415489 - ], - [ - 536870912, 805306368, 402653184, 469762048, 503316480, 721420288, 696254464, 1069547520, 631242752, 800063488, 786956288, 682885120, 294518784, 415301632, 975339520, 1064321024, 549986304, 231165952, 407250944, 159671296, 522528256, 85319936, 171750784, 740980160, 999627680, 847044848, 88768568, 67387436, 317071366, 230051895 - ], - [ - 536870912, 268435456, 671088640, 335544320, 1040187392, 989855744, 293601280, 213909504, 73400320, 904921088, 412614656, 747896832, 1045823488, 288817152, 491094016, 488423424, 199958528, 995004416, 593528832, 510772224, 962281984, 376716544, 686204032, 973874624, 298001568, 48293328, 716178568, 20608452, 159812790, 897364479 - ], - [ - 536870912, 268435456, 939524096, 603979776, 234881024, 587202560, 1048576000, 767557632, 752877568, 554696704, 858259456, 142868480, 1071775744, 932249600, 48988160, 241582080, 871555072, 423309312, 422340608, 816225280, 160509440, 166371584, 753212032, 875754560, 416997408, 633286672, 281962552, 3644452, 1006284302, 156033315 - ], - [ - 536870912, 805306368, 671088640, 469762048, 503316480, 1023410176, 847249408, 306184192, 769654784, 282066944, 189267968, 358350848, 241827840, 372178944, 235962368, 971685888, 854548480, 464523264, 1004128256, 955544576, 409351680, 768395520, 264387200, 908275904, 351524384, 347674928, 308548264, 583898332, 910379070, 937538573 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 436207616, 184549376, 243269632, 297795584, 840957952, 623902720, 1041760256, 487849984, 697958400, 89587712, 922255360, 881115136, 191963136, 678981632, 1028114432, 760245248, 726231552, 308117248, 902163328, 496123456, 887843360, 338591536, 843017128, 479592060, 148425274, 599117627 - ], - [ - 536870912, 268435456, 671088640, 872415232, 1040187392, 989855744, 763363328, 515899392, 488636416, 737148928, 345505792, 860094464, 386269184, 191299584, 980779008, 79609856, 1053892608, 459837440, 836716544, 725754880, 266581504, 349268224, 241848448, 257891520, 738316448, 839048400, 419655816, 478383332, 910203062, 358873311 - ], - [ - 536870912, 805306368, 939524096, 335544320, 771751936, 687865856, 1048576000, 624951296, 81788928, 967835648, 338165760, 56360960, 201719808, 206635008, 924352512, 607567872, 918134784, 694644736, 589363200, 705952768, 41646592, 54789376, 129094016, 891990848, 299684768, 323390064, 263280664, 422087716, 735937046, 340195645 - ], - [ - 536870912, 805306368, 939524096, 603979776, 637534208, 16777216, 729808896, 373293056, 291504128, 776994816, 276299776, 524550144, 912130048, 726204416, 929857536, 6537216, 231940096, 440004608, 203745280, 1057995776, 296837632, 367643392, 824133248, 430687680, 326960288, 58457840, 466004504, 379553556, 99273886, 958247653 - ], - [ - 536870912, 805306368, 134217728, 469762048, 1040187392, 352321536, 427819008, 884998144, 216006656, 588251136, 369623040, 732692480, 463863808, 17367040, 690978816, 736575488, 1017847808, 203239424, 119506944, 1000207360, 517779968, 989755136, 722347392, 186034240, 791844768, 737730416, 1035252264, 914519852, 574629302, 514041929 - ], - [ - 536870912, 805306368, 402653184, 738197504, 838860800, 452984832, 260046848, 130023424, 748683264, 623902720, 637009920, 963379200, 252837888, 596312064, 544571392, 338477056, 854728704, 559624192, 677361664, 887856128, 870799872, 1004837632, 1071979392, 971407552, 1021810720, 443001904, 153575960, 767870764, 597156274, 268364763 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 905969664, 553648128, 1031798784, 666894336, 1029701632, 894435328, 758644736, 606339072, 220332032, 686882816, 25919488, 437239808, 681402368, 684003328, 28530688, 497761280, 662500864, 181921024, 95124352, 192902720, 81059872, 413913104, 16627768, 34991164, 407424566, 309119265 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 436207616, 251658240, 780140544, 759169024, 1008730112, 542113792, 122159104, 514064384, 442368000, 948109312, 541163520, 698564608, 93478912, 53039104, 592844800, 1048984576, 806229504, 952780544, 744763776, 79527616, 238149536, 767038928, 553517096, 429064236, 153714706, 609697843 - ], - [ - 536870912, 268435456, 402653184, 738197504, 33554432, 117440512, 696254464, 1061158912, 937426944, 907018240, 495452160, 573833216, 512884736, 709427200, 840269824, 547405824, 636559360, 496627712, 381442048, 270914560, 622333440, 964524288, 738684032, 422100288, 835082272, 705221648, 276270616, 871414060, 614059138, 574393671 - ], - [ - 536870912, 268435456, 134217728, 335544320, 100663296, 553648128, 662700032, 943718400, 769654784, 294649856, 308805632, 537657344, 299499520, 643104768, 399409152, 8011776, 338026496, 557174784, 329013248, 1018328064, 484079104, 198526208, 344804480, 958058432, 1031228960, 545104144, 270533256, 993160916, 882494630, 775262193 - ], - [ - 536870912, 268435456, 939524096, 335544320, 33554432, 218103808, 260046848, 1061158912, 111149056, 613416960, 882376704, 786694144, 209846272, 1002504192, 23298048, 200359936, 610803712, 168611840, 995031040, 921498624, 721218048, 933726464, 757246336, 835837504, 322568224, 334823440, 140083256, 285491220, 431071234, 1028165645 - ], - [ - 536870912, 268435456, 134217728, 335544320, 838860800, 956301312, 310378496, 88080384, 354418688, 177209344, 998768640, 671350784, 1032978432, 638124032, 1019510784, 309542912, 477765632, 616501248, 214853632, 1035236352, 965296640, 151339264, 856886400, 88810048, 585525280, 861959184, 808665608, 483934484, 787319986, 715481721 - ], - [ - 536870912, 805306368, 939524096, 872415232, 503316480, 989855744, 343932928, 155189248, 148897792, 277872640, 671612928, 459014144, 758775808, 86441984, 234717184, 1003110400, 704471040, 768176128, 519890944, 323699712, 851326464, 875083008, 1072523904, 495000256, 1019362848, 136364336, 179492024, 867933172, 426085054, 312355531 - ], - [ - 536870912, 268435456, 939524096, 67108864, 167772160, 251658240, 796917760, 515899392, 585105408, 269484032, 491257856, 941359104, 555089920, 766181376, 856588288, 568180736, 7856128, 360239104, 228902912, 592606208, 40555008, 325977856, 864907648, 10276672, 72819616, 596117584, 184365592, 151443220, 887208370, 18004811 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 100663296, 1056964608, 444596224, 482344960, 1067450368, 244318208, 823656448, 313262080, 206438400, 1061093376, 836075520, 642924544, 616046592, 222220288, 618133504, 768668672, 570158592, 853423872, 908357248, 930723904, 270519968, 579217488, 426481288, 80039020, 705306766, 502734675 - ], - [ - 536870912, 805306368, 939524096, 335544320, 771751936, 419430400, 914358272, 515899392, 429916160, 617611264, 429391872, 1069809664, 779747328, 427229184, 1041334272, 641351680, 773152768, 996331520, 259164160, 642513920, 870298112, 251609344, 535597952, 844388672, 570511904, 318820656, 964885432, 625161556, 534972430, 984726569 - ], - [ - 536870912, 268435456, 939524096, 335544320, 503316480, 285212672, 528482304, 390070272, 18874368, 108003328, 246939648, 386138112, 270401536, 480968704, 770605056, 860930048, 113876992, 817852416, 211527680, 99904512, 560330240, 122670336, 744528000, 542333376, 709545632, 461169872, 511278616, 90444036, 827287206, 291735749 - ], - [ - 536870912, 805306368, 402653184, 335544320, 1040187392, 385875968, 125829120, 1010827264, 543162368, 781189120, 11010048, 554958848, 70123520, 537985024, 476741632, 582270976, 580689920, 273387520, 71796736, 10845184, 469131776, 142540544, 874130304, 474843072, 713277856, 985793776, 10586168, 523271204, 454746662, 1070546691 - ], - [ - 536870912, 805306368, 134217728, 67108864, 637534208, 486539264, 947912704, 130023424, 610271232, 250609664, 691535872, 152305664, 891158528, 726728704, 782991360, 509394944, 384835584, 356036608, 588699648, 169718784, 684808704, 216594688, 92091520, 1000496832, 378615456, 231461872, 523073576, 1065993268, 1007657518, 517602585 - ], - [ - 536870912, 268435456, 402653184, 469762048, 503316480, 1023410176, 612368384, 281018368, 585105408, 506462208, 279445504, 871104512, 149028864, 691077120, 321486848, 950910976, 1027858432, 480432128, 185845760, 939052032, 708300288, 275200, 447496832, 239121088, 488890400, 592629776, 467388440, 736414748, 706596382, 690565949 - ], - [ - 536870912, 805306368, 402653184, 872415232, 838860800, 318767104, 645922816, 532676608, 195035136, 200278016, 250085376, 202113024, 280363008, 983629824, 376602624, 464175104, 510418944, 837029888, 171595776, 768939008, 326206976, 875259136, 405782912, 84293184, 883457952, 384587632, 589586488, 840437764, 1046763562, 1014502439 - ], - [ - 536870912, 268435456, 402653184, 738197504, 905969664, 553648128, 1048576000, 952107008, 383778816, 892338176, 14155776, 33816576, 566624256, 245825536, 81166336, 950812672, 398139392, 880226304, 868210688, 749786112, 798554624, 648481024, 550892672, 984607936, 750482592, 502770896, 352212152, 1007918332, 881396878, 95160541 - ], - [ - 536870912, 805306368, 402653184, 603979776, 973078528, 1023410176, 176160768, 20971520, 262144000, 569376768, 505937920, 219938816, 34734080, 318439424, 260407296, 8667136, 990289920, 919031808, 455501824, 955610112, 837700096, 649594624, 111537792, 641017792, 160253984, 397042736, 836534808, 594617124, 325602490, 79435005 - ], - [ - 536870912, 268435456, 402653184, 603979776, 33554432, 822083584, 864026624, 834666496, 106954752, 32505856, 640155648, 436994048, 596246528, 614268928, 198410240, 259735552, 120954880, 186601472, 202381312, 572034048, 541367808, 762798848, 280900736, 897783744, 314752544, 484668176, 666078360, 327732196, 748435490, 936483873 - ], - [ - 536870912, 268435456, 134217728, 201326592, 100663296, 218103808, 746586112, 230686720, 958398464, 363855872, 58195968, 298057728, 199622656, 601292800, 267354112, 734740480, 641540096, 333639680, 454277120, 847913984, 115185152, 1030929664, 182186624, 129346240, 817812128, 220420816, 129198760, 209354460, 977763502, 564429777 - ], - [ - 536870912, 805306368, 402653184, 335544320, 1040187392, 956301312, 478150656, 197132288, 887095296, 821035008, 301465600, 65798144, 435814400, 1072627712, 737902592, 753811456, 813195264, 44945408, 333031424, 226323456, 103998976, 798647040, 232651136, 174284224, 3335712, 848978736, 928905624, 748903892, 374531614, 816472841 - ], - [ - 536870912, 268435456, 939524096, 67108864, 838860800, 855638016, 260046848, 1019215872, 270532608, 36700160, 588775424, 1002700800, 14548992, 790298624, 633765888, 1037942784, 630743040, 394694656, 767428608, 80434176, 441212416, 661858560, 519784064, 760533952, 381098144, 690485968, 1070358040, 1018374420, 190531210, 614781943 - ], - [ - 536870912, 805306368, 134217728, 335544320, 838860800, 989855744, 796917760, 314572800, 912261120, 439353344, 954728448, 104071168, 215351296, 262471680, 703430656, 747159552, 520478720, 129978368, 1028794368, 442024960, 765379072, 859926784, 161740672, 47243456, 815273888, 134131952, 259112872, 944485604, 275193242, 17651167 - ], - [ - 536870912, 805306368, 939524096, 67108864, 1040187392, 520093696, 360710144, 734003200, 996147200, 881852416, 1017643008, 161218560, 753532928, 239009792, 177831936, 398934016, 634281984, 211857408, 99760128, 288918528, 1001737728, 624289024, 762696832, 517387456, 1051119136, 1012770096, 948581560, 388842692, 435197470, 456825135 - ], - [ - 536870912, 805306368, 671088640, 738197504, 369098752, 587202560, 796917760, 624951296, 648019968, 97517568, 844627968, 644612096, 318111744, 293142528, 738033664, 244203520, 33988608, 1034997760, 376145920, 105221120, 898870784, 678993664, 25126016, 256853312, 40323744, 763402864, 608374280, 941707036, 370240702, 725125455 - ], - [ - 536870912, 268435456, 939524096, 872415232, 771751936, 352321536, 578813952, 616562688, 278921216, 458227712, 105381888, 940834816, 617742336, 470351872, 779583488, 539049984, 412344320, 57331712, 704997376, 259697664, 1017993728, 22945024, 759588992, 664333120, 1050634272, 443001872, 42523192, 951475508, 125962414, 776174421 - ], - [ - 536870912, 268435456, 134217728, 67108864, 838860800, 788529152, 998244352, 440401920, 882900992, 632291328, 354942976, 28573696, 614858752, 1044316160, 161710080, 556908544, 1022091264, 727027712, 129263616, 564653056, 650040832, 509834496, 315794304, 964297408, 973941664, 1036549840, 363304360, 213706708, 1029955610, 525439035 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 704643072, 654311424, 209715200, 20971520, 769654784, 405798912, 618135552, 1050935296, 546701312, 827129856, 275349504, 725368832, 1003741184, 904400896, 805083136, 586378240, 1023123968, 1043708160, 664541312, 1040421056, 16810144, 159448304, 381887144, 169952716, 328284674, 495703339 - ], - [ - 536870912, 805306368, 939524096, 201326592, 1040187392, 486539264, 142606336, 1035993088, 589299712, 573571072, 336068608, 26476544, 170786816, 787546112, 833126400, 996622336, 965025792, 244789248, 296736768, 1051792384, 734678528, 968188160, 832510848, 834223552, 870092192, 953698544, 479156248, 159536188, 54619654, 937644305 - ], - [ - 536870912, 805306368, 134217728, 335544320, 637534208, 117440512, 92274688, 432013312, 48234496, 598736896, 186122240, 18087936, 441319424, 175702016, 208109568, 506970112, 622731264, 970166272, 837478400, 1034839040, 893968896, 4152576, 864140928, 650316480, 459332768, 141727728, 687391272, 539348260, 219469486, 273592019 - ], - [ - 536870912, 805306368, 671088640, 603979776, 973078528, 855638016, 444596224, 457179136, 115343360, 594542592, 247988224, 796655616, 362938368, 831717376, 1069187072, 917913600, 442343424, 208809984, 306718720, 826110976, 616795648, 438413056, 89191552, 1033415616, 1072111648, 969175088, 982878248, 34554916, 174827066, 996987699 - ], - [ - 536870912, 805306368, 671088640, 469762048, 369098752, 654311424, 964689920, 742391808, 320864256, 47185920, 946339840, 859570176, 694812672, 499056640, 346587136, 1054785536, 324657152, 593801216, 562984960, 359691264, 108677632, 515365120, 342330496, 1034944, 221399584, 526113072, 761629864, 848087772, 653314614, 456792343 - ], - [ - 536870912, 268435456, 939524096, 738197504, 1040187392, 520093696, 377487360, 750780416, 18874368, 776994816, 379060224, 205783040, 560070656, 649134080, 443252736, 63881216, 568188928, 27717632, 504489984, 645565440, 750170624, 283653376, 957288832, 738136128, 729047072, 88682512, 580880440, 432454700, 220248638, 5327135 - ], - [ - 536870912, 805306368, 402653184, 872415232, 704643072, 251658240, 478150656, 817889280, 790626304, 680525824, 684195840, 1025769472, 199098368, 635502592, 548569088, 819642368, 992862208, 1020809216, 355350528, 31015936, 850247168, 127490816, 575452544, 480884416, 315937696, 644151792, 213868600, 546476036, 885774386, 992285755 - ], - [ - 536870912, 268435456, 402653184, 201326592, 838860800, 318767104, 578813952, 281018368, 136314880, 812646400, 629669888, 787218432, 83755008, 434569216, 852656128, 20463616, 625369088, 929091584, 990984192, 614175744, 225928704, 353085696, 1026420096, 912136512, 894842272, 762977616, 212110264, 649244764, 279533578, 85738511 - ], - [ - 536870912, 805306368, 939524096, 201326592, 167772160, 922746880, 713031680, 1027604480, 962592768, 571473920, 105381888, 697040896, 193069056, 583204864, 765689856, 179355648, 494444544, 691499008, 294955008, 44487680, 907875840, 705192192, 929858688, 827328704, 103415840, 673120304, 722042936, 418365452, 496050186, 579383351 - ], - [ - 536870912, 805306368, 939524096, 335544320, 301989888, 318767104, 293601280, 339738624, 505413632, 204472320, 1017643008, 968622080, 859963392, 369164288, 151093248, 780255232, 62955520, 190877696, 277911552, 894995456, 259301888, 418312448, 366698880, 437609792, 763334112, 134478352, 396361736, 1013973004, 143130638, 848035845 - ], - [ - 536870912, 268435456, 402653184, 201326592, 369098752, 218103808, 1015021568, 465567744, 236978176, 867172352, 594018304, 163315712, 58589184, 866582528, 158564352, 464601088, 661135360, 196874240, 343848960, 338050048, 590533120, 852495104, 20517504, 356837312, 219837216, 1032679760, 441850152, 192628308, 543021486, 552577687 - ], - [ - 536870912, 268435456, 402653184, 603979776, 704643072, 721420288, 427819008, 624951296, 815792128, 934281216, 344457216, 1066663936, 775553024, 662241280, 960266240, 48152576, 740958208, 213962752, 501291008, 990981120, 758733312, 706579712, 590227840, 897729088, 195351456, 1022560592, 231522824, 200696068, 9393030, 800202569 - ], - [ - 536870912, 805306368, 402653184, 603979776, 905969664, 687865856, 125829120, 566231040, 731906048, 521142272, 556269568, 181141504, 191234048, 19988480, 821657600, 918863872, 486219776, 387887104, 649447424, 887323648, 556527104, 286739712, 304627840, 508304704, 237450336, 936431664, 1023993864, 740084748, 636462598, 585953545 - ], - [ - 536870912, 805306368, 671088640, 335544320, 570425344, 654311424, 327155712, 943718400, 421527552, 544210944, 465043456, 123469824, 706084864, 339542016, 742883328, 7618560, 1055072256, 824135680, 339286016, 958221312, 506927616, 348972288, 1044343168, 21622976, 1042630496, 648730224, 1035717000, 877846732, 88571754, 452250229 - ], - [ - 536870912, 805306368, 402653184, 335544320, 1040187392, 654311424, 947912704, 398458880, 916455424, 521142272, 382205952, 87818240, 813039616, 149356544, 359563264, 389169152, 1039458304, 977932288, 202483712, 541600768, 771584512, 710366976, 1043777408, 302448064, 899569184, 210483856, 20053544, 907581084, 693373998, 5931417 - ], - [ - 536870912, 805306368, 939524096, 603979776, 1040187392, 520093696, 360710144, 12582912, 182452224, 751828992, 1049100288, 921960448, 855506944, 20512768, 913145856, 224641024, 962732032, 258174976, 207861760, 65195008, 572757504, 574832384, 466788992, 796538432, 1069425312, 521757808, 375131656, 607879948, 446631054, 346555721 - ], - [ - 536870912, 268435456, 402653184, 67108864, 570425344, 285212672, 75497472, 1027604480, 94371840, 508559360, 452460544, 315883520, 280363008, 853213184, 312049664, 509886464, 482271232, 103165952, 71440384, 1056828416, 198946304, 437860096, 489023360, 773806400, 804661088, 914055184, 273280744, 1037913684, 701156878, 432031493 - ], - [ - 536870912, 268435456, 134217728, 469762048, 637534208, 1056964608, 226492416, 1010827264, 748683264, 149946368, 508035072, 947650560, 170786816, 139395072, 232751104, 59228160, 501424128, 520622080, 73197568, 1042154496, 241608192, 959685376, 1030788224, 638090944, 651976992, 132016720, 42385704, 996325972, 348686634, 230452819 - ], - [ - 536870912, 805306368, 671088640, 469762048, 167772160, 419430400, 394264576, 473956352, 799014912, 233832448, 455606272, 1033633792, 866516992, 761331712, 831619072, 288964608, 316989440, 199380992, 921946112, 420101120, 227484160, 1031560448, 796270464, 410575168, 952412384, 928127792, 66805768, 640028684, 69249034, 732965895 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 369098752, 587202560, 511705088, 859832320, 970981376, 347078656, 179830784, 371458048, 851836928, 756088832, 560562176, 795688960, 1035722752, 675524608, 159881216, 418460672, 198752768, 987094784, 589229440, 180619712, 66537248, 510228272, 401471496, 100385804, 857915914, 947280655 - ], - [ - 536870912, 268435456, 402653184, 335544320, 100663296, 721420288, 562036736, 264241152, 102760448, 164626432, 955777024, 354680832, 66453504, 693567488, 902266880, 1029652480, 1011605504, 246796288, 686786560, 310576128, 530135552, 982805248, 473838976, 955996736, 821921632, 914561744, 295200616, 496356052, 801009518, 440045265 - ], - [ - 536870912, 268435456, 671088640, 335544320, 838860800, 150994944, 109051904, 843055104, 824180736, 768606208, 275251200, 156499968, 243138560, 134152192, 406814720, 1021231104, 15622144, 204992512, 16496640, 1021938688, 504700416, 937301760, 930036096, 83335872, 630915168, 454663056, 741146728, 438475668, 858030178, 294083473 - ], - [ - 536870912, 805306368, 939524096, 872415232, 838860800, 654311424, 92274688, 1010827264, 736100352, 714080256, 769130496, 917766144, 925761536, 15269888, 303923200, 181649408, 715825152, 107941888, 227047424, 189647872, 598348288, 720328448, 759779456, 946723008, 236668064, 411525360, 244664840, 689851148, 599890574, 211833805 - ], - [ - 536870912, 805306368, 939524096, 469762048, 100663296, 1023410176, 411041792, 851443712, 312475648, 600834048, 159907840, 355205120, 160563200, 504430592, 749305856, 62767104, 536535040, 722284544, 176318464, 439878656, 634713600, 317154560, 287774336, 352729152, 488085344, 79674768, 998500360, 213500940, 236197390, 46617863 - ], - [ - 536870912, 268435456, 402653184, 469762048, 100663296, 989855744, 494927872, 1010827264, 937426944, 19922944, 481820672, 278134784, 15335424, 26673152, 455180288, 605044736, 262676480, 482136064, 119007232, 719336448, 934383104, 628661504, 120936064, 809163840, 656324960, 177074160, 137341416, 959728308, 121348110, 614436867 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 570425344, 889192448, 176160768, 666894336, 891289600, 982515712, 77070336, 873725952, 916586496, 293404672, 132087808, 648200192, 427646976, 64966656, 950175744, 243016704, 1012909568, 367228160, 480038528, 871254976, 736821536, 739336016, 827941000, 204835532, 984768942, 270849439 - ], - [ - 536870912, 268435456, 671088640, 469762048, 771751936, 385875968, 914358272, 700448768, 60817408, 590348288, 832045056, 379846656, 480378880, 693043200, 402751488, 604094464, 436314112, 620859392, 260163584, 138480640, 484506112, 156324608, 285803648, 67933504, 1000290784, 592007216, 770518888, 357485172, 637534210, 452984835 - ], - [ - 536870912, 805306368, 402653184, 872415232, 503316480, 587202560, 679477248, 171966464, 106954752, 439353344, 946339840, 82575360, 607780864, 233242624, 389316608, 796868608, 110125056, 712560640, 651503616, 361757696, 601417216, 323287296, 1064789632, 592306368, 715826976, 1000279856, 65071528, 871437308, 818456718, 956163521 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 838860800, 687865856, 411041792, 79691776, 627048448, 89128960, 326631424, 610009088, 581042176, 739835904, 1007517696, 526106624, 730128384, 944640000, 55805952, 1037149184, 666498560, 960250624, 468885120, 224486848, 827327968, 628628880, 56432136, 555897612, 425268878, 86819279 - ], - [ - 536870912, 268435456, 134217728, 738197504, 436207616, 285212672, 1048576000, 1035993088, 589299712, 709885952, 950534144, 73662464, 486146048, 318701568, 867532800, 169000960, 620371968, 654192640, 230004736, 756210688, 293267968, 884887296, 768878464, 430155200, 547493216, 572774768, 233018088, 331582644, 487833482, 159021519 - ], - [ - 536870912, 805306368, 939524096, 67108864, 234881024, 788529152, 343932928, 1027604480, 224395264, 504365056, 996671488, 272367616, 700055552, 426442752, 178421760, 112148480, 571301888, 1000476672, 892332032, 936184832, 25298432, 123649280, 691340672, 51897024, 251198752, 177502704, 900175144, 698430972, 397439782, 484038909 - ], - [ - 536870912, 805306368, 402653184, 603979776, 369098752, 352321536, 377487360, 658505728, 442499072, 449839104, 483917824, 214171648, 178913280, 460259328, 189038592, 493568000, 726589440, 963973120, 706959360, 875756544, 860528128, 8368384, 851278208, 891252288, 837652960, 654719728, 831055976, 534598844, 307198350, 905211461 - ], - [ - 536870912, 805306368, 402653184, 872415232, 838860800, 788529152, 444596224, 448790528, 547356672, 179306496, 845676544, 764149760, 480903168, 428277760, 329023488, 645087232, 828530688, 205172736, 194947072, 886590464, 702902784, 874928896, 78498944, 945466560, 546258976, 662830000, 524348584, 954328956, 80807054, 712528065 - ], - [ - 536870912, 805306368, 671088640, 872415232, 1040187392, 889192448, 377487360, 1027604480, 786432000, 418381824, 1004011520, 623116288, 124649472, 114753536, 155353088, 781565952, 1062690816, 830607360, 45447168, 679881728, 168498688, 165214464, 35963520, 116363840, 303447648, 123898256, 105138280, 425681052, 607089378, 758587089 - ], - [ - 536870912, 805306368, 671088640, 603979776, 1040187392, 520093696, 310378496, 549453824, 312475648, 428867584, 986185728, 145489920, 858128384, 540344320, 660832256, 837697536, 345612288, 642068480, 349870080, 8078336, 988450304, 547567872, 231718528, 533288256, 187495648, 912752624, 617883784, 848521292, 521561194, 770515897 - ], - [ - 536870912, 268435456, 134217728, 603979776, 905969664, 788529152, 8388608, 381681664, 245366784, 466616320, 904396800, 617873408, 983695360, 835911680, 82542592, 727171072, 685826048, 464539648, 211396608, 418245632, 849246720, 2408192, 433756544, 101642944, 304906848, 910094960, 787860072, 296963700, 765073514, 527310205 - ], - [ - 536870912, 268435456, 939524096, 738197504, 33554432, 16777216, 461373440, 1010827264, 362807296, 227540992, 653787136, 161218560, 833224704, 923598848, 634552320, 223395840, 328851456, 560844800, 128149504, 614059008, 99445248, 459518208, 1006235264, 941427392, 418113632, 388761232, 386041480, 612943556, 810844782, 534689691 - ], - [ - 536870912, 268435456, 671088640, 201326592, 369098752, 721420288, 562036736, 792723456, 1054867456, 632291328, 134742016, 1055129600, 611188736, 542310400, 606175232, 370262016, 173613056, 64802816, 558098432, 569988096, 898430464, 779865344, 366328448, 682057152, 437694304, 496908368, 54209512, 573844628, 899063810, 769527815 - ], - [ - 536870912, 268435456, 134217728, 603979776, 704643072, 922746880, 645922816, 725614592, 635437056, 1009778688, 585629696, 798228480, 1008336896, 97845248, 511344640, 86327296, 766746624, 597692416, 273684480, 1058546688, 232636928, 392121088, 915800960, 454200384, 108005152, 143145104, 191136648, 634637380, 340895522, 85534873 - ], - [ - 536870912, 268435456, 134217728, 67108864, 100663296, 150994944, 343932928, 264241152, 383778816, 636485632, 881328128, 657719296, 540672000, 501678080, 584679424, 980205568, 504782848, 256970752, 30996480, 904702976, 39254528, 267516160, 797528192, 884240320, 914015200, 373800816, 386468200, 695482804, 664527370, 708281605 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 503316480, 687865856, 478150656, 624951296, 861929472, 890241024, 506986496, 163315712, 814350336, 801439744, 483885056, 471842816, 164323328, 849653760, 415754240, 581317632, 993522176, 407799552, 512921216, 84538560, 502549600, 337590800, 499842184, 145011660, 331850470, 153583327 - ], - [ - 536870912, 268435456, 402653184, 603979776, 301989888, 889192448, 729808896, 188743680, 132120576, 500170752, 192413696, 654049280, 1041629184, 109379584, 946503680, 55820288, 449748992, 650760192, 487901184, 728902656, 960446976, 960617216, 585105536, 777028288, 607652960, 857490160, 382157448, 645749188, 366349542, 983941177 - ], - [ - 536870912, 805306368, 939524096, 335544320, 100663296, 956301312, 1015021568, 373293056, 501219328, 166723584, 361234432, 1052508160, 125435904, 878641152, 870350848, 753942528, 50946048, 66883584, 421263360, 779037696, 290051584, 270277888, 99336320, 359101376, 112468384, 252158512, 310685480, 951021820, 15294470, 386699273 - ], - [ - 536870912, 268435456, 671088640, 738197504, 838860800, 117440512, 998244352, 331350016, 119537664, 898629632, 566755328, 693895168, 142213120, 693567488, 81100800, 1002946560, 245178368, 693792768, 768075776, 127730688, 266015232, 780648192, 452802944, 699028672, 108968352, 876124080, 778356776, 1000241012, 805940098, 293415887 - ], - [ - 536870912, 805306368, 134217728, 201326592, 973078528, 251658240, 310378496, 1069547520, 190840832, 907018240, 1073217536, 698613760, 332005376, 784531456, 416186368, 91799552, 711303168, 715911168, 466798592, 263699456, 471716352, 542019840, 230221184, 931421248, 360349280, 441081520, 226673768, 493847484, 327793642, 1003303679 - ], - [ - 536870912, 268435456, 671088640, 469762048, 1040187392, 452984832, 914358272, 994050048, 656408576, 143654912, 146276352, 97779712, 395968512, 912326656, 112230400, 1000947712, 128770048, 112193536, 772528128, 559428608, 61086208, 30578944, 767317120, 123203008, 33489568, 265532112, 247226376, 97955844, 415184906, 234079239 - ], - [ - 536870912, 805306368, 939524096, 67108864, 503316480, 117440512, 159383552, 29360128, 639631360, 667942912, 577241088, 338427904, 212992000, 1058340864, 45580288, 946520064, 887136256, 510701568, 1064949760, 65313792, 663668224, 963527936, 102759552, 870804544, 641978080, 556652624, 271770248, 307541324, 836203630, 685453585 - ], - [ - 536870912, 805306368, 939524096, 335544320, 301989888, 251658240, 931135488, 549453824, 392167424, 313524224, 272105472, 238288896, 640811008, 698023936, 570851328, 615071744, 370991104, 1030746112, 5588992, 369284096, 232915456, 705831168, 982186112, 317667136, 76851680, 727896048, 72582120, 531335932, 461263206, 339605689 - ], - [ - 536870912, 805306368, 134217728, 201326592, 301989888, 285212672, 411041792, 37748736, 295698432, 324009984, 225968128, 764674048, 827981824, 912982016, 404914176, 905887744, 578330624, 102051840, 848967680, 822852608, 177360384, 729158400, 155476352, 367222336, 161360096, 1028139824, 475803880, 155674428, 697067242, 897464383 - ], - [ - 536870912, 268435456, 402653184, 67108864, 570425344, 587202560, 847249408, 138412032, 1063256064, 384827392, 457703424, 946601984, 560332800, 809304064, 1031700480, 147439616, 833396736, 1019727872, 367802368, 765854720, 505190912, 24039168, 498083200, 111712576, 1054683360, 21932912, 1017134472, 609324356, 840544998, 636842097 - ], - [ - 536870912, 805306368, 671088640, 469762048, 570425344, 218103808, 142606336, 952107008, 698351616, 783286272, 919076864, 404488192, 100007936, 654114816, 329744384, 761544704, 329474048, 735531008, 84674560, 344953856, 380177920, 93157632, 5147520, 889796416, 977053536, 470170352, 416574344, 518727500, 747261802, 337362679 - ], - [ - 536870912, 805306368, 134217728, 738197504, 33554432, 922746880, 343932928, 113246208, 681574400, 328204288, 303562752, 745275392, 1057882112, 207290368, 937984000, 289783808, 887824384, 337670144, 156248064, 817454080, 620622336, 999777024, 301425024, 885401664, 139396512, 968523280, 983086632, 279725404, 78543370, 625708807 - ], - [ - 536870912, 268435456, 671088640, 738197504, 905969664, 587202560, 494927872, 4194304, 467664896, 902823936, 299368448, 437518336, 5373952, 851247104, 439255040, 498221056, 476897280, 309751808, 501626880, 316652544, 731539968, 198216448, 249057408, 429185984, 252871968, 47998160, 213803656, 168549572, 870868906, 404551707 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 771751936, 922746880, 864026624, 289406976, 123731968, 1034944512, 1036517376, 395051008, 934412288, 124059648, 1064206336, 49168384, 883843072, 676311040, 952014848, 739757056, 824926720, 147869440, 158864256, 113552192, 1056920800, 150428496, 903582088, 242816068, 222674794, 1002343455 - ], - [ - 536870912, 805306368, 134217728, 738197504, 973078528, 318767104, 1065353216, 759169024, 350224384, 829423616, 755499008, 246153216, 360054784, 69140480, 251822080, 802996224, 8298496, 783544320, 208971776, 46363648, 603729408, 330236160, 900353664, 165724352, 871370912, 852083600, 227319464, 187052700, 222754858, 469124695 - ], - [ - 536870912, 268435456, 402653184, 469762048, 234881024, 587202560, 1031798784, 130023424, 991952896, 877658112, 769130496, 533987328, 580255744, 735117312, 253263872, 1047838720, 1049026560, 401174528, 20813824, 1059793920, 465296896, 717367552, 797440640, 392766144, 8130720, 575374768, 487299080, 728378372, 341532166, 3336455 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 838860800, 822083584, 343932928, 826277888, 752877568, 544210944, 459800576, 43778048, 1035075584, 636157952, 838828032, 304136192, 475013120, 339292160, 455473152, 1062648832, 891135488, 963823872, 80457344, 808378304, 936942624, 349473328, 620708392, 815808308, 974219938, 324606459 - ], - [ - 536870912, 805306368, 939524096, 335544320, 570425344, 16777216, 796917760, 708837376, 509607936, 212860928, 601358336, 130809856, 49414144, 481886208, 352157696, 862699520, 286629888, 952012800, 218810368, 765811712, 593887744, 516332288, 223750528, 1054741696, 632969568, 343714832, 833331720, 297011980, 984539534, 465717445 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 301989888, 318767104, 327155712, 490733568, 178257920, 611319808, 491257856, 821821440, 929693696, 94437376, 904953856, 722059264, 366862336, 475697152, 21600256, 855383040, 476785152, 706786560, 984691584, 849982016, 573373408, 475251024, 991289352, 568758276, 75733006, 791485455 - ], - [ - 536870912, 805306368, 134217728, 872415232, 905969664, 251658240, 763363328, 784334848, 828375040, 986710016, 182976512, 302252032, 507379712, 56557568, 59670528, 208060416, 1055088640, 446484480, 618899456, 798770176, 207876608, 568137984, 121773952, 640475328, 89896160, 464647952, 137942248, 619521820, 238779626, 610362129 - ], - [ - 536870912, 268435456, 402653184, 603979776, 301989888, 989855744, 1048576000, 1061158912, 375390208, 34603008, 115867648, 197918720, 417202176, 519766016, 996769792, 1040990208, 1006624768, 361410560, 319866880, 929590272, 912896, 788461824, 638249856, 1003588544, 466102048, 364654992, 52896424, 1063207764, 742125070, 281671949 - ], - [ - 536870912, 268435456, 134217728, 872415232, 1040187392, 1023410176, 763363328, 876609536, 10485760, 999292928, 749207552, 509870080, 331481088, 508231680, 503283712, 490061824, 1007378432, 73338880, 1025783808, 769897472, 152815104, 473373440, 841065344, 89217216, 1053332704, 898963312, 597308136, 519445620, 708847978, 765538489 - ], - [ - 536870912, 805306368, 402653184, 201326592, 100663296, 654311424, 394264576, 230686720, 748683264, 303038464, 295174144, 747372544, 924975104, 1022820352, 846757888, 360529920, 994746368, 236146688, 448759808, 936231936, 381940224, 432896, 479206784, 282650688, 74228384, 793983600, 39832872, 935070012, 611045902, 63146767 - ], - [ - 536870912, 805306368, 402653184, 201326592, 100663296, 352321536, 645922816, 884998144, 257949696, 261095424, 946339840, 356253696, 635043840, 660537344, 997228544, 28917760, 83140608, 789991424, 16619520, 909777920, 386880000, 871972096, 257259392, 937932736, 990187168, 493828400, 854078248, 402518012, 666581006, 38751247 - ], - [ - 536870912, 268435456, 939524096, 67108864, 33554432, 117440512, 75497472, 247463936, 622854144, 592445440, 426246144, 207355904, 679608320, 841285632, 1062633472, 755679232, 344563712, 523063296, 691787776, 693179392, 845733376, 920450304, 658729088, 377783360, 289859936, 453145040, 275050120, 683058500, 763002862, 733057169 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 436207616, 822083584, 260046848, 71303168, 861929472, 842006528, 137887744, 1040973824, 129368064, 637337600, 766410752, 992034816, 55664640, 1057525760, 531916800, 385526784, 799713792, 832726784, 697725824, 120453824, 31953376, 863339632, 492477320, 540743364, 353033186, 833762175 - ], - [ - 536870912, 805306368, 671088640, 335544320, 100663296, 855638016, 612368384, 717225984, 304087040, 95420416, 1041760256, 1042546688, 770310144, 373227520, 707559424, 522633216, 780722176, 386732032, 471263232, 659627008, 948552192, 1007492864, 77019264, 529644352, 531138784, 775739376, 886036584, 425046204, 634581634, 61581385 - ], - [ - 536870912, 805306368, 939524096, 738197504, 905969664, 486539264, 662700032, 398458880, 987758592, 1005584384, 446169088, 356253696, 959315968, 212402176, 776306688, 358858752, 861822976, 754003968, 504932352, 746429440, 697200128, 830050048, 256740224, 292984512, 687186144, 224129520, 615728648, 341299980, 233145742, 238168523 - ], - [ - 536870912, 268435456, 402653184, 872415232, 838860800, 520093696, 696254464, 750780416, 1033895936, 464519168, 113770496, 409206784, 978714624, 318308352, 258768896, 823312384, 39755776, 943460352, 520796160, 1038298112, 452384256, 935970048, 551848320, 1041689664, 857309216, 20727344, 193621512, 1067706628, 370597766, 253356365 - ], - [ - 536870912, 268435456, 939524096, 469762048, 100663296, 452984832, 276824064, 121634816, 631242752, 265289728, 315097088, 797179904, 623771648, 695533568, 695631872, 312000512, 546070528, 223080448, 833304576, 215692288, 1061331456, 38734080, 1002755200, 604959552, 65359520, 522160432, 1062046856, 464205636, 970609838, 281244727 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 33554432, 620756992, 914358272, 71303168, 664797184, 883949568, 182976512, 1021575168, 825360384, 27852800, 80052224, 1027751936, 832626688, 531730432, 325675008, 388256768, 642920960, 871961856, 733843840, 1002321216, 289290784, 662617104, 769634824, 334451980, 524775810, 553821519 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 167772160, 989855744, 125829120, 4194304, 392167424, 632291328, 272105472, 275513344, 790233088, 917831680, 864518144, 913719296, 19881984, 485724160, 533854208, 856247296, 345319936, 332852992, 557816704, 484138176, 664071136, 408374672, 58708360, 213590988, 262473834, 858725727 - ], - [ - 536870912, 268435456, 402653184, 872415232, 167772160, 251658240, 478150656, 708837376, 530579456, 187695104, 1062731776, 624689152, 45481984, 530513920, 685473792, 857817088, 695328768, 217657344, 269322240, 955173888, 690146816, 481086208, 425703040, 356204096, 196147872, 588820112, 329006248, 604498324, 319202350, 730213593 - ], - [ - 536870912, 268435456, 671088640, 872415232, 436207616, 721420288, 998244352, 884998144, 333447168, 709885952, 974651392, 815529984, 802291712, 735772672, 100630528, 197181440, 576741376, 495988736, 645408768, 873223168, 757801472, 177726720, 620096384, 57138496, 572319392, 127064752, 830106792, 227453876, 48842018, 653616121 - ], - [ - 536870912, 268435456, 134217728, 469762048, 838860800, 922746880, 612368384, 197132288, 148897792, 164626432, 864550912, 608960512, 1029308416, 83558400, 319520768, 640925696, 963059712, 366522368, 444860416, 624405504, 1094144, 342463744, 488409984, 722603968, 760641952, 872506736, 1040243112, 218174836, 260075946, 490850675 - ], - [ - 536870912, 268435456, 402653184, 335544320, 637534208, 83886080, 679477248, 717225984, 740294656, 1028653056, 722993152, 146014208, 939917312, 237961216, 255033344, 124338176, 847044608, 258691072, 62699520, 181066752, 44956160, 909333248, 367603072, 935189312, 1019888608, 531366736, 179462632, 422091860, 513633902, 689625105 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 33554432, 822083584, 713031680, 297795584, 933232640, 311427072, 362283008, 428081152, 940441600, 928710656, 1026392064, 142786560, 944283648, 209547264, 62642176, 769408000, 237718016, 700840704, 569318784, 522970688, 323237344, 942546128, 344682600, 64226964, 481767306, 663703883 - ], - [ - 536870912, 268435456, 134217728, 201326592, 100663296, 956301312, 461373440, 549453824, 639631360, 653262848, 1009254400, 40632320, 852885504, 729088000, 506626048, 931086336, 718921728, 642052096, 884729856, 329485312, 172457472, 198042880, 652627328, 175949376, 305073632, 1036067952, 664820616, 825356100, 881450594, 433977139 - ], - [ - 536870912, 268435456, 134217728, 67108864, 973078528, 150994944, 142606336, 851443712, 912261120, 355467264, 376963072, 857997312, 859701248, 732495872, 632061952, 327303168, 163782656, 492982272, 909346816, 830186496, 774350336, 658361088, 925603200, 200251840, 195149856, 80742768, 101256712, 511524612, 705379202, 520074945 - ], - [ - 536870912, 268435456, 671088640, 335544320, 704643072, 83886080, 562036736, 297795584, 882900992, 506462208, 403177472, 877920256, 652869632, 644153344, 954368000, 19939328, 76029952, 940838912, 1032488960, 603282432, 442115584, 489482496, 861298560, 302675264, 624188192, 913992464, 224188296, 557787460, 676232490, 900104725 - ], - [ - 536870912, 268435456, 939524096, 872415232, 570425344, 150994944, 25165824, 809500672, 446693376, 340787200, 739770368, 15466496, 251527168, 403374080, 991526912, 913129472, 406740992, 745254912, 791205888, 742720512, 201059840, 818996992, 467251072, 957105728, 1016023456, 864237456, 873269288, 923768532, 113503750, 959244041 - ], - [ - 536870912, 805306368, 671088640, 603979776, 973078528, 16777216, 813694976, 834666496, 589299712, 600834048, 383254528, 88342528, 599392256, 849149952, 645890048, 149307392, 331587584, 927469568, 217966592, 290337792, 701396480, 202360064, 1026481280, 1006585280, 665228192, 304256144, 574139016, 45383884, 288509738, 1061212505 - ], - [ - 536870912, 805306368, 402653184, 872415232, 973078528, 16777216, 310378496, 725614592, 1012924416, 164626432, 586678272, 863240192, 347471872, 811663360, 936476672, 33079296, 351641600, 393728000, 641796096, 283186176, 26319360, 957891328, 962961024, 544153536, 606343072, 588152752, 477470728, 221761548, 278988806, 108073997 - ], - [ - 536870912, 805306368, 939524096, 738197504, 301989888, 452984832, 696254464, 675282944, 102760448, 835715072, 1045954560, 914096128, 439484416, 139526144, 504987648, 610123776, 367222784, 1057591296, 451237888, 1068403712, 869474816, 383787264, 825300608, 577248960, 546636256, 510044304, 416765960, 738167820, 130720270, 96329995 - ], - [ - 536870912, 805306368, 134217728, 603979776, 905969664, 687865856, 58720256, 88080384, 216006656, 97517568, 668467200, 83623936, 123076608, 337051648, 32931840, 262586368, 155181056, 924995584, 480581632, 753533952, 748727808, 682625280, 810076032, 558180672, 918214304, 339281936, 464279208, 776980508, 1028372138, 965842965 - ], - [ - 536870912, 805306368, 402653184, 335544320, 436207616, 452984832, 327155712, 339738624, 824180736, 74448896, 906493952, 537657344, 100270080, 389349376, 39813120, 1030995968, 234364928, 1011191808, 232175616, 171961344, 1050814976, 557944064, 329383296, 11545408, 350749408, 454895632, 497217416, 381782604, 98694502, 1049632341 - ], - [ - 536870912, 268435456, 671088640, 67108864, 301989888, 150994944, 1031798784, 390070272, 417333248, 655360000, 749207552, 515112960, 680919040, 887554048, 656375808, 56803328, 898686976, 627666944, 160806912, 732369920, 738102784, 510810368, 339241344, 341688512, 1061396320, 975181008, 1018218344, 693727444, 403468642, 889912789 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 704643072, 150994944, 192937984, 88080384, 459276288, 869269504, 783810560, 971767808, 61997056, 84738048, 656637952, 232079360, 815685632, 111022080, 362752000, 522177536, 769606144, 436139776, 944737408, 782748352, 1018306528, 495844688, 686025864, 611637964, 930002914, 160919903 - ], - [ - 536870912, 268435456, 671088640, 872415232, 100663296, 452984832, 243269632, 952107008, 161480704, 498073600, 645398528, 737935360, 212205568, 18808832, 163807232, 236240896, 265445376, 954060800, 1071106048, 499571712, 84888064, 436932352, 932241024, 780777280, 778391456, 965441552, 584156584, 224966420, 817183522, 384028761 - ], - [ - 536870912, 268435456, 671088640, 335544320, 905969664, 721420288, 645922816, 616562688, 174063616, 355467264, 495452160, 894697472, 55443456, 679936000, 359890944, 174899200, 416505856, 935153664, 715835392, 704748544, 419523072, 327201024, 1027613824, 1042322112, 277975392, 609762192, 422411112, 569592468, 195936226, 590497873 - ], - [ - 536870912, 805306368, 402653184, 67108864, 570425344, 285212672, 511705088, 725614592, 480247808, 275775488, 167247872, 892600320, 541982720, 674824192, 148209664, 564051968, 154214400, 744001536, 667174912, 620155904, 850217472, 929819904, 899659648, 53589440, 559488160, 524675568, 1018612232, 562834700, 316348294, 193455553 - ], - [ - 536870912, 268435456, 671088640, 469762048, 838860800, 788529152, 880803840, 1002438656, 958398464, 831520768, 1042808832, 435421184, 790495232, 938409984, 909606912, 379240448, 954736640, 726970368, 969885696, 388410368, 359862784, 423365376, 475733888, 273242816, 243659616, 528991888, 547560296, 393484948, 937353570, 542100883 - ], - [ - 536870912, 805306368, 671088640, 872415232, 436207616, 251658240, 394264576, 423624704, 144703488, 978321408, 790102016, 1062469632, 900333568, 919273472, 502956032, 315867136, 120479744, 87601152, 885377024, 886240256, 372145664, 800594688, 17127808, 682785088, 849326048, 634425520, 844713960, 99934396, 888825826, 340944049 - ], - [ - 536870912, 268435456, 402653184, 872415232, 167772160, 654311424, 310378496, 843055104, 56623104, 441450496, 8912896, 802947072, 38141952, 970784768, 323387392, 710787072, 713498624, 620597248, 880154624, 495256576, 810781184, 698818304, 1053579392, 774806336, 328296032, 103410032, 489445512, 87989060, 284780134, 317057405 - ], - [ - 536870912, 805306368, 134217728, 201326592, 570425344, 520093696, 494927872, 448790528, 270532608, 984612864, 957874176, 1006895104, 411172864, 254738432, 783319040, 790216704, 84156416, 872640512, 896460800, 651203584, 46791168, 206337792, 462300288, 306246976, 878820576, 131161648, 440961640, 269305980, 586082314, 521180175 - ], - [ - 536870912, 268435456, 939524096, 469762048, 905969664, 452984832, 998244352, 926941184, 606076928, 858783744, 480772096, 214695936, 898236416, 560660480, 658210816, 260194304, 190226432, 804851712, 150259712, 866096128, 296021504, 447131392, 925943424, 648567744, 432927136, 151760880, 464179624, 794558452, 588462502, 328154099 - ], - [ - 536870912, 268435456, 134217728, 335544320, 369098752, 520093696, 75497472, 390070272, 60817408, 621805568, 731381760, 538181632, 991559680, 391708672, 678723584, 384450560, 410099712, 266874880, 1039972352, 132547584, 524225024, 847996160, 796970112, 365004480, 65097120, 909121616, 264866312, 388769028, 983559298, 278591173 - ], - [ - 536870912, 268435456, 134217728, 872415232, 234881024, 855638016, 360710144, 717225984, 111149056, 1049624576, 642252800, 861143040, 181534720, 335216640, 488603648, 768983040, 429088768, 228233216, 741328896, 495748096, 13566464, 234708736, 670457728, 219215808, 461905504, 645202288, 428080232, 680726132, 152767466, 309259705 - ], - [ - 536870912, 268435456, 939524096, 469762048, 771751936, 452984832, 427819008, 683671552, 81788928, 1041235968, 230162432, 43253760, 856031232, 711000064, 156270592, 513392640, 333766656, 493842432, 590206976, 932334592, 644318720, 145835776, 168411264, 186488256, 31148192, 534410800, 752541704, 291139588, 194729998, 981109767 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 369098752, 754974720, 444596224, 515899392, 119537664, 613416960, 566755328, 656146432, 54657024, 670892032, 947027968, 56934400, 604463104, 1021997056, 252774400, 596190208, 738049536, 108248320, 711264896, 344329024, 422248032, 1068612432, 56158856, 332708676, 48141934, 746581855 - ], - [ - 536870912, 268435456, 134217728, 738197504, 301989888, 788529152, 763363328, 289406976, 257949696, 579862528, 935854080, 562298880, 372113408, 629342208, 813268992, 809287680, 716382208, 369160192, 16869376, 411063296, 1069581824, 564158720, 330307456, 934921920, 630995040, 251905616, 817465832, 874353044, 71519754, 1020790031 - ], - [ - 536870912, 268435456, 402653184, 67108864, 369098752, 654311424, 125829120, 884998144, 471859200, 294649856, 344457216, 985399296, 210370560, 1042481152, 672104448, 445464576, 408051712, 582438912, 535308288, 97383424, 716325376, 34007808, 678544256, 700026304, 350521120, 241091312, 329557288, 952072692, 622153390, 673644597 - ], - [ - 536870912, 268435456, 134217728, 335544320, 637534208, 855638016, 612368384, 843055104, 216006656, 1051721728, 359137280, 450625536, 492175360, 995295232, 858882048, 313049088, 503111680, 516395008, 749447168, 261438464, 379221504, 951850240, 145130112, 257603264, 10346912, 364345936, 736279848, 22603156, 183871498, 32128001 - ], - [ - 536870912, 268435456, 939524096, 201326592, 369098752, 184549376, 528482304, 406847488, 362807296, 802160640, 115867648, 892600320, 431882240, 608239616, 731938816, 282181632, 57171968, 812953600, 413030400, 206699520, 547897856, 529886464, 871308928, 669615936, 531984800, 562033136, 740327432, 345096196, 952655886, 413446147 - ], - [ - 536870912, 805306368, 939524096, 872415232, 704643072, 822083584, 964689920, 104857600, 1042284544, 11534336, 133693440, 150208512, 86638592, 458424320, 635863040, 653082624, 152035328, 17838080, 503904256, 732746752, 934270464, 845176576, 1066520192, 113887040, 1028517856, 436138032, 801651176, 13479740, 230651750, 350824561 - ], - [ - 536870912, 805306368, 939524096, 201326592, 167772160, 218103808, 612368384, 943718400, 576716800, 1007681536, 172490752, 342097920, 851050496, 609550336, 696483840, 468238336, 534110208, 71536640, 390662144, 954528768, 1056598528, 3495680, 311685760, 941746496, 393316256, 752457104, 762092168, 658394444, 993985966, 960472723 - ], - [ - 536870912, 268435456, 939524096, 67108864, 637534208, 922746880, 612368384, 373293056, 618659840, 1055916032, 323485696, 254017536, 664403968, 664993792, 705658880, 177225728, 905535488, 864866304, 281978880, 338734080, 904441344, 188051712, 958546560, 961444544, 603008224, 180992944, 283454184, 616261300, 510805606, 647441781 - ], - [ - 536870912, 268435456, 671088640, 201326592, 436207616, 452984832, 830472192, 759169024, 903872512, 667942912, 336068608, 1036255232, 512098304, 362217472, 557809664, 717930496, 294952960, 751792128, 70395904, 958948352, 78982656, 834580736, 1024182144, 280286144, 532630496, 403325648, 741663720, 41936596, 707456482, 583329751 - ], - [ - 536870912, 805306368, 134217728, 738197504, 167772160, 318767104, 92274688, 96468992, 203423744, 420478976, 642252800, 369885184, 900071424, 803667968, 218529792, 968278016, 623878144, 4976640, 745629696, 272122880, 758508032, 957598464, 892691328, 756187584, 456419744, 403851408, 129296808, 190023836, 198560170, 463648919 - ], - [ - 536870912, 805306368, 402653184, 469762048, 637534208, 587202560, 1065353216, 868220928, 811597824, 334495744, 354942976, 639369216, 446562304, 80281600, 153976832, 1045872640, 1038475264, 796569600, 531814400, 882875392, 331935232, 346897152, 345404288, 923074368, 332064736, 918221168, 47386120, 1072597772, 815868806, 873571143 - ], - [ - 536870912, 268435456, 402653184, 872415232, 167772160, 620756992, 494927872, 507510784, 425721856, 487587840, 465043456, 249823232, 261750784, 1018494976, 180518912, 201441280, 771825664, 922783744, 209750016, 163625984, 572643840, 435169024, 417864320, 205264576, 477011872, 681025808, 949097096, 156854980, 515138982, 331486749 - ], - [ - 536870912, 268435456, 402653184, 335544320, 33554432, 251658240, 578813952, 784334848, 1063256064, 770703360, 352845824, 627834880, 512884736, 6225920, 526221312, 192561152, 327376896, 870789120, 270084096, 450202624, 131469824, 485573888, 646539392, 674045376, 884128288, 328150384, 461714088, 634339508, 19251342, 266260929 - ], - [ - 536870912, 805306368, 671088640, 603979776, 100663296, 654311424, 25165824, 381681664, 379584512, 510656512, 258473984, 557056000, 638451712, 130744320, 99385344, 695386112, 121724928, 408981504, 80758784, 857216000, 257722880, 565918464, 914705024, 38256320, 609191904, 1059809872, 830244200, 462143644, 369952898, 1046630853 - ], - [ - 536870912, 805306368, 939524096, 738197504, 704643072, 822083584, 478150656, 1019215872, 908066816, 680525824, 239599616, 620494848, 377356288, 890044416, 566722560, 38322176, 1056759808, 528388096, 93186048, 923153408, 90746368, 183350528, 771109504, 391129920, 166221664, 1043165104, 265730696, 968970060, 480276846, 928104123 - ], - [ - 536870912, 268435456, 939524096, 469762048, 436207616, 788529152, 847249408, 180355072, 698351616, 951058432, 326631424, 600571904, 14811136, 887422976, 973504512, 266518528, 375742464, 147296256, 977491968, 886318080, 884915712, 722436352, 1056421760, 704276672, 700046048, 577629008, 475246984, 563977668, 751463278, 310408855 - ], - [ - 536870912, 268435456, 134217728, 738197504, 637534208, 620756992, 343932928, 297795584, 786432000, 466616320, 1048051712, 710148096, 200146944, 485556224, 1061715968, 234635264, 818110464, 717893632, 135702528, 98919424, 646393344, 482109184, 501425792, 955912128, 373207200, 394916464, 161302536, 1003688964, 617801218, 726872843 - ], - [ - 536870912, 268435456, 402653184, 201326592, 436207616, 620756992, 578813952, 138412032, 559939584, 397410304, 394788864, 208928768, 819068928, 19333120, 775258112, 1018314752, 538419200, 670904320, 782743552, 16096256, 462644736, 633827584, 977562240, 983287744, 938680032, 351696816, 730690664, 613331060, 219277966, 228165575 - ], - [ - 536870912, 268435456, 134217728, 67108864, 33554432, 452984832, 780140544, 960495616, 1038090240, 298844160, 633864192, 184811520, 79560704, 605356032, 139886592, 417415168, 978362368, 654856192, 1009055744, 642737152, 556536320, 493492992, 669123712, 403136832, 820577952, 586494896, 654736520, 208160068, 146093218, 812071089 - ], - [ - 536870912, 805306368, 134217728, 67108864, 369098752, 218103808, 780140544, 507510784, 278921216, 642777088, 246939648, 431751168, 426901504, 558039040, 1045069824, 792641536, 274259968, 390942720, 1033549824, 608603136, 629530112, 881765120, 1066488192, 148381760, 873306016, 196771120, 408375208, 765223228, 107104682, 115070525 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 973078528, 50331648, 1065353216, 180355072, 782237696, 1028653056, 93847552, 636747776, 354287616, 335347712, 97746944, 860241920, 1009344512, 215814144, 121812992, 922668032, 785194496, 1035620608, 729538688, 266059712, 428587040, 529705648, 178767496, 840524492, 590620330, 700339327 - ], - [ - 536870912, 805306368, 939524096, 335544320, 33554432, 922746880, 8388608, 213909504, 1038090240, 219152384, 889716736, 971767808, 802553856, 766705664, 642285568, 340541440, 1038573568, 155955200, 305997824, 205519872, 936247808, 290961664, 141782912, 36281536, 874312992, 206565584, 991402152, 877843740, 291013126, 38074633 - ], - [ - 536870912, 268435456, 671088640, 469762048, 771751936, 989855744, 226492416, 1002438656, 631242752, 9437184, 739770368, 808189952, 275120128, 873398272, 726368256, 300466176, 277159936, 755159040, 352143360, 656294912, 1066543616, 1038483200, 162678656, 95760704, 965450016, 1019827344, 894720808, 251395988, 337764002, 89155027 - ], - [ - 536870912, 805306368, 939524096, 603979776, 436207616, 553648128, 1048576000, 926941184, 396361728, 200278016, 315097088, 20709376, 339607552, 291569664, 647069696, 978960384, 946151424, 400216064, 360318976, 839611392, 713226752, 1017044224, 789639040, 613953088, 17090016, 491395056, 690135048, 359534604, 953722894, 19227657 - ], - [ - 536870912, 805306368, 134217728, 201326592, 100663296, 922746880, 276824064, 633339904, 169869312, 1041235968, 284688384, 1059848192, 95551488, 395771904, 1069580288, 52543488, 495984640, 800608256, 567117824, 369310720, 205433344, 1073086208, 227434880, 559699776, 674934432, 666049776, 446123304, 373299388, 224428042, 619823119 - ], - [ - 536870912, 268435456, 939524096, 738197504, 33554432, 989855744, 25165824, 801112064, 1012924416, 116391936, 1033371648, 574357504, 158203904, 555286528, 830242816, 911196160, 550002688, 557092864, 104470528, 584215552, 62320128, 973372160, 348265344, 329196224, 914479840, 1010890992, 278982152, 387021572, 380148622, 415621835 - ], - [ - 536870912, 268435456, 671088640, 469762048, 570425344, 922746880, 8388608, 675282944, 807403520, 831520768, 688390144, 520880128, 487194624, 161021952, 126124032, 197607424, 91480064, 845975552, 993687552, 297837568, 903885312, 712009984, 1048105088, 183836224, 490701664, 1002955216, 1030900232, 107793668, 87745162, 79722311 - ], - [ - 536870912, 805306368, 671088640, 469762048, 771751936, 486539264, 8388608, 171966464, 106954752, 714080256, 390594560, 181141504, 65667072, 547291136, 392200192, 470859776, 873046016, 1043173376, 272340992, 741862400, 1039980032, 76718336, 850118528, 394198720, 825275424, 108561712, 1018535336, 392079100, 734109698, 312578059 - ], - [ - 536870912, 268435456, 671088640, 469762048, 301989888, 989855744, 645922816, 608174080, 1050673152, 758120448, 46661632, 952369152, 423231488, 275841024, 434667520, 590692352, 252895232, 304451584, 850089984, 193557504, 769999360, 734668032, 467227008, 427635264, 311852064, 876603600, 522967048, 826815492, 50700810, 911914247 - ], - [ - 536870912, 805306368, 134217728, 603979776, 301989888, 1023410176, 880803840, 1019215872, 966787072, 888143872, 376963072, 373555200, 315752448, 419627008, 172654592, 257343488, 670162944, 301494272, 486807552, 674495488, 856832512, 606267136, 175827072, 76472128, 390404960, 676505840, 650306408, 208282876, 484852074, 1030356981 - ], - [ - 536870912, 805306368, 939524096, 335544320, 234881024, 687865856, 260046848, 297795584, 715128832, 105906176, 754450432, 538181632, 1029832704, 255000576, 499810304, 752828416, 171827200, 449744896, 77944832, 564814848, 380570112, 114609920, 960734592, 992192064, 273886432, 121325808, 997618920, 122760444, 1064926950, 332784633 - ], - [ - 536870912, 805306368, 671088640, 469762048, 234881024, 117440512, 729808896, 918552576, 824180736, 47185920, 344457216, 915144704, 600440832, 176750592, 697139200, 1011564544, 776593408, 296611840, 303790080, 662748160, 549471744, 35713280, 995207808, 726229568, 724305248, 1012552912, 434128392, 753987852, 165259914, 113599047 - ], - [ - 536870912, 805306368, 939524096, 201326592, 905969664, 1023410176, 746586112, 482344960, 23068672, 1051721728, 742916096, 203685888, 603324416, 266141696, 689668096, 969850880, 617668608, 192540672, 606881792, 141734912, 419151360, 633210624, 16332672, 795717440, 1012109216, 459976816, 484884872, 574954572, 1053230638, 752097331 - ], - [ - 536870912, 268435456, 134217728, 603979776, 33554432, 922746880, 260046848, 222298112, 434110464, 363855872, 462946304, 94633984, 951975936, 209256448, 286556160, 296108032, 404496384, 814387200, 734984192, 289463296, 669039104, 212866816, 85582208, 845487808, 345974304, 48791152, 194812424, 63604484, 724507010, 443663049 - ], - [ - 536870912, 805306368, 134217728, 469762048, 973078528, 1056964608, 545259520, 658505728, 291504128, 347078656, 74973184, 742129664, 878051328, 482017280, 967081984, 463192064, 905289728, 26390528, 672229376, 568957952, 420851200, 165849344, 348781184, 910541888, 157977888, 292338896, 668975016, 194925724, 746583178, 311352651 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 973078528, 788529152, 394264576, 88080384, 601882624, 829423616, 285736960, 883163136, 672792576, 36110336, 308379648, 825311232, 845684736, 722743296, 632465408, 185779200, 226694656, 335246592, 525808768, 23688128, 378873184, 938660336, 57905128, 62006068, 236068870, 218312715 - ], - [ - 536870912, 805306368, 671088640, 872415232, 234881024, 385875968, 360710144, 104857600, 148897792, 1037041664, 46661632, 418119680, 920780800, 948895744, 598507520, 713211904, 497016832, 4542464, 404621312, 503706624, 218025472, 433388800, 389520768, 62478016, 840186912, 899106288, 612999592, 537727804, 590552450, 239572673 - ], - [ - 536870912, 805306368, 402653184, 738197504, 503316480, 184549376, 1031798784, 4194304, 1059061760, 391118848, 318242816, 585367552, 377356288, 630784000, 244678656, 970375168, 746872832, 311390208, 1022466048, 90770432, 234631680, 321569024, 472819328, 98586048, 1001407008, 701082480, 166580744, 796094732, 937123462, 893792715 - ], - [ - 536870912, 805306368, 671088640, 67108864, 301989888, 184549376, 310378496, 1002438656, 6291456, 32505856, 688390144, 108265472, 908460032, 653066240, 749436928, 95830016, 890544128, 961957888, 170145792, 935306240, 971068928, 414281472, 984126848, 65334592, 215890720, 43020528, 242834312, 784102988, 1060356266, 297424561 - ], - [ - 536870912, 805306368, 671088640, 603979776, 301989888, 218103808, 327155712, 440401920, 329252864, 384827392, 936902656, 61603840, 242876416, 816644096, 385581056, 241975296, 630890496, 285003776, 5425152, 844647424, 921442816, 727437568, 194784640, 985837504, 93343968, 424242192, 241446280, 148811724, 336744682, 49835033 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 771751936, 788529152, 696254464, 364904448, 819986432, 821035008, 940048384, 1024196608, 1018822656, 731316224, 247234560, 538132480, 659169280, 404623360, 1064323072, 382243840, 778940928, 613073152, 201213056, 268459456, 671157536, 604078896, 302115240, 16813820, 109087886, 1010862531 - ], - [ - 536870912, 805306368, 671088640, 67108864, 100663296, 1023410176, 964689920, 339738624, 102760448, 948961280, 400031744, 144441344, 582615040, 983629824, 156336128, 800669696, 153886720, 259141632, 891611136, 144067584, 491971072, 330600704, 240071808, 776943296, 508500192, 911192016, 843980808, 877604876, 156198922, 818809857 - ], - [ - 536870912, 268435456, 402653184, 738197504, 838860800, 587202560, 142606336, 767557632, 547356672, 380633088, 1054343168, 586416128, 779223040, 722141184, 735019008, 1017462784, 452665344, 863449088, 348153856, 790662144, 905024000, 246996736, 224679552, 5970496, 851869408, 1016625648, 823446760, 279156468, 373486190, 353566911 - ], - [ - 536870912, 268435456, 939524096, 738197504, 771751936, 721420288, 578813952, 884998144, 723517440, 317718528, 92798976, 157548544, 506068992, 356843520, 677019648, 453820416, 715120640, 639086592, 418625536, 60302336, 129818112, 217554176, 10713472, 379701568, 380663456, 661231120, 355768712, 823294276, 759811758, 608481819 - ], - [ - 536870912, 805306368, 402653184, 603979776, 503316480, 1023410176, 1031798784, 281018368, 492830720, 103809024, 87556096, 672923648, 709754880, 355139584, 274235392, 573390848, 225959936, 976670720, 613914624, 658916352, 755894784, 327941376, 931701376, 912559168, 250805024, 599042960, 901436328, 45193948, 108653070, 12397829 - ], - [ - 536870912, 805306368, 939524096, 469762048, 301989888, 754974720, 578813952, 423624704, 870318080, 967835648, 845676544, 827588608, 532545536, 112001024, 160661504, 192856064, 730619904, 469946368, 604456960, 501343232, 917598720, 99140352, 378823552, 656358976, 570205216, 550174000, 285456776, 914819404, 1017191854, 424735863 - ], - [ - 536870912, 805306368, 402653184, 469762048, 771751936, 285212672, 578813952, 322961408, 559939584, 797966336, 904396800, 469499904, 700841984, 482934784, 613253120, 629063680, 796778496, 126283776, 690571264, 358380544, 1031219712, 424698624, 407410816, 315456832, 211689696, 816634032, 244271624, 1032082188, 433205382, 670234951 - ], - [ - 536870912, 805306368, 134217728, 335544320, 301989888, 117440512, 931135488, 197132288, 861929472, 204472320, 801636352, 595329024, 24772608, 929366016, 532643840, 218841088, 369893376, 512970752, 185194496, 60558336, 478852608, 953007872, 359830400, 796508992, 116686176, 128424464, 768597384, 627187788, 564134114, 835824213 - ], - [ - 536870912, 268435456, 671088640, 335544320, 234881024, 520093696, 260046848, 977272832, 60817408, 412090368, 26738688, 309592064, 381550592, 810745856, 303661056, 573947904, 740286464, 742641664, 675350528, 379667456, 772820480, 1062805248, 705974656, 684608576, 628765024, 589588816, 616967912, 1522196, 422465026, 977936129 - ], - [ - 536870912, 805306368, 939524096, 738197504, 771751936, 721420288, 914358272, 20971520, 195035136, 1018167296, 134742016, 365690880, 584187904, 432734208, 851345408, 480854016, 771563520, 379310080, 908478464, 891100160, 747283968, 186532608, 488186496, 343249088, 446121888, 890590896, 759597480, 734910908, 30623014, 994776695 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 100663296, 385875968, 192937984, 373293056, 350224384, 554696704, 905445376, 735313920, 736231424, 212271104, 603750400, 602816512, 547430400, 686837760, 912869376, 686621696, 253156864, 334867712, 617771904, 695129408, 576796256, 634485040, 802688488, 971352188, 749430150, 1006320707 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 436207616, 855638016, 931135488, 12582912, 195035136, 483393536, 339214336, 456392704, 830603264, 504430592, 681082880, 1046822912, 813424640, 268816384, 25892864, 145619968, 342320640, 480955648, 1010638464, 247336384, 523167648, 594992400, 817076232, 890813444, 899974666, 408624399 - ], - [ - 536870912, 268435456, 402653184, 738197504, 704643072, 318767104, 260046848, 197132288, 794820608, 321912832, 503840768, 952369152, 85590016, 590807040, 370769920, 425476096, 730308608, 366030848, 804866048, 220996608, 112148992, 914715904, 582744704, 149411264, 1021413472, 988906992, 375951592, 578098484, 701639182, 672342287 - ], - [ - 536870912, 268435456, 134217728, 872415232, 369098752, 150994944, 8388608, 541065216, 811597824, 200278016, 242745344, 994836480, 642121728, 625016832, 182484992, 145768448, 362389504, 259829760, 832456704, 89981952, 957317632, 592757504, 133922688, 838828992, 380482144, 192366128, 974684168, 1052524548, 490708994, 1015918605 - ], - [ - 536870912, 268435456, 134217728, 872415232, 570425344, 184549376, 1031798784, 4194304, 891289600, 324009984, 365428736, 988545024, 798359552, 772734976, 850100224, 848412672, 648634368, 1033695232, 730785792, 518759424, 430978560, 687376128, 1020580224, 665005504, 966634400, 294597008, 703296936, 842011284, 28938794, 1064613977 - ], - [ - 536870912, 805306368, 671088640, 738197504, 436207616, 520093696, 310378496, 985661440, 996147200, 399507456, 846725120, 1033633792, 818020352, 575078400, 633896960, 213172224, 686170112, 905490432, 316516352, 669199360, 37167616, 1040211200, 419519872, 1065457984, 457185568, 153197040, 158353064, 206106044, 586459650, 71811335 - ], - [ - 536870912, 805306368, 939524096, 872415232, 838860800, 486539264, 1031798784, 499122176, 593494016, 529530880, 1006108672, 254541824, 182059008, 225378304, 520650752, 793001984, 873357312, 563687424, 389871616, 1038271488, 446931456, 948102400, 439504768, 469380928, 22952096, 494972080, 767669544, 459364092, 730937862, 167317761 - ], - [ - 536870912, 268435456, 402653184, 738197504, 234881024, 922746880, 260046848, 960495616, 878706688, 66060288, 824705024, 379322368, 458620928, 676790272, 232226816, 966213632, 393617408, 457592832, 533719040, 134452224, 749493760, 350158080, 639328896, 188263360, 872726304, 671348112, 1017954088, 216003988, 169525038, 87618975 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 301989888, 150994944, 746586112, 910163968, 236978176, 839909376, 657981440, 1007419392, 121503744, 948109312, 760578048, 201539584, 924131328, 673443840, 805574656, 832195584, 860390912, 335866624, 261870976, 273265472, 226876576, 123368208, 556347688, 490044500, 607384454, 876472395 - ], - [ - 536870912, 805306368, 402653184, 67108864, 234881024, 1056964608, 411041792, 859832320, 216006656, 657457152, 772276224, 824967168, 887488512, 609943552, 518291456, 996884480, 82698240, 474468352, 185223168, 782081024, 430861824, 26731776, 154356352, 1060641728, 337953312, 189454800, 419209384, 551538204, 251634830, 99598029 - ], - [ - 536870912, 805306368, 402653184, 201326592, 637534208, 50331648, 1048576000, 624951296, 392167424, 495976448, 1041760256, 214171648, 553517056, 805896192, 236814336, 312131584, 373776384, 293449728, 722163712, 442389504, 884537856, 276091648, 848797824, 906329792, 761224992, 272202864, 137732616, 343377676, 374659718, 577138115 - ], - [ - 536870912, 268435456, 671088640, 603979776, 704643072, 889192448, 511705088, 952107008, 1042284544, 567279616, 49807360, 477364224, 706871296, 1063714816, 122519552, 83345408, 894787584, 343076864, 434026496, 215612416, 94740992, 618397440, 756251520, 846178112, 269523296, 341405232, 375765736, 863634804, 998463874, 49780813 - ], - [ - 536870912, 805306368, 134217728, 201326592, 1040187392, 218103808, 260046848, 817889280, 673185792, 523239424, 648544256, 1065091072, 775028736, 321323008, 541622272, 896385024, 271196160, 909283328, 656873472, 440980480, 174873088, 749410048, 74662016, 809937088, 496606368, 466981232, 709756456, 865463996, 841939466, 12863247 - ], - [ - 536870912, 805306368, 939524096, 335544320, 33554432, 218103808, 159383552, 801112064, 736100352, 200278016, 447217664, 1026293760, 897712128, 663158784, 518553600, 67911680, 605249536, 220180480, 277673984, 173171712, 624906752, 647762176, 336279680, 104517312, 141704736, 36658288, 524571816, 63865788, 95801862, 1055346953 - ], - [ - 536870912, 268435456, 671088640, 738197504, 704643072, 620756992, 176160768, 130023424, 413138944, 770703360, 836239360, 758382592, 322306048, 1638400, 43286528, 356990976, 981491712, 1069666304, 480274432, 737227776, 1054436864, 45477120, 511130496, 528003264, 935668896, 158250544, 644738568, 29535492, 261053322, 696082635 - ], - [ - 536870912, 268435456, 671088640, 201326592, 369098752, 822083584, 494927872, 255852544, 455081984, 290455552, 112721920, 527171584, 169738240, 745996288, 1021542400, 733003776, 218734592, 40210432, 544954368, 840704, 720346624, 811470592, 551012736, 770840128, 380202016, 133522000, 732146216, 76593492, 777551266, 802971671 - ], - [ - 536870912, 268435456, 134217728, 201326592, 973078528, 922746880, 864026624, 29360128, 287309824, 462422016, 750256128, 860094464, 390987776, 263651328, 957579264, 611172352, 414359552, 599584768, 770344960, 684241920, 852281856, 753044224, 388268928, 935328832, 746509664, 442413200, 978296680, 456588180, 55721194, 948713431 - ], - [ - 536870912, 268435456, 134217728, 738197504, 771751936, 855638016, 696254464, 281018368, 606076928, 185597952, 184025088, 472121344, 853147648, 376635392, 38764544, 344047616, 440508416, 358633472, 334596096, 197764096, 785142272, 226945792, 676134784, 46640704, 195931744, 108445744, 126219368, 772493108, 455834090, 884710015 - ], - [ - 536870912, 268435456, 939524096, 201326592, 167772160, 855638016, 343932928, 398458880, 207618048, 336592896, 35127296, 299106304, 626917376, 787808256, 49184768, 10272768, 53665792, 252612608, 1053587456, 84653056, 166430208, 473659136, 323196544, 1023897536, 318784544, 75566896, 801240712, 6307780, 504388654, 823716659 - ], - [ - 536870912, 805306368, 402653184, 872415232, 771751936, 754974720, 260046848, 817889280, 350224384, 477102080, 833093632, 122945536, 980549632, 271777792, 1066565632, 834813952, 301719552, 452366336, 196737024, 1036813312, 78545408, 1065739520, 990520960, 169778112, 499984736, 883922672, 663071080, 252368636, 605997422, 818743025 - ], - [ - 536870912, 805306368, 671088640, 67108864, 973078528, 587202560, 729808896, 675282944, 199229440, 336592896, 498597888, 888930304, 899284992, 515047424, 255229952, 712097792, 149479424, 35958784, 313976832, 791712768, 428377600, 854917376, 1026530688, 259834432, 98267808, 961805040, 623320232, 784953340, 882149154, 880700605 - ], - [ - 536870912, 268435456, 671088640, 67108864, 167772160, 989855744, 746586112, 935329792, 962592768, 460324864, 268959744, 777256960, 1029308416, 378208256, 764641280, 859750400, 628678656, 526233600, 747563008, 881970176, 1069142528, 129861888, 834660992, 867794624, 431864416, 683599792, 540553832, 150756276, 488630370, 782872245 - ], - [ - 536870912, 805306368, 402653184, 335544320, 436207616, 654311424, 931135488, 331350016, 14680064, 105906176, 363331584, 884736000, 1042415616, 875233280, 73826304, 194789376, 110354432, 47427584, 569624576, 1061295104, 951777792, 61805824, 775005056, 330902720, 808816672, 1060017328, 879757864, 630813116, 839188910, 311867769 - ], - [ - 536870912, 268435456, 671088640, 469762048, 167772160, 50331648, 411041792, 784334848, 941621248, 1009778688, 175636480, 748945408, 51511296, 78577664, 726237184, 995999744, 955752448, 383627264, 397854720, 867998720, 971493888, 420783872, 405428352, 409691712, 395000032, 538634416, 1007850088, 103700980, 780737026, 133970691 - ], - [ - 536870912, 268435456, 939524096, 335544320, 167772160, 855638016, 109051904, 692060160, 736100352, 17825792, 79167488, 18612224, 975831040, 411631616, 596934656, 46120960, 817340416, 610521088, 876468224, 807130112, 1057061376, 142653184, 675296384, 174089152, 617642464, 890787024, 762151432, 381842180, 919451278, 431100101 - ], - [ - 536870912, 805306368, 671088640, 872415232, 167772160, 956301312, 662700032, 88080384, 257949696, 361758720, 361234432, 594804736, 438960128, 523304960, 783908864, 533544960, 552050688, 643256320, 1051674624, 813890560, 657738240, 516639488, 434164864, 860891200, 1034474912, 881185872, 934504456, 361622540, 1057432074, 168208141 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 637534208, 1056964608, 612368384, 473956352, 715128832, 275775488, 777519104, 1029439488, 736755712, 123535360, 585793536, 886849536, 640376832, 608006144, 603625472, 1049908224, 750680576, 42139904, 276429184, 158200768, 991089504, 812747920, 1046083976, 358478788, 401265514, 559778975 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 503316480, 922746880, 444596224, 507510784, 836763648, 691011584, 558366720, 287047680, 709230592, 7929856, 475299840, 224083968, 557768704, 414019584, 944666624, 117797888, 249782784, 810190592, 124142976, 48831552, 801926624, 20910256, 145562120, 273675012, 990193546, 283351887 - ], - [ - 536870912, 805306368, 671088640, 738197504, 301989888, 117440512, 897581056, 406847488, 106954752, 179306496, 274202624, 259784704, 362414080, 261816320, 345669632, 454803456, 677027840, 163196928, 474613760, 1072931840, 578774528, 568153344, 730464384, 986841664, 556710304, 141833584, 357480872, 902051196, 412531106, 251147639 - ], - [ - 536870912, 268435456, 671088640, 469762048, 33554432, 822083584, 1031798784, 440401920, 555745280, 745537536, 56098816, 208404480, 732299264, 270336000, 285114368, 678445056, 626548736, 191713280, 958883840, 81591296, 656398848, 48276736, 823251328, 151536576, 834955488, 810728432, 3586440, 30719940, 1021031146, 531767031 - ], - [ - 536870912, 268435456, 134217728, 67108864, 771751936, 889192448, 310378496, 213909504, 878706688, 112197632, 1035468800, 61079552, 834273280, 110559232, 57769984, 693682176, 517234688, 904089600, 113498112, 273857536, 16462336, 800466176, 383846016, 309452864, 98163936, 789945072, 386019432, 582214580, 747264010, 393116677 - ], - [ - 536870912, 268435456, 671088640, 67108864, 33554432, 16777216, 243269632, 1002438656, 757071872, 191889408, 163053568, 917241856, 619315200, 1045233664, 1035632640, 486817792, 820944896, 337793024, 945399808, 226337792, 979547648, 490220800, 812457344, 692721856, 167601376, 346246544, 345587080, 98306244, 22179050, 249608593 - ], - [ - 536870912, 268435456, 671088640, 469762048, 33554432, 922746880, 612368384, 322961408, 1046478848, 737148928, 694681600, 470548480, 310509568, 347275264, 66813952, 417775616, 851189760, 1015754752, 449775616, 617737216, 469358080, 303322368, 682091136, 643683776, 423304096, 38248112, 653104040, 976466612, 733734306, 671487923 - ], - [ - 536870912, 805306368, 402653184, 469762048, 905969664, 117440512, 1048576000, 943718400, 908066816, 862978048, 174587904, 28573696, 371064832, 68878336, 957120512, 57884672, 121184256, 212652032, 801327104, 1051732992, 612894208, 1067748096, 229064320, 905362112, 728717280, 628265680, 674865512, 908870684, 1032016014, 965856715 - ], - [ - 536870912, 805306368, 134217728, 603979776, 905969664, 822083584, 209715200, 834666496, 987758592, 76546048, 548929536, 367788032, 308412416, 369426432, 483885056, 295387136, 768188416, 38039552, 125233152, 69989376, 268514816, 939653888, 738242176, 302107840, 117531872, 1031822928, 1027666056, 186680268, 1047616610, 606607769 - ], - [ - 536870912, 268435456, 939524096, 603979776, 973078528, 956301312, 461373440, 666894336, 102760448, 466616320, 434634752, 671350784, 575537152, 105971712, 153649152, 245743616, 417275904, 534302720, 572344320, 863181824, 326311424, 57827584, 997414528, 527659840, 628280864, 477256560, 133384200, 540154884, 638819854, 1036230921 - ], - [ - 536870912, 805306368, 134217728, 335544320, 301989888, 318767104, 964689920, 675282944, 836763648, 542113792, 779616256, 210501632, 719978496, 700252160, 402882560, 912867328, 722804736, 439799808, 724514816, 1010031616, 771824128, 620831488, 813707392, 381703360, 840999648, 720384656, 105392264, 719608012, 973013218, 797609365 - ], - [ - 536870912, 805306368, 402653184, 335544320, 838860800, 419430400, 830472192, 88080384, 1046478848, 951058432, 410517504, 22806528, 420872192, 279117824, 448823296, 740376576, 273702912, 722022400, 948262912, 861619200, 601662976, 282482944, 805566080, 340862528, 822614304, 763652688, 618328488, 228335900, 104235022, 1014120457 - ], - [ - 536870912, 268435456, 402653184, 872415232, 167772160, 687865856, 662700032, 826277888, 551550976, 504365056, 688390144, 988020736, 392822784, 675872768, 302284800, 628801536, 1061199872, 199282688, 1016170496, 29924352, 138795520, 656035584, 160484480, 273171008, 906235936, 930868176, 574708232, 643862276, 617639046, 111710797 - ], - [ - 536870912, 805306368, 134217728, 469762048, 436207616, 419430400, 92274688, 675282944, 94371840, 898629632, 608698368, 94109696, 232128512, 878116864, 907444224, 582402048, 245768192, 414117888, 26359808, 1012143104, 67786240, 841022208, 684824448, 912889280, 491637024, 868179856, 891013416, 531128220, 246237482, 344891291 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 570425344, 889192448, 343932928, 264241152, 199229440, 95420416, 244842496, 1020002304, 264896512, 634322944, 518029312, 556875776, 425271296, 187494400, 679131136, 508955648, 917264896, 557539584, 930501248, 276572480, 131230368, 1002615856, 843840040, 747569276, 935403534, 132182019 - ], - [ - 536870912, 268435456, 402653184, 603979776, 503316480, 352321536, 159383552, 884998144, 761266176, 510656512, 452460544, 328466432, 862322688, 595263488, 938573824, 1043873792, 653647872, 152555520, 662919168, 828728320, 81766912, 827206912, 327665792, 130759744, 224972640, 509443472, 632026600, 26806484, 887445518, 35546125 - ], - [ - 536870912, 805306368, 939524096, 67108864, 704643072, 352321536, 444596224, 868220928, 962592768, 739246080, 820510720, 679215104, 928382976, 291831808, 51609600, 507953152, 856465408, 615452672, 1047545856, 829957120, 416654848, 554407680, 1065515648, 946862656, 9469024, 136881008, 211629192, 587618636, 464283886, 417212977 - ], - [ - 536870912, 268435456, 671088640, 872415232, 704643072, 520093696, 662700032, 71303168, 572522496, 99614720, 813170688, 615776256, 396754944, 198901760, 470908928, 535412736, 85778432, 127594496, 439396352, 404308992, 509894144, 783192832, 383217280, 375575616, 63265376, 589290128, 848249576, 908532180, 916178946, 816935945 - ], - [ - 536870912, 268435456, 134217728, 469762048, 436207616, 218103808, 847249408, 348127232, 232783872, 59768832, 775421952, 349437952, 457834496, 920322048, 65241088, 985120768, 381493248, 298250240, 93657088, 770395136, 384485888, 728388864, 338317696, 965405760, 876331232, 737292208, 885971176, 206136244, 997987050, 950482611 - ], - [ - 536870912, 268435456, 134217728, 469762048, 234881024, 687865856, 260046848, 415236096, 245366784, 573571072, 375914496, 80478208, 155582464, 244645888, 719486976, 413089792, 670130176, 357085184, 289269760, 722398208, 824770048, 179159296, 836234112, 684580928, 524792544, 865460464, 929234312, 660524356, 265332578, 540656055 - ], - [ - 536870912, 805306368, 134217728, 335544320, 167772160, 117440512, 746586112, 633339904, 1063256064, 191889408, 970457088, 62128128, 491126784, 680853504, 521633792, 807223296, 715857920, 774311936, 98834432, 936309760, 103347712, 867036928, 932404608, 664979904, 802872352, 587139568, 835845512, 1036622284, 958161954, 858435061 - ], - [ - 536870912, 268435456, 402653184, 469762048, 771751936, 587202560, 696254464, 281018368, 6291456, 774897664, 851968000, 25952256, 360316928, 426442752, 817070080, 191315968, 1007263744, 720228352, 382355456, 157467648, 1012802048, 984453376, 787093632, 192033472, 646439072, 821568624, 356878504, 871854196, 395428526, 874100083 - ], - [ - 536870912, 805306368, 671088640, 67108864, 905969664, 419430400, 360710144, 20971520, 1000341504, 875560960, 1062731776, 200540160, 192806912, 272695296, 438403072, 728842240, 435691520, 474329088, 744933376, 899001344, 607095296, 1070177536, 1008468352, 51579584, 774616992, 948946928, 863600648, 159727628, 788930570, 155496449 - ], - [ - 536870912, 805306368, 402653184, 872415232, 167772160, 50331648, 998244352, 834666496, 639631360, 36700160, 956825600, 702808064, 329121792, 340066304, 275742720, 325959680, 263856128, 872124416, 823867392, 193711104, 133330432, 847207680, 626276224, 903318848, 885073056, 278945712, 426776456, 577314124, 230005926, 1011241917 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 301989888, 419430400, 394264576, 968884224, 543162368, 359661568, 72876032, 348389376, 420610048, 669057024, 347176960, 272121856, 800448512, 373985280, 1034274816, 602094592, 779652608, 236282624, 391805824, 42732224, 947849760, 758025872, 514318344, 1034653708, 856967170, 383482895 - ], - [ - 536870912, 805306368, 939524096, 469762048, 234881024, 1056964608, 897581056, 1019215872, 367001600, 292552704, 1051197440, 874250240, 912392192, 363003904, 96632832, 275988480, 658219008, 207081472, 1000089600, 799179776, 549708288, 821234944, 58369664, 569885632, 156101408, 484117552, 304573224, 146033724, 998165286, 222338107 - ], - [ - 536870912, 805306368, 671088640, 603979776, 369098752, 318767104, 209715200, 213909504, 622854144, 567279616, 913833984, 721158144, 1027735552, 6356992, 665944064, 449396736, 817176576, 859222016, 326604800, 177660928, 644326912, 365938944, 525033088, 469072832, 710343648, 21405712, 421437448, 313716748, 659109898, 770970633 - ], - [ - 536870912, 268435456, 134217728, 738197504, 570425344, 889192448, 461373440, 230686720, 224395264, 550502400, 594018304, 972292096, 296353792, 787546112, 144211968, 854343680, 176644096, 655757312, 408823808, 660282368, 40422912, 880073472, 795516544, 51453760, 688473504, 1067826256, 142854152, 899959812, 25363970, 69506827 - ], - [ - 536870912, 805306368, 134217728, 201326592, 637534208, 956301312, 679477248, 364904448, 1063256064, 655360000, 739770368, 130809856, 579469312, 708640768, 247693312, 1011433472, 779476992, 616001536, 855549952, 59438080, 918398464, 956505856, 271156864, 1055228864, 216988384, 924006032, 749784712, 686360524, 990147810, 624860563 - ], - [ - 536870912, 268435456, 402653184, 335544320, 1040187392, 889192448, 427819008, 71303168, 652214272, 15728640, 231211008, 656670720, 924975104, 994902016, 513179648, 983023616, 211230720, 899067904, 102123520, 156687360, 53975552, 503726848, 829378944, 811208512, 172056480, 467710416, 359754632, 596196420, 180708902, 458478229 - ], - [ - 536870912, 805306368, 939524096, 201326592, 570425344, 989855744, 897581056, 46137344, 887095296, 808452096, 417857536, 491520000, 97386496, 764346368, 137265152, 591347712, 528949248, 72495104, 1016719360, 973423616, 76730880, 58307840, 129291392, 314262464, 148165024, 155886544, 308040104, 527885276, 459010470, 275026911 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 100663296, 956301312, 243269632, 683671552, 1067450368, 103809024, 359137280, 635699200, 172097536, 858718208, 634945536, 340606976, 235347968, 979161088, 186546176, 95452160, 556356096, 696535808, 1045685376, 959962816, 901089888, 607892528, 861052136, 632730108, 108341774, 370882307 - ], - [ - 536870912, 805306368, 671088640, 67108864, 905969664, 83886080, 796917760, 322961408, 660602880, 51380224, 129499136, 1069285376, 185466880, 94830592, 312639488, 378650624, 335077376, 744280064, 903854080, 801104896, 523193856, 299310336, 1040865664, 714427968, 290103456, 670374992, 224024232, 953017692, 1025982754, 761509405 - ], - [ - 536870912, 805306368, 671088640, 603979776, 838860800, 553648128, 713031680, 222298112, 186646528, 456130560, 235405312, 623640576, 931790848, 27197440, 372277248, 42516480, 325869568, 321564672, 258971648, 1062788096, 490077696, 1017008896, 850473088, 281653696, 97273120, 1020955440, 210178984, 765834748, 971479042, 104127493 - ], - [ - 536870912, 268435456, 671088640, 469762048, 771751936, 419430400, 662700032, 54525952, 165675008, 756023296, 582483968, 580124672, 80347136, 264175616, 912621568, 862175232, 999464960, 574230528, 253196288, 1019859968, 66942464, 222711040, 26231680, 561537856, 1052041312, 419156848, 615908328, 196714548, 1024826242, 864790339 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 436207616, 285212672, 209715200, 423624704, 450887680, 292552704, 702021632, 600047616, 1014366208, 419495936, 411140096, 658554880, 769777664, 384880640, 756582400, 753165312, 782682624, 994694912, 65866624, 288067264, 726924832, 721925040, 198705160, 1053032460, 854982662, 759234575 - ], - [ - 536870912, 805306368, 939524096, 603979776, 838860800, 452984832, 662700032, 113246208, 874512384, 512753664, 237502464, 166461440, 921829376, 297467904, 304513024, 290275328, 19095552, 829583360, 662366208, 503788544, 735949312, 1024088832, 597674880, 906555584, 159172768, 232463024, 852925096, 747991484, 244734246, 418743669 - ], - [ - 536870912, 805306368, 671088640, 738197504, 1040187392, 620756992, 310378496, 482344960, 425721856, 691011584, 196608000, 704905216, 942800896, 922550272, 588742656, 56508416, 780394496, 788803584, 447907840, 37504000, 376888832, 342804224, 3928960, 394319040, 1044429984, 765549264, 475049352, 478761932, 79507242, 11992603 - ], - [ - 536870912, 805306368, 939524096, 872415232, 369098752, 50331648, 864026624, 599785472, 681574400, 252706816, 370671616, 128712704, 192544768, 212926464, 378109952, 678805504, 91725824, 777760768, 526424064, 28433408, 571047424, 372528384, 957796480, 745157824, 648560480, 186925264, 34551816, 793144332, 731112974, 267684109 - ], - [ - 536870912, 268435456, 134217728, 469762048, 570425344, 318767104, 562036736, 633339904, 228589568, 5242880, 529006592, 350486528, 56754176, 187105280, 714440704, 846905344, 946577408, 646082560, 420890624, 1072477184, 650580480, 614820608, 84052864, 1070994624, 466480224, 525803952, 344770536, 45565300, 45966218, 567267523 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 637534208, 452984832, 411041792, 977272832, 811597824, 533725184, 228065280, 462684160, 882245632, 1069350912, 910852096, 229064704, 548691968, 648540160, 540309504, 686199808, 173373952, 171376384, 72194176, 862160320, 989533472, 594435312, 519633544, 952377028, 290426786, 357151295 - ], - [ - 536870912, 268435456, 134217728, 603979776, 301989888, 218103808, 645922816, 591396864, 819986432, 508559360, 580386816, 240386048, 814088192, 223412224, 790134784, 479477760, 749150208, 874614784, 225503232, 946435072, 234633728, 366679808, 263953024, 346792128, 299018400, 240575280, 193521672, 372077572, 25311746, 265164553 - ], - [ - 536870912, 268435456, 134217728, 603979776, 570425344, 956301312, 914358272, 230686720, 929038336, 244318208, 694681600, 803471360, 499515392, 272695296, 757104640, 783302656, 458825728, 612175872, 442222592, 810202112, 904130048, 937851648, 795907200, 976862016, 971818784, 414360112, 116293640, 730152964, 685219842, 677924873 - ], - [ - 536870912, 805306368, 134217728, 872415232, 369098752, 855638016, 679477248, 591396864, 425721856, 330301440, 669515776, 706478080, 533069824, 1054277632, 11436032, 260751360, 973692928, 15519744, 944687104, 1056623616, 373421568, 987811072, 611444864, 1070162880, 97325344, 807325712, 954349864, 257231900, 608888618, 808000785 - ], - [ - 536870912, 805306368, 939524096, 872415232, 369098752, 922746880, 444596224, 658505728, 589299712, 657457152, 770179072, 482607104, 173670400, 421724160, 410943488, 942227456, 614850560, 340447232, 117155840, 315841536, 611784192, 691803904, 910576256, 257238976, 407063776, 804257200, 875565800, 694773436, 8676966, 301615729 - ], - [ - 536870912, 268435456, 402653184, 335544320, 100663296, 50331648, 478150656, 490733568, 912261120, 95420416, 641204224, 947126272, 725221376, 1010892800, 669024256, 191938560, 60334080, 333721600, 559028224, 645784576, 968256000, 397308672, 277548416, 494420416, 487930784, 705424848, 322469896, 804569092, 653959174, 90255365 - ], - [ - 536870912, 268435456, 939524096, 335544320, 637534208, 184549376, 998244352, 901775360, 85983232, 300941312, 785907712, 603717632, 733085696, 992018432, 519077888, 190431232, 154968064, 856895488, 336680960, 243883008, 211054080, 158763264, 977190784, 260746944, 487359456, 820712336, 169648136, 971190276, 961107982, 213212165 - ], - [ - 536870912, 805306368, 134217728, 603979776, 369098752, 318767104, 360710144, 331350016, 354418688, 953155584, 645398528, 380895232, 339345408, 493158400, 398688256, 269565952, 853057536, 598011904, 274970624, 813767680, 625051136, 459293952, 439384192, 495528640, 454945568, 829898256, 204193928, 196884172, 577137954, 326269721 - ], - [ - 536870912, 805306368, 939524096, 67108864, 570425344, 352321536, 981467136, 717225984, 320864256, 646971392, 6815744, 128188416, 813563904, 492240896, 361922560, 614285312, 1058168832, 106819584, 271718400, 114076672, 660310528, 787073792, 124121984, 173976256, 659018976, 138109072, 530112232, 968682396, 579063142, 934670685 - ], - [ - 536870912, 805306368, 402653184, 201326592, 704643072, 889192448, 142606336, 918552576, 719323136, 705691648, 497549312, 557580288, 295043072, 940244992, 497844224, 436158464, 1012375552, 560705536, 50116608, 66505728, 1020985856, 652540160, 953416576, 90720192, 819851680, 939920592, 149105192, 926006044, 64570254, 658869199 - ], - [ - 536870912, 805306368, 671088640, 201326592, 905969664, 150994944, 243269632, 12582912, 983564288, 923795456, 1019740160, 528744448, 236322816, 828440576, 674332672, 513359872, 615276544, 761507840, 156190720, 971830272, 377669120, 734000384, 181725312, 247389760, 39116832, 796807856, 980803592, 783216652, 891103242, 146424835 - ], - [ - 536870912, 268435456, 134217728, 738197504, 100663296, 117440512, 360710144, 264241152, 555745280, 177209344, 752353280, 921436160, 536215552, 485687296, 434208768, 640729088, 227090432, 286609408, 579471360, 1029542912, 700338688, 247871232, 486260096, 590660160, 261835168, 994440400, 116624936, 14730644, 280010762, 1036619791 - ], - [ - 536870912, 805306368, 402653184, 469762048, 369098752, 16777216, 494927872, 457179136, 144703488, 91226112, 838336512, 345767936, 572391424, 1060700160, 863862784, 1036959744, 11657216, 479801344, 210552832, 334892032, 105736704, 1041747200, 245172096, 488519104, 666472928, 1069306736, 959375880, 299896076, 785475462, 973718983 - ], - [ - 536870912, 268435456, 939524096, 469762048, 234881024, 620756992, 411041792, 373293056, 463470592, 288358400, 820510720, 156499968, 36044800, 968032256, 678789120, 106381312, 192552960, 751898624, 309860352, 210553856, 698017280, 432027392, 778123392, 424720576, 683229920, 728530704, 336329320, 194545620, 1008539782, 121809091 - ], - [ - 536870912, 268435456, 402653184, 67108864, 100663296, 687865856, 645922816, 448790528, 123731968, 911212544, 143130624, 304873472, 694550528, 434044928, 61571072, 849952768, 324820992, 270454784, 424302592, 263834624, 234154496, 155400448, 978603904, 460469696, 286055328, 378985488, 1046874536, 39778580, 569046062, 34159061 - ], - [ - 536870912, 805306368, 671088640, 738197504, 570425344, 1056964608, 343932928, 264241152, 165675008, 886046720, 580386816, 640942080, 152698880, 685834240, 626098176, 47792128, 982867968, 652939264, 482932736, 242033664, 156188160, 6958848, 872953472, 386673856, 1012905376, 907232976, 225271816, 667881484, 883619850, 661136395 - ], - [ - 536870912, 805306368, 402653184, 603979776, 100663296, 184549376, 864026624, 775946240, 371195904, 112197632, 174587904, 828637184, 572653568, 228261888, 1032224768, 811089920, 281829376, 942133248, 682117120, 344224768, 737310208, 115506944, 595281536, 131518400, 358683104, 403827568, 152686568, 661418108, 97965934, 677405877 - ], - [ - 536870912, 805306368, 134217728, 335544320, 33554432, 788529152, 1065353216, 381681664, 295698432, 569376768, 1022885888, 585891840, 538836992, 658440192, 982417408, 227983360, 543842304, 924610560, 786827264, 584283136, 823132672, 1047097088, 608522368, 620470080, 615885856, 646149840, 505007144, 125568732, 221725738, 924496601 - ], - [ - 536870912, 805306368, 939524096, 67108864, 771751936, 1023410176, 8388608, 784334848, 857735168, 556793856, 953679872, 129236992, 1054736384, 204800000, 429883392, 122994688, 474980352, 52277248, 298993664, 823112704, 729562624, 293776640, 520583040, 352422848, 209754656, 1019323696, 606173064, 850430924, 731453998, 450127153 - ], - [ - 536870912, 268435456, 402653184, 872415232, 369098752, 922746880, 595591168, 205520896, 81788928, 900726784, 43515904, 50069504, 548798464, 132972544, 931037184, 1010417664, 346890240, 740192256, 1070143488, 131410944, 433265152, 86481664, 702873472, 856411072, 221955680, 1071899504, 66996104, 66672580, 68019302, 693052541 - ], - [ - 536870912, 268435456, 671088640, 67108864, 1040187392, 419430400, 511705088, 62914560, 404750336, 414187520, 534249472, 259784704, 1061027840, 909443072, 304775168, 355352576, 882745344, 799944704, 425502720, 110076928, 460154368, 613833984, 355573632, 496519616, 1058814816, 418329776, 230551944, 94339268, 1061448426, 919766129 - ], - [ - 536870912, 805306368, 402653184, 603979776, 100663296, 855638016, 377487360, 507510784, 467664896, 537919488, 890765312, 831258624, 1001521152, 53411840, 973373440, 761741312, 686874624, 864587776, 47540224, 903744512, 512587264, 1060254976, 812559232, 543554112, 62360480, 726149488, 796149800, 841998140, 696563086, 245809989 - ], - [ - 536870912, 268435456, 134217728, 335544320, 33554432, 620756992, 696254464, 146800640, 115343360, 376438784, 953679872, 56885248, 540672000, 759496704, 548044800, 200097792, 253108224, 716394496, 661129216, 249404416, 82808320, 214354688, 926567808, 969168320, 501990048, 332219920, 948366728, 144328132, 1033235106, 597920277 - ], - [ - 536870912, 268435456, 134217728, 335544320, 570425344, 620756992, 696254464, 356515840, 1059061760, 407896064, 209190912, 959184896, 222429184, 612433920, 952139776, 6307840, 376479744, 531173376, 85272576, 584010752, 617851392, 790132992, 433848960, 388662208, 343243104, 792646160, 54132744, 682426372, 335708162, 631324677 - ], - [ - 536870912, 805306368, 134217728, 872415232, 905969664, 654311424, 897581056, 901775360, 685768704, 225443840, 261619712, 938737664, 870973440, 891748352, 912818176, 657309696, 281010176, 345837568, 944179200, 920245248, 1012146688, 674961664, 971945088, 672435008, 857380192, 863906800, 729637864, 146172348, 947989002, 356633857 - ], - [ - 536870912, 268435456, 134217728, 335544320, 570425344, 218103808, 998244352, 272629760, 727711744, 489684992, 709361664, 662437888, 600965120, 401670144, 82345984, 845955072, 1061855232, 53743616, 665774080, 1017289728, 64594432, 421825280, 498491776, 195444288, 264192480, 62534032, 459040776, 654564356, 558465538, 738056965 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 234881024, 486539264, 964689920, 331350016, 371195904, 783286272, 556269568, 652476416, 354811904, 981663744, 650477568, 177684480, 338370560, 853544960, 1041356800, 249103360, 447529472, 789755648, 954065024, 446410432, 63492448, 552942224, 671003112, 774820948, 349618310, 197902027 - ], - [ - 536870912, 805306368, 402653184, 67108864, 234881024, 989855744, 92274688, 230686720, 673185792, 277872640, 542638080, 188481536, 252051456, 938934272, 249462784, 252329984, 184049664, 703401984, 666847232, 1056613376, 928082432, 226073344, 1026385792, 589232448, 388642464, 40424336, 230006440, 578955164, 184376494, 86395037 - ], - [ - 536870912, 268435456, 671088640, 67108864, 503316480, 788529152, 880803840, 205520896, 362807296, 286261248, 837287936, 14942208, 629538816, 233897984, 148406272, 467484672, 602546176, 291762176, 242677760, 103375872, 1032159744, 91700480, 1017651328, 918889280, 542636320, 1073309488, 1032607752, 86234116, 668424714, 624470273 - ], - [ - 536870912, 805306368, 939524096, 469762048, 234881024, 285212672, 1031798784, 4194304, 178257920, 273678336, 272105472, 613154816, 931790848, 1069744128, 132546560, 196689920, 567058432, 715870208, 752031744, 1073714176, 329524736, 824122112, 726959488, 376950336, 794882848, 917512176, 1019833640, 702857468, 817780390, 1032176059 - ], - [ - 536870912, 268435456, 939524096, 335544320, 771751936, 754974720, 176160768, 54525952, 1063256064, 955252736, 370671616, 903610368, 633470976, 844824576, 524779520, 237256704, 800055296, 685838336, 422590464, 104434688, 139298304, 137020672, 907955840, 110712896, 631079840, 86158128, 392824232, 461336116, 292145958, 772109937 - ], - [ - 536870912, 268435456, 939524096, 738197504, 1040187392, 989855744, 528482304, 322961408, 610271232, 869269504, 730333184, 1046740992, 286392320, 931594240, 212697088, 840384512, 935698432, 190976000, 377415680, 724681728, 681104896, 617398528, 801558912, 525168832, 109455456, 707543856, 64369128, 140879860, 773031814, 34009551 - ], - [ - 536870912, 805306368, 134217728, 469762048, 1040187392, 419430400, 662700032, 968884224, 174063616, 856686592, 624427008, 1003749376, 460718080, 129040384, 315195392, 1002192896, 708501504, 543354880, 19286016, 397016064, 439152128, 658703104, 756498560, 983674304, 653272224, 1005116080, 915220488, 884165644, 125715970, 820842247 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 637534208, 889192448, 746586112, 222298112, 715128832, 896532480, 292028416, 846462976, 457048064, 5308416, 551059456, 545013760, 131850240, 869675008, 65284096, 336045056, 66898432, 622527744, 95843200, 32778048, 838823328, 170979056, 80332808, 813995012, 580280834, 524673295 - ], - [ - 536870912, 268435456, 134217728, 67108864, 33554432, 587202560, 880803840, 624951296, 845152256, 217055232, 209190912, 481034240, 283508736, 514785280, 870023168, 155303936, 610328576, 636514304, 536422400, 258780160, 617059840, 348003584, 370368128, 737433408, 618266912, 666988944, 773930792, 621871252, 390633386, 653654741 - ], - [ - 536870912, 268435456, 134217728, 603979776, 167772160, 788529152, 662700032, 297795584, 1067450368, 193986560, 698875904, 770965504, 129105920, 336527360, 649691136, 203210752, 690446336, 185364480, 751806464, 798557184, 483136000, 40854272, 780728704, 136641984, 746296544, 600552240, 640917352, 349150708, 328841738, 986539789 - ], - [ - 536870912, 805306368, 402653184, 469762048, 503316480, 83886080, 981467136, 641728512, 828375040, 244318208, 188219392, 447479808, 220332032, 676659200, 170885120, 617070592, 179462144, 804040704, 935561216, 537134080, 288786944, 538658560, 469293696, 999064768, 869404896, 360516432, 654037128, 1034486732, 1033185894, 294649751 - ], - [ - 536870912, 268435456, 671088640, 335544320, 436207616, 520093696, 109051904, 322961408, 232783872, 506462208, 537395200, 661389312, 847380480, 69271552, 512786432, 517554176, 349478912, 975622144, 275773440, 1029944320, 688937472, 504958720, 1005961600, 674728000, 720775008, 920011280, 71704584, 1017024516, 961271818, 15475717 - ], - [ - 536870912, 268435456, 939524096, 603979776, 637534208, 117440512, 394264576, 650117120, 278921216, 898629632, 651689984, 245104640, 695074816, 966721536, 603422720, 65159168, 132734976, 735399936, 1043064832, 770544640, 868614656, 237762304, 99353472, 801593664, 204190624, 619481552, 1061600168, 1030360532, 311177638, 443956957 - ], - [ - 536870912, 268435456, 939524096, 67108864, 167772160, 385875968, 159383552, 1027604480, 970981376, 240123904, 746061824, 333185024, 791019520, 507445248, 141787136, 973881344, 857694208, 310554624, 432359424, 116122624, 134348288, 738236672, 906067840, 419433024, 343964064, 599791888, 220260264, 183578644, 466178086, 838180437 - ], - [ - 536870912, 805306368, 671088640, 603979776, 771751936, 520093696, 478150656, 599785472, 979369984, 770703360, 778567680, 419692544, 953548800, 11206656, 522223616, 491831296, 913858560, 802967552, 656115712, 896080896, 461666816, 739740928, 38444160, 1058139328, 374965088, 504203920, 446860776, 81110876, 1064230914, 672632837 - ], - [ - 536870912, 805306368, 134217728, 872415232, 1040187392, 352321536, 58720256, 146800640, 765460480, 722468864, 1013448704, 752091136, 138805248, 866713600, 636846080, 1058422784, 908107776, 802189312, 331933696, 415611904, 481277440, 20759808, 189973632, 47113536, 688728992, 728443568, 1024603656, 539919628, 293364866, 817075533 - ], - [ - 536870912, 805306368, 939524096, 335544320, 436207616, 251658240, 394264576, 918552576, 337641472, 976224256, 465043456, 372506624, 936247296, 831062016, 93159424, 234602496, 138911744, 553930752, 284571648, 620551168, 195184128, 534956288, 360920448, 584206272, 901398176, 203899632, 55868936, 522065164, 1008825230, 640716485 - ], - [ - 536870912, 268435456, 134217728, 603979776, 838860800, 251658240, 947912704, 616562688, 341835776, 93323264, 700973056, 90963968, 940965888, 236388352, 588742656, 479707136, 618061824, 645361664, 948373504, 744410112, 607906304, 220285184, 1051747712, 981052352, 9814176, 12787728, 209043624, 831725588, 970834090, 359604253 - ], - [ - 536870912, 268435456, 939524096, 872415232, 704643072, 620756992, 461373440, 440401920, 325058560, 560988160, 623378432, 884736000, 486670336, 889782272, 724336640, 1818624, 394043392, 757321728, 983164928, 238418944, 376324608, 997397248, 849414016, 944870208, 792298208, 82166160, 647389704, 968295172, 413552526, 75415373 - ], - [ - 536870912, 268435456, 671088640, 469762048, 503316480, 251658240, 964689920, 88080384, 249561088, 737148928, 102236160, 190578688, 728629248, 575340544, 457801728, 953532416, 169582592, 876679168, 677382144, 1060172800, 297338368, 810331392, 159862912, 378512192, 1044103200, 1058125456, 417871528, 298100948, 301149698, 704940291 - ], - [ - 536870912, 805306368, 671088640, 603979776, 167772160, 285212672, 645922816, 314572800, 387973120, 661651456, 274202624, 293339136, 589168640, 269287424, 1011318784, 351289344, 504930304, 765267968, 298821632, 1071932416, 994287104, 660851968, 798100864, 126593984, 1024972896, 894967344, 637379976, 752865228, 262948458, 318231353 - ], - [ - 536870912, 805306368, 402653184, 872415232, 570425344, 318767104, 243269632, 541065216, 211812352, 435159040, 788004864, 564396032, 414056448, 212664320, 15958016, 19382272, 330375168, 760762368, 953546752, 320259072, 506038784, 1013778688, 18053504, 133607616, 259536800, 828679472, 693046152, 310214092, 674939942, 1058741501 - ], - [ - 536870912, 268435456, 939524096, 872415232, 1040187392, 419430400, 310378496, 121634816, 350224384, 760217600, 23592960, 300679168, 321781760, 75038720, 333742080, 139706368, 379494400, 171995136, 677480448, 185660416, 856189440, 100507392, 531052160, 709207360, 115511904, 153588976, 990208520, 117615364, 1022885006, 439175757 - ], - [ - 536870912, 805306368, 671088640, 872415232, 1040187392, 117440512, 209715200, 1035993088, 304087040, 953155584, 1000865792, 921436160, 771358720, 392626176, 220495872, 648462336, 218488832, 997707776, 925730816, 98204672, 1052129792, 151807744, 520749952, 136195520, 174083872, 78772272, 1008215208, 276134396, 860838274, 76044993 - ], - [ - 536870912, 268435456, 671088640, 738197504, 1040187392, 452984832, 25165824, 440401920, 601882624, 168820736, 401080320, 560726016, 605683712, 225902592, 359497728, 236699648, 746004480, 502075392, 819652608, 257422336, 803065344, 344139008, 270711680, 928195008, 191598880, 223219760, 88681128, 823996916, 664976258, 169025999 - ], - [ - 536870912, 805306368, 671088640, 469762048, 436207616, 251658240, 914358272, 381681664, 828375040, 479199232, 158859264, 488374272, 634781696, 622657536, 567771136, 186400768, 685203456, 681349120, 127342592, 968696832, 1017622016, 489991936, 877873792, 747037888, 696558176, 228280944, 642992776, 260498636, 755278442, 140200567 - ], - [ - 536870912, 805306368, 402653184, 603979776, 369098752, 117440512, 327155712, 541065216, 924844032, 464519168, 907542528, 349962240, 305004544, 961740800, 17596416, 271007744, 434561024, 327618560, 26658816, 721404928, 500846080, 58282752, 21827712, 386374464, 441948448, 27182352, 55208360, 1070681692, 923383950, 573837125 - ], - [ - 536870912, 805306368, 402653184, 469762048, 234881024, 385875968, 796917760, 230686720, 228589568, 764411904, 864550912, 31195136, 1051328512, 758448128, 80183296, 172474368, 319184896, 719728640, 202774528, 1043311616, 992609792, 368408832, 669456000, 244779840, 24032608, 298513040, 243593352, 18842188, 1051974630, 543253975 - ], - [ - 536870912, 268435456, 134217728, 872415232, 301989888, 184549376, 1048576000, 859832320, 635437056, 1032847360, 315097088, 554958848, 309723136, 978649088, 328630272, 499466240, 1046421504, 273797120, 342456320, 828711936, 154034688, 461982464, 737455744, 191237440, 618520096, 1004747504, 174206600, 228805956, 738393634, 754117373 - ], - [ - 536870912, 268435456, 134217728, 335544320, 973078528, 486539264, 343932928, 767557632, 534773760, 609222656, 465043456, 44826624, 467271680, 1043136512, 840597504, 332218368, 524951552, 653561856, 757516288, 911094784, 446342656, 805632, 799720576, 522499776, 903823840, 465707024, 779142280, 738834116, 457556450, 835674133 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 1040187392, 687865856, 461373440, 1027604480, 643825664, 204472320, 783810560, 605290496, 3801088, 227344384, 8355840, 239026176, 551510016, 690958336, 741763072, 330435584, 413168128, 319911680, 250105728, 765208768, 102235168, 644044944, 224976264, 350040012, 712424354, 22170719 - ], - [ - 536870912, 268435456, 671088640, 603979776, 838860800, 654311424, 360710144, 775946240, 945815552, 122683392, 141033472, 383516672, 298975232, 384368640, 723288064, 989020160, 1062739968, 769986560, 359036928, 317099008, 195518976, 239483648, 56063616, 23019840, 936525280, 1005146128, 362635784, 389233412, 1014625930, 542441801 - ], - [ - 536870912, 268435456, 134217728, 603979776, 1040187392, 318767104, 1048576000, 977272832, 522190848, 485490688, 139984896, 107741184, 20054016, 84606976, 53968896, 158187520, 1035198464, 1045139456, 731367424, 1012751360, 1024155136, 1060589312, 460063872, 884080704, 768231456, 1012397872, 666727976, 77260852, 884955818, 162079869 - ], - [ - 536870912, 268435456, 939524096, 469762048, 369098752, 352321536, 595591168, 826277888, 627048448, 611319808, 860356608, 471072768, 162922496, 685309952, 669810688, 63684608, 367779840, 603664384, 809691136, 316652544, 870160896, 342004480, 1003358080, 14971968, 826148256, 762075952, 386568712, 751509252, 493614478, 3906375 - ], - [ - 536870912, 805306368, 134217728, 738197504, 838860800, 50331648, 1015021568, 608174080, 274726912, 30408704, 567803904, 532938752, 880410624, 290783232, 625180672, 285294592, 260104192, 281137152, 404846592, 598766592, 587807232, 43869952, 268381312, 894340544, 902197408, 362442000, 21353608, 725334476, 431336098, 517200411 - ], - [ - 536870912, 805306368, 671088640, 738197504, 973078528, 50331648, 327155712, 171966464, 908066816, 902823936, 486014976, 871628800, 716046336, 609550336, 171933696, 252461056, 693821440, 654020608, 40630272, 1060277248, 626452992, 471883008, 785486976, 192422592, 800347936, 630130096, 17134728, 252097228, 9973546, 379323 - ], - [ - 536870912, 805306368, 671088640, 738197504, 301989888, 855638016, 713031680, 683671552, 115343360, 858783744, 1023934464, 975962112, 616169472, 694878208, 324173824, 41402368, 299933696, 397488128, 482945024, 156056576, 130750976, 155368704, 909065344, 3457216, 961427360, 692401520, 778551208, 414792060, 635800994, 796309623 - ], - [ - 536870912, 268435456, 402653184, 872415232, 1040187392, 620756992, 58720256, 239075328, 660602880, 49283072, 532152320, 1057226752, 247595008, 449249280, 981827584, 25313280, 405168128, 657838080, 81434624, 244536320, 313507328, 766038272, 34470016, 874386496, 510670048, 24700592, 480627816, 747827956, 900724878, 422122569 - ], - [ - 536870912, 805306368, 134217728, 67108864, 637534208, 587202560, 209715200, 918552576, 283115520, 152043520, 993525760, 349437952, 326500352, 280952832, 264404992, 572047360, 463855616, 513757184, 573769728, 1043385344, 323553792, 868037888, 876243328, 1026309696, 21220320, 567899856, 751053288, 701489116, 422199914, 269818013 - ], - [ - 536870912, 805306368, 402653184, 335544320, 436207616, 452984832, 360710144, 633339904, 517996544, 818937856, 401080320, 8650752, 154796032, 1020854272, 457015296, 957792256, 365404160, 607014912, 699045888, 537938944, 763895296, 51683072, 611549824, 766260544, 819865888, 938703440, 896345608, 918455052, 576914566, 220587589 - ], - [ - 536870912, 268435456, 939524096, 67108864, 301989888, 486539264, 125829120, 910163968, 354418688, 97517568, 730333184, 707526656, 700317696, 1021902848, 14450688, 652722176, 751640576, 974000128, 1007691776, 619224064, 350020096, 216424704, 902660736, 797869632, 391185504, 910717296, 659374600, 844083460, 439388814, 767035969 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 369098752, 721420288, 746586112, 926941184, 429916160, 282066944, 581435392, 475267072, 832176128, 145948672, 690388992, 626868224, 874487808, 234983424, 654411776, 42028032, 541091328, 589341440, 210807168, 394803904, 1002752864, 177387056, 70692200, 974460220, 834307302, 748908531 - ], - [ - 536870912, 805306368, 939524096, 201326592, 771751936, 553648128, 427819008, 138412032, 715128832, 32505856, 14155776, 802947072, 973471744, 264962048, 1002733568, 79314944, 769433600, 84316160, 256555008, 637871104, 140230144, 663535360, 498009728, 672068416, 427755808, 1013325648, 324704168, 218961948, 997079174, 1047465039 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 100663296, 50331648, 58720256, 88080384, 337641472, 535822336, 409468928, 238288896, 4063232, 76873728, 504266752, 471613440, 665542656, 152727552, 793933824, 328657920, 927011328, 1025551616, 829447552, 564770368, 450138144, 229526960, 346897800, 316851780, 509503530, 851829183 - ], - [ - 536870912, 805306368, 671088640, 469762048, 704643072, 1056964608, 897581056, 952107008, 908066816, 537919488, 290979840, 673447936, 237109248, 993722368, 226394112, 254656512, 574496768, 315486208, 59754496, 944063488, 324203008, 965921536, 884141952, 1059260224, 532403552, 557832176, 1028499304, 743431420, 669378786, 562293691 - ], - [ - 536870912, 805306368, 402653184, 67108864, 167772160, 218103808, 578813952, 952107008, 85983232, 688914432, 479723520, 211025920, 345374720, 1055457280, 654147584, 967491584, 1071849472, 592367616, 320612352, 966423552, 476739072, 809677056, 782115968, 77872832, 455061408, 1004919600, 410975752, 555078924, 802609798, 931720129 - ], - [ - 536870912, 805306368, 134217728, 469762048, 704643072, 956301312, 226492416, 205520896, 765460480, 999292928, 1054343168, 637272064, 527826944, 514523136, 940343296, 853524480, 373268480, 395259904, 797333504, 142836736, 802782720, 75282176, 825681280, 369843264, 605921824, 960979920, 333637544, 1059590044, 576036234, 786638923 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 301989888, 419430400, 796917760, 868220928, 698351616, 110100480, 67633152, 12845056, 448397312, 213319680, 887652352, 297058304, 860004352, 885682176, 231659520, 869561344, 947110400, 810803968, 1040335232, 220917952, 725494880, 1038994672, 128921576, 82059068, 787210754, 446583555 - ], - [ - 536870912, 805306368, 671088640, 469762048, 369098752, 788529152, 494927872, 121634816, 115343360, 930086912, 30932992, 539230208, 812253184, 951910400, 363823104, 472268800, 411721728, 617443328, 737630208, 507706368, 176263680, 516018944, 597800320, 345030592, 304709536, 339580176, 208643976, 1040657612, 492481066, 520379095 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 838860800, 654311424, 1048576000, 499122176, 782237696, 640679936, 620232704, 688652288, 393871360, 96272384, 272859136, 1058029568, 76046336, 253022208, 698800128, 292512768, 932926976, 762134784, 963313536, 246702784, 1024897504, 844529680, 724969352, 279316172, 586049514, 668696863 - ], - [ - 536870912, 268435456, 671088640, 469762048, 369098752, 452984832, 981467136, 884998144, 241172480, 202375168, 261619712, 797179904, 794689536, 355139584, 1019052032, 564903936, 930914304, 927649792, 514598912, 20147200, 678986240, 567635200, 610678656, 1071546944, 1022072800, 996005968, 1073424488, 340125204, 29332866, 150667075 - ], - [ - 536870912, 805306368, 939524096, 603979776, 704643072, 721420288, 461373440, 356515840, 283115520, 248512512, 197656576, 689700864, 628752384, 577830912, 158957568, 348504064, 655302656, 715542528, 783013888, 54107136, 1034275328, 194983680, 604921472, 489032256, 233514720, 920238800, 703952904, 630590476, 322122254, 858651401 - ], - [ - 536870912, 268435456, 939524096, 738197504, 503316480, 989855744, 109051904, 314572800, 849346560, 697303040, 397934592, 453771264, 269615104, 134021120, 152731648, 580435968, 131981312, 273362944, 444708864, 616580096, 497061376, 487637248, 544811648, 338489536, 767795424, 807775056, 153612936, 212026564, 211121902, 307175003 - ], - [ - 536870912, 805306368, 671088640, 67108864, 369098752, 50331648, 8388608, 666894336, 505413632, 40894464, 98041856, 647757824, 674365440, 702742528, 1040875520, 439336960, 672260096, 650661888, 886425600, 86412288, 904172032, 522081024, 606705792, 872698432, 525207712, 427913264, 104865960, 73444412, 1007811234, 684241725 - ], - [ - 536870912, 805306368, 939524096, 603979776, 570425344, 989855744, 830472192, 943718400, 471859200, 766509056, 1010302976, 619970560, 22151168, 267714560, 953384960, 733265920, 586326016, 520474624, 340490240, 842030080, 829995520, 206945536, 404903808, 1059888320, 527945760, 781076048, 1008359304, 265854156, 69586990, 1048266329 - ], - [ - 536870912, 805306368, 134217728, 67108864, 100663296, 16777216, 343932928, 901775360, 211812352, 550502400, 611844096, 4980736, 574488576, 111083520, 307134464, 943112192, 1031462912, 231002112, 1067177984, 905313280, 416453120, 225449728, 539607424, 435501632, 718521376, 40945616, 833168424, 1051989980, 313719850, 981593053 - ], - [ - 536870912, 268435456, 134217728, 872415232, 436207616, 788529152, 998244352, 742391808, 421527552, 540016640, 680001536, 46399488, 1058406400, 360120320, 266829824, 387956736, 175267840, 579907584, 888719360, 997037056, 702723584, 417914624, 928288384, 477000384, 609966304, 1042559568, 558282984, 762266196, 853151978, 988112473 - ], - [ - 536870912, 268435456, 402653184, 738197504, 503316480, 922746880, 8388608, 247463936, 702545920, 116391936, 276299776, 546045952, 47841280, 750452736, 738951168, 793985024, 315498496, 798806016, 72509440, 72346624, 576576000, 523384064, 629019264, 742758720, 923762976, 285079024, 258187560, 257304052, 601901358, 334596607 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 234881024, 16777216, 1015021568, 12582912, 429916160, 630194176, 918028288, 583270400, 114688000, 696320000, 104955904, 308396032, 867295232, 543715328, 815532032, 610526208, 622790144, 126635264, 588999808, 452629952, 403310112, 730009264, 451805192, 109379596, 330792974, 598786063 - ], - [ - 536870912, 268435456, 134217728, 603979776, 905969664, 654311424, 478150656, 960495616, 132120576, 344981504, 167247872, 142344192, 656539648, 939982848, 338264064, 509919232, 399466496, 81629184, 894568448, 384736256, 342724096, 966427904, 1016841088, 689643328, 131763744, 939162096, 214573992, 767734708, 487982602, 84990221 - ], - [ - 536870912, 268435456, 134217728, 67108864, 905969664, 687865856, 562036736, 37748736, 245366784, 118489088, 139984896, 170655744, 634781696, 204668928, 777093120, 544784384, 201089024, 854560768, 317716480, 49267712, 183426560, 250578688, 955129216, 300900928, 812517280, 841972176, 1016020008, 1000298644, 868644874, 971703301 - ], - [ - 536870912, 805306368, 939524096, 469762048, 100663296, 822083584, 159383552, 725614592, 480247808, 53477376, 150470656, 772538368, 802029568, 219742208, 312311808, 1049083904, 573431808, 440381440, 268519424, 134294528, 604023296, 436309248, 922772864, 947951040, 583129440, 937442800, 529582600, 197786892, 653577614, 29493703 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 100663296, 50331648, 192937984, 918552576, 715128832, 164626432, 915931136, 993787904, 223739904, 710737920, 849772544, 710197248, 442720256, 835645440, 1012955136, 863054848, 122260992, 832887040, 812372096, 604743104, 326892896, 775126384, 446050440, 578655684, 993453422, 875405695 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 33554432, 117440512, 780140544, 1010827264, 228589568, 258998272, 984088576, 672399360, 710541312, 555679744, 542932992, 136232960, 333291520, 165572608, 851208192, 844049408, 591709696, 1027856128, 709046912, 482546880, 880958688, 119772144, 223520360, 511367996, 615437442, 1058304963 - ], - [ - 536870912, 268435456, 402653184, 335544320, 33554432, 184549376, 729808896, 859832320, 132120576, 470810624, 33030144, 297533440, 802029568, 283574272, 990085120, 788611072, 562094080, 876638208, 979429376, 642847744, 647536128, 359463168, 446121344, 447467584, 153477792, 799259728, 619713704, 610799956, 805613358, 101845009 - ], - [ - 536870912, 268435456, 939524096, 872415232, 637534208, 1056964608, 864026624, 432013312, 127926272, 693108736, 721944576, 998506496, 347996160, 445972480, 282492928, 257998848, 1047601152, 35188736, 602691584, 726313984, 422721024, 925769984, 129877120, 985892160, 267830944, 980489648, 202972296, 283961668, 181096622, 435356861 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 33554432, 822083584, 310378496, 608174080, 199229440, 800063488, 382205952, 503054336, 305004544, 872873984, 835354624, 636239872, 750166016, 176304128, 634451968, 246959104, 773135872, 868358400, 380672128, 273221824, 532435488, 382621136, 976743464, 549616860, 87133358, 1049114643 - ], - [ - 536870912, 805306368, 134217728, 603979776, 704643072, 150994944, 159383552, 415236096, 492830720, 714080256, 715653120, 948174848, 956956672, 192872448, 701267968, 224378880, 1073504256, 294121472, 998266880, 230728704, 316774912, 894518528, 491299712, 173313984, 528627296, 483041008, 228503016, 1050494268, 1024940426, 371800773 - ], - [ - 536870912, 805306368, 939524096, 201326592, 838860800, 520093696, 75497472, 717225984, 874512384, 210763776, 98041856, 786169856, 982646784, 561184768, 105021440, 659243008, 867115008, 919646208, 356075520, 57469952, 609909248, 372685568, 334286720, 10148160, 924281760, 150747440, 419613608, 405522748, 241083302, 469275967 - ], - [ - 536870912, 805306368, 671088640, 201326592, 905969664, 184549376, 243269632, 490733568, 576716800, 697303040, 959971328, 218365952, 756154368, 1046937600, 136085504, 426164224, 10231808, 656822272, 545105920, 636996608, 807759360, 266486016, 961534848, 518051648, 902936288, 14278192, 810935656, 327914876, 785520002, 424019535 - ], - [ - 536870912, 805306368, 134217728, 201326592, 905969664, 620756992, 276824064, 348127232, 48234496, 707788800, 648544256, 561250304, 467533824, 713621504, 715489280, 717635584, 622157824, 808333312, 373319680, 958489600, 592532992, 567893760, 930899328, 599440192, 799971488, 956410224, 511817224, 901852940, 677473666, 770830147 - ], - [ - 536870912, 268435456, 671088640, 335544320, 771751936, 721420288, 864026624, 507510784, 65011712, 533725184, 1018691584, 55836672, 436338688, 266928128, 741113856, 133644288, 777756672, 820834304, 1020696576, 481000448, 698655232, 793507584, 242539136, 804510656, 924884896, 821089680, 541604360, 824019716, 975108234, 58092741 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 838860800, 855638016, 578813952, 448790528, 278921216, 644874240, 135790592, 243007488, 549584896, 671416320, 778993664, 867057664, 529424384, 171921408, 1057404928, 491496448, 217185792, 1054456064, 81549696, 162721728, 815599456, 164768336, 558712712, 188368580, 1021939434, 614740383 - ], - [ - 536870912, 805306368, 402653184, 201326592, 838860800, 654311424, 461373440, 616562688, 811597824, 296747008, 848822272, 856424448, 414056448, 297467904, 190349312, 468533248, 274636800, 780333056, 386148352, 942318592, 256924160, 191419648, 380987008, 582131008, 677209760, 768032784, 302930472, 359270492, 217111054, 691639567 - ], - [ - 536870912, 268435456, 671088640, 603979776, 637534208, 16777216, 696254464, 205520896, 1029701632, 909115392, 217579520, 817102848, 589955072, 121700352, 132153344, 485572608, 827924480, 941961216, 700581888, 433867776, 586605056, 968338176, 341250432, 195532736, 880700832, 681215312, 435716104, 120930308, 577445898, 295710729 - ], - [ - 536870912, 805306368, 671088640, 67108864, 33554432, 1056964608, 578813952, 817889280, 174063616, 267386880, 915931136, 1046740992, 660209664, 267190272, 546799616, 36323328, 1035247616, 1049808896, 293705728, 608216064, 799092224, 470851328, 690552192, 224238016, 1043254176, 555644816, 770108296, 879915724, 565248042, 305763665 - ], - [ - 536870912, 268435456, 939524096, 738197504, 234881024, 956301312, 880803840, 784334848, 350224384, 122683392, 1070071808, 714342400, 875167744, 223805440, 89751552, 104677376, 548315136, 320081920, 476788736, 947301376, 929575424, 719642880, 919860608, 714764480, 860873952, 834961136, 769852264, 180600628, 670206470, 313199887 - ], - [ - 536870912, 268435456, 671088640, 872415232, 838860800, 620756992, 327155712, 247463936, 379584512, 124780544, 216530944, 476839936, 490864640, 27066368, 854228992, 244334592, 251207680, 248827904, 41322496, 234490880, 61398528, 822995200, 923970944, 818274880, 114221280, 768571728, 223225224, 789507652, 904838890, 192925789 - ], - [ - 536870912, 268435456, 939524096, 67108864, 369098752, 251658240, 176160768, 130023424, 773849088, 594542592, 260571136, 201064448, 735707136, 574685184, 861962240, 848412672, 114827264, 822390784, 548304896, 149378048, 1027325440, 227619072, 609778560, 180694080, 479115232, 848741072, 926056456, 187482116, 643997710, 634679297 - ], - [ - 536870912, 268435456, 939524096, 469762048, 637534208, 117440512, 562036736, 4194304, 1012924416, 1016070144, 469237760, 9175040, 948830208, 1033961472, 280002560, 587841536, 1004855296, 100347904, 44251136, 874417152, 240665088, 876364544, 562558080, 658782144, 868909152, 6959728, 869949448, 190050308, 301422606, 250379271 - ], - [ - 536870912, 805306368, 671088640, 469762048, 436207616, 385875968, 578813952, 968884224, 463470592, 607125504, 734527488, 270270464, 774504448, 720306176, 836796416, 433111040, 806985728, 50606080, 162424832, 394308608, 138500608, 786453248, 391191680, 1004056512, 329606816, 354346416, 310962216, 561874300, 490414082, 232255499 - ], - [ - 536870912, 268435456, 134217728, 872415232, 234881024, 553648128, 142606336, 910163968, 740294656, 1001390080, 838336512, 534511616, 347471872, 630915072, 662011904, 188923904, 10018816, 936202240, 1027553280, 593488896, 583927296, 897981184, 690133120, 990507072, 260311072, 136010448, 263465128, 203654804, 629720714, 616863561 - ], - [ - 536870912, 268435456, 671088640, 872415232, 436207616, 16777216, 427819008, 356515840, 627048448, 330301440, 410517504, 583270400, 853671936, 865271808, 952860672, 677298176, 867524608, 297447424, 386349056, 958411776, 189890048, 747218176, 719102080, 1509184, 222930784, 360462704, 612835176, 358731124, 732987746, 74979449 - ], - [ - 536870912, 268435456, 134217728, 335544320, 905969664, 587202560, 595591168, 322961408, 631242752, 760217600, 1027080192, 572784640, 137756672, 782172160, 1013153792, 553762816, 645947392, 465653760, 23070720, 766620672, 382246400, 298625792, 74112384, 556576320, 932909664, 247855440, 432407656, 343287380, 314550250, 192066321 - ], - [ - 536870912, 268435456, 939524096, 201326592, 234881024, 520093696, 1015021568, 624951296, 467664896, 781189120, 794296320, 56885248, 843448320, 567738368, 856653824, 246038528, 852238336, 220942336, 990652416, 193694720, 41715200, 71436544, 826398080, 165798720, 126918240, 14169424, 346338920, 333953364, 673591398, 394702935 - ], - [ - 536870912, 805306368, 939524096, 201326592, 503316480, 150994944, 880803840, 784334848, 119537664, 267386880, 310902784, 298057728, 789708800, 341377024, 230522880, 752861184, 374300672, 651587584, 122357760, 1071940608, 610510336, 269492480, 391676800, 306003520, 429804832, 237902864, 709348872, 986895628, 16264590, 688757571 - ], - [ - 536870912, 805306368, 939524096, 469762048, 570425344, 721420288, 360710144, 826277888, 35651584, 963641344, 876085248, 472645632, 724959232, 243859456, 620068864, 839630848, 22536192, 56201216, 696064000, 394234880, 69040640, 355457280, 265617280, 100394944, 699312736, 806730544, 454812168, 1069454604, 494790030, 561999559 - ], - [ - 536870912, 805306368, 402653184, 201326592, 973078528, 654311424, 511705088, 138412032, 442499072, 110100480, 1009254400, 794034176, 2228224, 648740864, 810450944, 825507840, 414392320, 327315456, 278530048, 987126784, 364490240, 704419072, 154594688, 770210496, 334852448, 210962416, 175341416, 530752252, 90847982, 267301951 - ], - [ - 536870912, 268435456, 671088640, 872415232, 167772160, 486539264, 796917760, 373293056, 115343360, 630194176, 626524160, 434372608, 788135936, 134021120, 645824512, 114704384, 1010442240, 199004160, 63866880, 272550912, 271985152, 833303296, 444951168, 271246272, 600063648, 944480912, 26591368, 447975620, 159478826, 222351709 - ], - [ - 536870912, 805306368, 402653184, 738197504, 369098752, 50331648, 998244352, 968884224, 1029701632, 516947968, 106430464, 149159936, 789708800, 1039335424, 283279360, 651837440, 611262464, 426086400, 735217664, 202626048, 913529344, 824381696, 934950784, 750693696, 473771616, 414663920, 448794216, 920769788, 1058014830, 389562615 - ], - [ - 536870912, 805306368, 402653184, 738197504, 771751936, 50331648, 260046848, 297795584, 287309824, 802160640, 83361792, 532414464, 122028032, 32571392, 581533696, 1032110080, 73097216, 363229184, 973117440, 822164480, 981544448, 826317056, 559945344, 741360576, 898109408, 626277680, 220461064, 920341516, 552056326, 23110923 - ], - [ - 536870912, 268435456, 671088640, 603979776, 905969664, 956301312, 947912704, 759169024, 966787072, 1064304640, 565706752, 637272064, 501350400, 721092608, 569868288, 543997952, 529195008, 323932160, 1041291264, 1017674752, 450168320, 905442048, 778839168, 713799488, 969881504, 475056688, 76075432, 811985204, 11414818, 222372477 - ], - [ - 536870912, 268435456, 939524096, 872415232, 33554432, 855638016, 847249408, 926941184, 241172480, 242221056, 1018691584, 105119744, 128581632, 290914304, 918126592, 692404224, 992632832, 588689408, 995624960, 301288448, 204623360, 302217472, 5900416, 875551296, 131865056, 738145904, 456417128, 429102388, 408047110, 192117001 - ], - [ - 536870912, 268435456, 939524096, 335544320, 973078528, 16777216, 562036736, 12582912, 689963008, 684720128, 120061952, 60030976, 295567360, 415039488, 336232448, 505593856, 37167104, 275353600, 360048640, 854572032, 50626048, 584523008, 202933376, 743201344, 812778784, 593433136, 211614344, 190531396, 919241134, 839075957 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 838860800, 520093696, 377487360, 633339904, 950009856, 59768832, 190316544, 1035730944, 241041408, 14352384, 361267200, 914702336, 424878080, 151875584, 215410688, 887065600, 1058732544, 371800832, 764772736, 449462848, 93393184, 844629520, 574474920, 740249436, 641372686, 49870595 - ], - [ - 536870912, 268435456, 134217728, 872415232, 369098752, 822083584, 545259520, 994050048, 148897792, 919601152, 211288064, 6553600, 983433216, 424345600, 945651712, 88784896, 173858816, 709595136, 802977792, 663464960, 763178496, 960181504, 745866624, 1025941568, 543085792, 308941648, 19745128, 367234836, 393300874, 229164361 - ], - [ - 536870912, 805306368, 134217728, 67108864, 33554432, 285212672, 1048576000, 683671552, 316669952, 277872640, 470286336, 2359296, 507904000, 297992192, 917798912, 558874624, 912744448, 984788992, 145512448, 329423872, 702923264, 170322176, 630341504, 1046281920, 586880096, 464014992, 1024773096, 444514396, 559835018, 632185549 - ], - [ - 536870912, 805306368, 134217728, 469762048, 369098752, 788529152, 310378496, 289406976, 165675008, 600834048, 145227776, 549191680, 155582464, 923467776, 991199232, 494649344, 135110656, 192925696, 50235392, 994020352, 312372736, 422550784, 664229248, 941767104, 694711200, 756852560, 16158248, 749863580, 253836170, 552707275 - ], - [ - 536870912, 805306368, 939524096, 738197504, 167772160, 1023410176, 461373440, 616562688, 975175680, 355467264, 647495680, 175898624, 413532160, 815464448, 492601344, 504774656, 650354688, 184659968, 612497408, 373396480, 593545728, 1020350208, 789073024, 110389056, 715362336, 223407696, 113859752, 523618588, 928246918, 468309831 - ], - [ - 536870912, 805306368, 402653184, 67108864, 838860800, 822083584, 562036736, 926941184, 207618048, 835715072, 873988096, 307494912, 158728192, 312541184, 653361152, 665370624, 278667264, 230395904, 776112128, 663194624, 420084224, 409797376, 756219520, 475961536, 234686112, 770323888, 891002888, 1035096076, 330246150, 265608193 - ], - [ - 536870912, 805306368, 939524096, 67108864, 234881024, 385875968, 578813952, 717225984, 601882624, 149946368, 871890944, 563347456, 17432576, 520028160, 323256320, 90324992, 27451392, 88264704, 389253120, 168479744, 109007360, 411427072, 386065536, 252949056, 681289312, 1060607600, 449422056, 688780348, 598674566, 1047391821 - ], - [ - 536870912, 805306368, 939524096, 201326592, 503316480, 385875968, 92274688, 717225984, 157286400, 19922944, 296222720, 531890176, 857866240, 808910848, 180649984, 715800576, 571645952, 698224640, 561055744, 193508352, 455354880, 836449536, 614147712, 171689664, 988414432, 3362864, 554633064, 1032374012, 136621702, 509227727 - ], - [ - 536870912, 268435456, 402653184, 603979776, 973078528, 83886080, 327155712, 213909504, 1012924416, 665845760, 416808960, 105119744, 609615872, 1052966912, 125665280, 442646528, 783081472, 470446080, 1034958848, 232330240, 231074304, 211193088, 950178432, 634139968, 289131488, 606645008, 71139688, 616823380, 310220942, 300140621 - ], - [ - 536870912, 805306368, 402653184, 872415232, 301989888, 50331648, 931135488, 381681664, 723517440, 68157440, 68681728, 1044119552, 719716352, 135069696, 40861696, 761905152, 240394240, 103960576, 645838848, 426880000, 678030848, 416646400, 1014212224, 404681152, 847312224, 4275696, 291585672, 980487628, 803840870, 370414845 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 436207616, 150994944, 377487360, 658505728, 136314880, 261095424, 258473984, 1011613696, 663355392, 242024448, 823820288, 260423680, 370630656, 976162816, 518662144, 316482560, 174248448, 727713024, 833666688, 200857152, 279296224, 805722128, 260562568, 776455748, 422023398, 580353055 - ], - [ - 536870912, 805306368, 671088640, 872415232, 167772160, 251658240, 511705088, 205520896, 652214272, 495976448, 827850752, 515112960, 598081536, 445710336, 735674368, 821379072, 1044881408, 327241728, 432142336, 371307520, 204587520, 514418432, 826053760, 875265728, 911447968, 89565744, 43644936, 932557836, 420987402, 1014523661 - ], - [ - 536870912, 805306368, 402653184, 872415232, 771751936, 318767104, 1048576000, 364904448, 14680064, 32505856, 119013376, 595329024, 257556480, 361299968, 903184384, 748601344, 931045376, 336588800, 81188864, 776606720, 593509888, 162598656, 884568960, 61680320, 659795680, 589082704, 543835656, 15854348, 412620166, 423489997 - ], - [ - 536870912, 805306368, 671088640, 872415232, 1040187392, 452984832, 494927872, 432013312, 803209216, 477102080, 173539328, 40632320, 453115904, 5439488, 823820288, 304070656, 512253952, 333746176, 459786240, 838165504, 110004736, 790742272, 252812928, 527020096, 211068192, 280978992, 542739752, 393040444, 897756962, 806511409 - ], - [ - 536870912, 805306368, 671088640, 469762048, 369098752, 16777216, 25165824, 339738624, 195035136, 726663168, 346554368, 424411136, 317849600, 756482048, 900235264, 684507136, 783523840, 985092096, 150484992, 1030013952, 914296320, 1007005440, 776880000, 597539776, 169582880, 200954608, 101355688, 108152380, 47648258, 357150475 - ], - [ - 536870912, 805306368, 939524096, 872415232, 301989888, 218103808, 662700032, 968884224, 908066816, 588251136, 866648064, 325844992, 256245760, 278069248, 286294016, 245907456, 216817664, 42414080, 884209664, 1057084416, 444641792, 641736448, 1004640640, 120618432, 498618912, 121901904, 636125608, 703964572, 580122630, 739365889 - ], - [ - 536870912, 268435456, 939524096, 335544320, 100663296, 184549376, 276824064, 29360128, 899678208, 326107136, 299368448, 559153152, 516292608, 158793728, 177176576, 65683456, 563404800, 854052864, 1044776960, 548916224, 321823232, 43753216, 1028484224, 137510464, 834682592, 497101776, 1064417000, 64530388, 743830758, 88598737 - ], - [ - 536870912, 805306368, 402653184, 603979776, 234881024, 754974720, 612368384, 331350016, 807403520, 212860928, 746061824, 647757824, 920256512, 374800384, 377782272, 580337664, 287629312, 744935424, 507303936, 732621824, 353241600, 522835712, 745926784, 193925184, 132686368, 701817264, 444557992, 728813052, 978950798, 992761669 - ], - [ - 536870912, 268435456, 671088640, 603979776, 905969664, 520093696, 645922816, 348127232, 685768704, 737148928, 296222720, 143917056, 1063124992, 911015936, 597852160, 484851712, 553689088, 226521088, 742430720, 119645184, 328330752, 832080640, 391957888, 150694976, 811293728, 915122224, 296991624, 54477636, 813498282, 191500153 - ], - [ - 536870912, 268435456, 134217728, 335544320, 436207616, 419430400, 645922816, 1019215872, 455081984, 655360000, 704118784, 64749568, 41549824, 374538240, 542605312, 727826432, 32530432, 793260032, 1073002496, 813640704, 258284032, 130452224, 962152320, 881626688, 493025696, 457059056, 168090536, 355880436, 563144234, 87586993 - ], - [ - 536870912, 805306368, 134217728, 67108864, 167772160, 318767104, 645922816, 314572800, 379584512, 13631488, 580386816, 100925440, 666501120, 760938496, 501907456, 721600512, 407822336, 937996288, 986523648, 501718016, 340019712, 249192192, 212519296, 484615488, 662671712, 776000176, 794947944, 1022468796, 1049147754, 725372605 - ], - [ - 536870912, 268435456, 939524096, 201326592, 771751936, 83886080, 746586112, 322961408, 81788928, 577765376, 320339968, 300154880, 6946816, 455409664, 323649536, 452247552, 79880192, 293187584, 802473984, 605279232, 812765696, 270054144, 207905152, 497793984, 663058080, 475665552, 341631368, 295599044, 644290222, 99771539 - ], - [ - 536870912, 268435456, 939524096, 67108864, 33554432, 218103808, 92274688, 62914560, 878706688, 17825792, 199753728, 262930432, 893517824, 371392512, 196313088, 1008353280, 219570176, 178548736, 415176704, 648590336, 579660288, 863119616, 721080704, 994465472, 896384928, 782462896, 636739496, 935010228, 1046923174, 257731509 - ], - [ - 536870912, 805306368, 134217728, 67108864, 1040187392, 352321536, 713031680, 1035993088, 929038336, 189792256, 709361664, 443809792, 834273280, 591724544, 35880960, 582565888, 613261312, 269987840, 270764032, 1035478016, 755795456, 374771456, 235103360, 692662592, 301249824, 284820880, 954551432, 714253644, 727825186, 156348049 - ], - [ - 536870912, 268435456, 671088640, 335544320, 436207616, 721420288, 998244352, 608174080, 887095296, 542113792, 623378432, 190578688, 358481920, 1033043968, 54886400, 943439872, 802742272, 29683712, 150652928, 922297344, 238333440, 417504512, 933026176, 981424576, 1063505056, 232590992, 396254504, 464761684, 758407042, 660803777 - ], - [ - 536870912, 805306368, 671088640, 603979776, 436207616, 184549376, 1031798784, 331350016, 593494016, 609222656, 463994880, 751566848, 1020657664, 992280576, 398163968, 725762048, 900177920, 75304960, 267368448, 547380224, 523286016, 871972608, 157624448, 18506816, 829594080, 48131696, 207101576, 433331020, 237212010, 1022843449 - ], - [ - 536870912, 268435456, 939524096, 335544320, 436207616, 385875968, 159383552, 918552576, 228589568, 823132160, 213385216, 327417856, 251002880, 445579264, 430669824, 13385728, 1035722752, 385134592, 863913984, 543351808, 113271296, 631244544, 487689088, 45726784, 512012128, 276174672, 634342760, 583684180, 1014834918, 1268753 - ], - [ - 536870912, 268435456, 134217728, 469762048, 503316480, 587202560, 696254464, 1010827264, 333447168, 611319808, 73924608, 192675840, 276168704, 630784000, 894730240, 1072316416, 975167488, 367357952, 413390848, 607316992, 564818432, 83801856, 856971136, 353000768, 519007968, 625802032, 687843848, 890592004, 571123074, 896444999 - ], - [ - 536870912, 268435456, 134217728, 335544320, 973078528, 452984832, 176160768, 96468992, 656408576, 15728640, 620232704, 942407680, 669122560, 1054539776, 769097728, 751157248, 65429504, 1033646080, 586885120, 933633024, 100499968, 149574400, 546187392, 601406784, 685573920, 186289328, 318178600, 808787892, 153046442, 615617265 - ], - [ - 536870912, 268435456, 402653184, 335544320, 704643072, 385875968, 914358272, 994050048, 346030080, 653262848, 699924480, 867434496, 506855424, 1057161216, 947224576, 148258816, 517169152, 972845056, 565946368, 759196672, 899751424, 561010432, 225984128, 399852608, 916920160, 690637456, 728312296, 1052511956, 52149902, 984613953 - ], - [ - 536870912, 268435456, 402653184, 469762048, 503316480, 16777216, 847249408, 1035993088, 98566144, 818937856, 1023934464, 364118016, 648151040, 977076224, 517373952, 25149440, 138108928, 1017229312, 502310912, 549012480, 648934912, 645874432, 934999168, 903888192, 953199136, 956912848, 397738632, 966950468, 163372710, 295086487 - ], - [ - 536870912, 268435456, 402653184, 67108864, 369098752, 150994944, 394264576, 113246208, 987758592, 433061888, 434634752, 743178240, 796000256, 985726976, 954236928, 516997120, 57155584, 722251776, 441600000, 242334720, 1041806848, 294983424, 428273280, 660045632, 876522080, 120752016, 425754632, 17874948, 906502150, 807186433 - ], - [ - 536870912, 268435456, 402653184, 603979776, 637534208, 520093696, 880803840, 633339904, 652214272, 730857472, 198705152, 924581888, 262275072, 146341888, 1053589504, 702201856, 169091072, 977776640, 947337216, 807339008, 187391488, 220049152, 44214400, 490232000, 344802272, 947561360, 1034255880, 141500164, 182653062, 630758601 - ], - [ - 536870912, 268435456, 402653184, 469762048, 33554432, 956301312, 662700032, 264241152, 1004535808, 995098624, 425197568, 830734336, 1043464192, 96927744, 396197888, 789987328, 772087808, 1039298560, 606476288, 164467712, 332337664, 692144384, 530663808, 359691840, 1021873632, 906818864, 539982952, 370222964, 419027854, 536117059 - ], - [ - 536870912, 805306368, 939524096, 201326592, 369098752, 553648128, 729808896, 683671552, 1004535808, 716177408, 847773696, 684982272, 951975936, 655425536, 177831936, 751681536, 892493824, 973320192, 1028360192, 738073600, 1009804800, 801722112, 787828096, 409931840, 552199328, 564431088, 357984264, 188050444, 772673038, 999826179 - ], - [ - 536870912, 268435456, 134217728, 738197504, 234881024, 83886080, 780140544, 1052770304, 534773760, 749731840, 720896000, 111935488, 858390528, 150274048, 60194816, 976699392, 111599616, 462401536, 44730368, 666215424, 590745088, 1042805504, 72310656, 298496704, 1053140448, 1034814992, 75182472, 1018999236, 750916194, 137421019 - ], - [ - 536870912, 805306368, 402653184, 469762048, 100663296, 419430400, 864026624, 574619648, 39845888, 160432128, 854065152, 844365824, 616693760, 227082240, 574980096, 862633984, 188604416, 416788480, 892012544, 593361920, 373711360, 826538752, 113868928, 195378496, 79361440, 1035220112, 974357000, 276843276, 1052805254, 312590663 - ], - [ - 536870912, 268435456, 939524096, 469762048, 905969664, 654311424, 897581056, 222298112, 186646528, 252706816, 1069023232, 69468160, 705560576, 733806592, 851083264, 743096320, 1065574400, 11530240, 736991232, 857979904, 536789504, 66329856, 1003910784, 262765248, 35395232, 762031664, 831771784, 362190788, 185202734, 692873463 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 905969664, 620756992, 813694976, 1069547520, 98566144, 808452096, 599261184, 394526720, 442892288, 726597632, 962822144, 485081088, 818749440, 171577344, 333215744, 47422464, 957354496, 334050560, 55419008, 679115584, 628954208, 1052976336, 175758952, 660954580, 316060906, 188112795 - ], - [ - 536870912, 805306368, 671088640, 738197504, 369098752, 83886080, 947912704, 1052770304, 153092096, 275775488, 392691712, 274464768, 683278336, 958201856, 752582656, 655114240, 513990656, 346615808, 368887808, 336212992, 408272384, 125222144, 463412608, 948098624, 928548704, 97795984, 825662856, 75470412, 231991146, 641830811 - ], - [ - 536870912, 268435456, 939524096, 738197504, 838860800, 1056964608, 92274688, 79691776, 450887680, 814743552, 918028288, 877920256, 374996992, 671547392, 968982528, 140591104, 634429440, 915992576, 321153024, 720622592, 732629504, 99578112, 474813312, 842928448, 97789792, 479893616, 132609768, 533830708, 228163590, 816136207 - ], - [ - 536870912, 268435456, 402653184, 738197504, 503316480, 385875968, 427819008, 171966464, 547356672, 519045120, 227016704, 871628800, 530186240, 175177728, 860389376, 1033158656, 386621440, 594145280, 933509120, 836897792, 143405568, 99054848, 203394944, 60964928, 338460064, 488006096, 982923272, 936840196, 385266182, 776385803 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 1040187392, 721420288, 1065353216, 306184192, 257949696, 938475520, 827850752, 452198400, 197525504, 814809088, 178880512, 1034764288, 104062976, 987164672, 58316800, 132463616, 506343936, 48065280, 346724224, 1040412352, 867096992, 496797488, 457848840, 640928780, 181922314, 729306895 - ], - [ - 536870912, 268435456, 134217728, 67108864, 1040187392, 218103808, 92274688, 239075328, 568328192, 1060110336, 217579520, 44826624, 932315136, 296550400, 789741568, 309149696, 78815232, 851226624, 981125120, 963156992, 17086976, 1052152576, 9094016, 254883008, 351876832, 246192208, 227722120, 581776580, 663959266, 430807121 - ], - [ - 536870912, 268435456, 939524096, 738197504, 33554432, 184549376, 142606336, 1010827264, 677380096, 711983104, 376963072, 445906944, 366608384, 962265088, 52133888, 913981440, 831201280, 439562240, 386361344, 873278464, 629132800, 681118976, 765730432, 1010994496, 327150048, 496561968, 338029032, 797175604, 232679910, 684306239 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 436207616, 352321536, 176160768, 994050048, 773849088, 781189120, 640155648, 909377536, 239206400, 891224064, 994607104, 981778432, 888840192, 201469952, 331282432, 798571520, 504147456, 404675328, 365469056, 264628672, 702211808, 655613104, 290870632, 105655932, 733908482, 194521859 - ], - [ - 536870912, 268435456, 671088640, 201326592, 570425344, 520093696, 612368384, 54525952, 153092096, 311427072, 222822400, 790888448, 165019648, 500760576, 762085376, 712196096, 458186752, 462721024, 177158144, 418710528, 750774784, 300802304, 489924736, 342754368, 939799072, 507995952, 252760584, 193520900, 348406410, 648537411 - ], - [ - 536870912, 268435456, 939524096, 738197504, 771751936, 218103808, 25165824, 943718400, 610271232, 128974848, 470286336, 1061421056, 387842048, 632356864, 789086208, 197509120, 48193536, 395341824, 30992384, 301845504, 433234432, 464212736, 885511552, 122465344, 39458848, 95374320, 70838280, 1041091588, 431661582, 257905419 - ], - [ - 536870912, 805306368, 939524096, 738197504, 33554432, 285212672, 847249408, 574619648, 782237696, 101711872, 746061824, 800325632, 376832000, 3211264, 86605824, 636338176, 546529280, 606015488, 536610816, 116118528, 246067712, 353010944, 932964480, 111304640, 641190816, 932211888, 632907784, 97895436, 847723022, 402166027 - ], - [ - 536870912, 805306368, 134217728, 603979776, 167772160, 788529152, 8388608, 759169024, 836763648, 267386880, 782761984, 762052608, 520749056, 182255616, 532905984, 226574336, 381722624, 505417728, 407918592, 439899136, 242487808, 766479104, 436868480, 358382144, 973264096, 891415824, 584174984, 276393548, 454321890, 85947929 - ], - [ - 536870912, 268435456, 402653184, 469762048, 301989888, 956301312, 796917760, 130023424, 895483904, 32505856, 266862592, 231473152, 551944192, 77791232, 855212032, 991182848, 388112384, 926511104, 796252160, 626160640, 756064768, 786007296, 734309504, 563866816, 613269280, 835160656, 1039372712, 746623892, 88168974, 186745091 - ], - [ - 536870912, 805306368, 134217728, 872415232, 100663296, 788529152, 746586112, 104857600, 480247808, 735051776, 1018691584, 972292096, 977928192, 226820096, 195264512, 461979648, 624697344, 72773632, 113498112, 809096192, 263490048, 787112192, 307625088, 823904448, 226348320, 871842192, 261227656, 297823436, 6332194, 372372637 - ], - [ - 536870912, 268435456, 671088640, 469762048, 1040187392, 989855744, 746586112, 624951296, 312475648, 397410304, 484966400, 859570176, 503185408, 984023040, 326336512, 850444288, 459874304, 318525440, 907986944, 28724224, 589960704, 837032704, 283779712, 654680000, 142314272, 1016896848, 969889064, 630114900, 246374818, 64966291 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 234881024, 620756992, 880803840, 79691776, 450887680, 1020264448, 749207552, 1067188224, 522321920, 294322176, 488013824, 129351680, 343875584, 1011470336, 206387200, 940293120, 156649984, 60138752, 625934208, 867193024, 171526432, 840216496, 621740840, 93391548, 269089954, 745364083 - ], - [ - 536870912, 805306368, 939524096, 67108864, 436207616, 150994944, 746586112, 205520896, 44040192, 238026752, 956825600, 252968960, 48103424, 671940608, 364085248, 65978368, 444899328, 291934208, 777037824, 81269760, 873282048, 1001593088, 686729088, 990213952, 732379168, 699477296, 617190792, 259385932, 252677550, 722835313 - ], - [ - 536870912, 268435456, 671088640, 603979776, 234881024, 956301312, 260046848, 289406976, 211812352, 95420416, 428343296, 869531648, 1029308416, 377028608, 712802304, 184500224, 1036656640, 369225728, 620759040, 226499584, 37870080, 874634496, 577870208, 199768640, 730165664, 767795792, 966087176, 1031438596, 302539658, 1016403785 - ], - [ - 536870912, 268435456, 671088640, 335544320, 234881024, 83886080, 243269632, 381681664, 379584512, 248512512, 842530816, 819200000, 1007550464, 666173440, 637435904, 538722304, 955392000, 586559488, 448858112, 883016704, 970030592, 599265536, 596940928, 938440896, 662975008, 427225776, 981481608, 146868420, 1000413738, 340788917 - ], - [ - 536870912, 805306368, 134217728, 67108864, 301989888, 855638016, 310378496, 683671552, 908066816, 856686592, 849870848, 614727680, 621412352, 448593920, 240615424, 760954880, 661954560, 495144960, 319354880, 1022731264, 549588480, 90807552, 637885056, 400210496, 1001699488, 832795536, 387517576, 249353036, 531010594, 79933649 - ], - [ - 536870912, 268435456, 939524096, 335544320, 100663296, 620756992, 377487360, 792723456, 580911104, 412090368, 306708480, 547094528, 815661056, 247922688, 408125440, 896548864, 947511296, 306532352, 374061056, 415542272, 51013120, 895752960, 974818176, 1038988224, 619076128, 243422800, 756646952, 506847572, 45279654, 717228433 - ], - [ - 536870912, 805306368, 671088640, 469762048, 570425344, 1023410176, 75497472, 985661440, 190840832, 877658112, 215482368, 780402688, 669122560, 195756032, 630620160, 354533376, 904929280, 468234240, 168564736, 666819584, 1070406144, 224274688, 31223680, 237436736, 258596960, 684500464, 417227368, 899518716, 512178146, 383383227 - ], - [ - 536870912, 268435456, 939524096, 67108864, 637534208, 385875968, 142606336, 775946240, 740294656, 743440384, 292028416, 851181568, 742785024, 565903360, 777879552, 1031225344, 69394432, 764973056, 801425408, 145955840, 965813760, 763960064, 864894848, 836698048, 645873056, 451923024, 652706344, 413823892, 26500998, 953823173 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 503316480, 83886080, 226492416, 935329792, 610271232, 338690048, 683147264, 314834944, 132775936, 634454016, 256409600, 337461248, 639623168, 470020096, 119384064, 44018688, 272768512, 767406848, 558872960, 504013248, 1042404384, 395426384, 820529160, 307059716, 597112330, 905928463 - ], - [ - 536870912, 805306368, 939524096, 67108864, 234881024, 587202560, 478150656, 171966464, 526385152, 126877696, 974651392, 121372672, 595722240, 426442752, 400457728, 1064910848, 632053760, 438013952, 43403264, 209521664, 23326208, 423275776, 224806272, 460668736, 285624736, 811914032, 425693096, 741925436, 860646438, 743079037 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 301989888, 352321536, 75497472, 79691776, 576716800, 846200832, 155713536, 814481408, 835846144, 462225408, 710115328, 449593344, 645029888, 152883200, 782944256, 48821248, 1895936, 137029376, 992607616, 452750656, 748411360, 83891152, 478281096, 281046348, 207739370, 896603103 - ], - [ - 536870912, 268435456, 939524096, 738197504, 905969664, 419430400, 8388608, 750780416, 115343360, 735051776, 498597888, 602669056, 977403904, 512688128, 58556416, 274415616, 504602624, 645353472, 842086400, 132705280, 102003200, 697256192, 654120320, 840603968, 20080544, 1036395248, 832131624, 1071426484, 413904262, 370816335 - ], - [ - 536870912, 268435456, 671088640, 738197504, 637534208, 922746880, 327155712, 1002438656, 1000341504, 703594496, 555220992, 378798080, 420610048, 816644096, 439779328, 717635584, 324984832, 596373504, 569907200, 914689024, 681276928, 502376704, 320341376, 60125120, 932316192, 166509776, 1054315400, 282474180, 467048874, 106405659 - ], - [ - 536870912, 805306368, 939524096, 201326592, 905969664, 285212672, 1031798784, 331350016, 815792128, 552599552, 600309760, 746848256, 980287488, 522649600, 853704704, 862797824, 676995072, 501288960, 487643136, 249107456, 442341888, 741558016, 85300352, 653783232, 672867296, 327207952, 1052817896, 52464412, 775007590, 417938399 - ], - [ - 536870912, 805306368, 134217728, 469762048, 570425344, 1023410176, 914358272, 650117120, 450887680, 439353344, 511180800, 948174848, 310509568, 652935168, 449216512, 495501312, 127737856, 678932480, 170989568, 645450752, 746924544, 746763520, 971710592, 289905984, 231248480, 1002288624, 682033256, 242793724, 8729322, 109242555 - ], - [ - 536870912, 805306368, 402653184, 67108864, 905969664, 184549376, 1048576000, 1069547520, 710934528, 732954624, 347602944, 588513280, 897187840, 387121152, 932085760, 798507008, 889544704, 1007898624, 957270016, 140024832, 459608576, 564377856, 649552000, 365806400, 299764960, 483523760, 982038248, 787319228, 130944110, 364408829 - ], - [ - 536870912, 805306368, 939524096, 201326592, 234881024, 318767104, 847249408, 658505728, 367001600, 357564416, 784859136, 663486464, 759824384, 497352704, 941064192, 753319936, 2023424, 55259136, 1051047936, 848806912, 128414208, 469709568, 85699712, 585944896, 844875744, 1057844112, 319438472, 331664460, 696767342, 521101523 - ], - [ - 536870912, 805306368, 134217728, 67108864, 637534208, 16777216, 713031680, 801112064, 937426944, 611319808, 765984768, 741605376, 847118336, 532348928, 808222720, 520339456, 604069888, 369135616, 151091200, 780237824, 163650048, 920701184, 250726528, 40448192, 466990048, 370135504, 840106856, 471375132, 763177610, 1002128845 - ], - [ - 536870912, 268435456, 402653184, 201326592, 369098752, 956301312, 830472192, 180355072, 408944640, 397410304, 668467200, 848560128, 959315968, 159711232, 740720640, 955891712, 696573952, 1009152000, 553166848, 629521408, 707223040, 435695360, 335862656, 552007104, 26854688, 62165424, 121508744, 856488388, 983225126, 247165619 - ], - [ - 536870912, 268435456, 671088640, 67108864, 570425344, 285212672, 8388608, 859832320, 421527552, 609222656, 973602816, 1015808000, 457572352, 417923072, 649887744, 373243904, 792535040, 436178944, 190629888, 328115200, 646236672, 936042752, 732853888, 978674240, 310638944, 671255216, 910387720, 568537348, 32710282, 291182145 - ], - [ - 536870912, 805306368, 402653184, 335544320, 838860800, 553648128, 713031680, 901775360, 882900992, 1053818880, 717750272, 815005696, 485359616, 987037696, 890208256, 1013301248, 725032960, 522735616, 941893632, 500564992, 874055168, 710729984, 880513152, 842663744, 1037749280, 678124592, 1037176968, 31377228, 330066982, 455330869 - ], - [ - 536870912, 268435456, 402653184, 67108864, 33554432, 318767104, 209715200, 46137344, 815792128, 462422016, 445120512, 242483200, 168165376, 1005256704, 1020362752, 594034688, 822403072, 780021760, 178751488, 679181312, 978924032, 723383040, 704883072, 169189568, 943115232, 963840400, 544069736, 75179604, 878184462, 639384581 - ], - [ - 536870912, 268435456, 134217728, 603979776, 100663296, 1023410176, 897581056, 1027604480, 65011712, 122683392, 805830656, 253493248, 997851136, 459997184, 797147136, 89112576, 436002816, 1034670080, 404994048, 981390336, 182738432, 853430528, 726938496, 470169536, 184609056, 276830192, 616616232, 480314356, 1068527402, 1071153917 - ], - [ - 536870912, 268435456, 939524096, 603979776, 1040187392, 486539264, 780140544, 859832320, 442499072, 670040064, 936902656, 298582016, 450232320, 728039424, 562200576, 522108928, 1027645440, 794865664, 359663616, 513385472, 682394112, 245845760, 24957312, 426670016, 945398496, 101578736, 687233928, 24485060, 309031278, 220860217 - ], - [ - 536870912, 805306368, 402653184, 469762048, 973078528, 822083584, 964689920, 792723456, 136314880, 420478976, 924319744, 108265472, 37093376, 106496000, 693469184, 833011712, 176283648, 197152768, 1021396992, 326183936, 631810560, 910018816, 50005120, 877380288, 302183072, 30316848, 660417032, 818612492, 381871238, 330273479 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 167772160, 419430400, 226492416, 79691776, 845152256, 504365056, 844627968, 49545216, 1036648448, 776929280, 340623360, 628047872, 352133120, 1061629952, 205543424, 555860992, 162650624, 799579392, 545087360, 638028864, 48331360, 827436912, 804871656, 100980532, 314811782, 826483019 - ], - [ - 536870912, 805306368, 671088640, 469762048, 234881024, 1023410176, 662700032, 876609536, 358612992, 812646400, 142082048, 392953856, 1057095680, 24444928, 111116288, 533610496, 514220032, 398700544, 383043584, 374303744, 669424128, 220360448, 249906560, 89636544, 1039916512, 500746576, 750632840, 699032012, 321933418, 228137879 - ], - [ - 536870912, 268435456, 939524096, 67108864, 771751936, 285212672, 696254464, 272629760, 685768704, 321912832, 167247872, 381943808, 236060672, 683868160, 428572672, 368459776, 926965760, 73404416, 1022367744, 609784832, 714356224, 362414336, 916394112, 36475712, 306079584, 66908400, 267788136, 541095156, 14692710, 791798261 - ], - [ - 536870912, 268435456, 134217728, 201326592, 369098752, 520093696, 109051904, 71303168, 1054867456, 309329920, 154664960, 866910208, 514457600, 601817088, 489259008, 799326208, 39723008, 199872512, 117753856, 734956544, 522286592, 542237952, 988404864, 176459328, 990856864, 545351472, 54643752, 1013046388, 204578314, 1054456071 - ], - [ - 536870912, 268435456, 939524096, 872415232, 369098752, 285212672, 562036736, 792723456, 1004535808, 28311552, 608698368, 995360768, 274071552, 418971648, 211582976, 994295808, 936288256, 219492352, 372754432, 738749440, 540338688, 656811776, 470886784, 463037504, 535574432, 296483888, 97198600, 507136772, 236176270, 1052132173 - ], - [ - 536870912, 805306368, 402653184, 738197504, 167772160, 83886080, 394264576, 826277888, 689963008, 97517568, 152567808, 675020800, 310509568, 235208704, 7307264, 522174464, 748150784, 529666048, 343738368, 673369088, 76894720, 56061184, 712155264, 349044672, 910819424, 455129424, 483398280, 211321548, 813541606, 639863451 - ], - [ - 536870912, 805306368, 671088640, 872415232, 369098752, 620756992, 645922816, 557842432, 593494016, 118489088, 639107072, 157548544, 869400576, 678625280, 348291072, 1047248896, 900096000, 968413184, 198506496, 142232576, 322897408, 480001280, 166131072, 274320704, 663077472, 167976688, 147530344, 731320060, 206649954, 846811889 - ], - [ - 536870912, 805306368, 134217728, 872415232, 503316480, 520093696, 813694976, 381681664, 224395264, 942669824, 493355008, 941359104, 529399808, 652935168, 922779648, 880918528, 12705792, 643911680, 380635136, 346651648, 100479488, 830397696, 920824448, 925739712, 912714656, 506977424, 250485544, 81413980, 594018314, 387710977 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 436207616, 989855744, 578813952, 801112064, 610271232, 9437184, 771227648, 675545088, 839778304, 193134592, 138510336, 606158848, 816848896, 55128064, 906823680, 126012416, 977365504, 455138560, 875620224, 227052352, 200080864, 173214288, 471455848, 395698196, 727154694, 62275595 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 167772160, 251658240, 612368384, 440401920, 480247808, 61865984, 208142336, 1054081024, 1001521152, 1056636928, 744390656, 417611776, 1744896, 1062105088, 87902208, 27675648, 346664448, 355803904, 723698304, 971188160, 486714976, 689063792, 877371496, 431363196, 737192686, 331890611 - ], - [ - 536870912, 268435456, 134217728, 872415232, 369098752, 16777216, 578813952, 197132288, 316669952, 879755264, 126353408, 575930368, 642908160, 890568704, 443711488, 788873216, 390799360, 750383104, 771565568, 135783424, 528414208, 240825088, 67122560, 234938176, 1023524640, 8421840, 482391432, 828415812, 489692962, 514339293 - ], - [ - 536870912, 268435456, 402653184, 738197504, 436207616, 754974720, 142606336, 876609536, 182452224, 479199232, 987234304, 749993984, 491388928, 887422976, 624066560, 203538432, 523362304, 1009258496, 314312704, 465998848, 881576448, 1053135616, 84084352, 562635200, 122466592, 776881296, 365399688, 1066104260, 423893798, 952240027 - ], - [ - 536870912, 268435456, 671088640, 738197504, 436207616, 16777216, 864026624, 574619648, 1059061760, 951058432, 314048512, 448004096, 960364544, 785317888, 987201536, 328384512, 414556160, 742289408, 55572480, 798467072, 70424064, 818208512, 275169920, 1009402688, 58841312, 440523280, 992059624, 246464020, 163092194, 674566431 - ], - [ - 536870912, 268435456, 402653184, 469762048, 905969664, 754974720, 662700032, 926941184, 803209216, 238026752, 771227648, 528744448, 54657024, 597229568, 66355200, 584761344, 795729920, 430911488, 443983872, 316824576, 533285376, 343717632, 700898688, 459009472, 556656416, 600819088, 604416520, 746227460, 868021638, 99054023 - ], - [ - 536870912, 805306368, 671088640, 738197504, 436207616, 620756992, 528482304, 46137344, 987758592, 986710016, 522715136, 504102912, 62259200, 401276928, 724860928, 24297472, 486612992, 729821184, 482392064, 702592000, 441465344, 661186816, 967638400, 21445056, 150134304, 281131856, 65051560, 391198364, 350814082, 560833735 - ], - [ - 536870912, 268435456, 402653184, 67108864, 637534208, 520093696, 964689920, 1044381696, 492830720, 860880896, 192413696, 44302336, 456523776, 88539136, 856653824, 167985152, 464084992, 446517248, 477308928, 836838400, 26310144, 886631680, 374697856, 12576832, 980076384, 135610832, 232722280, 289043924, 124531054, 695921877 - ], - [ - 536870912, 268435456, 134217728, 738197504, 33554432, 889192448, 226492416, 12582912, 538968064, 531628032, 83361792, 287047680, 838991872, 392888320, 843022336, 156876800, 510500864, 517681152, 902289408, 113529856, 976159232, 332483328, 2624128, 968106816, 251066016, 360465712, 450071720, 1036151348, 1003183146, 114251391 - ], - [ - 536870912, 268435456, 671088640, 201326592, 905969664, 654311424, 578813952, 440401920, 207618048, 493879296, 806879232, 719585280, 559808512, 557252608, 810254336, 3194880, 251240448, 97816576, 287762432, 547527680, 101547520, 694314240, 95189632, 682776640, 853865568, 358551824, 859267688, 759949332, 867198690, 288937303 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 973078528, 452984832, 377487360, 339738624, 513802240, 303038464, 880279552, 742129664, 679346176, 1030422528, 1030782976, 906608640, 850763776, 462041088, 868222976, 1063382016, 980440576, 713668352, 905295232, 799796032, 261191200, 247005200, 316415400, 584020060, 973285386, 682957827 - ], - [ - 536870912, 805306368, 402653184, 738197504, 503316480, 855638016, 612368384, 566231040, 1025507328, 80740352, 265814016, 714342400, 1032454144, 506134528, 305823744, 490881024, 927408128, 276156416, 729499648, 933424128, 162963968, 234679040, 49700224, 169724736, 730227680, 315917744, 518734824, 379213244, 936545262, 754907575 - ], - [ - 536870912, 805306368, 939524096, 738197504, 167772160, 855638016, 1031798784, 180355072, 761266176, 1047527424, 282591232, 1048313856, 222691328, 875888640, 22249472, 1001832448, 447602688, 772673536, 1050687488, 764500992, 568876544, 621051648, 707402112, 618341312, 641861472, 52300144, 889823112, 1068830924, 982776046, 207014331 - ], - [ - 536870912, 805306368, 939524096, 201326592, 369098752, 452984832, 914358272, 490733568, 954204160, 133169152, 285736960, 789839872, 183369728, 979173376, 446398464, 696434688, 904847360, 517861376, 1054537728, 652452864, 350118400, 133520128, 85956992, 525599040, 797958688, 778845104, 573733768, 797416012, 855153582, 740084467 - ], - [ - 536870912, 805306368, 939524096, 603979776, 570425344, 117440512, 662700032, 432013312, 891289600, 355467264, 361234432, 709623808, 1036386304, 567214080, 457342976, 220545024, 110845952, 640741376, 403277824, 680383488, 694610432, 138300160, 460027520, 203018432, 37026208, 228739344, 1043600296, 1000538652, 590734630, 1059295957 - ], - [ - 536870912, 805306368, 671088640, 67108864, 838860800, 318767104, 763363328, 532676608, 664797184, 735051776, 973602816, 217317376, 265945088, 423034880, 766541824, 595116032, 967663616, 476557312, 1039665152, 1005351936, 201773568, 898163456, 406090624, 704337600, 455605216, 286914416, 987615848, 1044313788, 835053570, 333644813 - ], - [ - 536870912, 805306368, 134217728, 872415232, 167772160, 251658240, 813694976, 230686720, 652214272, 735051776, 486014976, 838074368, 7733248, 699203584, 972259328, 164839424, 241377280, 864718848, 1021777920, 561296384, 1035347456, 122452736, 639810688, 522932928, 815223840, 58587120, 411712136, 1047001548, 531910818, 366395709 - ], - [ - 536870912, 268435456, 402653184, 872415232, 771751936, 117440512, 176160768, 826277888, 337641472, 776994816, 678952960, 551813120, 158728192, 764870656, 640122880, 879706112, 1057153024, 91852800, 191145984, 431389696, 410400256, 68663040, 736589184, 571452992, 569609568, 890270928, 492367208, 792044756, 13575534, 17959129 - ], - [ - 536870912, 805306368, 939524096, 201326592, 167772160, 822083584, 914358272, 339738624, 819986432, 787480576, 716701696, 434372608, 1011744768, 923729920, 242122752, 224346112, 46604288, 485715968, 131397632, 1062620160, 880438784, 522823936, 90996352, 582130496, 909462624, 522613264, 109300840, 1009594908, 651357286, 159728159 - ], - [ - 536870912, 805306368, 939524096, 872415232, 637534208, 251658240, 176160768, 734003200, 1021313024, 428867584, 571998208, 131334144, 257032192, 359596032, 94404608, 179322880, 426270720, 123506688, 102713344, 958999552, 704416256, 674199808, 142707584, 180448320, 895522400, 718385200, 473481192, 656742780, 362471430, 662949889 - ], - [ - 536870912, 268435456, 402653184, 738197504, 1040187392, 989855744, 864026624, 977272832, 857735168, 149946368, 887619584, 936116224, 438173696, 526450688, 617644032, 93896704, 275079168, 678686720, 1062131712, 901258240, 387289600, 14301440, 748935040, 718671680, 1037875808, 325566192, 26599432, 572207108, 239319046, 122153995 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 503316480, 1023410176, 847249408, 499122176, 908066816, 890241024, 706215936, 512491520, 62783488, 128122880, 289767424, 998916096, 373301248, 727814144, 636606464, 447323136, 818252288, 566933248, 723553664, 395351616, 802739616, 346857744, 682590248, 280669012, 1028218766, 636878155 - ], - [ - 536870912, 805306368, 402653184, 67108864, 973078528, 419430400, 8388608, 473956352, 367001600, 544210944, 662175744, 274989056, 917897216, 329449472, 351043584, 879443968, 609345536, 472412160, 466475008, 180022272, 221787648, 176489728, 692545664, 253491776, 782780384, 848149776, 970651496, 369666908, 463242894, 479400781 - ], - [ - 536870912, 268435456, 939524096, 67108864, 301989888, 855638016, 880803840, 608174080, 14680064, 141557760, 153616384, 512491520, 993656832, 914292736, 79265792, 441794560, 929030144, 132755456, 925730816, 439090176, 48735744, 574371072, 347249792, 727928512, 240824096, 231629488, 632321448, 738765172, 534629894, 490895621 - ], - [ - 536870912, 268435456, 939524096, 67108864, 905969664, 654311424, 478150656, 490733568, 1038090240, 95420416, 682098688, 373555200, 278790144, 193265664, 306085888, 450150400, 10919936, 335114240, 31299584, 741512192, 675213824, 668285696, 824622976, 121155136, 754804128, 849569456, 956710792, 1009348164, 654656942, 662623921 - ], - [ - 536870912, 268435456, 671088640, 738197504, 973078528, 620756992, 528482304, 364904448, 111149056, 793772032, 122159104, 41680896, 447610880, 125108224, 934445056, 640303104, 299819008, 825036800, 535267328, 604507136, 614315520, 731869440, 441213056, 840371520, 437295712, 1051245744, 164451976, 232209476, 296786666, 578347515 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 33554432, 218103808, 964689920, 406847488, 664797184, 550502400, 133693440, 354680832, 673841152, 692387840, 505053184, 642596864, 123166720, 228282368, 520882176, 326573056, 67766784, 81035520, 868449408, 905447104, 2478496, 631945616, 251960456, 918230724, 840710562, 560969119 - ], - [ - 536870912, 805306368, 671088640, 603979776, 1040187392, 822083584, 897581056, 960495616, 648019968, 984612864, 479723520, 152829952, 660209664, 557252608, 613711872, 1072611328, 698966016, 331698176, 610744320, 337380352, 953816576, 1064777472, 582282368, 933219136, 466710816, 860380080, 475276712, 101602556, 146317954, 443394117 - ], - [ - 536870912, 805306368, 939524096, 335544320, 1040187392, 184549376, 931135488, 557842432, 731906048, 330301440, 295174144, 413401088, 334364672, 254738432, 13533184, 1012875264, 1018683392, 23728128, 959465472, 274265088, 935624192, 733930240, 606592640, 126034496, 468483936, 562232336, 887947112, 268614684, 179150694, 841215001 - ], - [ - 536870912, 805306368, 671088640, 469762048, 33554432, 922746880, 796917760, 507510784, 224395264, 714080256, 176685056, 1026293760, 644743168, 30998528, 1015382016, 145965056, 430956544, 1073254400, 938833920, 124443648, 137036288, 466305792, 26890368, 515045952, 11419744, 226002160, 758512136, 969662220, 110834314, 422734151 - ], - [ - 536870912, 805306368, 402653184, 469762048, 503316480, 922746880, 847249408, 62914560, 878706688, 546308096, 879230976, 732168192, 351928320, 429850624, 176455680, 835403776, 134684672, 744001536, 364644352, 778439680, 231250432, 542471424, 914508672, 127061440, 683357024, 431924592, 506853608, 185804988, 746318734, 123608523 - ], - [ - 536870912, 268435456, 134217728, 201326592, 33554432, 150994944, 411041792, 717225984, 799014912, 598736896, 1063780352, 194248704, 497156096, 240844800, 668434432, 657047552, 469016576, 53620736, 1027815424, 638262272, 829299200, 4542208, 677086848, 819389376, 1017759328, 750010608, 483542120, 311632884, 234053866, 216159031 - ], - [ - 536870912, 268435456, 671088640, 335544320, 838860800, 83886080, 629145600, 482344960, 404750336, 674234368, 1019740160, 669777920, 539623424, 272171008, 788824064, 569851904, 802922496, 173019136, 312076288, 1064619008, 643814912, 904296704, 824427904, 678751296, 383678560, 614986192, 566410760, 711324932, 120042378, 436372805 - ], - [ - 536870912, 805306368, 671088640, 469762048, 704643072, 16777216, 545259520, 650117120, 1012924416, 860880896, 277348352, 304873472, 914751488, 304807936, 426541056, 1051115520, 249208832, 274018304, 43227136, 655993856, 331612672, 897240320, 266638720, 797703360, 98338848, 775895248, 6167976, 907002908, 403051906, 468335819 - ], - [ - 536870912, 268435456, 402653184, 335544320, 369098752, 218103808, 58720256, 952107008, 383778816, 852492288, 868745216, 483655680, 854458368, 666828800, 850886656, 964902912, 943579136, 260722688, 965326848, 997516288, 958382592, 1019651328, 255576960, 80761280, 784901472, 122973968, 506404200, 660572948, 224878446, 164261393 - ], - [ - 536870912, 805306368, 134217728, 872415232, 771751936, 822083584, 1031798784, 893386752, 836763648, 879755264, 250085376, 237240320, 284033024, 356974592, 595755008, 110936064, 846356480, 825593856, 532076544, 1051350016, 647556608, 718108928, 164359808, 1026058176, 268793824, 280963600, 218044904, 211718940, 531535722, 195519697 - ], - [ - 536870912, 268435456, 939524096, 469762048, 167772160, 251658240, 796917760, 851443712, 991952896, 844103680, 699924480, 758382592, 367132672, 728694784, 884572160, 28655616, 983769088, 831500288, 407480320, 664552448, 714066432, 164232960, 878502784, 657333056, 601435744, 881154480, 506071016, 607305204, 303548934, 162397955 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 369098752, 989855744, 25165824, 926941184, 685768704, 596639744, 792199168, 614203392, 720502784, 493027328, 274366464, 499597312, 666148864, 555159552, 342640640, 874185728, 10886656, 560220416, 936320384, 1071669312, 1007737504, 662242352, 670864040, 320995388, 540708006, 563497267 - ], - [ - 536870912, 268435456, 671088640, 872415232, 33554432, 385875968, 293601280, 574619648, 417333248, 988807168, 522715136, 781451264, 325976064, 697106432, 619872256, 245776384, 652746752, 657838080, 184440832, 219429888, 506411520, 1022145280, 172190080, 477068352, 873266208, 414378416, 927370120, 412660548, 484183978, 256620285 - ], - [ - 536870912, 268435456, 939524096, 738197504, 973078528, 184549376, 880803840, 96468992, 513802240, 439353344, 885522432, 870055936, 81133568, 198115328, 9142272, 978862080, 1042554880, 591622144, 788916224, 540191744, 346886656, 25075456, 260250240, 841300672, 155442464, 470140944, 951224104, 728615700, 350144422, 557052639 - ], - [ - 536870912, 268435456, 134217728, 872415232, 301989888, 50331648, 1065353216, 423624704, 81788928, 923795456, 84410368, 478937088, 97386496, 1008795648, 397443072, 611860480, 760586240, 795512832, 861083648, 1046903808, 1021118976, 824657664, 826132608, 112689216, 888459360, 379199600, 1045110792, 1046728708, 769538050, 816360461 - ], - [ - 536870912, 268435456, 402653184, 872415232, 771751936, 956301312, 343932928, 1002438656, 975175680, 271581184, 1010302976, 494141440, 180224000, 226689024, 588349440, 814235648, 915234816, 938135552, 899072, 1059843072, 564967936, 224079616, 653648000, 956270656, 786636384, 1069582416, 471891176, 87065364, 850974734, 833960969 - ], - [ - 536870912, 268435456, 671088640, 335544320, 33554432, 520093696, 494927872, 171966464, 1050673152, 258998272, 150470656, 1002176512, 226361344, 712704000, 991526912, 1005436928, 1052237824, 782217216, 36399104, 483447808, 1024056832, 411326208, 337888896, 198522944, 342580256, 611368208, 125355176, 117183060, 979353090, 759834369 - ], - [ - 536870912, 268435456, 671088640, 872415232, 771751936, 956301312, 8388608, 1010827264, 157286400, 267386880, 742916096, 486801408, 767688704, 305987584, 47087616, 546979840, 289415168, 937472000, 582035456, 296276992, 11885056, 837519104, 4757888, 1057246016, 650353824, 834458576, 688843656, 742004804, 722525994, 561602461 - ], - [ - 536870912, 805306368, 671088640, 603979776, 301989888, 587202560, 897581056, 423624704, 970981376, 877658112, 966262784, 914620416, 282460160, 623968256, 67731456, 54345728, 2301952, 1057984512, 433428480, 550464512, 351644160, 943718144, 383543936, 846452928, 529924640, 500251568, 249083912, 845544460, 67613194, 23646985 - ], - [ - 536870912, 268435456, 402653184, 603979776, 33554432, 1056964608, 847249408, 473956352, 723517440, 74448896, 471334912, 690749440, 541982720, 455409664, 665485312, 1022345216, 982818816, 609374208, 1037244416, 420684800, 762464768, 379802880, 797648256, 1008653248, 533475296, 266223408, 892098440, 374289092, 1042610278, 237751801 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 570425344, 184549376, 1031798784, 910163968, 169869312, 546308096, 914882560, 114032640, 20054016, 33882112, 601849856, 312983552, 500391936, 511004672, 958855168, 378723328, 617978368, 125285632, 150676096, 141151040, 297589216, 642415696, 812726408, 284802636, 724867942, 445048607 - ], - [ - 536870912, 268435456, 671088640, 469762048, 973078528, 620756992, 109051904, 205520896, 656408576, 198180864, 728236032, 772538368, 296615936, 400883712, 98729984, 376061952, 643260416, 136384512, 273680384, 363348992, 594311680, 576713984, 349970560, 172405824, 44578272, 216846768, 983456392, 113000772, 439784810, 189801975 - ], - [ - 536870912, 805306368, 671088640, 67108864, 570425344, 251658240, 394264576, 4194304, 48234496, 540016640, 1043857408, 282853376, 408027136, 74514432, 786006016, 401424384, 904536064, 921440256, 996931584, 606927872, 625713664, 859653888, 920836480, 680009152, 539319520, 414071184, 573732872, 58833932, 977371658, 568416001 - ], - [ - 536870912, 805306368, 939524096, 335544320, 234881024, 956301312, 612368384, 79691776, 291504128, 303038464, 641204224, 564920320, 702676992, 750321664, 745373696, 604225536, 778674176, 355856384, 784205824, 87196672, 484496896, 978387712, 530109568, 954058688, 717897312, 917255056, 73586184, 888668940, 768431246, 695338949 - ], - [ - 536870912, 805306368, 671088640, 335544320, 436207616, 50331648, 679477248, 918552576, 929038336, 1041235968, 900202496, 951320576, 270925824, 708902912, 732004352, 577847296, 926457856, 568119296, 485627904, 754336768, 42546688, 101022464, 998117504, 151838016, 775589280, 39034160, 856129544, 250626060, 66658314, 700289029 - ], - [ - 536870912, 268435456, 939524096, 201326592, 503316480, 889192448, 679477248, 708837376, 656408576, 133169152, 574095360, 176422912, 724959232, 16318464, 400850944, 870825984, 691101696, 559443968, 659843072, 712975360, 470065664, 611717376, 928627584, 911516608, 687758624, 289779248, 14033416, 124309764, 831282062, 686494659 - ], - [ - 536870912, 805306368, 939524096, 603979776, 436207616, 150994944, 360710144, 926941184, 241172480, 808452096, 724041728, 1035730944, 1039532032, 273350656, 633110528, 704004096, 843833344, 146632704, 645322752, 202048512, 324822528, 554111232, 692254336, 516996800, 937010592, 79033552, 110842664, 241519132, 323155590, 667991749 - ], - [ - 536870912, 268435456, 671088640, 603979776, 973078528, 956301312, 696254464, 289406976, 333447168, 363855872, 188219392, 529793024, 648937472, 1051656192, 581926912, 346996736, 867164160, 422457344, 418379776, 869184512, 618544640, 699834624, 682232960, 447239488, 490580448, 663886992, 792570344, 714218644, 347974114, 651304093 - ], - [ - 536870912, 805306368, 939524096, 872415232, 301989888, 318767104, 58720256, 968884224, 715128832, 619708416, 585629696, 776208384, 998113280, 792395776, 994344960, 167657472, 1048272896, 530952192, 745424896, 29615104, 880304640, 578605824, 291673728, 1065996992, 487945824, 870817616, 752345320, 1067339164, 984258182, 1023267521 - ], - [ - 536870912, 805306368, 939524096, 67108864, 301989888, 553648128, 427819008, 935329792, 966787072, 19922944, 896008192, 400818176, 428474368, 660537344, 129794048, 419840000, 808509440, 619261952, 472143872, 908846080, 359588352, 173406976, 547571840, 668662976, 992405856, 801153776, 228719080, 724679228, 275378822, 476373965 - ], - [ - 536870912, 268435456, 134217728, 738197504, 33554432, 50331648, 360710144, 398458880, 35651584, 221249536, 983040000, 557056000, 915537920, 687931392, 713064448, 138428416, 987848704, 412094464, 594024448, 202157056, 223788544, 657133824, 797305216, 785061056, 982854048, 1046627472, 448266248, 1057226756, 294256642, 871694347 - ], - [ - 536870912, 268435456, 134217728, 469762048, 1040187392, 1056964608, 494927872, 524288000, 828375040, 468713472, 378011648, 430178304, 524156928, 322240512, 38174720, 337199104, 417095680, 638824448, 917379072, 768384000, 623624704, 576898816, 778483072, 797505344, 1059399328, 939461552, 538234248, 878172996, 614530210, 609308855 - ], - [ - 536870912, 805306368, 402653184, 738197504, 503316480, 16777216, 998244352, 247463936, 941621248, 277872640, 819462144, 1029439488, 841613312, 1037631488, 685604864, 636141568, 309878784, 680357888, 739428352, 70630400, 616498688, 347474176, 240302208, 206913728, 323879904, 824089040, 266798600, 388630796, 475576454, 219955403 - ], - [ - 536870912, 268435456, 671088640, 603979776, 100663296, 956301312, 864026624, 356515840, 195035136, 426770432, 159907840, 284426240, 932839424, 103350272, 528777216, 789790720, 22814720, 996061184, 463177728, 875117568, 142957056, 26473728, 563955584, 482319936, 986369696, 831578448, 442071560, 1066222852, 430362506, 367436361 - ], - [ - 536870912, 268435456, 134217728, 67108864, 301989888, 989855744, 1015021568, 272629760, 350224384, 831520768, 953679872, 705429504, 126746624, 777584640, 491552768, 837697536, 579411968, 619974656, 1035180032, 637453312, 361861632, 987348736, 420219008, 1058010304, 739884896, 850201840, 1023382024, 168869636, 437815426, 195933377 - ], - [ - 536870912, 805306368, 939524096, 335544320, 234881024, 956301312, 746586112, 750780416, 408944640, 368050176, 584581120, 523501568, 1015939072, 780861440, 381452288, 871514112, 60317696, 588599296, 736000000, 750980096, 471921152, 659565824, 977823872, 513544000, 446862432, 13639248, 285738216, 498949404, 879886982, 416824905 - ], - [ - 536870912, 268435456, 134217728, 335544320, 100663296, 318767104, 864026624, 398458880, 794820608, 619708416, 714604544, 859045888, 980549632, 281608192, 289177600, 1018052608, 819437568, 567521280, 819550208, 345373696, 409103872, 140538624, 24155008, 643346112, 1003839648, 256049424, 103814664, 897089284, 998507906, 1011519941 - ], - [ - 536870912, 268435456, 134217728, 67108864, 704643072, 989855744, 629145600, 1061158912, 643825664, 179306496, 851968000, 710672384, 1007026176, 439418880, 688422912, 637288448, 236331008, 292048896, 642603008, 778005504, 267704832, 308994816, 104779136, 71637568, 908277984, 849505072, 191059976, 1002597380, 106060290, 155951873 - ], - [ - 536870912, 805306368, 134217728, 201326592, 369098752, 1023410176, 109051904, 926941184, 119537664, 321912832, 530055168, 131334144, 568983552, 66387968, 895188992, 866992128, 871358464, 383250432, 921896960, 979387392, 118616576, 858299648, 864820096, 1029679552, 227524896, 197575824, 786168712, 845961676, 193906978, 247955603 - ], - [ - 536870912, 268435456, 939524096, 738197504, 167772160, 1056964608, 696254464, 901775360, 10485760, 821035008, 38273024, 446955520, 843186176, 234160128, 360349696, 316194816, 775806976, 1042255872, 1044092928, 171482112, 900535808, 352839936, 178657664, 64372544, 207595168, 978993744, 854090120, 39138116, 604711086, 827340635 - ], - [ - 536870912, 805306368, 671088640, 335544320, 301989888, 486539264, 176160768, 834666496, 933232640, 921698304, 129499136, 296484864, 1056833536, 280297472, 220430336, 724713472, 706355200, 442454016, 130385920, 383427584, 1065293312, 1022734592, 549639552, 388125376, 305393120, 446428848, 580903816, 686076876, 216707178, 98959477 - ], - [ - 536870912, 268435456, 134217728, 738197504, 503316480, 50331648, 780140544, 859832320, 736100352, 554696704, 539492352, 1038876672, 719192064, 469434368, 559513600, 370458624, 993730560, 75010048, 153380864, 245574656, 223120896, 472823040, 214110080, 329096640, 833045536, 979361424, 1002169768, 741893716, 675661322, 787613967 - ], - [ - 536870912, 268435456, 939524096, 335544320, 234881024, 218103808, 377487360, 88080384, 845152256, 223346688, 936902656, 923533312, 114163712, 786366464, 996638720, 960118784, 472702976, 201297920, 995522560, 976456704, 406373888, 412910848, 850818944, 883152192, 549507872, 77720656, 15805224, 396894292, 1021644070, 281752913 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 503316480, 1023410176, 494927872, 390070272, 1029701632, 319815680, 1010302976, 144441344, 232390656, 327221248, 843153408, 887177216, 642899968, 576253952, 990767104, 992144384, 826128896, 300575488, 138991744, 548766144, 335541472, 50816720, 951713800, 210829324, 947486730, 1031618575 - ], - [ - 536870912, 268435456, 939524096, 67108864, 704643072, 385875968, 562036736, 448790528, 866123776, 265289728, 699924480, 988020736, 523632640, 332595200, 635797504, 313999360, 521330688, 793047040, 31893504, 451630080, 490809856, 945939200, 485603200, 606705984, 649869792, 904100112, 577605224, 64675924, 122271622, 500013381 - ], - [ - 536870912, 268435456, 671088640, 469762048, 503316480, 1056964608, 947912704, 985661440, 1012924416, 357564416, 952631296, 69468160, 280625152, 834469888, 139886592, 253902848, 340877312, 793325568, 778328064, 169595904, 109960704, 449797888, 189724800, 974033728, 841963680, 48115984, 900169352, 433723460, 829193770, 1004535127 - ], - [ - 536870912, 805306368, 671088640, 335544320, 771751936, 117440512, 931135488, 801112064, 975175680, 869269504, 1004011520, 1059323904, 1049755648, 250413056, 189759488, 420102144, 304619520, 120434688, 309319680, 458976256, 355513856, 464033024, 938261632, 600744384, 1028390560, 1036562640, 668750472, 719788236, 132633642, 23540757 - ], - [ - 536870912, 805306368, 402653184, 738197504, 100663296, 352321536, 444596224, 994050048, 618659840, 147849216, 533200896, 584843264, 174718976, 686227456, 151289856, 912211968, 622895104, 661704704, 737695744, 432348160, 830422528, 357651712, 822621568, 754819776, 1050390432, 1021195056, 912376360, 932285948, 153736078, 353217479 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 704643072, 486539264, 411041792, 549453824, 102760448, 506462208, 309854208, 412876800, 545652736, 467206144, 871137280, 882884608, 127197184, 855887872, 647112704, 110797824, 77469184, 798324992, 922994048, 814943680, 832301536, 18862000, 399832584, 300132612, 679701902, 1037265359 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 503316480, 654311424, 629145600, 759169024, 513802240, 638582784, 390594560, 434896896, 862846976, 787546112, 75005952, 720650240, 988536832, 287567872, 923711488, 436268032, 486558208, 679585024, 230758528, 794844736, 393326944, 658057328, 458610696, 91970564, 892015106, 390314255 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 704643072, 16777216, 746586112, 801112064, 195035136, 66060288, 680001536, 312213504, 11665408, 865140736, 114917376, 451166208, 724033536, 150884352, 278562816, 192783360, 866344448, 143240448, 580724608, 145963072, 261121760, 752390800, 467986440, 128431116, 658388482, 456808719 - ], - [ - 536870912, 268435456, 939524096, 335544320, 704643072, 956301312, 427819008, 331350016, 52428800, 420478976, 279445504, 171704320, 516292608, 806682624, 934969344, 531808256, 442441728, 143724544, 1063790592, 253557760, 14067200, 708660480, 247976576, 135532096, 599408224, 900936432, 593458312, 286278468, 749300974, 205323445 - ], - [ - 536870912, 268435456, 402653184, 469762048, 771751936, 16777216, 75497472, 683671552, 65011712, 483393536, 870842368, 18087936, 562954240, 535363584, 655654912, 613335040, 694804480, 550891520, 586074112, 435799040, 941405696, 1019926272, 391062144, 352856384, 994336672, 229109488, 77379080, 403363588, 581902982, 349710663 - ], - [ - 536870912, 805306368, 134217728, 603979776, 167772160, 83886080, 813694976, 188743680, 375390208, 475004928, 656932864, 202113024, 6422528, 592117760, 356941824, 405061632, 804184064, 1005072384, 816633856, 865319936, 605279744, 248757504, 561177472, 16977088, 379212192, 799961392, 571049896, 440257596, 488334378, 594460917 - ], - [ - 536870912, 268435456, 939524096, 67108864, 637534208, 218103808, 696254464, 205520896, 954204160, 1043333120, 728236032, 324796416, 413794304, 60358656, 1007976448, 921157632, 868950016, 250130432, 354232320, 927640576, 992506368, 431759104, 899356032, 141645120, 747147232, 401431504, 520346120, 736391940, 590268302, 826751553 - ], - [ - 536870912, 268435456, 402653184, 469762048, 905969664, 1023410176, 713031680, 88080384, 6291456, 110100480, 120061952, 711196672, 33685504, 156565504, 496664576, 761905152, 126115840, 944992256, 14419968, 684614656, 384958976, 267138816, 156757632, 198111808, 359850912, 304946000, 460785288, 750724676, 101321126, 281147479 - ], - [ - 536870912, 268435456, 671088640, 201326592, 973078528, 855638016, 545259520, 784334848, 375390208, 263192576, 558366720, 419168256, 187301888, 729088000, 129400832, 955138048, 453763072, 6623232, 758003712, 837481472, 857005568, 621166336, 1009235840, 79166272, 544208736, 298557840, 537258376, 731874372, 52666602, 631851731 - ], - [ - 536870912, 805306368, 134217728, 738197504, 637534208, 922746880, 125829120, 322961408, 1067450368, 959447040, 474480640, 163315712, 982646784, 626720768, 94797824, 429178880, 427728896, 844173312, 966289408, 459600896, 978746880, 742222592, 617780864, 75213504, 861281312, 146634288, 840065576, 362487100, 591819946, 235173879 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 637534208, 50331648, 260046848, 62914560, 249561088, 883949568, 1066926080, 833880064, 257556480, 1032650752, 33456128, 375341056, 994992128, 113700864, 729430016, 895314944, 831919616, 13861632, 422612864, 1029177792, 567641376, 782952080, 632584584, 89862852, 277729954, 830421855 - ], - [ - 536870912, 805306368, 134217728, 603979776, 503316480, 1056964608, 1015021568, 1010827264, 673185792, 441450496, 893911040, 120324096, 931004416, 869597184, 1034649600, 301940736, 513122304, 504049664, 795842560, 566014976, 341256704, 193543424, 474776704, 831406400, 76388064, 972010800, 83629704, 334936140, 723091554, 476384633 - ], - [ - 536870912, 268435456, 134217728, 603979776, 33554432, 1056964608, 830472192, 104857600, 383778816, 477102080, 696778752, 821297152, 604897280, 321323008, 541294592, 892715008, 330293248, 70676480, 905660416, 128558080, 363177472, 760641792, 650882688, 1010891968, 367046240, 66159248, 919169128, 714361748, 817786602, 462381917 - ], - [ - 536870912, 805306368, 134217728, 603979776, 436207616, 117440512, 813694976, 943718400, 639631360, 776994816, 943194112, 330039296, 109707264, 105185280, 132087808, 637747200, 31563776, 347148288, 436819968, 14971904, 701442560, 337349888, 35501184, 922940096, 945864416, 158398224, 401196680, 441715660, 650616930, 125815001 - ], - [ - 536870912, 805306368, 402653184, 603979776, 905969664, 889192448, 528482304, 910163968, 652214272, 508559360, 79167488, 648806400, 895090688, 219348992, 615940096, 522731520, 146038784, 340152320, 438319104, 561079296, 306718208, 1051023616, 1059047296, 794642496, 634560032, 899074160, 416833576, 960292220, 490985902, 17809461 - ], - [ - 536870912, 268435456, 671088640, 201326592, 33554432, 50331648, 696254464, 390070272, 543162368, 1039138816, 1023934464, 900464640, 174981120, 343474176, 258244608, 107167744, 860315648, 767922176, 917755904, 887057408, 1058097664, 574147328, 361077632, 760376896, 896474208, 133721072, 1059361288, 25339652, 418795914, 439149891 - ], - [ - 536870912, 268435456, 402653184, 872415232, 1040187392, 553648128, 1031798784, 876609536, 551550976, 544210944, 164102144, 732692480, 572653568, 332070912, 959938560, 168640512, 825483264, 926126080, 842192896, 699552768, 150185472, 731011328, 514047616, 168541888, 899040928, 1050497840, 646676648, 878107188, 104629806, 739959033 - ], - [ - 536870912, 268435456, 134217728, 738197504, 973078528, 452984832, 192937984, 20971520, 811597824, 873463808, 607649792, 848560128, 357433344, 686751744, 73367552, 441958400, 353017856, 45707264, 156542976, 1022260224, 174013952, 525819136, 327904640, 695858240, 687140064, 845026448, 727174376, 227255444, 611861738, 41181343 - ], - [ - 536870912, 805306368, 939524096, 872415232, 33554432, 318767104, 813694976, 213909504, 488636416, 384827392, 145227776, 356777984, 101580800, 144637952, 413564928, 1021001728, 86564864, 1007022080, 242149376, 403680256, 631237120, 891736832, 630938752, 893947328, 412473824, 827786384, 49500648, 900536476, 816460774, 776066961 - ], - [ - 536870912, 805306368, 939524096, 738197504, 973078528, 117440512, 931135488, 583008256, 488636416, 999292928, 847773696, 854327296, 387055616, 990838784, 577011712, 1056849920, 429760512, 279654400, 205203456, 959603712, 287193600, 925755136, 229800320, 442439360, 567107104, 226750832, 990326696, 784921532, 462177158, 568521159 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 704643072, 587202560, 981467136, 507510784, 723517440, 571473920, 537395200, 255590400, 98959360, 234553344, 135036928, 50216960, 693051392, 957755392, 788727808, 415788032, 543020544, 400016128, 157496704, 326762176, 286368, 969087312, 44583720, 32298908, 344923526, 502768323 - ], - [ - 536870912, 268435456, 402653184, 201326592, 838860800, 922746880, 729808896, 457179136, 903872512, 514850816, 484966400, 820248576, 133562368, 69140480, 461078528, 567099392, 422715392, 846737408, 144492544, 611038208, 569728512, 449788160, 392427648, 1017184704, 206610400, 836364496, 994951656, 821219796, 710424942, 671928343 - ], - [ - 536870912, 805306368, 402653184, 67108864, 436207616, 452984832, 142606336, 213909504, 492830720, 907018240, 289931264, 138674176, 178126848, 122224640, 625311744, 522108928, 101261312, 1030049792, 724441088, 946955264, 64566784, 332198656, 448517248, 843529280, 738521376, 725540976, 876164616, 102560524, 471061638, 533937217 - ], - [ - 536870912, 805306368, 402653184, 469762048, 905969664, 754974720, 595591168, 683671552, 509607936, 309329920, 640155648, 954990592, 249167872, 1047461888, 678461440, 355024896, 845946880, 798707712, 332388352, 719385600, 707860992, 436835584, 364720256, 388201152, 574325280, 559901616, 234385576, 508915836, 372234254, 1011938315 - ], - [ - 536870912, 805306368, 402653184, 335544320, 100663296, 117440512, 830472192, 851443712, 480247808, 386924544, 997720064, 299630592, 1064173568, 571408384, 775847936, 798375936, 1007869952, 829476864, 214558720, 934667264, 13283840, 1010693888, 924843904, 1011244096, 80395936, 305955792, 1008656040, 533074908, 923522734, 941369305 - ], - [ - 536870912, 805306368, 134217728, 67108864, 301989888, 788529152, 360710144, 784334848, 748683264, 508559360, 395837440, 594804736, 855244800, 297336832, 1046839296, 721567744, 373104640, 945229824, 886454272, 43387904, 846669312, 1070005504, 644755072, 259179200, 45472416, 1004189520, 690488840, 22867212, 69703298, 476024513 - ], - [ - 536870912, 805306368, 402653184, 335544320, 436207616, 184549376, 1031798784, 4194304, 10485760, 412090368, 619184128, 436469760, 566099968, 718077952, 837517312, 284934144, 106045440, 469143552, 291026944, 238869504, 334686720, 132563200, 259072640, 660198464, 993894304, 661821744, 623372424, 672171340, 875136294, 979718517 - ], - [ - 536870912, 805306368, 939524096, 872415232, 100663296, 721420288, 125829120, 507510784, 249561088, 909115392, 552075264, 271319040, 779485184, 834469888, 869236736, 1007206400, 991698944, 438300672, 206698496, 186223616, 509897216, 428600064, 143815552, 133605440, 956058848, 816801520, 225979272, 1066669132, 247725806, 368046589 - ], - [ - 536870912, 805306368, 134217728, 335544320, 1040187392, 150994944, 662700032, 549453824, 207618048, 321912832, 696778752, 1057226752, 739901440, 654901248, 138772480, 146423808, 744071168, 217870336, 389416960, 415669248, 657356288, 874179328, 185189760, 709155392, 733659936, 1020845392, 45905416, 471329548, 659965314, 301439557 - ], - [ - 536870912, 268435456, 134217728, 335544320, 838860800, 754974720, 411041792, 180355072, 601882624, 389021696, 876085248, 311689216, 716046336, 488701952, 382763008, 101203968, 707567616, 16486400, 963536896, 71386112, 773887488, 491912960, 390695296, 277699008, 963328160, 113690480, 75243528, 473157636, 950192130, 126538757 - ], - [ - 536870912, 805306368, 671088640, 738197504, 704643072, 83886080, 947912704, 104857600, 408944640, 653262848, 92798976, 395051008, 420347904, 1055457280, 385712128, 256327680, 600072192, 488820736, 263612416, 961291264, 523215360, 75090688, 864371584, 843195968, 281539424, 67492336, 964936200, 510073612, 282405770, 681247307 - ], - [ - 536870912, 268435456, 939524096, 201326592, 973078528, 989855744, 192937984, 20971520, 668991488, 382730240, 29884416, 384565248, 789446656, 670629888, 544505856, 980140032, 1048272896, 85086208, 550475776, 802716672, 780466688, 223516416, 330269312, 1036636224, 82658912, 537855984, 444072456, 540326660, 755687566, 577387331 - ], - [ - 536870912, 268435456, 134217728, 738197504, 637534208, 218103808, 981467136, 633339904, 299892736, 296747008, 565706752, 23855104, 825622528, 590020608, 600145920, 175292416, 462954496, 809291776, 364845056, 121625600, 519981568, 555616512, 296711808, 748109376, 87716256, 527246160, 137862952, 464191764, 17138826, 169081679 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 771751936, 83886080, 58720256, 532676608, 568328192, 663748608, 58195968, 211025920, 154533888, 8978432, 113016832, 783990784, 712695808, 85651456, 449538048, 898808832, 343354880, 1059649280, 739104896, 288522688, 809906592, 954220592, 437298696, 28949252, 318054022, 526781135 - ], - [ - 536870912, 805306368, 134217728, 201326592, 234881024, 83886080, 494927872, 155189248, 970981376, 152043520, 887619584, 906231808, 506331136, 20119552, 895516672, 668057600, 189276160, 477368320, 1008097280, 738182144, 964306432, 898974976, 218507136, 454475712, 226406240, 549139792, 347395816, 985078684, 437133322, 453185551 - ], - [ - 536870912, 805306368, 939524096, 469762048, 301989888, 754974720, 679477248, 524288000, 966787072, 584056832, 573046784, 882114560, 934936576, 104136704, 384532480, 148684800, 253714432, 752242688, 716376064, 3183616, 123286016, 862796032, 948368512, 551247936, 746906656, 737320848, 244421768, 67711052, 679865390, 368249751 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 905969664, 83886080, 813694976, 817889280, 866123776, 217055232, 311951360, 125566976, 843972608, 897122304, 183271424, 143048704, 334290944, 503787520, 1043195904, 556196864, 874378752, 85906688, 252810112, 352869056, 246764256, 559660016, 567514632, 1059464452, 85728134, 664751823 - ], - [ - 536870912, 268435456, 402653184, 469762048, 234881024, 318767104, 478150656, 281018368, 1063256064, 47185920, 678952960, 485752832, 299237376, 102432768, 639205376, 396640256, 586031104, 1003458560, 129984512, 200752128, 1055638016, 647015680, 333030784, 725973312, 981454432, 857085968, 880421352, 860392532, 798876174, 532364547 - ], - [ - 536870912, 805306368, 671088640, 335544320, 704643072, 788529152, 327155712, 281018368, 77594624, 831520768, 232259584, 691273728, 46268416, 1003290624, 782729216, 846610432, 919478272, 709529600, 696260608, 667003904, 723602944, 525349120, 209305216, 606415296, 207288864, 110647120, 424988808, 905087180, 1015340202, 868913813 - ], - [ - 536870912, 805306368, 402653184, 469762048, 234881024, 654311424, 662700032, 356515840, 937426944, 563085312, 34078720, 588513280, 786825216, 894763008, 478642176, 814071808, 904880128, 247574528, 480270336, 695307264, 404320768, 979170048, 487759488, 497259328, 1050295840, 955684976, 169680520, 208819020, 770924070, 733096055 - ], - [ - 536870912, 805306368, 402653184, 603979776, 301989888, 285212672, 343932928, 373293056, 996147200, 804257792, 835190784, 394002432, 353239040, 672989184, 419397632, 282443776, 1057136640, 26955776, 1031743488, 571765760, 170023424, 822808320, 826701184, 362850624, 483474016, 442080048, 985978248, 846985548, 47059558, 868085561 - ], - [ - 536870912, 805306368, 134217728, 872415232, 301989888, 184549376, 427819008, 750780416, 392167424, 628097024, 865599488, 567017472, 237895680, 278462464, 1011712000, 955138048, 955817984, 314380288, 750131200, 399797248, 354579968, 416785152, 790939520, 276540096, 293277024, 268052208, 347764232, 35365644, 814401410, 404925133 - ], - [ - 536870912, 268435456, 939524096, 872415232, 838860800, 855638016, 109051904, 222298112, 354418688, 391118848, 571998208, 168034304, 846331904, 883228672, 199393280, 828162048, 257368064, 445075456, 803190784, 268166144, 710414848, 816180480, 300071040, 240985536, 265698464, 382151760, 260020360, 325809604, 270599342, 953223261 - ], - [ - 536870912, 805306368, 671088640, 335544320, 369098752, 956301312, 545259520, 583008256, 631242752, 919601152, 650641408, 955514880, 1010171904, 512557056, 905674752, 378945536, 31203328, 963801088, 1023617024, 949720064, 250064384, 910459136, 135230592, 136353088, 311427104, 816401264, 520376968, 418361420, 470930090, 661240629 - ], - [ - 536870912, 268435456, 134217728, 1006632960, 637534208, 50331648, 25165824, 29360128, 681574400, 116391936, 215482368, 691273728, 923402240, 449380352, 779911168, 783695872, 400482304, 47362048, 125687808, 305605632, 547331584, 808586496, 233624448, 843013312, 63151776, 196447440, 659170824, 1000919300, 1009579394, 43945423 - ], - [ - 536870912, 268435456, 134217728, 335544320, 167772160, 16777216, 562036736, 977272832, 1029701632, 934281216, 196608000, 251396096, 278265856, 984285184, 396197888, 891731968, 739500032, 652308480, 351311872, 190440448, 487337472, 760111360, 593908352, 393395776, 106025760, 566805968, 358875560, 708557716, 116765322, 265539137 - ], - [ - 536870912, 268435456, 671088640, 603979776, 570425344, 989855744, 494927872, 255852544, 547356672, 506462208, 647495680, 974389248, 1019871232, 883228672, 697466880, 198197248, 1057595392, 826036224, 302446592, 375061504, 369893888, 35531008, 378530688, 556237248, 707471648, 1018431120, 737874824, 482115012, 625445674, 989556633 - ], - [ - 536870912, 805306368, 671088640, 738197504, 704643072, 956301312, 780140544, 700448768, 782237696, 789577728, 520617984, 659816448, 302120960, 125501440, 462848000, 844742656, 599629824, 539455488, 591460352, 828402688, 984658432, 194522880, 354161536, 188169664, 977849952, 87399664, 1060349032, 195260412, 166354402, 954163511 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 637534208, 50331648, 260046848, 364904448, 81788928, 741343232, 748158976, 644087808, 523894784, 997261312, 87588864, 385138688, 397664256, 870068224, 630102016, 652459008, 766823936, 1267456, 1011702144, 75974848, 948925728, 107141840, 166991880, 775060484, 1025355270, 317630223 - ], - [ - 536870912, 268435456, 134217728, 469762048, 167772160, 50331648, 746586112, 507510784, 517996544, 682622976, 364380160, 697040896, 402522112, 283312128, 699760640, 397590528, 1061003264, 122040320, 351209472, 327818240, 560989696, 1033387264, 530327168, 555201088, 568801952, 868136976, 352465960, 965011028, 172630154, 22056771 - ], - [ - 536870912, 268435456, 402653184, 738197504, 503316480, 654311424, 1031798784, 79691776, 396361728, 168820736, 489160704, 75759616, 1069678592, 706019328, 749371392, 410107904, 639229952, 754724864, 1041127424, 794958848, 226795008, 759369984, 659871360, 231425088, 1019247776, 731915088, 202411656, 371742788, 654598822, 470020699 - ], - [ - 536870912, 268435456, 939524096, 67108864, 905969664, 218103808, 444596224, 88080384, 1042284544, 957349888, 927465472, 537133056, 923926528, 745603072, 695762944, 987611136, 740171776, 700887040, 55306240, 742167552, 602884608, 25075968, 871870592, 798160448, 976352800, 1020815248, 772622344, 456647684, 426934798, 633373953 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 1040187392, 788529152, 327155712, 381681664, 262144000, 955252736, 641204224, 4456448, 599392256, 885325824, 855277568, 396673024, 682319872, 200093696, 613816320, 586394624, 309964288, 899961088, 699017600, 258785472, 500661152, 93549840, 170404232, 955105476, 421002158, 590525727 - ], - [ - 536870912, 805306368, 671088640, 469762048, 100663296, 1056964608, 931135488, 801112064, 304087040, 934281216, 404226048, 640942080, 510263296, 230621184, 440696832, 374521856, 289054720, 246829056, 479725568, 544498688, 680219136, 95405824, 590207104, 853444416, 110428768, 949665904, 147258088, 497080124, 477188226, 943203147 - ], - [ - 536870912, 805306368, 939524096, 603979776, 838860800, 620756992, 578813952, 390070272, 987758592, 300941312, 219676672, 513540096, 259129344, 20381696, 293109760, 439107584, 629858304, 148615168, 911357952, 442989568, 150064640, 161062144, 652017792, 370305856, 386304544, 348216944, 220251304, 559015996, 545861126, 657796357 - ], - [ - 536870912, 805306368, 402653184, 872415232, 503316480, 150994944, 897581056, 624951296, 1000341504, 923795456, 890765312, 482607104, 564527104, 295895040, 753172480, 183975936, 848977920, 376557568, 1005189120, 32277504, 464246272, 423186176, 93585792, 564024896, 162994656, 71040656, 316774504, 380758236, 218653070, 559711809 - ], - [ - 536870912, 805306368, 939524096, 335544320, 973078528, 486539264, 696254464, 1010827264, 945815552, 380633088, 348651520, 185860096, 620625920, 259325952, 340754432, 280805376, 98246656, 109252608, 974047232, 702405632, 753658368, 487276288, 133844864, 324161856, 452414240, 281074864, 161574792, 277954892, 857309998, 451739829 - ], - [ - 536870912, 805306368, 671088640, 469762048, 167772160, 553648128, 125829120, 1069547520, 325058560, 286261248, 974651392, 226230272, 724434944, 894107648, 949518336, 993837056, 412065792, 129740800, 13752320, 108655616, 82600448, 511169792, 940985216, 143060032, 241154336, 717453200, 582848680, 542002908, 274358786, 343987467 - ], - [ - 536870912, 268435456, 134217728, 603979776, 301989888, 721420288, 461373440, 557842432, 811597824, 814743552, 576192512, 26476544, 913702912, 792788992, 895516672, 1041252352, 93921280, 842305536, 658987008, 925490176, 924682752, 727433984, 267625600, 1034814144, 882152608, 553029552, 612401160, 817905668, 371269634, 762351625 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 503316480, 184549376, 75497472, 432013312, 329252864, 898629632, 1572864, 692846592, 622198784, 491978752, 416382976, 578371584, 192684032, 849285120, 554149888, 453770240, 125610496, 77525760, 772202880, 1032545344, 196970144, 415133904, 114713896, 938679188, 79702022, 136428555 - ], - [ - 536870912, 805306368, 939524096, 603979776, 905969664, 654311424, 444596224, 348127232, 392167424, 254803968, 786956288, 545521664, 609353728, 639565824, 366510080, 812400640, 1071046656, 181243904, 906430464, 257240064, 248173056, 408120576, 69098112, 1020865216, 703368544, 127343024, 778855912, 886541948, 978180614, 398868741 - ], - [ - 536870912, 268435456, 134217728, 67108864, 637534208, 855638016, 461373440, 440401920, 668991488, 141557760, 902299648, 958660608, 482213888, 345571328, 415006720, 1015169024, 568008704, 13021184, 903108608, 448150528, 219972096, 118699776, 845379456, 992712768, 768477216, 1003565936, 1029274120, 823982852, 1024593282, 727933761 - ], - [ - 536870912, 268435456, 402653184, 469762048, 167772160, 150994944, 58720256, 88080384, 685768704, 403701760, 671612928, 671875072, 796524544, 330235904, 208764928, 634929152, 1059332096, 759607296, 728569856, 640340992, 491255296, 594283776, 573282176, 189196480, 544025632, 682248624, 227005864, 231553140, 408631310, 1033856003 - ], - [ - 536870912, 805306368, 939524096, 469762048, 771751936, 117440512, 729808896, 398458880, 744488960, 653262848, 1572864, 563871744, 873070592, 354877440, 664043520, 1061044224, 50864128, 833884160, 829327360, 671122432, 335614464, 167781632, 889317504, 42006848, 994072352, 270583600, 491894696, 176814716, 125063814, 361711691 - ], - [ - 536870912, 805306368, 134217728, 67108864, 301989888, 654311424, 75497472, 725614592, 736100352, 210763776, 378011648, 899940352, 326238208, 362610688, 1030717440, 993214464, 419209216, 901730304, 114972672, 411571200, 1017459200, 787620608, 190622336, 206477632, 344115872, 113612112, 446881928, 301317708, 836381218, 604580625 - ], - [ - 536870912, 805306368, 134217728, 603979776, 1040187392, 16777216, 226492416, 750780416, 727711744, 745537536, 509083648, 473694208, 776601600, 1012203520, 219119616, 527646720, 35233792, 874262528, 379283456, 865975296, 1029381632, 947683072, 711641472, 511999936, 1036415328, 598097680, 72826760, 466615500, 991135458, 719867865 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 33554432, 218103808, 125829120, 239075328, 656408576, 594542592, 301465600, 375652352, 23986176, 509542400, 495419392, 991084544, 465903616, 1004417024, 247977984, 867312640, 183825920, 252133120, 919854208, 614778688, 210737760, 885959184, 821019240, 857624084, 438703202, 547569947 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 234881024, 620756992, 830472192, 499122176, 966787072, 149946368, 251133952, 999030784, 830341120, 370081792, 406224896, 530235392, 164962304, 58871808, 1011480576, 806663168, 807565824, 733570816, 409802880, 216955712, 707218720, 326269392, 917550376, 832163292, 375148330, 657877715 - ], - [ - 536870912, 268435456, 402653184, 67108864, 301989888, 419430400, 394264576, 155189248, 996147200, 179306496, 232259584, 673447936, 241565696, 173735936, 179929088, 613695488, 280944640, 687845376, 136304640, 99562496, 1012372992, 37904640, 104642176, 31637312, 1034707424, 795535120, 438354280, 1037138260, 157906446, 721277189 - ], - [ - 536870912, 268435456, 939524096, 469762048, 369098752, 486539264, 947912704, 650117120, 903872512, 959447040, 562561024, 1007943680, 511049728, 963575808, 753106944, 215498752, 552443904, 600543232, 777893888, 453188608, 183032320, 384122112, 379461760, 277504704, 771608928, 353534288, 766546792, 961048660, 821424614, 365421459 - ], - [ - 536870912, 268435456, 134217728, 201326592, 905969664, 83886080, 629145600, 566231040, 429916160, 726663168, 689438720, 664535040, 611450880, 364576768, 805273600, 405913600, 795385856, 328568832, 764934144, 841331712, 490637824, 823242496, 142113152, 250425152, 251356832, 287230896, 595596456, 1019334836, 941713194, 814780663 - ], - [ - 536870912, 268435456, 671088640, 67108864, 905969664, 218103808, 142606336, 247463936, 182452224, 634388480, 986185728, 303300608, 380764160, 688979968, 858292224, 507854848, 406462464, 69513216, 254470144, 772539392, 133092864, 838313728, 933947008, 416080448, 554659488, 640120464, 912418824, 257508356, 838661642, 186062593 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 570425344, 1056964608, 192937984, 683671552, 916455424, 416284672, 790102016, 738983936, 82968576, 487260160, 238518272, 74268672, 58957824, 407056384, 258115584, 611578880, 675955200, 693575424, 10255744, 168501056, 834079776, 715921456, 337866280, 370308916, 1010547630, 497020027 - ], - [ - 536870912, 805306368, 134217728, 335544320, 369098752, 1056964608, 897581056, 817889280, 325058560, 588251136, 62390272, 886308864, 406716416, 781778944, 803569664, 943079424, 503685120, 979841024, 538753024, 365071360, 990541312, 66536192, 518308992, 515310528, 289784224, 616970096, 216815112, 254489356, 440818818, 799932357 - ], - [ - 536870912, 268435456, 134217728, 67108864, 570425344, 419430400, 528482304, 373293056, 853540864, 787480576, 1028128768, 67895296, 539361280, 218038272, 202080256, 873054208, 40689664, 370634752, 244774912, 542548992, 746014208, 111556864, 356426368, 548090560, 739801504, 869645584, 911419304, 893210644, 449821482, 509820885 - ], - [ - 536870912, 805306368, 402653184, 469762048, 704643072, 520093696, 947912704, 574619648, 153092096, 814743552, 876085248, 1056702464, 654704640, 215416832, 340688896, 467812352, 758947840, 837218304, 682002432, 520489984, 550977024, 642696960, 417524608, 1069315648, 212228000, 419869840, 232153000, 500103324, 673431982, 199085979 - ], - [ - 536870912, 268435456, 939524096, 872415232, 167772160, 587202560, 176160768, 859832320, 425721856, 439353344, 454557696, 714342400, 1030619136, 82640896, 600473600, 865779712, 271720448, 519966720, 778369024, 618062848, 829010432, 846001920, 109811584, 268068288, 495144992, 354937648, 122684808, 589857476, 512507822, 595290877 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 369098752, 352321536, 562036736, 633339904, 769654784, 946864128, 715653120, 356253696, 881983488, 1049952256, 439320576, 617037824, 31154176, 349728768, 311724032, 875437056, 96982528, 173734656, 840534400, 200554560, 136199008, 659465552, 183918472, 340968268, 183874274, 866098463 - ], - [ - 536870912, 268435456, 402653184, 1006632960, 301989888, 117440512, 964689920, 197132288, 840957952, 735051776, 589824000, 272367616, 586809344, 244908032, 2392064, 10403840, 803659776, 171118592, 274036736, 195456000, 181595648, 1025857792, 169769600, 732336960, 449999584, 623144528, 908064264, 967304452, 500403334, 480540239 - ], - [ - 536870912, 268435456, 939524096, 335544320, 100663296, 218103808, 1065353216, 448790528, 924844032, 611319808, 932708352, 180617216, 675151872, 726859776, 928088064, 1038696448, 475881472, 259690496, 313350144, 430117888, 193587712, 1003310848, 179530368, 637622080, 486581984, 125856208, 247529064, 824255892, 695220230, 135889921 - ], - [ - 536870912, 268435456, 402653184, 872415232, 234881024, 50331648, 662700032, 624951296, 35651584, 470810624, 491257856, 805568512, 68812800, 406126592, 574783488, 83476480, 69017600, 863416320, 70957056, 757386240, 227242496, 20794624, 249993856, 322130752, 41968800, 1036053648, 585171592, 40972100, 704229030, 815623581 - ], - [ - 536870912, 805306368, 402653184, 603979776, 503316480, 654311424, 159383552, 88080384, 446693376, 242221056, 977797120, 448528384, 503185408, 365756416, 490176512, 95535104, 472424448, 321662976, 392566784, 625589248, 121410048, 515791104, 208435584, 80115520, 498622048, 364237232, 98722184, 574868300, 749915238, 624593081 - ], - [ - 536870912, 268435456, 671088640, 603979776, 436207616, 50331648, 360710144, 314572800, 249561088, 842006528, 50855936, 689176576, 256507904, 176095232, 31817728, 916701184, 593190912, 715550720, 440928256, 1010062336, 219843072, 403048704, 769131136, 791440320, 47676896, 434156144, 95526760, 516516276, 209029762, 918290381 - ], - [ - 536870912, 268435456, 671088640, 872415232, 234881024, 855638016, 1048576000, 406847488, 840957952, 26214400, 136839168, 505675776, 414056448, 221184000, 670007296, 529448960, 624910336, 788992000, 751470592, 1050770432, 13680128, 294235904, 1047847808, 174523072, 200967136, 978935440, 494699496, 1045585556, 985465826, 867409561 - ], - [ - 536870912, 268435456, 671088640, 201326592, 100663296, 754974720, 729808896, 901775360, 635437056, 5242880, 912785408, 142868480, 506855424, 728170496, 42958848, 499826688, 18653184, 715886592, 755857408, 65201152, 213510656, 514610432, 261271424, 828455104, 17905376, 46694992, 343166696, 950953556, 58434786, 430256983 - ], - [ - 536870912, 268435456, 939524096, 872415232, 436207616, 822083584, 176160768, 708837376, 127926272, 30408704, 967311360, 439091200, 869924864, 72810496, 794656768, 337854464, 622026752, 776663040, 895424512, 757087232, 999372288, 101209856, 805085056, 276012480, 796569376, 369621552, 976572584, 233740276, 1001973638, 702894537 - ], - [ - 536870912, 805306368, 402653184, 603979776, 973078528, 822083584, 192937984, 339738624, 442499072, 686817280, 355991552, 791412736, 33161216, 887029760, 353402880, 529088512, 393601024, 581365760, 886921216, 977425408, 640892416, 265015552, 675677312, 451741248, 383401120, 835677360, 580443688, 889040892, 735229966, 494642181 - ], - [ - 536870912, 268435456, 134217728, 469762048, 1040187392, 855638016, 864026624, 272629760, 526385152, 663748608, 665321472, 423362560, 816185344, 553451520, 914784256, 848117760, 75390976, 1035513856, 97908736, 293219328, 92994048, 598939392, 975693440, 37583424, 254191456, 113085296, 115828360, 412957252, 9848674, 140802935 - ], - [ - 536870912, 268435456, 402653184, 738197504, 771751936, 822083584, 377487360, 490733568, 1025507328, 202375168, 544735232, 641990656, 190185472, 332464128, 303595520, 276086784, 750739456, 808218624, 778766336, 792949760, 475924992, 157145344, 866306176, 187590592, 630571040, 22003632, 799377416, 279360516, 291105286, 341141771 - ], - [ - 536870912, 805306368, 671088640, 469762048, 33554432, 50331648, 830472192, 339738624, 576716800, 911212544, 461897728, 518782976, 874905600, 44367872, 803962880, 993148928, 148267008, 836620288, 746469376, 629226496, 977390080, 190961408, 416310400, 1011413312, 734850272, 295063792, 993799816, 149841484, 665413738, 635253175 - ], - [ - 536870912, 268435456, 939524096, 335544320, 704643072, 687865856, 377487360, 415236096, 597688320, 326107136, 454557696, 273416192, 345636864, 625410048, 727023616, 349650944, 165437440, 437481472, 360896512, 873126912, 89088512, 391148288, 36274816, 573963584, 151473056, 87414576, 881324328, 242599540, 661053574, 627412545 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 838860800, 419430400, 847249408, 54525952, 950009856, 386924544, 54001664, 239337472, 1054736384, 785580032, 771784704, 453001216, 327163904, 230715392, 165763072, 917593088, 648646144, 238935808, 138116480, 119382336, 65792992, 994395344, 912187496, 814962332, 706740230, 609222659 - ], - [ - 536870912, 268435456, 671088640, 201326592, 100663296, 1056964608, 92274688, 884998144, 601882624, 999292928, 932708352, 561774592, 499777536, 921894912, 406814720, 27049984, 500932608, 782897152, 354560000, 705111040, 97571328, 490276096, 701336960, 941816640, 579217824, 697349232, 983096232, 972841332, 428564002, 492006967 - ], - [ - 536870912, 268435456, 671088640, 1006632960, 570425344, 687865856, 1015021568, 675282944, 794820608, 856686592, 608698368, 553910272, 421658624, 601161728, 483033088, 199245824, 525426688, 1026052096, 622110720, 183170048, 1058081280, 1044913920, 470129280, 1000585536, 9732256, 640295760, 741454472, 1010306372, 6056618, 728706143 - ], - [ - 536870912, 268435456, 402653184, 67108864, 973078528, 318767104, 226492416, 742391808, 174063616, 206569472, 303562752, 141295616, 312606720, 182517760, 345014272, 850968576, 731652096, 281792512, 94738432, 496430080, 483303936, 625210112, 586216064, 283666624, 142942048, 36085520, 214310920, 576114692, 66000902, 636693505 - ], - [ - 536870912, 268435456, 939524096, 67108864, 234881024, 956301312, 209715200, 1027604480, 421527552, 137363456, 675807232, 683409408, 629538816, 488177664, 224690176, 671334400, 625680384, 460845056, 212961280, 956892160, 60586496, 515330304, 248552832, 756646976, 627426016, 335703728, 793399816, 745956612, 959467406, 147398977 - ], - [ - 536870912, 805306368, 402653184, 738197504, 973078528, 587202560, 696254464, 767557632, 270532608, 711983104, 634912768, 823918592, 317849600, 917700608, 995262464, 419577856, 984293376, 342814720, 344057856, 423732224, 962677248, 185666304, 46741632, 165004864, 942102176, 655723824, 830985896, 950324540, 679376558, 432569655 - ], - [ - 536870912, 268435456, 939524096, 335544320, 973078528, 587202560, 746586112, 700448768, 383778816, 896532480, 300417024, 721682432, 684064768, 893452288, 388005888, 261210112, 177774592, 602787840, 205723648, 415654912, 490786304, 992081664, 563137408, 328859456, 745377824, 151206448, 669417480, 1053868036, 532160526, 461115397 - ], - [ - 536870912, 805306368, 402653184, 67108864, 570425344, 788529152, 897581056, 239075328, 559939584, 57671680, 817364992, 164364288, 612499456, 351207424, 666664960, 1052459008, 1055121408, 673165312, 709109760, 93828096, 441527808, 933802240, 1015288960, 3610688, 461442720, 792785136, 98597416, 833624252, 655899790, 1058843725 - ], - [ - 536870912, 805306368, 671088640, 872415232, 905969664, 486539264, 109051904, 750780416, 891289600, 894435328, 698875904, 696516608, 230817792, 932118528, 368607232, 11321344, 1032249344, 1038946304, 233232384, 350002176, 662663680, 146882304, 455134080, 877667264, 757608288, 776277808, 593753832, 681493500, 632400386, 693740289 - ], - [ - 536870912, 805306368, 402653184, 738197504, 637534208, 117440512, 310378496, 289406976, 652214272, 686817280, 970457088, 408682496, 648937472, 32571392, 676954112, 161267712, 470769664, 1012936704, 1035057152, 221795328, 1034807808, 754321152, 493649792, 735500992, 389908704, 60744304, 1015658504, 647255052, 240904710, 253429515 - ], - [ - 536870912, 268435456, 671088640, 603979776, 905969664, 318767104, 125829120, 574619648, 786432000, 781189120, 498597888, 129761280, 557711360, 821231616, 568688640, 613662720, 632643584, 134877184, 20539392, 377291776, 866115072, 126016768, 592187264, 265802560, 710343456, 353780368, 595000488, 975603156, 238989698, 494083661 - ], - [ - 536870912, 268435456, 939524096, 335544320, 167772160, 218103808, 931135488, 398458880, 291504128, 256901120, 617086976, 203685888, 363462656, 234160128, 186810368, 846249984, 590880768, 165515264, 479643648, 452127744, 351884800, 146568960, 734504064, 708468032, 316515232, 269950736, 296971400, 920236356, 835483054, 1014933525 - ], - [ - 536870912, 268435456, 402653184, 469762048, 704643072, 855638016, 394264576, 826277888, 610271232, 774897664, 536346624, 952893440, 657850368, 416874496, 228360192, 863944704, 565043200, 193449984, 551573504, 418438144, 316152320, 781998848, 1023319424, 216919488, 99015008, 1037042224, 277445128, 458574596, 768288134, 169271751 - ], - [ - 536870912, 805306368, 402653184, 738197504, 234881024, 822083584, 343932928, 155189248, 241172480, 101711872, 42467328, 364118016, 996802560, 936181760, 84377600, 284934144, 746971136, 764620800, 820062208, 877671424, 325677568, 493108992, 356691584, 113812800, 693488160, 825980304, 228922504, 551722572, 49856166, 355212251 - ], - [ - 536870912, 805306368, 134217728, 335544320, 838860800, 687865856, 780140544, 4194304, 979369984, 818937856, 782761984, 569638912, 114950144, 255000576, 86409216, 250396672, 114778112, 880046080, 823916544, 328395776, 467017216, 418772224, 274366336, 326247616, 424085088, 624751408, 805279848, 994166332, 232818666, 370184953 - ], - [ - 536870912, 805306368, 402653184, 469762048, 100663296, 285212672, 578813952, 650117120, 299892736, 324009984, 734527488, 570163200, 995753984, 811794432, 1059487744, 913850368, 518365184, 925765632, 384129024, 53357568, 350579200, 137350400, 560255872, 493790144, 885272352, 958354800, 498941224, 544990332, 752024750, 180287163 - ], - [ - 536870912, 268435456, 671088640, 335544320, 33554432, 486539264, 377487360, 775946240, 849346560, 196083712, 372768768, 225705984, 546963456, 141623296, 995655680, 765804544, 561160192, 460132352, 840853504, 762508288, 896291328, 287196416, 821187968, 313341376, 108929440, 824323536, 331671560, 606254084, 21262858, 543364357 - ], - [ - 536870912, 268435456, 134217728, 201326592, 301989888, 218103808, 1065353216, 801112064, 44040192, 674234368, 287834112, 1000603648, 452329472, 145948672, 731217920, 534691840, 622272512, 576942080, 938293248, 331559936, 794636800, 397112064, 169414784, 437109440, 873665376, 212084752, 880190440, 49502932, 133441674, 416216775 - ], - [ - 536870912, 805306368, 671088640, 335544320, 503316480, 385875968, 511705088, 549453824, 916455424, 72351744, 488112128, 96731136, 996540416, 996999168, 587956224, 686178304, 338436096, 15347712, 777410560, 302261248, 591891968, 939333888, 481427584, 930239424, 626251168, 549704560, 385513096, 925769420, 271688490, 48876981 - ], - [ - 536870912, 805306368, 402653184, 67108864, 570425344, 83886080, 578813952, 1052770304, 819986432, 428867584, 483917824, 630980608, 756416512, 338231296, 731217920, 636665856, 764616704, 1002672128, 259680256, 213349376, 219710976, 519954176, 382075008, 634395840, 586740192, 351021360, 744476168, 258751244, 639594118, 1045264321 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 167772160, 352321536, 226492416, 390070272, 648019968, 747634688, 586678272, 400818176, 352714752, 1015611392, 497909760, 189415424, 485679104, 884396032, 44066816, 579881984, 167332352, 962866432, 281538688, 367552960, 224189472, 885130160, 601768456, 943517964, 506606210, 22534351 - ], - [ - 536870912, 268435456, 134217728, 335544320, 771751936, 419430400, 159383552, 809500672, 589299712, 791674880, 543686656, 237764608, 727842816, 374669312, 337018880, 41107456, 982327296, 890482688, 10299392, 1061886976, 492403200, 491109632, 332367744, 167178304, 916631008, 859155408, 486995336, 1051451716, 327776354, 603847317 - ], - [ - 536870912, 805306368, 671088640, 603979776, 704643072, 553648128, 595591168, 834666496, 119537664, 288358400, 306708480, 172752896, 33947648, 893976576, 919437312, 860307456, 623386624, 412930048, 668878848, 146619392, 577723904, 263549184, 306394496, 48368704, 269665120, 679155120, 512187912, 873033996, 246232458, 957811785 - ], - [ - 536870912, 805306368, 134217728, 872415232, 704643072, 989855744, 780140544, 96468992, 677380096, 972029952, 73924608, 985923584, 829554688, 1063321600, 829521920, 749223936, 421896192, 851660800, 53008384, 828699648, 232943104, 158982912, 899489664, 524270400, 770048544, 753563024, 835559432, 851922956, 381343746, 1026946061 - ], - [ - 536870912, 805306368, 939524096, 201326592, 301989888, 620756992, 276824064, 448790528, 740294656, 749731840, 730333184, 532414464, 708968448, 928448512, 244875264, 449069056, 479698944, 473559040, 599013376, 582904832, 930427392, 832481024, 440790144, 240606656, 68757408, 285476592, 1043749160, 491260988, 295479814, 468859663 - ], - [ - 536870912, 268435456, 671088640, 603979776, 771751936, 318767104, 696254464, 641728512, 983564288, 829423616, 358088704, 749993984, 244973568, 223412224, 434667520, 336412672, 427761664, 354578432, 188028928, 735742976, 913330688, 718865664, 368386944, 398089920, 660695968, 210799568, 101201928, 509475844, 1058523658, 946850057 - ], - [ - 536870912, 805306368, 671088640, 872415232, 838860800, 721420288, 243269632, 457179136, 236978176, 179306496, 520617984, 181665792, 530448384, 639827968, 578322432, 868007936, 56287232, 826617856, 111626240, 733965312, 60001792, 703658752, 1026038912, 778414528, 764878048, 997680976, 52883048, 243254684, 1056065026, 425744129 - ], - [ - 536870912, 268435456, 939524096, 603979776, 436207616, 452984832, 998244352, 616562688, 501219328, 982515712, 39321600, 357826560, 280625152, 104529920, 343638016, 198852608, 384524288, 763604992, 431974400, 641250304, 604279296, 377683200, 843049344, 989354816, 501539296, 907222064, 728162792, 338435124, 698311142, 768171069 - ], - [ - 536870912, 268435456, 134217728, 201326592, 301989888, 486539264, 931135488, 507510784, 589299712, 1064304640, 1067974656, 149684224, 306053120, 392888320, 910262272, 1059110912, 628105216, 782823424, 762083328, 293557248, 63589888, 393243392, 598221440, 317466304, 54479392, 854306448, 889257640, 729843540, 71401482, 841007111 - ], - [ - 536870912, 268435456, 134217728, 335544320, 369098752, 1056964608, 713031680, 801112064, 610271232, 982515712, 354942976, 638844928, 720764928, 830275584, 566394880, 549142528, 644292608, 190148608, 626497536, 831259648, 628758016, 788954880, 977610368, 507498560, 548970784, 29150576, 1059303560, 1038872388, 53356450, 30420277 - ], - [ - 536870912, 805306368, 939524096, 201326592, 234881024, 419430400, 427819008, 432013312, 316669952, 946864128, 690487296, 698613760, 448921600, 902234112, 777289728, 925515776, 755146752, 237408256, 933623808, 197272576, 407294464, 898892032, 852189312, 368238784, 659423584, 354548144, 999375336, 1020840316, 458004614, 914867407 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 1040187392, 117440512, 327155712, 994050048, 543162368, 856686592, 117964800, 764674048, 265420800, 619511808, 954171392, 610484224, 869621760, 892481536, 809277440, 192351232, 533156352, 796837632, 466873984, 384694592, 165591840, 216230992, 622150792, 689046092, 818716578, 70147615 - ], - [ - 536870912, 268435456, 671088640, 872415232, 838860800, 989855744, 897581056, 725614592, 866123776, 852492288, 343408640, 176422912, 198574080, 559611904, 505511936, 361873408, 165208064, 89403392, 590235648, 236942336, 949450240, 519702272, 49376128, 1021887808, 1071407072, 725765776, 789899880, 974112980, 940498946, 990851081 - ], - [ - 536870912, 805306368, 134217728, 335544320, 973078528, 855638016, 729808896, 46137344, 106954752, 456130560, 792199168, 835977216, 325713920, 58654720, 99909632, 58441728, 30924800, 558493696, 72189952, 1055794176, 681392640, 187165952, 328298112, 610912832, 282935904, 990300016, 25210088, 163630396, 836767370, 938539593 - ], - [ - 536870912, 805306368, 671088640, 67108864, 234881024, 318767104, 142606336, 918552576, 329252864, 110100480, 20447232, 293863424, 676462592, 192086016, 656572416, 398180352, 430956544, 625315840, 317851648, 811781120, 257669632, 635324160, 17572736, 851427904, 356323936, 211182320, 583070312, 94434044, 965769826, 62521085 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 503316480, 117440512, 914358272, 960495616, 350224384, 533725184, 718798848, 126615552, 108134400, 834994176, 180781056, 946520064, 594042880, 29732864, 583407616, 1013687296, 23626240, 415525632, 323395712, 866790336, 751381984, 334845904, 642693768, 520037572, 758607726, 608347935 - ], - [ - 536870912, 268435456, 134217728, 335544320, 704643072, 285212672, 260046848, 130023424, 480247808, 416284672, 614989824, 185335808, 987365376, 787808256, 767459328, 1057177600, 738271232, 637636608, 654338048, 545360896, 859956736, 98570496, 204506240, 656014912, 735345632, 229520656, 998967944, 849175364, 110336354, 273193557 - ], - [ - 536870912, 268435456, 671088640, 469762048, 503316480, 218103808, 931135488, 364904448, 199229440, 135266304, 750256128, 588513280, 198836224, 461701120, 438468608, 707805184, 558391296, 582856704, 804685824, 948587520, 211633664, 335946496, 673336960, 19966656, 801636384, 50155280, 584500872, 33285828, 175490602, 92941335 - ], - [ - 536870912, 805306368, 671088640, 67108864, 234881024, 50331648, 461373440, 440401920, 44040192, 1066401792, 43515904, 158597120, 332267520, 714932224, 303267840, 816726016, 1038917632, 96120832, 13793280, 734923776, 916290048, 806498560, 967828096, 728505280, 125556256, 62062640, 213893256, 154457804, 74421930, 562927345 - ], - [ - 536870912, 268435456, 671088640, 738197504, 301989888, 822083584, 830472192, 432013312, 316669952, 810549248, 180879360, 781451264, 208535552, 1006567424, 282558464, 647151616, 611688448, 675164160, 657864704, 826438656, 947689984, 113966336, 38397824, 987067840, 1028645728, 72247568, 164518760, 705617172, 636445026, 910037023 - ], - [ - 536870912, 268435456, 134217728, 872415232, 301989888, 553648128, 578813952, 700448768, 874512384, 959447040, 432537600, 180617216, 1038483456, 544800768, 63733760, 495075328, 728670208, 1029509120, 775669760, 428078080, 560987648, 543029504, 716879232, 54715456, 382664992, 304925616, 781334024, 77008132, 198298498, 559504717 - ], - [ - 536870912, 805306368, 671088640, 335544320, 369098752, 587202560, 713031680, 406847488, 387973120, 978321408, 192413696, 52166656, 573440000, 285147136, 113672192, 863748096, 231038976, 253939712, 76105728, 242605056, 57376256, 1016960768, 66047360, 488548928, 670456992, 57881296, 485561512, 266989276, 755296930, 759413209 - ], - [ - 536870912, 268435456, 134217728, 469762048, 838860800, 721420288, 209715200, 281018368, 799014912, 779091968, 603455488, 529268736, 891420672, 524877824, 550797312, 475938816, 928243712, 380637184, 5871616, 201114624, 568063488, 1044690176, 775344000, 540458432, 691431264, 112719760, 116846088, 194392324, 558291330, 541989063 - ] -] // End Direction Vectors - - - - -// The Market / Model Data -// md_c md_vols md_drifts md_starts md_detval md_disc - -[ [ // md_c[3][3] (begin) - [ 1.0000000 , 0.6000000 , 0.8000000 ], - [ 0.6000000 , 0.8000000 , 0.1500000 ], - [ 0.8000000 , 0.1500000 , 0.5809475 ] -] ] // md_c (end) - -[ [ // md_vols[367][3] volatility (begin) - [ 0.0000000 , 0.0000000 , 0.0000000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ] -] ] // md_vols volatility (end) - -[ [ // md_drifts[367][3] (begin) - [ 0.0000000000000000 , 0.0000000000000000 , 0.0000000000000000 ], - [ -0.0000769148269844 , 0.0000327749731970 , -0.0000051340050666 ], - [ -0.0000769148269844 , 0.0000327749731970 , -0.0000051340050666 ], - [ -0.0000769148269844 , 0.0000327749731970 , -0.0000051340050666 ], - [ -0.0000769117410220 , 0.0000327819160986 , -0.0000051309191042 ], - [ -0.0000769117410220 , 0.0000327819160986 , -0.0000051309191042 ], - [ -0.0000769197006278 , 0.0000342555768863 , -0.0000036470215480 ], - [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], - [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], - [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], - [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], - [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], - [ -0.0000769364349073 , 0.0000371477302492 , -0.0000007324359000 ], - [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], - [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], - [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], - [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], - [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], - [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], - [ -0.0000769609069770 , 0.0000476737925826 , 0.0000098342203061 ], - [ -0.0000769695550586 , 0.0000523282070770 , 0.0000145040722083 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], - [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], - [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], - [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], - [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], - [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], - [ -0.0000770387184138 , 0.0000516935336623 , 0.0000148283938103 ], - [ -0.0000770931821601 , 0.0000481674750561 , 0.0000109174165401 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000486764057747 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000486764057747 , 0.0000104828635101 ], - [ -0.0000770992336875 , 0.0000486764057747 , 0.0000104828635101 ], - [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000489308711339 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000491853364932 , 0.0000112366493239 ], - [ -0.0000772189449197 , 0.0000491853364932 , 0.0000112366493239 ], - [ -0.0000773147139055 , 0.0000491853364932 , 0.0000118396779749 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351376 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], - [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351376 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], - [ -0.0000775909658212 , 0.0000511403391975 , 0.0000142949696444 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], - [ -0.0000778667234691 , 0.0000478503243642 , 0.0000114070604692 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], - [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ] -] ] // md_drifts (end) - -// md_starts[3] -[ [ 3758.0500000000001819, 11840.0000000000000000, 1200.0000000000000000 ] ] - -// model deterministic values [0] -[ [ ] ] - -// model discounts [2] -[ [ 0.9800680293073579 , 0.9800680293073579 ] ] - -// Brownian Bridge (BB) Metadata - -//BB indirect accessing: -[ [ 367, 183, 91, 45, 22, 11, 5, 2, 1, 3, 4, 8, 6, 7, 9, 10, 16, 13, 12, 14, 15, 19, 17, 18, 20, 21, 33, 27, 24, 23, 25, 26, 30, 28, 29, 31, 32, 39, 36, 34, 35, 37, 38, 42, 40, 41, 43, 44, 68, 56, 50, 47, 46, 48, 49, 53, 51, 52, 54, 55, 62, 59, 57, 58, 60, 61, 65, 63, 64, 66, 67, 79, 73, 70, 69, 71, 72, 76, 74, 75, 77, 78, 85, 82, 80, 81, 83, 84, 88, 86, 87, 89, 90, 137, 114, 102, 96, 93, 92, 94, 95, 99, 97, 98, 100, 101, 108, 105, 103, 104, 106, 107, 111, 109, 110, 112, 113, 125, 119, 116, 115, 117, 118, 122, 120, 121, 123, 124, 131, 128, 126, 127, 129, 130, 134, 132, 133, 135, 136, 160, 148, 142, 139, 138, 140, 141, 145, 143, 144, 146, 147, 154, 151, 149, 150, 152, 153, 157, 155, 156, 158, 159, 171, 165, 162, 161, 163, 164, 168, 166, 167, 169, 170, 177, 174, 172, 173, 175, 176, 180, 178, 179, 181, 182, 275, 229, 206, 194, 188, 185, 184, 186, 187, 191, 189, 190, 192, 193, 200, 197, 195, 196, 198, 199, 203, 201, 202, 204, 205, 217, 211, 208, 207, 209, 210, 214, 212, 213, 215, 216, 223, 220, 218, 219, 221, 222, 226, 224, 225, 227, 228, 252, 240, 234, 231, 230, 232, 233, 237, 235, 236, 238, 239, 246, 243, 241, 242, 244, 245, 249, 247, 248, 250, 251, 263, 257, 254, 253, 255, 256, 260, 258, 259, 261, 262, 269, 266, 264, 265, 267, 268, 272, 270, 271, 273, 274, 321, 298, 286, 280, 277, 276, 278, 279, 283, 281, 282, 284, 285, 292, 289, 287, 288, 290, 291, 295, 293, 294, 296, 297, 309, 303, 300, 299, 301, 302, 306, 304, 305, 307, 308, 315, 312, 310, 311, 313, 314, 318, 316, 317, 319, 320, 344, 332, 326, 323, 322, 324, 325, 329, 327, 328, 330, 331, 338, 335, 333, 334, 336, 337, 341, 339, 340, 342, 343, 355, 349, 346, 345, 347, 348, 352, 350, 351, 353, 354, 361, 358, 356, 357, 359, 360, 364, 362, 363, 365, 366 ], //bb_bi[367] - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 5, 6, 8, 9, 11, 11, 11, 13, 14, 16, 16, 17, 19, 20, 22, 22, 22, 22, 24, 25, 27, 27, 28, 30, 31, 33, 33, 33, 34, 36, 37, 39, 39, 40, 42, 43, 45, 45, 45, 45, 45, 47, 48, 50, 50, 51, 53, 54, 56, 56, 56, 57, 59, 60, 62, 62, 63, 65, 66, 68, 68, 68, 68, 70, 71, 73, 73, 74, 76, 77, 79, 79, 79, 80, 82, 83, 85, 85, 86, 88, 89, 91, 91, 91, 91, 91, 91, 93, 94, 96, 96, 97, 99, 100, 102, 102, 102, 103, 105, 106, 108, 108, 109, 111, 112, 114, 114, 114, 114, 116, 117, 119, 119, 120, 122, 123, 125, 125, 125, 126, 128, 129, 131, 131, 132, 134, 135, 137, 137, 137, 137, 137, 139, 140, 142, 142, 143, 145, 146, 148, 148, 148, 149, 151, 152, 154, 154, 155, 157, 158, 160, 160, 160, 160, 162, 163, 165, 165, 166, 168, 169, 171, 171, 171, 172, 174, 175, 177, 177, 178, 180, 181, 183, 183, 183, 183, 183, 183, 183, 185, 186, 188, 188, 189, 191, 192, 194, 194, 194, 195, 197, 198, 200, 200, 201, 203, 204, 206, 206, 206, 206, 208, 209, 211, 211, 212, 214, 215, 217, 217, 217, 218, 220, 221, 223, 223, 224, 226, 227, 229, 229, 229, 229, 229, 231, 232, 234, 234, 235, 237, 238, 240, 240, 240, 241, 243, 244, 246, 246, 247, 249, 250, 252, 252, 252, 252, 254, 255, 257, 257, 258, 260, 261, 263, 263, 263, 264, 266, 267, 269, 269, 270, 272, 273, 275, 275, 275, 275, 275, 275, 277, 278, 280, 280, 281, 283, 284, 286, 286, 286, 287, 289, 290, 292, 292, 293, 295, 296, 298, 298, 298, 298, 300, 301, 303, 303, 304, 306, 307, 309, 309, 309, 310, 312, 313, 315, 315, 316, 318, 319, 321, 321, 321, 321, 321, 323, 324, 326, 326, 327, 329, 330, 332, 332, 332, 333, 335, 336, 338, 338, 339, 341, 342, 344, 344, 344, 344, 346, 347, 349, 349, 350, 352, 353, 355, 355, 355, 356, 358, 359, 361, 361, 362, 364, 365 ], //bb_li[367] - [ 0, 367, 183, 91, 45, 22, 11, 5, 2, 5, 5, 11, 8, 8, 11, 11, 22, 16, 13, 16, 16, 22, 19, 19, 22, 22, 45, 33, 27, 24, 27, 27, 33, 30, 30, 33, 33, 45, 39, 36, 36, 39, 39, 45, 42, 42, 45, 45, 91, 68, 56, 50, 47, 50, 50, 56, 53, 53, 56, 56, 68, 62, 59, 59, 62, 62, 68, 65, 65, 68, 68, 91, 79, 73, 70, 73, 73, 79, 76, 76, 79, 79, 91, 85, 82, 82, 85, 85, 91, 88, 88, 91, 91, 183, 137, 114, 102, 96, 93, 96, 96, 102, 99, 99, 102, 102, 114, 108, 105, 105, 108, 108, 114, 111, 111, 114, 114, 137, 125, 119, 116, 119, 119, 125, 122, 122, 125, 125, 137, 131, 128, 128, 131, 131, 137, 134, 134, 137, 137, 183, 160, 148, 142, 139, 142, 142, 148, 145, 145, 148, 148, 160, 154, 151, 151, 154, 154, 160, 157, 157, 160, 160, 183, 171, 165, 162, 165, 165, 171, 168, 168, 171, 171, 183, 177, 174, 174, 177, 177, 183, 180, 180, 183, 183, 367, 275, 229, 206, 194, 188, 185, 188, 188, 194, 191, 191, 194, 194, 206, 200, 197, 197, 200, 200, 206, 203, 203, 206, 206, 229, 217, 211, 208, 211, 211, 217, 214, 214, 217, 217, 229, 223, 220, 220, 223, 223, 229, 226, 226, 229, 229, 275, 252, 240, 234, 231, 234, 234, 240, 237, 237, 240, 240, 252, 246, 243, 243, 246, 246, 252, 249, 249, 252, 252, 275, 263, 257, 254, 257, 257, 263, 260, 260, 263, 263, 275, 269, 266, 266, 269, 269, 275, 272, 272, 275, 275, 367, 321, 298, 286, 280, 277, 280, 280, 286, 283, 283, 286, 286, 298, 292, 289, 289, 292, 292, 298, 295, 295, 298, 298, 321, 309, 303, 300, 303, 303, 309, 306, 306, 309, 309, 321, 315, 312, 312, 315, 315, 321, 318, 318, 321, 321, 367, 344, 332, 326, 323, 326, 326, 332, 329, 329, 332, 332, 344, 338, 335, 335, 338, 338, 344, 341, 341, 344, 344, 367, 355, 349, 346, 349, 349, 355, 352, 352, 355, 355, 367, 361, 358, 358, 361, 361, 367, 364, 364, 367, 367 ] //bb_ri[367] -] - -//BB (real) data: -[ [ 1.0013689260344547, 0.5006769876043941, 0.3530474200541117, 0.2482204548705323, 0.1734206441019846, 0.1197954333762150, 0.0810884854079383, 0.0453298413911625, 0.0000000000000000, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0864406158858196, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.1253939592915132, 0.0864406158858196, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0906596827823249, 0.0641060764756032, 0.0427373843170688, 0.0370116605098802, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098802, 0.0427373843170688, 0.0370116605098803, 0.1775016882034323, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0906596827823249, 0.0641060764756033, 0.0427373843170689, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.1253939592915132, 0.0864406158858196, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756033, 0.0427373843170689, 0.0370116605098802, 0.0427373843170689, 0.0370116605098803, 0.0906596827823249, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170689, 0.0370116605098802, 0.2510252948014144, 0.1775016882034323, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756033, 0.0427373843170690, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170690, 0.0370116605098802, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098802, 0.0427373843170690, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170690, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.1775016882034323, 0.1253939592915131, 0.0864406158858195, 0.0573382179080996, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0906596827823249, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170690, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756033, 0.0427373843170690, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.3550033764068646, 0.2510252948014144, 0.1775016882034323, 0.1253939592915132, 0.0864406158858196, 0.0573382179080996, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170693, 0.0370116605098802, 0.1253939592915131, 0.0864406158858195, 0.0573382179080995, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1775016882034323, 0.1253939592915131, 0.0864406158858196, 0.0573382179080996, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1253939592915133, 0.0864406158858197, 0.0573382179080998, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170693, 0.0370116605098802, 0.2510252948014144, 0.1775016882034322, 0.1253939592915131, 0.0864406158858195, 0.0573382179080995, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170693, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1253939592915131, 0.0864406158858196, 0.0573382179080996, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1775016882034324, 0.1253939592915133, 0.0864406158858197, 0.0573382179080998, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170693, 0.0370116605098802, 0.1253939592915133, 0.0864406158858195, 0.0573382179080995, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756035, 0.0427373843170693, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806 ], //bb_sd[367] (standard deviation) - [ 0.0000000000000000, 0.5027322404371586, 0.5054945054945055, 0.5111111111111111, 0.5227272727272727, 0.5238095238095238, 0.6000000000000000, 0.7500000000000001, 1.0000000000000000, 0.6666666666666666, 0.5000000000000001, 0.4999999999999999, 0.6666666666666669, 0.5000000000000003, 0.6666666666666666, 0.5000000000000000, 0.5454545454545455, 0.6000000000000001, 0.4999999999999994, 0.6666666666666664, 0.4999999999999994, 0.5000000000000000, 0.6666666666666664, 0.4999999999999994, 0.6666666666666664, 0.5000000000000007, 0.5217391304347826, 0.5454545454545455, 0.5999999999999996, 0.5000000000000000, 0.6666666666666677, 0.5000000000000000, 0.4999999999999996, 0.6666666666666666, 0.5000000000000000, 0.6666666666666677, 0.5000000000000000, 0.5000000000000000, 0.5000000000000004, 0.6666666666666661, 0.4999999999999987, 0.6666666666666666, 0.5000000000000000, 0.5000000000000004, 0.6666666666666661, 0.5000000000000012, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.5217391304347827, 0.5454545454545453, 0.5999999999999996, 0.5000000000000026, 0.6666666666666677, 0.5000000000000026, 0.5000000000000000, 0.6666666666666677, 0.4999999999999974, 0.6666666666666677, 0.4999999999999974, 0.4999999999999996, 0.4999999999999992, 0.6666666666666655, 0.5000000000000026, 0.6666666666666677, 0.5000000000000026, 0.5000000000000000, 0.6666666666666677, 0.4999999999999974, 0.6666666666666677, 0.4999999999999974, 0.5217391304347823, 0.5454545454545457, 0.5999999999999996, 0.4999999999999974, 0.6666666666666677, 0.4999999999999974, 0.5000000000000009, 0.6666666666666644, 0.5000000000000000, 0.6666666666666655, 0.5000000000000026, 0.5000000000000000, 0.5000000000000000, 0.6666666666666677, 0.5000000000000026, 0.6666666666666677, 0.4999999999999974, 0.5000000000000000, 0.6666666666666677, 0.4999999999999974, 0.6666666666666644, 0.5000000000000000, 0.4999999999999999, 0.5000000000000000, 0.5217391304347829, 0.5454545454545453, 0.5999999999999975, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.4999999999999992, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.5217391304347829, 0.5454545454545453, 0.6000000000000016, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.5000000000000051, 0.6666666666666666, 0.5000000000000000, 0.5000000000000009, 0.4999999999999983, 0.6666666666666690, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000002, 0.5217391304347825, 0.5454545454545453, 0.6000000000000016, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666690, 0.4999999999999949, 0.5000000000000000, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.5000000000000051, 0.6666666666666666, 0.5000000000000000, 0.5217391304347829, 0.5454545454545453, 0.5999999999999975, 0.5000000000000051, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.4999999999999992, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666690, 0.4999999999999949, 0.5000000000000000, 0.5000000000000001, 0.4999999999999998, 0.5217391304347820, 0.5454545454545461, 0.5999999999999975, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.5217391304347825, 0.5454545454545471, 0.6000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000004, 0.5217391304347825, 0.5454545454545434, 0.6000000000000032, 0.5000000000000000, 0.6666666666666712, 0.4999999999999899, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5217391304347816, 0.5454545454545451, 0.5999999999999951, 0.4999999999999899, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.5000000000000004, 0.5000000000000000, 0.5217391304347825, 0.5454545454545471, 0.6000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666576, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5217391304347825, 0.5454545454545434, 0.6000000000000032, 0.5000000000000000, 0.6666666666666712, 0.4999999999999899, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.5217391304347816, 0.5454545454545451, 0.5999999999999951, 0.4999999999999899, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.5217391304347834, 0.5454545454545471, 0.6000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101 ], //bb_lw[367] - [ 0.0000000000000000, 0.4972677595628415, 0.4945054945054945, 0.4888888888888889, 0.4772727272727272, 0.4761904761904762, 0.4000000000000000, 0.2500000000000000, 0.0000000000000000, 0.3333333333333333, 0.4999999999999998, 0.5000000000000001, 0.3333333333333332, 0.4999999999999997, 0.3333333333333333, 0.5000000000000000, 0.4545454545454545, 0.3999999999999999, 0.5000000000000007, 0.3333333333333336, 0.5000000000000007, 0.5000000000000000, 0.3333333333333336, 0.5000000000000007, 0.3333333333333336, 0.4999999999999994, 0.4782608695652174, 0.4545454545454545, 0.4000000000000004, 0.5000000000000000, 0.3333333333333322, 0.5000000000000000, 0.5000000000000004, 0.3333333333333333, 0.5000000000000000, 0.3333333333333322, 0.5000000000000000, 0.5000000000000000, 0.4999999999999996, 0.3333333333333339, 0.5000000000000012, 0.3333333333333333, 0.5000000000000000, 0.4999999999999996, 0.3333333333333339, 0.4999999999999987, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.4782608695652172, 0.4545454545454547, 0.4000000000000004, 0.4999999999999974, 0.3333333333333322, 0.4999999999999974, 0.5000000000000000, 0.3333333333333322, 0.5000000000000026, 0.3333333333333322, 0.5000000000000026, 0.5000000000000004, 0.5000000000000009, 0.3333333333333345, 0.4999999999999974, 0.3333333333333322, 0.4999999999999974, 0.5000000000000000, 0.3333333333333322, 0.5000000000000026, 0.3333333333333322, 0.5000000000000026, 0.4782608695652177, 0.4545454545454543, 0.4000000000000004, 0.5000000000000026, 0.3333333333333322, 0.5000000000000026, 0.4999999999999992, 0.3333333333333356, 0.5000000000000000, 0.3333333333333345, 0.4999999999999974, 0.5000000000000000, 0.5000000000000000, 0.3333333333333322, 0.4999999999999974, 0.3333333333333322, 0.5000000000000026, 0.5000000000000000, 0.3333333333333322, 0.5000000000000026, 0.3333333333333356, 0.5000000000000000, 0.5000000000000001, 0.5000000000000000, 0.4782608695652171, 0.4545454545454547, 0.4000000000000024, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.5000000000000009, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.4782608695652171, 0.4545454545454547, 0.3999999999999984, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.4999999999999949, 0.3333333333333333, 0.5000000000000000, 0.4999999999999992, 0.5000000000000017, 0.3333333333333311, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999998, 0.4782608695652175, 0.4545454545454547, 0.3999999999999984, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333311, 0.5000000000000051, 0.5000000000000000, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.4999999999999949, 0.3333333333333333, 0.5000000000000000, 0.4782608695652171, 0.4545454545454547, 0.4000000000000024, 0.4999999999999949, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.5000000000000009, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333311, 0.5000000000000051, 0.4999999999999999, 0.4999999999999999, 0.5000000000000002, 0.4782608695652179, 0.4545454545454539, 0.4000000000000024, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.4782608695652175, 0.4545454545454529, 0.4000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999996, 0.4782608695652175, 0.4545454545454565, 0.3999999999999967, 0.5000000000000000, 0.3333333333333288, 0.5000000000000101, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4782608695652184, 0.4545454545454549, 0.4000000000000049, 0.5000000000000101, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.4999999999999996, 0.5000000000000000, 0.4782608695652175, 0.4545454545454529, 0.4000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333424, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4782608695652175, 0.4545454545454565, 0.3999999999999967, 0.5000000000000000, 0.3333333333333288, 0.5000000000000101, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.4782608695652184, 0.4545454545454549, 0.4000000000000049, 0.5000000000000101, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.4782608695652166, 0.4545454545454529, 0.4000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899 ] //bb_rw[367] -] - -// [(EXsimple_price(EUR, 1046.247619993985, "MC BS (C) 3dim, Sobol, 131072 paths, 34771 ms"))] diff --git a/benchmarks/GenericPricing/datasets/large/input.json b/benchmarks/GenericPricing/datasets/large/input.json new file mode 100644 index 0000000..5dc0044 --- /dev/null +++ b/benchmarks/GenericPricing/datasets/large/input.json @@ -0,0 +1,4088 @@ +{ + "contract_number" : 3, + "monte_carlo_iterations" : 131072, + "num_path_dates" : 367, + "num_underlyings" : 3, + "num_models" : 1, + "num_bits" : 30, + + "dir_vs" : + [ + [ + 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 570425344, 855638016, 713031680, 1069547520, 538968064, 808452096, 673710080, 1010565120, 572653568, 858980352, 715816960, 1073725440, 536879104, 805318656, 671098880, 1006648320, 570434048, 855651072, 713042560, 1069563840, 538976288, 808464432, 673720360, 1010580540, 572662306, 858993459 + ], + [ + 536870912, 805306368, 402653184, 603979776, 973078528, 385875968, 595591168, 826277888, 438304768, 657457152, 999817216, 358875136, 538574848, 807862272, 406552576, 605372416, 975183872, 389033984, 597170176, 828646400, 437926400, 656873216, 1002152832, 357921088, 536885792, 805312304, 402662296, 603992420, 973085210, 385885991 + ], + [ + 536870912, 805306368, 939524096, 335544320, 234881024, 721420288, 411041792, 616562688, 920649728, 1062207488, 381157376, 258736128, 771883008, 453181440, 545488896, 817971200, 954261504, 340963328, 238651392, 732843008, 417426944, 609285376, 909831040, 1068349120, 383778848, 256901168, 783810616, 460062740, 537001998, 805503019 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 167772160, 285212672, 713031680, 566231040, 853540864, 489684992, 952631296, 208928768, 316801024, 758317056, 550076416, 813154304, 417505280, 1009913856, 172697600, 297131008, 704744960, 553894656, 847291520, 499194688, 954376224, 204607536, 306915352, 766893116, 536972810, 805552913 + ], + [ + 536870912, 805306368, 402653184, 469762048, 301989888, 721420288, 92274688, 264241152, 941621248, 741343232, 169345024, 924581888, 395444224, 619380736, 1034256384, 603963392, 838868992, 452997120, 494934016, 331357184, 706744832, 120597248, 261621120, 953946048, 800208928, 148581424, 935168536, 350484252, 630339474, 1072370923 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 503316480, 754974720, 629145600, 440401920, 94371840, 711983104, 229113856, 374079488, 330694656, 996212736, 907247616, 557531136, 867573760, 190918656, 1041467392, 490437632, 766918144, 643898624, 462663040, 125527616, 672545696, 202454896, 373006376, 288845836, 1000351766, 930090001 + ], + [ + 536870912, 268435456, 402653184, 872415232, 838860800, 956301312, 612368384, 717225984, 211812352, 386924544, 302514176, 688128000, 1015414784, 516751360, 1051492352, 773734400, 914432000, 63877120, 807741440, 165200896, 748683776, 118489344, 168296832, 486802240, 243663648, 667747216, 439124552, 81674924, 975249610, 350138737 + ], + [ + 536870912, 268435456, 671088640, 469762048, 973078528, 1023410176, 713031680, 339738624, 912261120, 797966336, 176685056, 71565312, 510263296, 865533952, 814120960, 961232896, 887136256, 668078080, 116070400, 382772224, 1047134720, 597098752, 411468416, 625689024, 249602976, 449975248, 745216680, 43033924, 134873446, 201786361 + ], + [ + 536870912, 268435456, 402653184, 67108864, 704643072, 385875968, 696254464, 205520896, 920649728, 946864128, 359137280, 859045888, 302907392, 50659328, 462192640, 524599296, 895541248, 590794752, 168810496, 118033408, 831447552, 138662144, 485185920, 796511296, 1021313184, 1064304752, 619184920, 997458052, 250479054, 745865975 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 838860800, 889192448, 645922816, 46137344, 476053504, 584056832, 210239488, 465829888, 820903936, 689897472, 73695232, 249118720, 110075904, 315338752, 610637824, 517665792, 1049494016, 785318144, 376210304, 735921088, 402760480, 738505552, 168368744, 151499820, 344957894, 936096557 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 503316480, 922746880, 41943040, 423624704, 228589568, 651165696, 195559424, 500957184, 791019520, 261292032, 1040285696, 118407168, 982065152, 625250304, 329533440, 298984448, 153690624, 76845824, 579619712, 692987840, 900670432, 450334832, 363187112, 719119956, 765461306, 382730781 + ], + [ + 536870912, 805306368, 402653184, 603979776, 838860800, 117440512, 478150656, 658505728, 752877568, 1060110336, 141033472, 209453056, 244187136, 272957440, 678068224, 1014546432, 377724928, 876875776, 443160576, 998185984, 168665600, 318837504, 914397568, 71818816, 40763680, 527762288, 939688008, 335855668, 705536494, 587273091 + ], + [ + 536870912, 268435456, 671088640, 738197504, 637534208, 150994944, 813694976, 943718400, 77594624, 179306496, 798490624, 967049216, 134348800, 1006698496, 235044864, 620937216, 377643008, 826314752, 874711040, 854819840, 725109248, 856992512, 664336768, 94804544, 100663328, 419430416, 411041832, 339738668, 580911142, 61865993 + ], + [ + 536870912, 805306368, 939524096, 603979776, 100663296, 452984832, 998244352, 188743680, 866123776, 389021696, 287834112, 172228608, 824836096, 977731584, 153714688, 507854848, 254402560, 88403968, 883578880, 235160576, 118055424, 422917888, 371224704, 326210368, 654926368, 691353392, 773877944, 930190180, 554263078, 842348331 + ], + [ + 536870912, 268435456, 134217728, 872415232, 771751936, 486539264, 629145600, 163577856, 467664896, 472907776, 168296448, 993787904, 201981952, 37552128, 260734976, 587087872, 535322624, 705662976, 729954304, 79891456, 912360960, 569626368, 1072277120, 974077120, 595691040, 818138896, 409052808, 1022573812, 443254286, 869191437 + ], + [ + 536870912, 805306368, 134217728, 67108864, 369098752, 654311424, 562036736, 1044381696, 333447168, 1068498944, 487063552, 614727680, 652869632, 790036480, 635600896, 682835968, 881451008, 518402048, 587823104, 933663744, 426354176, 844586752, 25366144, 239108416, 467682848, 1001484080, 185235080, 61216068, 124379190, 290861079 + ], + [ + 536870912, 805306368, 134217728, 603979776, 436207616, 1023410176, 830472192, 1061158912, 274726912, 946864128, 752353280, 1040973824, 660209664, 206503936, 247103488, 796737536, 671293440, 335712256, 302135296, 419587072, 730054144, 37987072, 568382336, 120820672, 1018805792, 108831536, 193090440, 843240420, 702586426, 590426893 + ], + [ + 536870912, 805306368, 402653184, 335544320, 637534208, 452984832, 578813952, 364904448, 903872512, 84934656, 498597888, 152829952, 794951680, 886243328, 374964224, 51200000, 911761408, 856600576, 777627648, 655301632, 140164608, 1007657216, 718934912, 701382080, 523919392, 752726064, 41953304, 633494548, 769842726, 286331163 + ], + [ + 536870912, 805306368, 134217728, 67108864, 1040187392, 721420288, 696254464, 272629760, 945815552, 202375168, 973602816, 360448000, 47579136, 965935104, 671121408, 872464384, 905977856, 788533248, 394328064, 994094080, 299935232, 475021568, 40427904, 426520640, 954132512, 753882608, 718703448, 227747404, 503316482, 452984835 + ], + [ + 536870912, 268435456, 134217728, 335544320, 167772160, 822083584, 343932928, 884998144, 618659840, 753926144, 953679872, 852230144, 61734912, 386334720, 598638592, 117915648, 732864512, 319229952, 565086208, 570938368, 892262912, 382142208, 298731904, 976729280, 689351392, 150700016, 716743768, 536617964, 152480482, 419135473 + ], + [ + 536870912, 268435456, 402653184, 603979776, 33554432, 486539264, 679477248, 155189248, 580911104, 678428672, 745013248, 1043595264, 997326848, 936706048, 1021870080, 57950208, 64118784, 648384512, 973113344, 687879168, 847299072, 809547008, 136348288, 1009833408, 642257824, 520412624, 901408584, 563183252, 737329666, 177583361 + ], + [ + 536870912, 805306368, 134217728, 738197504, 234881024, 687865856, 176160768, 750780416, 429916160, 355467264, 1017643008, 563347456, 825622528, 514523136, 110526464, 312197120, 952016896, 869232640, 505976832, 290771968, 781595136, 245081856, 1052701824, 919569344, 447225376, 345248144, 1035356408, 929807420, 464961058, 40591763 + ], + [ + 536870912, 805306368, 671088640, 335544320, 436207616, 486539264, 511705088, 742391808, 375390208, 995098624, 229113856, 905183232, 966393856, 533528576, 209747968, 356564992, 987799552, 504385536, 524838912, 1071936512, 1020426752, 1026142464, 785570176, 69807424, 38934176, 560547792, 280145512, 729389876, 368705538, 161284099 + ], + [ + 536870912, 805306368, 134217728, 335544320, 100663296, 721420288, 713031680, 666894336, 371195904, 326107136, 918028288, 904134656, 997851136, 317915136, 1004699648, 73908224, 1042325504, 930123776, 951597056, 182778880, 402305536, 506671872, 121795200, 819401408, 515383904, 300157520, 897191688, 770924636, 392310882, 145205587 + ], + [ + 536870912, 268435456, 939524096, 201326592, 1040187392, 385875968, 713031680, 398458880, 140509184, 609222656, 174587904, 627310592, 64094208, 708509696, 895123456, 1003438080, 637558784, 184578048, 746592256, 213937152, 484463104, 613417728, 680037248, 385142336, 31066144, 722404560, 1021355752, 881884540, 277363234, 452229073 + ], + [ + 536870912, 268435456, 134217728, 603979776, 905969664, 721420288, 109051904, 20971520, 664797184, 919601152, 422051840, 198967296, 617480192, 71892992, 638091264, 592199680, 583409664, 923111424, 214849536, 810150912, 403225088, 743232768, 306603648, 491120448, 770582176, 131712624, 645969848, 289415012, 799054338, 315639041 + ], + [ + 536870912, 805306368, 939524096, 469762048, 570425344, 1056964608, 58720256, 557842432, 786432000, 632291328, 270008320, 139722752, 607518720, 1048248320, 494436352, 1017430016, 583983104, 262107136, 190187520, 898317312, 402681344, 738211072, 436261760, 587209408, 562087520, 507533392, 761275736, 82897452, 1056476674, 769934595 + ], + [ + 536870912, 268435456, 671088640, 67108864, 33554432, 486539264, 310378496, 239075328, 186646528, 634388480, 96993280, 367263744, 1032454144, 966590464, 1000374272, 646987776, 879271936, 980684800, 828508160, 346649600, 291686912, 78215424, 962727040, 11126592, 996294432, 497644432, 702714920, 334101364, 583180290, 909709313 + ], + [ + 536870912, 268435456, 402653184, 335544320, 503316480, 117440512, 746586112, 876609536, 236978176, 523239424, 950534144, 712769536, 154009600, 870907904, 209747968, 608190464, 371220480, 187715584, 648574976, 763108352, 632205824, 128569600, 44087424, 997211328, 780698272, 558692848, 797334712, 513135524, 690880514, 602472449 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 100663296, 218103808, 746586112, 641728512, 1029701632, 883949568, 439877632, 996933632, 967442432, 920715264, 492863488, 78692352, 37249024, 124579840, 1068111872, 1004614656, 836776448, 586176768, 1062770048, 870064832, 630354144, 9296304, 139121832, 336691844, 574119938, 929886211 + ], + [ + 536870912, 805306368, 939524096, 335544320, 570425344, 553648128, 981467136, 62914560, 488636416, 76546048, 748158976, 818675712, 1054212096, 701431808, 273580032, 134463488, 739794944, 906792960, 58091520, 463459328, 964092416, 513755904, 435617408, 677350720, 475410144, 235914608, 393104184, 965967628, 402705634, 604016243 + ], + [ + 536870912, 805306368, 671088640, 67108864, 973078528, 285212672, 343932928, 692060160, 148897792, 1058013184, 669515776, 14942208, 185204736, 904724480, 367558656, 635748352, 227188736, 162336768, 864577536, 582255616, 906162688, 521778432, 394939264, 682457152, 252243360, 267679376, 81938344, 822706164, 618852866, 17413379 + ], + [ + 536870912, 805306368, 939524096, 201326592, 704643072, 754974720, 897581056, 1019215872, 656408576, 680525824, 824705024, 397148160, 633208832, 881393664, 320241664, 249937920, 906518528, 255651840, 748046336, 790987776, 480837120, 392988416, 278833792, 1025073472, 1035890720, 143231216, 18277464, 803573652, 696815138, 519835635 + ], + [ + 536870912, 268435456, 134217728, 469762048, 637534208, 587202560, 25165824, 1019215872, 442499072, 355467264, 715653120, 557056000, 11141120, 739573760, 1046642688, 923877376, 1004576768, 972042240, 952678400, 671415296, 201498112, 773947136, 1061744512, 667215808, 534962976, 466722832, 696299528, 817952900, 878763298, 707850001 + ], + [ + 536870912, 805306368, 402653184, 67108864, 167772160, 721420288, 612368384, 817889280, 312475648, 630194176, 253231104, 516685824, 62521344, 841154560, 523927552, 920895488, 530243584, 1014222848, 1040369664, 964656128, 194533888, 504151808, 152735872, 330557760, 438455520, 53428848, 950012424, 1049638652, 865619170, 705446515 + ], + [ + 536870912, 805306368, 671088640, 335544320, 1040187392, 452984832, 260046848, 566231040, 580911104, 292552704, 446169088, 490995712, 411172864, 742719488, 841121792, 422952960, 1052385280, 191991808, 397989888, 502594560, 146433536, 879868672, 238603392, 859074240, 463109856, 532801488, 964754152, 515911108, 991977186, 1068529619 + ], + [ + 536870912, 805306368, 402653184, 603979776, 973078528, 620756992, 679477248, 239075328, 639631360, 187695104, 798490624, 669253632, 987365376, 108331008, 706772992, 218251264, 346038272, 275787776, 959977472, 110371840, 157432320, 262219008, 400730240, 584273472, 578455072, 272071472, 673224600, 1006793700, 505428186, 523253621 + ], + [ + 536870912, 805306368, 671088640, 469762048, 503316480, 922746880, 1048576000, 750780416, 933232640, 359661568, 231211008, 302776320, 822476800, 1031995392, 276594688, 845529088, 728637440, 184496128, 78817280, 32168960, 336903680, 840550144, 18888320, 363856064, 208142752, 746339952, 474885448, 877595084, 677034022, 911655987 + ], + [ + 536870912, 268435456, 939524096, 872415232, 436207616, 419430400, 729808896, 943718400, 648019968, 433061888, 1071120384, 549715968, 72482816, 547684352, 384663552, 592920576, 805969920, 673255424, 203405312, 774009856, 54508032, 850544896, 331854720, 518413376, 1064150176, 639067344, 522851928, 615589252, 619162482, 913730613 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 1040187392, 754974720, 629145600, 775946240, 689963008, 397410304, 626524160, 496762880, 575537152, 253034496, 111771648, 1053310976, 517480448, 786182144, 921573376, 182795264, 886160896, 434400512, 1011746176, 303373888, 992588064, 747137968, 167263064, 342622364, 909516750, 960044373 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 234881024, 687865856, 427819008, 457179136, 333447168, 890241024, 664272896, 441712640, 911343616, 544669696, 491290624, 918994944, 176332800, 702935040, 504891392, 823397376, 229778944, 694621440, 886085504, 93516352, 626043488, 315809360, 280018040, 851632964, 547919818, 450289443 + ], + [ + 536870912, 805306368, 402653184, 67108864, 503316480, 318767104, 763363328, 708837376, 199229440, 328204288, 157810688, 1048313856, 1036648448, 478478336, 1053982720, 421904384, 144220160, 148959232, 371865600, 1058354176, 800753152, 593090304, 726832000, 124111168, 91790944, 208719312, 750920840, 942213868, 873504546, 101507001 + ], + [ + 536870912, 268435456, 402653184, 603979776, 771751936, 452984832, 947912704, 146800640, 253755392, 512753664, 802684928, 1032060928, 595460096, 56819712, 325877760, 189710336, 794304512, 21237760, 442374144, 586359808, 708095488, 621468416, 998643840, 343349440, 701142816, 178911888, 164274648, 447346308, 298492926, 1051328419 + ], + [ + 536870912, 268435456, 134217728, 603979776, 369098752, 620756992, 595591168, 616562688, 98566144, 544210944, 699924480, 737935360, 962199552, 807862272, 403210240, 739131392, 842047488, 858935296, 109750272, 124089344, 557465088, 630657280, 164674944, 37905856, 313692256, 156856752, 671098840, 872422220, 503319298, 16792235 + ], + [ + 536870912, 805306368, 939524096, 738197504, 369098752, 452984832, 243269632, 960495616, 228589568, 737148928, 450363392, 293339136, 700317696, 704577536, 1005355008, 315113472, 90578944, 327364608, 617789440, 779578368, 623556096, 834366208, 904697472, 365454656, 635831200, 499330288, 837991000, 667377468, 1020435614, 846680143 + ], + [ + 536870912, 268435456, 134217728, 469762048, 1040187392, 956301312, 276824064, 868220928, 614465536, 30408704, 732430336, 877395968, 919994368, 437583872, 53903360, 60735488, 945168384, 13963264, 1058441216, 764337152, 157163008, 206121216, 854104192, 806875072, 404667040, 336783568, 572527400, 118492044, 696788086, 593247941 + ], + [ + 536870912, 805306368, 402653184, 67108864, 100663296, 989855744, 377487360, 767557632, 1033895936, 326107136, 209190912, 752091136, 571342848, 219611136, 898400256, 1062518784, 376840192, 365113344, 159553536, 222544896, 863675904, 1012386560, 886353536, 640735680, 186647456, 246422640, 702022904, 1000619540, 678825774, 448989351 + ], + [ + 536870912, 805306368, 939524096, 201326592, 973078528, 922746880, 41943040, 171966464, 509607936, 407896064, 761790464, 350486528, 639500288, 84475904, 29065216, 1053409280, 423337984, 864677888, 1037801472, 765066240, 886284800, 372099840, 1025876096, 226541888, 81805024, 772806928, 822621064, 934559220, 871771542, 749548797 + ], + [ + 536870912, 805306368, 134217728, 67108864, 838860800, 922746880, 931135488, 868220928, 429916160, 183500800, 656932864, 263454720, 1073348608, 798162944, 267747328, 665632768, 198844416, 363016192, 1023248384, 573096960, 254284288, 1001654016, 100286336, 479410112, 175483808, 594345456, 637153448, 747834484, 41266778, 661447011 + ], + [ + 536870912, 805306368, 134217728, 469762048, 33554432, 83886080, 1048576000, 750780416, 1029701632, 101711872, 590872576, 764674048, 157155328, 673644544, 738951168, 169492480, 420323328, 1018785792, 702556160, 63974400, 718801408, 507779328, 730217600, 711141824, 93160416, 628714192, 570441304, 889199492, 914367078, 817895859 + ], + [ + 536870912, 268435456, 402653184, 738197504, 33554432, 922746880, 394264576, 1044381696, 434110464, 800063488, 38273024, 64225280, 882769920, 402456576, 179601408, 987217920, 103456768, 288018432, 379467776, 821902336, 87333376, 681040640, 499824000, 161143104, 55981664, 224996848, 675971496, 282785636, 355861334, 815336809 + ], + [ + 536870912, 805306368, 134217728, 67108864, 838860800, 385875968, 1015021568, 784334848, 920649728, 181403648, 886571008, 366739456, 208535552, 154730496, 765820928, 1065041920, 933601280, 477851648, 824551424, 565933056, 155556352, 313221888, 939370112, 593972672, 967544928, 894584592, 750265528, 382472908, 987105494, 1022700533 + ], + [ + 536870912, 268435456, 402653184, 603979776, 503316480, 50331648, 360710144, 213909504, 190840832, 1041235968, 319291392, 227278848, 684851200, 359596032, 1024557056, 109232128, 21651456, 599240704, 727713792, 772801536, 185075200, 697043200, 919734144, 376373440, 680625504, 172147504, 170549976, 497532804, 946343106, 597428067 + ], + [ + 536870912, 268435456, 939524096, 469762048, 234881024, 922746880, 377487360, 1010827264, 996147200, 386924544, 109576192, 73138176, 661520384, 420937728, 831750144, 316096512, 456138752, 577417216, 646449152, 341574656, 527306240, 85395200, 1066632064, 634867136, 229647776, 506117904, 501745368, 55312836, 434507682, 21693975 + ], + [ + 536870912, 805306368, 671088640, 67108864, 838860800, 184549376, 545259520, 666894336, 52428800, 915406848, 785907712, 11796480, 902955008, 941686784, 1040285696, 218775552, 832495616, 138809344, 913442816, 426839040, 1006209536, 1059995904, 412413056, 1003688640, 488734752, 194659824, 927394504, 217193636, 832573238, 709889773 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 973078528, 285212672, 662700032, 725614592, 576716800, 714080256, 114819072, 270794752, 325976064, 1024786432, 630489088, 239714304, 66494464, 718581760, 305530880, 913378304, 479887872, 634179328, 448409216, 632910912, 623813088, 183547600, 156762776, 929302948, 51252534, 981798729 + ], + [ + 536870912, 805306368, 939524096, 738197504, 1040187392, 318767104, 595591168, 423624704, 228589568, 11534336, 2621440, 49545216, 973209600, 151846912, 446464000, 1003569152, 443277312, 616706048, 937682944, 377895936, 902424064, 830420736, 727148928, 279147456, 136315232, 384828816, 671615496, 604244412, 705299458, 17367553 + ], + [ + 536870912, 268435456, 134217728, 201326592, 1040187392, 620756992, 796917760, 482344960, 526385152, 722468864, 310902784, 927203328, 832962560, 795803648, 856326144, 379305984, 88891392, 716615680, 635963392, 5506048, 355336704, 824902400, 321687424, 3459392, 111602656, 201160496, 759984088, 917946052, 333975202, 693373649 + ], + [ + 536870912, 268435456, 671088640, 335544320, 100663296, 50331648, 58720256, 465567744, 522190848, 691011584, 305659904, 766246912, 610664448, 1044709376, 401899520, 495796224, 885825536, 649408512, 602712064, 193278976, 534028800, 824783104, 1043506048, 397160896, 895886176, 953251632, 213025960, 452480380, 419440678, 43282967 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 436207616, 654311424, 192937984, 583008256, 27262976, 917504000, 623378432, 335282176, 876740608, 1073676288, 910458880, 217923584, 466493440, 320991232, 921053184, 215874560, 816062976, 673379072, 392209536, 555727552, 110003808, 642663024, 350268936, 266318812, 892241218, 201212963 + ], + [ + 536870912, 268435456, 671088640, 738197504, 503316480, 486539264, 729808896, 574619648, 652214272, 957349888, 159907840, 156499968, 1014366208, 786366464, 270958592, 1026670592, 784277504, 149975040, 470288384, 638845952, 420874752, 428804864, 558794624, 276154176, 817965792, 222001296, 381190584, 216713796, 772253794, 622508373 + ], + [ + 536870912, 805306368, 939524096, 469762048, 234881024, 486539264, 713031680, 977272832, 283115520, 1053818880, 129499136, 1017905152, 522584064, 636682240, 5537792, 402145280, 592879616, 409120768, 798132224, 1021004800, 481963520, 792131328, 501361536, 474676032, 435956896, 1045820816, 854499768, 365868020, 741641934, 577261051 + ], + [ + 536870912, 268435456, 134217728, 872415232, 973078528, 352321536, 964689920, 415236096, 694157312, 781189120, 407371776, 237240320, 69861376, 153419776, 213286912, 444252160, 471293952, 504705024, 654444544, 412156928, 458523136, 616287488, 1047260800, 773518656, 1057744480, 613085744, 356769880, 196014756, 317317778, 256638921 + ], + [ + 536870912, 268435456, 939524096, 603979776, 704643072, 16777216, 931135488, 331350016, 295698432, 762314752, 811073536, 7602176, 568197120, 615448576, 150568960, 110182400, 206774272, 510636032, 852666368, 909833216, 111642112, 100551936, 118137984, 277805376, 324636512, 987840688, 864757640, 702265004, 682404606, 1055260417 + ], + [ + 536870912, 805306368, 939524096, 201326592, 704643072, 1023410176, 494927872, 734003200, 517996544, 510656512, 405274624, 353632256, 427950080, 902758400, 99450880, 351617024, 325951488, 1033916416, 851945472, 763059200, 380118528, 4267776, 707267712, 336855104, 369230816, 789513904, 747473496, 474300972, 136685266, 486823977 + ], + [ + 536870912, 805306368, 939524096, 201326592, 771751936, 956301312, 276824064, 339738624, 228589568, 839909376, 521666560, 496762880, 650510336, 251068416, 372015104, 700465152, 460201984, 82628608, 85985280, 441453568, 79171072, 445383424, 123603840, 1043009088, 768246816, 23545104, 536519528, 44080260, 663760838, 232250215 + ], + [ + 536870912, 805306368, 402653184, 67108864, 771751936, 218103808, 159383552, 457179136, 782237696, 684720128, 1056440320, 519831552, 787087360, 921894912, 853573632, 485867520, 301604864, 409210880, 53118976, 764857344, 88253952, 1002295552, 625124224, 196992832, 1027779680, 264100816, 323137064, 45995124, 448964702, 436068143 + ], + [ + 536870912, 805306368, 402653184, 201326592, 301989888, 184549376, 629145600, 868220928, 929038336, 770703360, 363331584, 268697600, 672268288, 335740928, 504004608, 421412864, 781099008, 374378496, 78948352, 446143488, 944516608, 96132864, 939526784, 1006636480, 167775200, 117443888, 931135544, 952108364, 316670418, 506463117 + ], + [ + 536870912, 268435456, 671088640, 603979776, 301989888, 150994944, 192937984, 767557632, 757071872, 149946368, 299368448, 591134720, 536215552, 625147904, 510754816, 496451584, 650125312, 129626112, 179415040, 53392384, 267485696, 223825152, 979381888, 260700992, 801746528, 203603248, 662670248, 773342284, 119513534, 479310259 + ], + [ + 536870912, 268435456, 671088640, 872415232, 167772160, 218103808, 159383552, 180355072, 522190848, 315621376, 321388544, 79953920, 540147712, 172032000, 779386880, 371572736, 692183040, 150097920, 745834496, 1059439616, 46262784, 993156352, 819235456, 708167488, 122284128, 669409200, 485395784, 912311284, 438791338, 1061592705 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 33554432, 822083584, 796917760, 801112064, 98566144, 682622976, 1058537472, 614203392, 625606656, 1002373120, 831094784, 214384640, 863248384, 351997952, 388999168, 954160128, 494404096, 267127552, 900860544, 982713152, 106662752, 220481456, 232237720, 619925980, 791283390, 751765259 + ], + [ + 536870912, 268435456, 134217728, 738197504, 570425344, 788529152, 629145600, 46137344, 1033895936, 328204288, 1002962944, 824442880, 365297664, 741933056, 390299648, 661438464, 170156032, 642207744, 132515840, 778634240, 514556416, 68733696, 503998592, 84564928, 646676832, 88655024, 274885992, 197025764, 713395826, 928367497 + ], + [ + 536870912, 268435456, 402653184, 201326592, 704643072, 117440512, 75497472, 20971520, 597688320, 292552704, 1058537472, 411303936, 860487680, 682819584, 1072070656, 962183168, 1067900928, 594243584, 873621504, 906343424, 890768896, 260310784, 801770624, 636682944, 910592928, 791265680, 71231944, 984577036, 620261166, 264681085 + ], + [ + 536870912, 268435456, 671088640, 872415232, 838860800, 1056964608, 310378496, 759169024, 631242752, 1001390080, 985137152, 959184896, 1073086464, 680460288, 910196736, 757186560, 502489088, 1066643456, 282290176, 845394944, 122380800, 381663488, 119893632, 787265216, 51112480, 77495696, 139854664, 1010762620, 913868262, 223201591 + ], + [ + 536870912, 268435456, 671088640, 469762048, 637534208, 1056964608, 847249408, 943718400, 652214272, 447741952, 1045954560, 167510016, 2752512, 436535296, 152076288, 631029760, 383279104, 950259712, 55109632, 377426944, 267420160, 791462656, 8414080, 761256128, 627240224, 863638992, 878708504, 854592444, 817366446, 256642067 + ], + [ + 536870912, 268435456, 939524096, 469762048, 234881024, 956301312, 1015021568, 532676608, 1008730112, 393216000, 9961472, 30670848, 1026686976, 939065344, 289636352, 83279872, 382967808, 682684416, 748824576, 784282624, 565315072, 943260416, 358845824, 260491584, 407612576, 275052976, 756033576, 109458988, 215058734, 733988521 + ], + [ + 536870912, 805306368, 402653184, 738197504, 771751936, 922746880, 528482304, 314572800, 908066816, 581959680, 703070208, 235143168, 117571584, 126681088, 1054507008, 404963328, 363667456, 913682432, 482813952, 826063872, 624930304, 388167424, 371197312, 313526976, 837290592, 570688112, 687997416, 814547420, 559579154, 182669213 + ], + [ + 536870912, 268435456, 671088640, 872415232, 33554432, 1056964608, 377487360, 926941184, 157286400, 435159040, 733478912, 390856704, 426115072, 838795264, 532447232, 358203392, 644440064, 661344256, 686778368, 472142848, 1066131968, 214014208, 1069318784, 89769664, 241790752, 325803792, 720334712, 589582444, 688647958, 998348671 + ], + [ + 536870912, 805306368, 939524096, 469762048, 838860800, 520093696, 8388608, 683671552, 287309824, 730857472, 240648192, 821821440, 188612608, 546373632, 415989760, 691159040, 932405248, 1011224576, 803604480, 195890176, 139824640, 166938368, 44100736, 970479552, 213084192, 618010160, 725484104, 277938660, 550207766, 892488959 + ], + [ + 536870912, 268435456, 134217728, 469762048, 905969664, 318767104, 209715200, 432013312, 547356672, 1072693248, 865599488, 994836480, 1047134208, 969211904, 817528832, 939245568, 798793728, 223064064, 762062848, 893744128, 695339520, 390660864, 275812224, 1053737920, 373173920, 188510896, 280658696, 670813580, 664577742, 290174511 + ], + [ + 536870912, 268435456, 939524096, 67108864, 436207616, 922746880, 612368384, 1044381696, 367001600, 321912832, 915931136, 626262016, 394133504, 75431936, 720273408, 464371712, 785080320, 430886912, 232515584, 524030976, 10356224, 877593856, 452364416, 867814592, 315977632, 128045648, 550331480, 213245788, 441675486, 536533145 + ], + [ + 536870912, 805306368, 939524096, 469762048, 838860800, 385875968, 360710144, 432013312, 85983232, 944766976, 989331456, 1013710848, 774242304, 801964032, 203522048, 819052544, 1034444800, 118935552, 495421440, 1037880320, 724168192, 492246784, 947381376, 808851904, 852517728, 314236272, 243370952, 910278868, 804284766, 116054955 + ], + [ + 536870912, 268435456, 939524096, 201326592, 973078528, 150994944, 343932928, 54525952, 1021313024, 728760320, 498597888, 42205184, 542244864, 426180608, 816807936, 403423232, 471556096, 34574336, 85026816, 782013440, 173336064, 678713088, 674367616, 559351104, 704087456, 1040171408, 468804760, 283940940, 23913846, 749756077 + ], + [ + 536870912, 268435456, 134217728, 603979776, 838860800, 318767104, 159383552, 952107008, 85983232, 808452096, 12058624, 251396096, 747503616, 4653056, 795246592, 542523392, 1063264256, 675786752, 460859392, 441168896, 141437440, 331398400, 817800832, 384694720, 9831648, 374015984, 242257320, 987582460, 238071686, 363525443 + ], + [ + 536870912, 268435456, 671088640, 738197504, 838860800, 251658240, 461373440, 448790528, 807403520, 762314752, 228065280, 467402752, 1050804224, 255787008, 249987072, 323371008, 904568832, 786329600, 372123648, 342307840, 117572096, 663686912, 14583424, 321538240, 82881120, 407729520, 812819176, 151157228, 848047470, 945304235 + ], + [ + 536870912, 805306368, 939524096, 469762048, 771751936, 117440512, 293601280, 272629760, 140509184, 770703360, 128450560, 47448064, 195690496, 617938944, 681738240, 122699776, 301293568, 432001024, 1038051328, 103472128, 446555648, 667589376, 991989120, 101796544, 320725472, 462066384, 624985592, 820069036, 724953490, 236886233 + ], + [ + 536870912, 268435456, 402653184, 335544320, 503316480, 285212672, 494927872, 490733568, 564133888, 1049624576, 197656576, 913047552, 452591616, 171376640, 786202624, 635486208, 246915072, 570773504, 319948800, 512427008, 466519552, 778814720, 251209600, 338596928, 1070280544, 947229520, 334341736, 60972708, 763792242, 357026011 + ], + [ + 536870912, 268435456, 671088640, 872415232, 301989888, 452984832, 411041792, 884998144, 195035136, 827326464, 1055391744, 631504896, 474087424, 125108224, 653492224, 698826752, 307421184, 979505152, 930711552, 518407168, 900426240, 876895488, 863169664, 888279744, 850494496, 181552176, 245460072, 1019565972, 799761690, 189027993 + ], + [ + 536870912, 805306368, 134217728, 67108864, 704643072, 754974720, 226492416, 834666496, 908066816, 141557760, 378011648, 123469824, 23461888, 17235968, 328957952, 1054097408, 314318848, 505868288, 1013032960, 881179648, 776866304, 652938496, 500533376, 675236416, 124365280, 840546096, 285738728, 731644524, 851839530, 1018626763 + ], + [ + 536870912, 805306368, 402653184, 201326592, 369098752, 83886080, 629145600, 12582912, 291504128, 30408704, 116916224, 102498304, 756940800, 830930944, 449085440, 41533440, 559079424, 597848064, 398231552, 1034275840, 917300736, 439710464, 694160768, 1037045056, 150474592, 253494064, 513671640, 877068596, 774146270, 57262519 + ], + [ + 536870912, 268435456, 134217728, 201326592, 838860800, 486539264, 998244352, 46137344, 769654784, 416284672, 753401856, 424935424, 1059979264, 1026359296, 942702592, 129548288, 997580800, 965226496, 131106816, 308855808, 605938176, 773600000, 656311424, 714457920, 189099232, 842068912, 245723128, 920712564, 407728090, 1052045797 + ], + [ + 536870912, 268435456, 134217728, 469762048, 570425344, 956301312, 327155712, 524288000, 618659840, 240123904, 996671488, 991166464, 981860352, 81068032, 666009600, 145276928, 204152832, 333950976, 517638144, 448578560, 757932544, 343062272, 1065877632, 625216064, 166594272, 599851216, 1060405688, 897437140, 941206074, 68122901 + ], + [ + 536870912, 805306368, 134217728, 738197504, 503316480, 50331648, 847249408, 465567744, 597688320, 47185920, 272105472, 1049886720, 902692864, 682295296, 474447872, 367935488, 507011072, 93753344, 593463296, 23743488, 586048000, 649698048, 659427200, 57347264, 937922208, 993938928, 268463976, 939692148, 605126830, 838944085 + ], + [ + 536870912, 268435456, 671088640, 201326592, 704643072, 687865856, 293601280, 583008256, 136314880, 944766976, 241696768, 19136512, 970850304, 78184448, 85360640, 731103232, 600104960, 364793856, 813729792, 793691136, 686057984, 358650624, 229433984, 77225536, 559842912, 669503408, 133358216, 401823572, 1072170362, 870581945 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 167772160, 184549376, 142606336, 968884224, 622854144, 426770432, 337117184, 638320640, 152698880, 1067122688, 994082816, 400670720, 885563392, 883322880, 388638720, 912307200, 578816512, 583011072, 631242880, 481299904, 993525920, 880544944, 360844136, 542574636, 393907278, 822792159 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 973078528, 83886080, 494927872, 859832320, 778043392, 418381824, 1027080192, 647233536, 1037697024, 665780224, 558989312, 528039936, 459923456, 224808960, 711714816, 250434560, 439905792, 35592960, 687997056, 1066076736, 173248480, 166871696, 783966840, 248781740, 221350838, 780748617 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 436207616, 754974720, 511705088, 750780416, 622854144, 389021696, 372768768, 448528384, 660733952, 114229248, 271155200, 1035911168, 484745216, 143405056, 63219712, 582759424, 58501632, 683686656, 457092224, 339685440, 61811488, 536738672, 487162472, 110022332, 417116134, 53492755 + ], + [ + 536870912, 805306368, 939524096, 67108864, 704643072, 788529152, 260046848, 826277888, 174063616, 240123904, 234356736, 51118080, 697958400, 139001856, 83197952, 897761280, 374808576, 973008896, 286099456, 42912768, 768421376, 448262400, 813171328, 692848576, 1048186336, 475598160, 653101080, 647940180, 936714398, 229375123 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 234881024, 486539264, 545259520, 633339904, 1025507328, 1053818880, 347602944, 295436288, 591790080, 569049088, 291536896, 482295808, 93872128, 155504640, 251168768, 586370048, 82208256, 1039392512, 796789632, 431426368, 419860000, 579094128, 784395464, 1017616628, 898032910, 290230551 + ], + [ + 536870912, 805306368, 402653184, 67108864, 1040187392, 654311424, 612368384, 926941184, 882900992, 586153984, 566755328, 921960448, 937295872, 233111552, 693141504, 599506944, 510320640, 311980032, 1012033536, 841464832, 145657344, 686738688, 550660480, 828881088, 437161632, 689883152, 463102472, 399750252, 1039172314, 827048129 + ], + [ + 536870912, 805306368, 939524096, 872415232, 100663296, 184549376, 109051904, 675282944, 681574400, 426770432, 336068608, 906756096, 856555520, 848101376, 776044544, 597868544, 535928832, 1010962432, 514205696, 712530944, 645923328, 406848256, 278922112, 762315584, 302514272, 1024196784, 898498664, 449643140, 115442314, 986890647 + ], + [ + 536870912, 268435456, 939524096, 469762048, 503316480, 285212672, 780140544, 910163968, 799014912, 36700160, 373817344, 1067712512, 977141760, 172949504, 564363264, 725237760, 616865792, 401477632, 76654592, 653536256, 27492864, 993673472, 482648960, 200151488, 445753824, 938749200, 790855912, 226116196, 862232954, 165548515 + ], + [ + 536870912, 805306368, 134217728, 335544320, 503316480, 385875968, 427819008, 20971520, 572522496, 198180864, 505937920, 836501504, 522846208, 727252992, 434995200, 524075008, 698081280, 193236992, 608659456, 782263296, 236708352, 767857408, 401041536, 808478016, 739501024, 13144688, 258304280, 737502548, 150233538, 1065177805 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 704643072, 117440512, 645922816, 1010827264, 106954752, 934281216, 841482240, 500432896, 127008768, 351469568, 382500864, 673234944, 584458240, 890458112, 1052735488, 1034722304, 1041932800, 171151616, 317282944, 150982592, 751163552, 120524144, 945552104, 592993540, 1071546950, 747880907 + ], + [ + 536870912, 268435456, 134217728, 335544320, 100663296, 251658240, 260046848, 658505728, 899678208, 34603008, 578289664, 604766208, 503709696, 319225856, 495222784, 776093696, 891297792, 718942208, 815577088, 330427392, 1046878720, 359832832, 662700672, 591396928, 1000341728, 420479408, 737673368, 206307972, 606471074, 911671893 + ], + [ + 536870912, 268435456, 671088640, 469762048, 704643072, 83886080, 578813952, 272629760, 35651584, 238026752, 432537600, 1004797952, 635043840, 337575936, 871792640, 1009205248, 758226944, 1011585024, 271075328, 1060826112, 222593536, 78397696, 7676544, 686281152, 945646240, 199048272, 521791528, 175209476, 1038928034, 852929571 + ], + [ + 536870912, 268435456, 939524096, 201326592, 436207616, 16777216, 528482304, 121634816, 1054867456, 663748608, 445120512, 650379264, 380502016, 301137920, 1054769152, 460079104, 836624384, 65327104, 169752576, 684270592, 296092160, 762773760, 722502528, 659505344, 787177888, 530354192, 377870840, 1019933812, 396409326, 242575225 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 33554432, 452984832, 327155712, 171966464, 891289600, 686817280, 781713408, 197394432, 208273408, 710475776, 841449472, 159006720, 668737536, 292384768, 752179200, 719369216, 43448832, 566462208, 862815104, 131285184, 560177568, 886256240, 384006424, 9749780, 985931882, 552169771 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 369098752, 83886080, 343932928, 843055104, 861929472, 309329920, 26738688, 464257024, 308150272, 906821632, 353271808, 1015988224, 239820800, 627847168, 393283584, 353723392, 702835200, 557077760, 612098176, 346026688, 657255392, 471570320, 325059112, 40895092, 697827582, 665584067 + ], + [ + 536870912, 268435456, 671088640, 738197504, 436207616, 251658240, 679477248, 717225984, 996147200, 554696704, 329777152, 24379392, 70385664, 18284544, 60850176, 695648256, 674603008, 454619136, 212318208, 33428480, 49619456, 545140992, 767171200, 307422912, 58760096, 608642544, 749189640, 301864300, 720708246, 209596705 + ], + [ + 536870912, 268435456, 402653184, 603979776, 436207616, 318767104, 880803840, 759169024, 790626304, 445644800, 736624640, 762576896, 681443328, 350552064, 1072988160, 684965888, 105816064, 799739904, 903686144, 868701184, 426516992, 1027199232, 573639040, 549357120, 956115872, 240604208, 67379400, 168677780, 185535186, 277579481 + ], + [ + 536870912, 268435456, 939524096, 872415232, 369098752, 989855744, 427819008, 46137344, 794820608, 250609664, 347602944, 698089472, 104988672, 656867328, 920027136, 367935488, 834215936, 387846144, 118228992, 327635968, 599820800, 803345664, 951396736, 463029824, 323780832, 832913904, 999662456, 55267548, 161589774, 261097331 + ], + [ + 536870912, 268435456, 939524096, 872415232, 301989888, 1056964608, 411041792, 1044381696, 748683264, 972029952, 369623040, 84148224, 730726400, 13434880, 1071939584, 853524480, 155066368, 31690752, 1003563008, 79002624, 740295168, 598737152, 279446400, 938738496, 923140384, 76088304, 541753736, 899859428, 208839370, 264786847 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 234881024, 251658240, 243269632, 113246208, 526385152, 1020264448, 345505792, 490471424, 915275776, 583598080, 627998720, 31408128, 454811648, 444452864, 564905984, 128998400, 306924032, 883301632, 608053888, 319065792, 277742176, 29950512, 770605192, 874464092, 83616254, 795726673 + ], + [ + 536870912, 268435456, 402653184, 738197504, 436207616, 50331648, 981467136, 784334848, 123731968, 946864128, 879230976, 183762944, 783155200, 1000275968, 265846784, 913817600, 291643392, 829583360, 367851520, 851241984, 487203328, 126251264, 960690560, 639889088, 844276640, 473018672, 364960296, 31562796, 347495382, 470376119 + ], + [ + 536870912, 268435456, 134217728, 469762048, 369098752, 385875968, 343932928, 801112064, 731906048, 254803968, 808976384, 683409408, 427687936, 970522624, 879525888, 1016152064, 721969152, 311267328, 818313216, 589640704, 922647040, 211367168, 855669376, 109065408, 986512352, 572618160, 897358504, 936437580, 929357842, 572314559 + ], + [ + 536870912, 268435456, 671088640, 469762048, 301989888, 318767104, 947912704, 901775360, 379584512, 254803968, 933756928, 884211712, 316801024, 198377472, 427196416, 542097408, 585408512, 869576704, 762316800, 776141824, 602710528, 407941376, 540674688, 220593600, 980951840, 550268976, 589834504, 729714332, 592218698, 845823171 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 234881024, 687865856, 595591168, 935329792, 559939584, 1009778688, 42467328, 407633920, 816447488, 140443648, 322666496, 68042752, 705617920, 856223744, 948230144, 860277760, 471990784, 152240896, 672236160, 126960576, 374694112, 574010000, 864172600, 801259388, 896325654, 238734531 + ], + [ + 536870912, 805306368, 134217728, 738197504, 167772160, 1023410176, 142606336, 1069547520, 761266176, 485490688, 116916224, 66322432, 796262400, 918355968, 752844800, 94420992, 874176512, 625020928, 1001146368, 387871744, 1053575680, 401504000, 976505472, 85620160, 398608928, 828864016, 519948968, 402109932, 25110654, 766682147 + ], + [ + 536870912, 268435456, 671088640, 335544320, 704643072, 150994944, 478150656, 448790528, 748683264, 141557760, 620232704, 104595456, 378929152, 551747584, 655458304, 883933184, 612294656, 855330816, 825358336, 689185792, 799537664, 234300672, 179730560, 609805376, 407411232, 90420432, 425288680, 1053266300, 1051106082, 1031582971 + ], + [ + 536870912, 805306368, 134217728, 469762048, 1040187392, 956301312, 75497472, 1035993088, 18874368, 588251136, 263716864, 769916928, 180224000, 661454848, 108298240, 1053540352, 648306688, 156487680, 752777216, 831663104, 662444544, 508100352, 828957312, 326898368, 205790048, 1047330384, 855040424, 184619852, 998807770, 339950637 + ], + [ + 536870912, 268435456, 134217728, 603979776, 301989888, 956301312, 226492416, 440401920, 622854144, 592445440, 811073536, 953942016, 287178752, 561446912, 25395200, 1011204096, 102932480, 869675008, 899577856, 1052126208, 451312128, 674901248, 740326016, 919678784, 102628256, 737406160, 423943032, 632036724, 782106922, 305595201 + ], + [ + 536870912, 268435456, 402653184, 469762048, 1040187392, 419430400, 25165824, 264241152, 954204160, 544210944, 396886016, 450101248, 654180352, 283836416, 880640000, 766459904, 568123392, 7614464, 128129024, 47582208, 989291008, 786723072, 763132288, 740720064, 773134816, 949554320, 668787608, 359936060, 539171310, 135663191 + ], + [ + 536870912, 268435456, 402653184, 335544320, 973078528, 553648128, 25165824, 809500672, 673185792, 357564416, 522715136, 198443008, 770572288, 657522688, 458260480, 337723392, 861724672, 137318400, 89516032, 119636992, 534045184, 401297664, 104065408, 450135360, 610427296, 461312784, 494504344, 444569156, 217443106, 842106437 + ], + [ + 536870912, 805306368, 939524096, 872415232, 167772160, 50331648, 964689920, 272629760, 354418688, 479199232, 187170816, 630980608, 161873920, 944832512, 113541120, 853655552, 687005696, 202493952, 300787712, 561116160, 609411584, 818008832, 937798528, 746452800, 752673440, 772592432, 17246232, 915224132, 399148018, 208454393 + ], + [ + 536870912, 268435456, 671088640, 335544320, 570425344, 788529152, 411041792, 734003200, 568328192, 667942912, 994574336, 237240320, 205127680, 664600576, 266633216, 114671616, 314646528, 610496512, 328284160, 1038685184, 31359488, 508084480, 765829760, 494317888, 45095456, 291137264, 830978952, 105240508, 27337374, 57897533 + ], + [ + 536870912, 805306368, 939524096, 201326592, 704643072, 352321536, 679477248, 725614592, 589299712, 944766976, 198705152, 856948736, 419037184, 860422144, 522944512, 710066176, 316596224, 832253952, 649558016, 955198464, 204831232, 44183296, 429717888, 582873024, 652974880, 1060707984, 355172776, 257081380, 39772570, 383463585 + ], + [ + 536870912, 805306368, 134217728, 335544320, 905969664, 16777216, 679477248, 759169024, 320864256, 9437184, 829947904, 503578624, 621674496, 377946112, 944275456, 229490688, 752508928, 182022144, 870029312, 122874880, 136280576, 741695232, 85983872, 831521344, 301466592, 658768208, 3015144, 387384004, 565216186, 1055507165 + ], + [ + 536870912, 268435456, 134217728, 603979776, 570425344, 989855744, 394264576, 96468992, 538968064, 435159040, 609746944, 929824768, 244711424, 985858048, 94732288, 791953408, 939139072, 156241920, 837400576, 64263168, 715495936, 45581568, 624009856, 955994944, 886577824, 724551152, 377323864, 228082412, 290202618, 241374083 + ], + [ + 536870912, 268435456, 402653184, 335544320, 973078528, 654311424, 8388608, 297795584, 1042284544, 225443840, 749207552, 666107904, 604897280, 838926336, 721977344, 780976128, 214867968, 430813184, 473933824, 55520256, 350265856, 98349312, 958343552, 683142464, 947913120, 364905328, 471859592, 1047527516, 371720258, 292815527 + ], + [ + 536870912, 268435456, 134217728, 603979776, 301989888, 754974720, 578813952, 725614592, 778043392, 1018167296, 422051840, 1020526592, 916062208, 477429760, 1015709696, 541343744, 1005002752, 1014763520, 746911744, 675421184, 535667200, 779636992, 25417856, 181276224, 882989856, 1986512, 1027373224, 333929972, 142213446, 914686555 + ], + [ + 536870912, 268435456, 134217728, 738197504, 503316480, 654311424, 1048576000, 633339904, 895483904, 1032847360, 691535872, 63700992, 644218880, 957939712, 435453952, 824328192, 665870336, 1040699392, 923576320, 915307520, 164121088, 728493312, 445940352, 397558720, 638083424, 319541424, 76196360, 818379820, 853854910, 30780549 + ], + [ + 536870912, 268435456, 671088640, 738197504, 503316480, 889192448, 729808896, 549453824, 698351616, 357564416, 469237760, 506200064, 329121792, 56164352, 317751296, 61652992, 710057984, 528240640, 309303296, 443620352, 31799808, 1051806976, 441229440, 15029184, 524229472, 361618832, 97491288, 706813020, 429734050, 744311961 + ], + [ + 536870912, 805306368, 939524096, 67108864, 570425344, 486539264, 1065353216, 557842432, 413138944, 745537536, 734527488, 174850048, 194904064, 605618176, 224165888, 704462848, 595910656, 927191040, 531032064, 184171520, 386564608, 780681984, 13001600, 48730176, 878610976, 74755536, 666929656, 342732052, 815532042, 613477767 + ], + [ + 536870912, 268435456, 402653184, 201326592, 905969664, 452984832, 578813952, 666894336, 954204160, 953155584, 999817216, 935067648, 17432576, 528547840, 105414656, 833110016, 301195264, 548376576, 377186304, 719846400, 299493888, 538885376, 335186816, 296054208, 33030368, 950796400, 443678920, 485294860, 182092486, 43335745 + ], + [ + 536870912, 805306368, 402653184, 201326592, 436207616, 1056964608, 578813952, 935329792, 668991488, 540016640, 79167488, 1047789568, 269615104, 861995008, 50298880, 651444224, 117891072, 512102400, 902195200, 350299136, 414476800, 208676608, 991161216, 132147136, 272566816, 481522736, 846520328, 169284428, 207743094, 544302671 + ], + [ + 536870912, 805306368, 671088640, 603979776, 100663296, 989855744, 729808896, 893386752, 308281344, 1039138816, 1008205824, 144965632, 752222208, 9109504, 113541120, 723861504, 228401152, 1022242816, 607848448, 984810496, 191900160, 701904640, 739221632, 302018880, 352496352, 881358320, 416153816, 472843236, 68321566, 883835595 + ], + [ + 536870912, 805306368, 134217728, 67108864, 100663296, 184549376, 343932928, 415236096, 266338304, 1022361600, 756547584, 652476416, 360579072, 576389120, 558137344, 950878208, 928309248, 46895104, 1055557632, 695804928, 677276160, 675460864, 556589696, 807375680, 23890144, 355869936, 930933544, 525399612, 918717238, 820134147 + ], + [ + 536870912, 268435456, 939524096, 201326592, 637534208, 956301312, 645922816, 482344960, 253755392, 974127104, 1073217536, 466354176, 212467712, 509411328, 420642816, 779862016, 746971136, 331845632, 681605120, 207195136, 169286144, 401988864, 801800576, 648528320, 22536672, 110531408, 339277832, 1064259164, 653818010, 759533421 + ], + [ + 536870912, 268435456, 134217728, 738197504, 369098752, 486539264, 679477248, 79691776, 387973120, 747634688, 270008320, 920387584, 251527168, 769982464, 448299008, 168017920, 319283200, 294375424, 373463040, 417364992, 238852608, 281378048, 891558528, 60211136, 530316256, 294743568, 681533800, 974656092, 903707162, 393719189 + ], + [ + 536870912, 268435456, 939524096, 67108864, 436207616, 50331648, 562036736, 62914560, 509607936, 974127104, 875036672, 196345856, 911605760, 411893760, 827097088, 70238208, 599777280, 173977600, 109262848, 676074496, 648372736, 33321216, 401628032, 587031616, 645512096, 423548208, 1008599960, 958988668, 187859910, 320259025 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 234881024, 721420288, 763363328, 566231040, 559939584, 326107136, 941096960, 40108032, 721027072, 869335040, 973635584, 822296576, 747151360, 357535744, 136931328, 358425600, 104974848, 698529536, 579904384, 808161472, 424896864, 273425776, 1051281464, 17954732, 987759438, 363856875 + ], + [ + 536870912, 805306368, 134217728, 335544320, 637534208, 520093696, 696254464, 406847488, 6291456, 1051721728, 264765440, 724303872, 760348672, 71106560, 873299968, 369737728, 386752512, 1032491008, 1045321728, 526519296, 390038016, 394576640, 726196352, 334451008, 200358496, 522558960, 995383448, 322113156, 159384198, 675283371 + ], + [ + 536870912, 268435456, 671088640, 335544320, 301989888, 721420288, 209715200, 71303168, 991952896, 651165696, 930611200, 1022099456, 1061027840, 969342976, 484802560, 791953408, 298115072, 149073920, 1027545088, 986274816, 73792000, 964488448, 31940736, 582873152, 234912672, 1023979504, 495158248, 936330228, 568812026, 851309417 + ], + [ + 536870912, 268435456, 402653184, 335544320, 704643072, 251658240, 964689920, 549453824, 463470592, 395313152, 710410240, 58458112, 1068105728, 899088384, 693207040, 82853888, 980230144, 414355456, 662779904, 365132800, 891861504, 450837760, 993500032, 4631616, 1005396256, 1014141104, 237058232, 424902588, 217102978, 912473733 + ], + [ + 536870912, 268435456, 671088640, 335544320, 436207616, 1056964608, 629145600, 146800640, 379584512, 103809024, 673710080, 158597120, 893517824, 845217792, 916226048, 521322496, 567533568, 779874304, 1020250112, 481180672, 289006080, 430895360, 464603776, 485358912, 299795360, 376685296, 13590744, 313078220, 876357834, 52809619 + ], + [ + 536870912, 268435456, 671088640, 603979776, 905969664, 721420288, 427819008, 423624704, 39845888, 1072693248, 117964800, 461635584, 743047168, 350814208, 155025408, 925024256, 1066557440, 234115072, 168138752, 17595392, 143131136, 969146624, 531235456, 374932032, 978682720, 945210032, 223371672, 467227028, 756160550, 490192895 + ], + [ + 536870912, 268435456, 402653184, 738197504, 1040187392, 687865856, 729808896, 876609536, 287309824, 1047527424, 745013248, 349437952, 1046347776, 93782016, 720732160, 1051410432, 272392192, 508416000, 975464448, 452701184, 916578816, 607293696, 205916544, 757169856, 409995744, 694321040, 22776120, 589184132, 1060268402, 550022839 + ], + [ + 536870912, 805306368, 939524096, 872415232, 100663296, 754974720, 293601280, 356515840, 90177536, 158334976, 446169088, 941883392, 806486016, 434831360, 1034977280, 851230720, 3547136, 637186048, 374884352, 604103680, 235170304, 553932544, 596025728, 1044803648, 971926496, 230380944, 180102008, 875933828, 603638478, 995501699 + ], + [ + 536870912, 268435456, 134217728, 201326592, 167772160, 452984832, 276824064, 557842432, 933232640, 829423616, 795344896, 940834816, 377094144, 770637824, 106201088, 929021952, 752459776, 353505280, 267520000, 53455872, 104800768, 29806848, 250423424, 47807680, 404359840, 108768432, 635773832, 173659092, 1028762458, 936558183 + ], + [ + 536870912, 805306368, 402653184, 67108864, 369098752, 117440512, 629145600, 633339904, 1004535808, 800063488, 1060634624, 510918656, 986841088, 717422592, 846102528, 7553024, 299114496, 88100864, 44378112, 252838912, 959392256, 30738176, 759933824, 513886016, 488311520, 673535792, 592871608, 755450220, 8790278, 155406487 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 637534208, 1056964608, 964689920, 432013312, 836763648, 407896064, 692584448, 380370944, 1039269888, 53936128, 257785856, 482983936, 560947200, 252899328, 82655232, 13775872, 34046464, 486720256, 344514688, 88093632, 145611360, 922617840, 548952472, 261867164, 732248478, 427701573 + ], + [ + 536870912, 268435456, 939524096, 738197504, 234881024, 721420288, 964689920, 926941184, 10485760, 103809024, 587726848, 1032060928, 760086528, 162201600, 447971328, 113426432, 870998016, 479449088, 741550080, 34475008, 889717248, 713294080, 583926656, 971702976, 764641504, 481477296, 700605336, 275239796, 584394762, 806423651 + ], + [ + 536870912, 268435456, 671088640, 603979776, 436207616, 251658240, 109051904, 180355072, 1059061760, 923795456, 657981440, 111935488, 56492032, 517668864, 814972928, 108216320, 919429120, 958566400, 773535744, 280488960, 535714304, 1060732160, 447438976, 357929792, 802601760, 589278896, 87079880, 94940508, 1004354330, 17886365 + ], + [ + 536870912, 268435456, 402653184, 469762048, 503316480, 117440512, 511705088, 490733568, 547356672, 1051721728, 414711808, 331087872, 188350464, 226295808, 760905728, 162217984, 791994368, 528461824, 743806976, 204157952, 854956544, 630928640, 751672192, 929510592, 425171552, 61486256, 842341256, 83719524, 916191618, 676316815 + ], + [ + 536870912, 268435456, 134217728, 872415232, 33554432, 117440512, 511705088, 289406976, 492830720, 433061888, 870842368, 278134784, 311033856, 1061748736, 610435072, 912048128, 959389696, 87134208, 435877888, 424879104, 61153792, 511217920, 932739200, 470804288, 638190112, 218694000, 763527528, 231522900, 187113974, 439718381 + ], + [ + 536870912, 268435456, 134217728, 738197504, 100663296, 385875968, 914358272, 767557632, 429916160, 686817280, 565706752, 819724288, 34471936, 755826688, 797474816, 542064640, 82436096, 194187264, 644397056, 340993024, 181287424, 924935424, 557275776, 303118272, 153092832, 36700848, 110625672, 434897260, 1008075410, 572588323 + ], + [ + 536870912, 268435456, 134217728, 469762048, 369098752, 654311424, 713031680, 71303168, 673185792, 883949568, 139984896, 965476352, 885391360, 358940672, 219316224, 69484544, 985096192, 995209216, 419436544, 25469952, 818149888, 392451328, 538837632, 531169472, 863273440, 1035027376, 31318984, 357167668, 900298794, 310122255 + ], + [ + 536870912, 805306368, 671088640, 738197504, 369098752, 587202560, 343932928, 121634816, 895483904, 435159040, 314048512, 30670848, 321781760, 958201856, 697073664, 751452160, 413294592, 618082304, 1017391104, 786314240, 564701696, 894727936, 610977920, 611534272, 477553120, 679048176, 980437672, 594543748, 49676670, 842596571 + ], + [ + 536870912, 268435456, 402653184, 335544320, 771751936, 16777216, 595591168, 792723456, 429916160, 118489088, 189267968, 1067712512, 169213952, 315424768, 1072660480, 825638912, 420864000, 38555648, 270804992, 526001152, 611287552, 443957504, 917889408, 274485568, 384576224, 247342096, 341409848, 552289268, 464674842, 433983793 + ], + [ + 536870912, 805306368, 134217728, 738197504, 704643072, 687865856, 25165824, 1027604480, 954204160, 110100480, 732430336, 671350784, 470155264, 570490880, 84246528, 730152960, 340074496, 962605056, 1003988992, 323951616, 781505024, 933983488, 167772288, 419430592, 159383584, 289407152, 316670120, 797966500, 707264518, 356778229 + ], + [ + 536870912, 805306368, 134217728, 67108864, 570425344, 989855744, 427819008, 1027604480, 564133888, 854589440, 391643136, 317980672, 660471808, 452263936, 593395712, 955334656, 408543232, 561147904, 622741504, 14042112, 401085952, 395095808, 85870720, 819348672, 535303712, 327986960, 656295944, 198591532, 107484742, 785166309 + ], + [ + 536870912, 268435456, 402653184, 67108864, 905969664, 553648128, 830472192, 901775360, 773849088, 401604608, 680001536, 925106176, 846331904, 860553216, 1006927872, 570736640, 252125184, 344371200, 843085824, 987882496, 139775488, 180070656, 831463552, 312651840, 699562080, 946529296, 745557720, 508520836, 662700102, 79691927 + ], + [ + 536870912, 268435456, 134217728, 603979776, 100663296, 285212672, 243269632, 12582912, 106954752, 26214400, 284688384, 185860096, 104464384, 343212032, 758022144, 38649856, 827891712, 191238144, 890615808, 725376000, 821185024, 518775552, 498055296, 797531200, 331139616, 959849360, 974067864, 1056656388, 773026330, 113213331 + ], + [ + 536870912, 268435456, 671088640, 67108864, 234881024, 922746880, 394264576, 171966464, 60817408, 600834048, 978845696, 105119744, 430047232, 852819968, 517505024, 361086976, 658825216, 86503424, 219269120, 708424704, 460757504, 336575232, 660111488, 952483904, 459595936, 683143184, 988399672, 950908124, 789355102, 719239977 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 167772160, 352321536, 209715200, 767557632, 463470592, 458227712, 566755328, 720633856, 530448384, 532611072, 615350272, 293617664, 893394944, 409227264, 603052032, 689505280, 1064952320, 260662528, 756152448, 439178432, 624966240, 811885040, 133569192, 521875860, 545014482, 369718663 + ], + [ + 536870912, 268435456, 134217728, 872415232, 436207616, 822083584, 411041792, 994050048, 174063616, 30408704, 375914496, 755236864, 646053888, 406913024, 400982016, 940785664, 374218752, 1043795968, 175990784, 692866048, 498121216, 280661248, 887619712, 927203392, 1013055520, 382795984, 300843112, 633815236, 1042554978, 808587501 + ], + [ + 536870912, 268435456, 402653184, 872415232, 973078528, 721420288, 746586112, 205520896, 1059061760, 986710016, 815267840, 158597120, 369754112, 516882432, 296255488, 39469056, 756473856, 696078336, 1036134400, 719639552, 741499392, 179179264, 652134528, 223773760, 408472160, 370187216, 502942312, 92658668, 801385042, 1038273441 + ], + [ + 536870912, 268435456, 402653184, 603979776, 704643072, 419430400, 276824064, 390070272, 593494016, 279969792, 142082048, 343670784, 176029696, 561840128, 217677824, 557629440, 203415552, 793636864, 549918720, 531067904, 286745088, 846032128, 194470528, 741174592, 544695008, 266169808, 560947784, 303132084, 870933002, 810577385 + ], + [ + 536870912, 268435456, 671088640, 603979776, 301989888, 117440512, 562036736, 918552576, 127926272, 424673280, 171442176, 787742720, 728367104, 684261376, 865763328, 379666432, 1037262848, 847245312, 437581824, 291267584, 989864448, 797301504, 801609856, 388207680, 454351520, 500809616, 659012296, 157699932, 317932198, 627714827 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 771751936, 16777216, 645922816, 188743680, 622854144, 657457152, 182976512, 83623936, 1059454976, 607584256, 728399872, 339623936, 432267264, 744747008, 85407744, 912231424, 231842304, 347818752, 1065712256, 700921664, 342089760, 286519472, 610220056, 584289524, 859808290, 306203433 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 771751936, 654311424, 1031798784, 356515840, 543162368, 860880896, 322437120, 660340736, 235536384, 271908864, 1072594944, 270614528, 800104448, 732532736, 784496640, 639816704, 78851584, 2633984, 545492608, 365011392, 94500448, 250836272, 566941912, 681002156, 26957486, 741336377 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 436207616, 553648128, 998244352, 289406976, 773849088, 942669824, 35127296, 176422912, 46530560, 459472896, 806846464, 19611648, 303570944, 579170304, 650586112, 1029784576, 185845248, 464462592, 954073216, 501678272, 819036256, 122175728, 59744360, 334377092, 561973486, 915682373 + ], + [ + 536870912, 268435456, 134217728, 67108864, 234881024, 1056964608, 343932928, 616562688, 920649728, 691011584, 492306432, 383516672, 916324352, 750714880, 930054144, 218513408, 965058560, 222638080, 866166784, 513209344, 231346688, 605182208, 101454464, 242309440, 268276384, 734533968, 253211288, 344680876, 296925898, 597208383 + ], + [ + 536870912, 268435456, 671088640, 335544320, 637534208, 956301312, 830472192, 1010827264, 966787072, 1064304640, 434634752, 656670720, 867303424, 294453248, 800489472, 864993280, 414588928, 789491712, 863127552, 334009344, 69475840, 154342656, 55320704, 584560704, 949930144, 1003443280, 387366552, 25060836, 253675590, 781145265 + ], + [ + 536870912, 805306368, 939524096, 67108864, 838860800, 721420288, 729808896, 247463936, 262144000, 577765376, 232259584, 664535040, 259653632, 1064108032, 820346880, 68665344, 93102080, 468897792, 404326400, 1002126336, 667652608, 253139200, 504107648, 758143424, 331297376, 734546384, 18324136, 51012988, 531832838, 502796359 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 771751936, 318767104, 511705088, 482344960, 207618048, 529530880, 220725248, 520355840, 142737408, 465895424, 15171584, 1045807104, 214589440, 47697920, 352950272, 389057536, 450785792, 935159040, 463995008, 801374272, 48365728, 726991088, 1028620472, 781303884, 380133498, 440586355 + ], + [ + 536870912, 805306368, 939524096, 469762048, 167772160, 1056964608, 461373440, 322961408, 903872512, 84934656, 878182400, 977010688, 476708864, 634716160, 117080064, 617201664, 69672960, 87347200, 392853504, 542204928, 79484416, 598672640, 1022490240, 860804544, 358682208, 735474096, 536541256, 843949132, 803305126, 840046017 + ], + [ + 536870912, 268435456, 939524096, 201326592, 838860800, 318767104, 260046848, 79691776, 39845888, 456130560, 436731904, 422838272, 554303488, 582156288, 466321408, 30752768, 477749248, 278704128, 65894400, 684129280, 543497728, 808598784, 428701824, 804715584, 812457696, 906378544, 84375624, 444988428, 642162398, 673414435 + ], + [ + 536870912, 805306368, 671088640, 469762048, 234881024, 318767104, 645922816, 1002438656, 127926272, 829423616, 1048051712, 230424576, 639238144, 829358080, 1343488, 623460352, 737222656, 1002106880, 823724032, 770227200, 986952192, 420252928, 348598912, 522571200, 834015776, 56573360, 151984664, 214401532, 723822722, 599198739 + ], + [ + 536870912, 805306368, 134217728, 469762048, 973078528, 251658240, 729808896, 272629760, 241172480, 519045120, 26738688, 718536704, 638451712, 171769856, 989954048, 1031815168, 759390208, 920760320, 523544576, 280845312, 297838080, 690353920, 789989504, 690793664, 271543840, 917314416, 376194664, 97060860, 806879246, 93585649 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 436207616, 754974720, 411041792, 759169024, 870318080, 640679936, 761790464, 774635520, 114163712, 662372352, 785678336, 484163584, 260071424, 146829312, 774199296, 76735488, 582959616, 141762304, 487309952, 584638272, 1015259680, 860139440, 283179592, 900811524, 799881258, 84841649 + ], + [ + 536870912, 805306368, 402653184, 335544320, 637534208, 956301312, 696254464, 826277888, 400556032, 384827392, 717750272, 1029963776, 758513664, 921370624, 800489472, 19578880, 26222592, 217690112, 1024321536, 591748096, 954609152, 511037696, 638460032, 1036431552, 354773088, 592485456, 157191832, 110731748, 213608486, 1064279045 + ], + [ + 536870912, 268435456, 402653184, 67108864, 905969664, 251658240, 125829120, 88080384, 228589568, 344981504, 196608000, 994836480, 218497024, 914423808, 298024960, 1030111232, 628563968, 436801536, 648304640, 890444800, 435693056, 896492800, 718724736, 1067329856, 966263008, 1050411088, 622723256, 308084780, 654147782, 988495913 + ], + [ + 536870912, 268435456, 402653184, 738197504, 771751936, 553648128, 729808896, 524288000, 157286400, 1048576, 180879360, 663486464, 703463424, 394067968, 728793088, 366559232, 1069768704, 379785216, 112490496, 343806976, 536245760, 404602624, 778499712, 781516608, 604870368, 313257968, 69201496, 140835700, 999758070, 227345417 + ], + [ + 536870912, 268435456, 134217728, 335544320, 234881024, 385875968, 998244352, 96468992, 232783872, 646971392, 921174016, 13369344, 616431616, 323420160, 983662592, 171065344, 937009152, 378556416, 787425280, 483095552, 1052333568, 172323584, 371291776, 880239424, 1073741472, 1038108432, 1050116248, 719929420, 449716470, 1035538459 + ], + [ + 536870912, 805306368, 134217728, 201326592, 369098752, 654311424, 780140544, 121634816, 710934528, 781189120, 916979712, 915144704, 368705536, 117637120, 512131072, 256000000, 644325376, 949219328, 296343552, 403469312, 314209792, 761613056, 806573696, 971570112, 284110496, 761823216, 380109048, 109838444, 502923458, 184746161 + ], + [ + 536870912, 805306368, 939524096, 67108864, 503316480, 50331648, 981467136, 88080384, 52428800, 554696704, 314048512, 610009088, 371851264, 589627392, 286359552, 716980224, 543105024, 137293824, 539138048, 731257856, 804826624, 595144960, 691801728, 849248704, 264779360, 970337744, 6234136, 942600412, 404920434, 798366729 + ], + [ + 536870912, 805306368, 134217728, 469762048, 503316480, 184549376, 880803840, 113246208, 719323136, 877658112, 586678272, 174850048, 863109120, 953090048, 302415872, 755384320, 730046464, 809791488, 958760960, 557114368, 619529728, 79039744, 665734784, 487893440, 39364768, 102421680, 221867608, 822712668, 912261162, 512753911 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 771751936, 620756992, 444596224, 448790528, 400556032, 753926144, 554172416, 115081216, 230817792, 912326656, 833650688, 178929664, 151871488, 853405696, 667224064, 23536640, 540156416, 804216576, 514509440, 319802304, 1037598816, 172376112, 170352728, 311488612, 348096722, 510682367 + ], + [ + 536870912, 805306368, 939524096, 738197504, 905969664, 16777216, 176160768, 742391808, 736100352, 986710016, 36175872, 473694208, 850526208, 976814080, 1001816064, 616382464, 234217472, 945483776, 1017190400, 481514496, 658159104, 1060321024, 637480576, 445916096, 802093152, 535602288, 371142200, 1011098548, 602339442, 785425525 + ], + [ + 536870912, 805306368, 134217728, 872415232, 503316480, 553648128, 142606336, 138412032, 383778816, 667942912, 1006108672, 510918656, 793640960, 547160064, 526680064, 387235840, 760979456, 457199616, 761325568, 605481984, 651846144, 277048064, 71813248, 887520448, 752298528, 209508304, 1069007608, 963263300, 435003522, 363417649 + ], + [ + 536870912, 805306368, 671088640, 335544320, 771751936, 352321536, 109051904, 641728512, 513802240, 1034944512, 628621312, 270794752, 1073086464, 1037893632, 748060672, 839630848, 515612672, 188764160, 337774592, 167179264, 349709824, 269682432, 793616512, 329076928, 372541600, 163394640, 985892536, 870537044, 412592282, 739222617 + ], + [ + 536870912, 268435456, 402653184, 201326592, 905969664, 687865856, 528482304, 817889280, 966787072, 384827392, 198705152, 334757888, 844759040, 305594368, 410746880, 33669120, 50765824, 411447296, 172144640, 551683072, 915531264, 990756608, 1041938560, 332792896, 627828320, 868925232, 465123416, 723764452, 196560414, 163287027 + ], + [ + 536870912, 805306368, 671088640, 335544320, 838860800, 352321536, 226492416, 482344960, 853540864, 464519168, 285736960, 351535104, 338558976, 723582976, 1020559360, 712720384, 287055872, 1013837824, 914765824, 306605056, 748760576, 957488384, 454867072, 627846336, 889294496, 1031843152, 885039176, 652390548, 699668630, 67804195 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 771751936, 50331648, 780140544, 205520896, 312475648, 558891008, 620232704, 776732672, 952500224, 669319168, 879788032, 912932864, 399613952, 79671296, 720328704, 647126016, 60734976, 360469760, 847824512, 489158976, 110526560, 329203888, 762912856, 243921148, 857798658, 93645885 + ], + [ + 536870912, 805306368, 134217728, 872415232, 704643072, 385875968, 713031680, 826277888, 1033895936, 789577728, 943194112, 861143040, 1966080, 998572032, 717258752, 660881408, 7626752, 206049280, 353945600, 33612800, 319080960, 143078144, 306202752, 1025549504, 156674592, 790504400, 755367976, 92340380, 667320458, 317014037 + ], + [ + 536870912, 805306368, 939524096, 335544320, 503316480, 50331648, 528482304, 348127232, 480247808, 533725184, 609746944, 689700864, 108658688, 1015873536, 80183296, 346046464, 869670912, 777703424, 874432512, 452500480, 936117760, 211942656, 399607424, 140295616, 588785248, 460991888, 537579032, 260399516, 482836582, 815808719 + ], + [ + 536870912, 805306368, 134217728, 469762048, 503316480, 922746880, 998244352, 675282944, 819986432, 430964736, 333971456, 57933824, 936247296, 837091328, 959807488, 371900416, 819027968, 991604736, 620685312, 583592960, 325516800, 368443648, 688744576, 801320128, 916725280, 374829424, 769220856, 652128284, 861464782, 605678801 + ], + [ + 536870912, 805306368, 939524096, 738197504, 369098752, 486539264, 226492416, 281018368, 65011712, 617611264, 941096960, 239337472, 530972672, 343343104, 1055752192, 183418880, 15310848, 871149568, 258643968, 69876736, 168655360, 549409536, 749961344, 420331712, 742007008, 535916720, 992524376, 277826676, 251380278, 51584835 + ], + [ + 536870912, 805306368, 671088640, 67108864, 973078528, 352321536, 713031680, 188743680, 778043392, 124780544, 176685056, 653524992, 877527040, 340852736, 949911552, 109985792, 686825472, 860426240, 802310144, 593058816, 917333504, 727837952, 905201792, 768367808, 915793568, 473607440, 559736936, 1068371092, 401018378, 364224829 + ], + [ + 536870912, 805306368, 134217728, 469762048, 1040187392, 83886080, 109051904, 415236096, 929038336, 783286272, 608698368, 69468160, 731250688, 324599808, 549421056, 500023296, 90415104, 766791680, 869160960, 946211840, 1060398592, 151970048, 872554624, 302289088, 855930912, 528915568, 541466360, 715226388, 525581978, 305933731 + ], + [ + 536870912, 268435456, 402653184, 335544320, 1040187392, 822083584, 612368384, 339738624, 1012924416, 705691648, 601358336, 167510016, 210632704, 583335936, 589529088, 636895232, 470507520, 411136000, 910309376, 1063425024, 361940480, 471430400, 878323328, 708724032, 53182176, 527540496, 692944920, 409157844, 470867978, 517681349 + ], + [ + 536870912, 805306368, 402653184, 67108864, 973078528, 117440512, 595591168, 658505728, 887095296, 785383424, 778567680, 1025245184, 474087424, 426049536, 747864064, 974110720, 755736576, 646877184, 499750912, 388756480, 83723776, 236336896, 936132224, 942445504, 997949664, 391364816, 1042915464, 846958604, 298981478, 971519105 + ], + [ + 536870912, 268435456, 939524096, 872415232, 771751936, 218103808, 260046848, 968884224, 689963008, 45088768, 364380160, 1066139648, 393609216, 916258816, 641564672, 877477888, 290807808, 749457408, 650545152, 430111744, 469230080, 500893952, 23030400, 303625536, 24840288, 154123408, 335708760, 1040243172, 889315846, 998640019 + ], + [ + 536870912, 805306368, 134217728, 603979776, 503316480, 822083584, 880803840, 272629760, 320864256, 1001390080, 162004992, 390856704, 119144448, 73596928, 957579264, 14565376, 142958592, 306540544, 270776320, 70417408, 40688128, 296617728, 189282944, 890910656, 258433696, 579894096, 354345176, 1063727252, 714397834, 823659541 + ], + [ + 536870912, 268435456, 134217728, 872415232, 570425344, 150994944, 931135488, 247463936, 375390208, 74448896, 260571136, 1062469632, 559546368, 600637440, 376471552, 512704512, 886218752, 966668288, 514439168, 746953728, 675341824, 321144064, 181508224, 916057152, 170622496, 683715024, 627205640, 116524388, 550090878, 217423019 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 301989888, 553648128, 763363328, 423624704, 362807296, 420478976, 781713408, 581173248, 194379776, 828047360, 516128768, 568606720, 725032960, 868888576, 639461376, 140809216, 745771520, 225082112, 261038208, 4075712, 590571616, 667653360, 270406216, 123812740, 854949942, 414138533 + ], + [ + 536870912, 805306368, 671088640, 201326592, 369098752, 1056964608, 1048576000, 171966464, 958398464, 311427072, 752353280, 785645568, 452853760, 717291520, 812089344, 725073920, 118382592, 329846784, 335325184, 457700352, 748788224, 341114624, 985344128, 316683456, 796392096, 623505200, 632914136, 476495932, 221372506, 269144089 + ], + [ + 536870912, 268435456, 402653184, 201326592, 503316480, 721420288, 562036736, 809500672, 916455424, 649068544, 954728448, 373555200, 27394048, 20119552, 799637504, 526893056, 1012359168, 788475904, 790333440, 277550080, 227849728, 941337856, 654934144, 47693888, 1027563616, 83570736, 102336632, 470291628, 995440262, 24669633 + ], + [ + 536870912, 268435456, 134217728, 603979776, 838860800, 117440512, 528482304, 490733568, 916455424, 347078656, 145227776, 845938688, 630063104, 429850624, 344162304, 79806464, 383983616, 512872448, 752809984, 371354624, 712382976, 1028652800, 24877696, 319897408, 647707296, 922824656, 126280296, 826446796, 547749910, 565379257 + ], + [ + 536870912, 805306368, 402653184, 469762048, 771751936, 83886080, 75497472, 297795584, 945815552, 969932800, 789053440, 769392640, 726794240, 399310848, 658276352, 440680448, 706764800, 670085120, 586999808, 941904896, 1022756352, 997946112, 828567168, 995305408, 1070524640, 590959792, 675448536, 19084132, 644910634, 935237523 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 503316480, 553648128, 394264576, 1069547520, 849346560, 210763776, 501743616, 1043070976, 42860544, 387514368, 561414144, 1050230784, 800284672, 599298048, 551675904, 317914112, 861801984, 437527296, 631803520, 189621056, 12316256, 409334704, 598869528, 364580660, 98699334, 662056139 + ], + [ + 536870912, 268435456, 402653184, 872415232, 301989888, 855638016, 629145600, 549453824, 987758592, 9437184, 864550912, 417595392, 999424000, 973799424, 505577472, 544227328, 740122624, 686698496, 581982208, 771243008, 570237440, 402172160, 788357248, 209596480, 456677472, 840711376, 770646600, 1043573196, 801103894, 207515843 + ], + [ + 536870912, 805306368, 671088640, 603979776, 637534208, 989855744, 746586112, 532676608, 387973120, 938475520, 675807232, 278134784, 131989504, 768147456, 651591680, 348110848, 1012588544, 747622400, 456611840, 133141504, 916575744, 666187008, 2963584, 763528384, 306507424, 895725968, 714593816, 651703596, 273528978, 747652143 + ], + [ + 536870912, 268435456, 134217728, 469762048, 838860800, 452984832, 8388608, 37748736, 346030080, 66060288, 246939648, 281804800, 968228864, 505085952, 893288448, 34324480, 659693568, 357298176, 175151104, 125729792, 246077952, 816255232, 905200256, 868117824, 625875104, 309705776, 326695656, 548200732, 430234186, 779096357 + ], + [ + 536870912, 805306368, 671088640, 738197504, 234881024, 117440512, 125829120, 549453824, 44040192, 1007681536, 515375104, 925106176, 232128512, 412942336, 242319360, 940556288, 294248448, 105869312, 728422400, 465187840, 161755648, 93351680, 293593216, 503476416, 520312992, 58848432, 46387768, 195436316, 1016248478, 972719171 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 637534208, 989855744, 8388608, 390070272, 509607936, 999292928, 760741888, 58458112, 805961728, 579272704, 776241152, 400965632, 223617024, 972795904, 172595200, 795030528, 1041585664, 362517760, 282982016, 532309440, 296373792, 741728560, 15335608, 962003164, 335315002, 1061830721 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 167772160, 553648128, 125829120, 29360128, 262144000, 240123904, 133693440, 121896960, 434241536, 674562048, 974094336, 82657280, 945430528, 823390208, 169392128, 427176960, 149498368, 173829888, 68518016, 1000095808, 867672224, 566997232, 38606888, 227050628, 1026273822, 603564807 + ], + [ + 536870912, 268435456, 671088640, 603979776, 100663296, 922746880, 310378496, 851443712, 488636416, 34603008, 22544384, 58982400, 121765888, 358940672, 167018496, 409518080, 936042496, 387731456, 593844224, 116401152, 115933696, 655264512, 993656960, 82903104, 669941920, 713670800, 1065115672, 756125916, 266025034, 994358475 + ], + [ + 536870912, 268435456, 134217728, 469762048, 1040187392, 251658240, 847249408, 633339904, 249561088, 808452096, 525860864, 989593600, 267255808, 694616064, 309362688, 603799552, 1047109632, 136736768, 709888000, 296334336, 1002643968, 299897088, 179569280, 647766336, 169683616, 819897648, 79667288, 223178764, 586582034, 658502875 + ], + [ + 536870912, 805306368, 671088640, 872415232, 704643072, 251658240, 1015021568, 146800640, 836763648, 999292928, 910688256, 820248576, 974520320, 286064640, 725778432, 497238016, 515170304, 574164992, 406345728, 255712256, 801104384, 964579584, 765255808, 630001856, 663115936, 776264912, 505635496, 49549628, 790397042, 944390371 + ], + [ + 536870912, 268435456, 939524096, 201326592, 234881024, 1056964608, 142606336, 138412032, 375390208, 506462208, 271056896, 213647360, 243662848, 323289088, 619085824, 728776704, 1070473216, 759885824, 135141376, 535479296, 840534528, 982549248, 154743424, 390461248, 249954400, 779419760, 172916952, 478953676, 564666394, 394260701 + ], + [ + 536870912, 268435456, 939524096, 738197504, 1040187392, 285212672, 780140544, 482344960, 375390208, 309329920, 273154048, 252968960, 129630208, 370868224, 797671424, 150388736, 243965952, 242520064, 105510912, 168950784, 993633792, 635063552, 107698304, 683764800, 341991136, 91533744, 63667832, 55763204, 471475930, 1015582083 + ], + [ + 536870912, 268435456, 402653184, 201326592, 973078528, 553648128, 41943040, 155189248, 576716800, 340787200, 486014976, 104595456, 664666112, 216858624, 270827520, 95928320, 459923456, 1038528512, 764418048, 47846400, 76168704, 1031090432, 399031936, 773058880, 421256928, 934248816, 122070536, 627369460, 366305282, 977105105 + ], + [ + 536870912, 268435456, 671088640, 335544320, 33554432, 285212672, 461373440, 213909504, 698351616, 529530880, 915931136, 236716032, 811466752, 851116032, 508133376, 232898560, 544727040, 1072599040, 376834048, 1022344192, 888606208, 1068137728, 328273536, 412974400, 555650592, 752598288, 922676776, 833613140, 748062278, 740229479 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 100663296, 285212672, 8388608, 12582912, 979369984, 519045120, 444071936, 884736000, 735969280, 397213696, 638746624, 1062092800, 455237632, 752316416, 438953984, 811000832, 216947200, 53667072, 782031488, 529311040, 826718944, 707253680, 1011962616, 49033716, 909478138, 337417463 + ], + [ + 536870912, 805306368, 939524096, 469762048, 234881024, 218103808, 327155712, 994050048, 849346560, 131072000, 768081920, 257687552, 355598336, 708378624, 998277120, 793001984, 413622272, 416305152, 1028446208, 714906624, 257351168, 604711680, 591038080, 168032192, 788740192, 679775408, 969369304, 342026052, 53608694, 188284953 + ], + [ + 536870912, 805306368, 134217728, 738197504, 234881024, 452984832, 729808896, 4194304, 564133888, 11534336, 590872576, 645660672, 257556480, 2818048, 553025536, 849035264, 784998400, 6311936, 676386816, 883862528, 422648320, 243068160, 325032576, 103525824, 402111136, 387775856, 898359960, 172101916, 681990198, 909503517 + ], + [ + 536870912, 805306368, 134217728, 67108864, 33554432, 956301312, 1031798784, 700448768, 920649728, 688914432, 163053568, 268173312, 299499520, 1068171264, 818118656, 996655104, 148299776, 995643392, 619309056, 560034816, 232158720, 148795648, 842004096, 285389248, 159553184, 599859664, 199728808, 378733876, 427524190, 77316243 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 33554432, 285212672, 192937984, 197132288, 962592768, 743440384, 135790592, 26476544, 242876416, 222494720, 723877888, 938950656, 716021760, 740110336, 798316544, 628841472, 734032384, 694415104, 340842624, 874257472, 60150496, 528146416, 113737864, 551567364, 244457678, 117010655 + ], + [ + 536870912, 268435456, 402653184, 872415232, 1040187392, 620756992, 679477248, 784334848, 559939584, 206569472, 427294720, 99876864, 894042112, 509542400, 369131520, 419872768, 981540864, 29642752, 317110272, 789945344, 1046036992, 101112576, 17242240, 243731520, 1069996640, 937629648, 127066744, 278612948, 660602946, 223346731 + ], + [ + 536870912, 805306368, 402653184, 201326592, 234881024, 1023410176, 1065353216, 926941184, 719323136, 663748608, 948436992, 402391040, 199360512, 1041563648, 650805248, 10240000, 674521088, 788353024, 510105600, 777384960, 212651520, 483275520, 262092416, 1018599360, 389832928, 843141360, 694523992, 114357444, 594431686, 32404265 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 973078528, 285212672, 562036736, 171966464, 379584512, 844103680, 129499136, 954466304, 452067328, 183304192, 165380096, 584138752, 1014833152, 201502720, 33785856, 84063232, 663214592, 558026496, 640065664, 429125696, 459188384, 470811888, 790385384, 901020484, 734755334, 851984233 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 100663296, 117440512, 343932928, 817889280, 564133888, 17825792, 756547584, 532414464, 2752512, 351469568, 90734592, 638730240, 161062912, 662679552, 495577088, 333675520, 796028416, 757949696, 963890816, 305059264, 435168928, 418294064, 961726648, 176000044, 806004330, 77850927 + ], + [ + 536870912, 805306368, 671088640, 67108864, 570425344, 385875968, 310378496, 289406976, 996147200, 867172352, 285736960, 240386048, 167641088, 523829248, 10125312, 596328448, 789929984, 446533632, 680331264, 865147904, 987475456, 879645952, 350644352, 326470848, 598484640, 79956240, 547399176, 898779548, 1071203946, 434739605 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 838860800, 855638016, 947912704, 557842432, 1042284544, 70254592, 616038400, 1047789568, 371064832, 755171328, 830570496, 784416768, 702668800, 441536512, 355092480, 121426944, 330739200, 1064981248, 705939584, 680105152, 516509408, 644350960, 974651464, 386138124, 109445122, 407306357 + ], + [ + 536870912, 268435456, 402653184, 469762048, 234881024, 956301312, 461373440, 222298112, 383778816, 403701760, 175636480, 1072431104, 232128512, 693698560, 349995008, 882655232, 872144896, 229298176, 1035311104, 898569216, 838913536, 654832896, 981685888, 180478272, 363272416, 938890288, 166309464, 953443732, 618639062, 1016948113 + ], + [ + 536870912, 268435456, 671088640, 335544320, 33554432, 553648128, 1048576000, 37748736, 354418688, 972029952, 221773824, 280231936, 60424192, 1065418752, 750813184, 1063600128, 953589760, 919572480, 1015572480, 766211072, 1046246912, 107119360, 709945472, 176829504, 514381472, 165155664, 782368904, 1060438212, 123371610, 350503001 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 905969664, 721420288, 1031798784, 264241152, 119537664, 214958080, 676855808, 9699328, 666501120, 685834240, 469073920, 210485248, 349102080, 288321536, 610244608, 244569088, 415113728, 526438144, 154146944, 489231424, 710754976, 831553520, 792420440, 228897004, 412186710, 599565519 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 905969664, 654311424, 293601280, 138412032, 396361728, 625999872, 817364992, 392429568, 406192128, 160104448, 812351488, 228376576, 771088384, 141078528, 27215872, 66409472, 325696000, 639192832, 749756544, 357265600, 185542752, 195962096, 662606552, 595815324, 356577990, 254221281 + ], + [ + 536870912, 805306368, 134217728, 469762048, 1040187392, 184549376, 360710144, 960495616, 685768704, 617611264, 301465600, 283901952, 3276800, 858718208, 504791040, 660226048, 1062969344, 458903552, 827938816, 408671232, 953972224, 522169600, 456765056, 776812992, 864221344, 373392560, 392507096, 882145628, 429774894, 335451145 + ], + [ + 536870912, 805306368, 134217728, 738197504, 503316480, 352321536, 427819008, 851443712, 73400320, 116391936, 1012400128, 676593664, 718143488, 687669248, 432504832, 954515456, 632692736, 654143488, 885209088, 90643456, 628405760, 698146560, 1051891840, 310291648, 998354464, 29799344, 753211128, 531984276, 33521862, 641777851 + ], + [ + 536870912, 805306368, 134217728, 469762048, 704643072, 352321536, 109051904, 197132288, 425721856, 179306496, 297271296, 84672512, 129105920, 859766784, 818839552, 1037352960, 581632, 959770624, 754542592, 531149824, 140610048, 36735232, 830005888, 971521472, 1061251232, 597996720, 726895240, 869239076, 878076466, 273481147 + ], + [ + 536870912, 805306368, 134217728, 335544320, 771751936, 754974720, 830472192, 29360128, 392167424, 680525824, 171442176, 111411200, 133562368, 1051262976, 916357120, 39305216, 635084800, 946974720, 577337344, 411012096, 1057358336, 377851648, 994320512, 505835712, 565434400, 420363344, 49248952, 574227380, 581050950, 569638855 + ], + [ + 536870912, 805306368, 402653184, 335544320, 838860800, 989855744, 1031798784, 843055104, 341835776, 1060110336, 887619584, 854327296, 199884800, 359202816, 246120448, 445497344, 182099968, 1015353344, 147281920, 631493632, 68628992, 725298944, 234304128, 374026176, 897528544, 261566352, 947728936, 319958908, 12366558, 783740853 + ], + [ + 536870912, 268435456, 134217728, 738197504, 33554432, 822083584, 964689920, 163577856, 127926272, 458227712, 639107072, 188481536, 19791872, 416743424, 719224832, 320389120, 213770240, 871256064, 1005758464, 63454208, 174343680, 586255616, 105883264, 161799488, 945131168, 647963120, 394045608, 223296564, 891471566, 773147987 + ], + [ + 536870912, 268435456, 134217728, 67108864, 33554432, 83886080, 629145600, 826277888, 467664896, 904921088, 857210880, 633602048, 354549760, 374407168, 1049133056, 359415808, 949919744, 126070784, 608544768, 912440320, 11984384, 721040128, 355631232, 62472256, 47456288, 810479632, 919308296, 889801748, 925882006, 167395269 + ], + [ + 536870912, 805306368, 134217728, 335544320, 503316480, 419430400, 159383552, 524288000, 660602880, 632291328, 794296320, 460062720, 124911616, 964624384, 146767872, 270221312, 202104832, 717459456, 35952640, 232023040, 241895936, 1022846208, 1027445376, 895222208, 610867360, 200287376, 633301592, 933213492, 38464222, 271054297 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 436207616, 654311424, 276824064, 641728512, 1012924416, 791674880, 145227776, 949747712, 78774272, 342556672, 767459328, 996589568, 263495680, 116158464, 956176384, 830923776, 1002936832, 94415616, 428966528, 666521536, 73668640, 187819056, 111876808, 966617964, 691249834, 95223749 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 838860800, 721420288, 964689920, 457179136, 836763648, 212860928, 911736832, 837550080, 238157824, 1016922112, 1061715968, 1029947392, 527835136, 712953856, 544839680, 125596672, 352123392, 415073536, 584934016, 506327488, 538155232, 101545008, 260471464, 239289692, 157532846, 963698945 + ], + [ + 536870912, 805306368, 671088640, 201326592, 704643072, 889192448, 998244352, 775946240, 929038336, 347078656, 876085248, 58982400, 977666048, 962920448, 129073152, 280838144, 591568896, 417427456, 888195072, 274689024, 867423744, 784213760, 407240832, 811925696, 1043431584, 134037552, 94544040, 387018964, 203999470, 690711737 + ], + [ + 536870912, 805306368, 671088640, 335544320, 838860800, 385875968, 8388608, 406847488, 694157312, 600834048, 722993152, 994312192, 736493568, 76873728, 385515520, 852639744, 1050468352, 478220288, 239568896, 610692096, 542382592, 31142656, 492994688, 567689408, 337305760, 801378384, 27592904, 988818524, 900659714, 26157921 + ], + [ + 536870912, 805306368, 402653184, 872415232, 33554432, 150994944, 427819008, 322961408, 329252864, 812646400, 1011351552, 673447936, 439746560, 778764288, 1058177024, 937312256, 1061036032, 15708160, 584263680, 163107840, 690814464, 514851072, 380117120, 787787968, 965322848, 574788816, 237297160, 959754532, 317294822, 64103565 + ], + [ + 536870912, 805306368, 671088640, 872415232, 637534208, 687865856, 327155712, 373293056, 492830720, 590348288, 735576064, 454295552, 219021312, 825819136, 946110464, 985120768, 782147584, 787755008, 620570624, 726006784, 417619456, 880140032, 289343616, 140643520, 313644704, 446239696, 150273560, 234418020, 952541294, 245379145 + ], + [ + 536870912, 805306368, 134217728, 738197504, 838860800, 419430400, 41943040, 37748736, 878706688, 967835648, 866648064, 991166464, 188612608, 619511808, 267878400, 566837248, 228827136, 1024823296, 876357632, 694975488, 137588224, 1047302400, 431360128, 61713600, 856909344, 657997232, 384626248, 384946596, 592160938, 266681465 + ], + [ + 536870912, 268435456, 134217728, 738197504, 838860800, 553648128, 58720256, 180355072, 950009856, 158334976, 964165632, 209977344, 37879808, 887160832, 647331840, 292438016, 648552448, 932081664, 826169344, 761631744, 827452928, 273272576, 672792704, 131399744, 521109536, 763052208, 176660680, 893726852, 140638222, 1020568619 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 1040187392, 553648128, 1048576000, 4194304, 1067450368, 560988160, 127401984, 133955584, 938344448, 115539968, 609255424, 212680704, 482369536, 820391936, 693565440, 607104000, 25170432, 264571136, 694612608, 579959104, 659483168, 1484208, 151576792, 917991476, 720935074, 258645109 + ], + [ + 536870912, 805306368, 939524096, 201326592, 301989888, 486539264, 478150656, 809500672, 102760448, 219152384, 941096960, 48496640, 1064697856, 355401728, 887980032, 369639424, 427728896, 878120960, 213698560, 145990656, 214716928, 605584128, 417669248, 376459456, 397404384, 195884080, 296630856, 950849396, 976075506, 91197185 + ], + [ + 536870912, 268435456, 134217728, 872415232, 100663296, 285212672, 125829120, 146800640, 383778816, 753926144, 4718592, 800849920, 796262400, 378208256, 341540864, 905986048, 151117824, 998592512, 986163200, 31532032, 980783616, 252477184, 832191104, 358701888, 976332960, 1001006224, 919474744, 821837716, 961796742, 412617511 + ], + [ + 536870912, 268435456, 134217728, 738197504, 436207616, 419430400, 595591168, 88080384, 383778816, 68157440, 677904384, 569638912, 251265024, 190644224, 179011584, 341065728, 386768896, 833073152, 1073170432, 838847488, 601815552, 426658048, 1047718016, 431782976, 683389472, 926451120, 545100520, 60519716, 1041201710, 170330597 + ], + [ + 536870912, 268435456, 134217728, 738197504, 1040187392, 654311424, 159383552, 213909504, 866123776, 361758720, 629669888, 617349120, 430833664, 782172160, 469925888, 637616128, 50831360, 461869056, 365135872, 488782848, 282357248, 451538688, 49868416, 699903808, 803065504, 560037872, 288482904, 832099180, 562036862, 817889375 + ], + [ + 536870912, 805306368, 939524096, 603979776, 234881024, 1056964608, 243269632, 390070272, 60817408, 846200832, 1018691584, 722731008, 246284288, 943390720, 1029079040, 76070912, 931684352, 453939200, 558483456, 963625984, 601699840, 973253376, 956377216, 763794624, 868490976, 635453328, 5453496, 386509628, 55552090, 342512653 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 1040187392, 788529152, 645922816, 37748736, 127926272, 854589440, 448266240, 114556928, 831127552, 906952704, 902397952, 850051072, 129982464, 961646592, 508356608, 393118720, 333014528, 348134144, 232884352, 290722880, 709758560, 225402864, 1054609016, 591683580, 103255674, 842375097 + ], + [ + 536870912, 805306368, 671088640, 738197504, 301989888, 989855744, 159383552, 281018368, 207618048, 814743552, 1065877504, 774635520, 777650176, 956760064, 713457664, 490913792, 580952064, 368316416, 1033652224, 149332992, 483624448, 732786432, 480093824, 644333504, 1066618400, 537791344, 1005060200, 45875356, 735183054, 2818079 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 1040187392, 721420288, 1048576000, 1002438656, 924844032, 691011584, 385351680, 156499968, 1043202048, 3735552, 267747328, 945602560, 857989120, 858886144, 402184192, 517460992, 778849792, 425665280, 346077312, 192120000, 849016480, 998352880, 910282360, 644342636, 668293338, 502207711 + ], + [ + 536870912, 805306368, 402653184, 738197504, 973078528, 452984832, 998244352, 37748736, 685768704, 827326464, 105381888, 314310656, 281149440, 237305856, 779517952, 280674304, 398467072, 396496896, 456407040, 970511360, 1070626304, 42697472, 983232128, 129468352, 303857888, 980664432, 918331528, 784453852, 455120902, 418710629 + ], + [ + 536870912, 268435456, 939524096, 201326592, 771751936, 654311424, 847249408, 163577856, 320864256, 472907776, 860356608, 395575296, 196739072, 947585024, 1046446080, 569163776, 48521216, 320278528, 964597760, 265851904, 11259392, 486966528, 662763648, 172262464, 56809184, 441897264, 312301112, 424284636, 982595242, 70844759 + ], + [ + 536870912, 805306368, 134217728, 469762048, 234881024, 721420288, 293601280, 20971520, 962592768, 110100480, 606601216, 477364224, 922615808, 868024320, 551124992, 390774784, 468049920, 844591104, 101582848, 445004800, 549480960, 807784704, 603318400, 750537920, 325050912, 990719344, 67527352, 705162604, 822313702, 679517621 + ], + [ + 536870912, 268435456, 939524096, 201326592, 167772160, 989855744, 360710144, 398458880, 56623104, 376438784, 355991552, 1000603648, 378667008, 495910912, 259883008, 856113152, 830627840, 700723200, 1046624256, 855002112, 746528256, 981921536, 340254848, 497512512, 932337888, 185433136, 20489768, 765715436, 529571542, 1057926943 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 369098752, 922746880, 394264576, 406847488, 929038336, 26214400, 746061824, 850132992, 909508608, 961085440, 1046511616, 353845248, 297738240, 9408512, 910505984, 744621056, 403746304, 1060893952, 72160896, 417509696, 903125216, 354407600, 943470136, 466100524, 614932614, 682856701 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 167772160, 889192448, 1065353216, 985661440, 106954752, 258998272, 930611200, 452722688, 289275904, 920322048, 7110656, 838189056, 339697664, 828280832, 783206400, 26510336, 609200640, 211854592, 823241344, 738960704, 461711904, 885155248, 761547272, 871888228, 222167798, 752529807 + ], + [ + 536870912, 268435456, 939524096, 469762048, 167772160, 855638016, 796917760, 725614592, 262144000, 1007681536, 547880960, 308019200, 575012864, 992280576, 483688448, 306888704, 418062336, 578654208, 219256832, 136977408, 949990912, 597767936, 504467072, 934050624, 735871072, 805748784, 671424712, 604278972, 369301654, 956685409 + ], + [ + 536870912, 268435456, 134217728, 738197504, 973078528, 754974720, 830472192, 46137344, 765460480, 590348288, 58195968, 751042560, 245497856, 565248000, 188579840, 623067136, 511156224, 522137600, 684840960, 178844672, 1038927360, 344841984, 85819520, 366166080, 858759200, 321597616, 53205224, 187561140, 657147590, 489398027 + ], + [ + 536870912, 268435456, 671088640, 201326592, 301989888, 889192448, 243269632, 750780416, 165675008, 948961280, 816316416, 29097984, 911605760, 877592576, 329809920, 876462080, 454549504, 652865536, 312379392, 740803584, 368320000, 905932544, 678729344, 79407936, 14026784, 1015678064, 72089320, 732602340, 272375538, 85159719 + ], + [ + 536870912, 805306368, 939524096, 603979776, 1040187392, 587202560, 662700032, 390070272, 39845888, 80740352, 15204352, 1002700800, 514195456, 871825408, 1063026688, 91996160, 911106048, 607252480, 67069952, 260574208, 865450496, 848186624, 118653056, 977846464, 909435104, 50147472, 286099704, 508705932, 590131870, 828617053 + ], + [ + 536870912, 268435456, 939524096, 872415232, 234881024, 922746880, 461373440, 1027604480, 702545920, 70254592, 592969728, 354680832, 965869568, 437190656, 545947648, 357548032, 745529344, 1073541120, 619833344, 486120448, 561075712, 784012032, 655843456, 432812096, 447514848, 324971728, 1025859128, 898990044, 537878254, 428769205 + ], + [ + 536870912, 268435456, 939524096, 335544320, 301989888, 855638016, 595591168, 171966464, 1054867456, 87031808, 430440448, 564396032, 693239808, 1046413312, 992903168, 727990272, 108224512, 466219008, 190154752, 626654208, 883537408, 656575744, 429252736, 242856000, 993847520, 811273296, 640204360, 98841036, 447985166, 770280809 + ], + [ + 536870912, 805306368, 134217728, 469762048, 234881024, 822083584, 562036736, 566231040, 534773760, 254803968, 996671488, 316932096, 280363008, 598278144, 814186496, 810008576, 908533760, 215461888, 979236864, 411687936, 601347584, 316429568, 214900864, 267628736, 1024194592, 672193648, 641226296, 25138628, 199098374, 21823559 + ], + [ + 536870912, 805306368, 402653184, 201326592, 570425344, 16777216, 763363328, 88080384, 1021313024, 449839104, 745013248, 1029963776, 227934208, 160104448, 104169472, 112869376, 151986176, 1022767104, 639232000, 247020544, 755575296, 183518464, 152641664, 4010176, 80504928, 517176368, 711854728, 174224644, 253151286, 38735061 + ], + [ + 536870912, 805306368, 671088640, 201326592, 503316480, 385875968, 713031680, 440401920, 2097152, 737148928, 16252928, 157024256, 409600000, 804716544, 586842112, 677068800, 703242240, 20148224, 798914560, 688741376, 413438464, 145888512, 358363776, 510289344, 485673504, 444299760, 991852632, 340614316, 436507250, 889328901 + ], + [ + 536870912, 805306368, 402653184, 603979776, 369098752, 822083584, 864026624, 406847488, 618659840, 644874240, 81264640, 818675712, 128057344, 34930688, 913276928, 775045120, 138076160, 717180928, 830208000, 366760960, 860615168, 132474112, 49343104, 102719936, 468541664, 191959120, 895162424, 394921044, 96832150, 430076325 + ], + [ + 536870912, 268435456, 671088640, 335544320, 100663296, 822083584, 125829120, 742391808, 874512384, 760217600, 112721920, 218890240, 1023803392, 763822080, 658997248, 279068672, 831971328, 677302272, 1069119488, 244124672, 1061170688, 1017183488, 194393728, 190472512, 255328288, 340525072, 547750072, 160891028, 341803014, 767443061 + ], + [ + 536870912, 805306368, 402653184, 738197504, 570425344, 553648128, 578813952, 952107008, 794820608, 927989760, 1027080192, 852754432, 545128448, 821493760, 218857472, 213598208, 563322880, 559747072, 503429120, 721845248, 931303936, 340245248, 346536064, 464878784, 271520352, 407894960, 177838088, 450899012, 839944938, 320657235 + ], + [ + 536870912, 268435456, 939524096, 872415232, 838860800, 721420288, 612368384, 624951296, 782237696, 831520768, 491257856, 287047680, 699793408, 849149952, 1047887872, 410697728, 448798720, 124088320, 913405952, 75144192, 616904192, 711348992, 200789632, 784011072, 195516512, 269675664, 160026152, 326766460, 776263898, 438643833 + ], + [ + 536870912, 805306368, 134217728, 738197504, 167772160, 922746880, 813694976, 994050048, 90177536, 13631488, 554172416, 29097984, 870449152, 915865600, 736919552, 648593408, 651010048, 94105600, 156760064, 197919744, 975148544, 647105280, 334352000, 44695488, 13607072, 949809264, 248739848, 574572, 70792938, 589495089 + ], + [ + 536870912, 268435456, 939524096, 335544320, 167772160, 754974720, 41943040, 29360128, 463470592, 938475520, 462946304, 775159808, 70909952, 734199808, 648052736, 225853440, 241115136, 1066733568, 516921344, 853025792, 156386816, 317474560, 309270656, 44983360, 1032677088, 951670608, 486572200, 713441524, 768024810, 94441559 + ], + [ + 536870912, 805306368, 671088640, 469762048, 570425344, 754974720, 696254464, 583008256, 371195904, 581959680, 108527616, 146014208, 125698048, 724631552, 347963392, 915750912, 969416704, 256405504, 822638592, 409777152, 809053696, 232258304, 623409280, 668775616, 935407264, 1000602480, 376862728, 56472692, 210021894, 658684923 + ], + [ + 536870912, 268435456, 671088640, 201326592, 33554432, 587202560, 864026624, 339738624, 308281344, 1028653056, 968359936, 149159936, 630325248, 639434752, 479559680, 43663360, 492134400, 700313600, 551798784, 697674752, 605854208, 1066688256, 824139904, 152367168, 1004292256, 498527280, 271481352, 754904972, 436488270, 386067473 + ], + [ + 536870912, 805306368, 671088640, 872415232, 637534208, 352321536, 1065353216, 163577856, 954204160, 699400192, 821559296, 519307264, 677249024, 996212736, 40927232, 320454656, 700456960, 149237760, 28743680, 83782656, 955567616, 1029546752, 81795200, 196259008, 737832608, 7361488, 941498392, 524562580, 749082718, 60271863 + ], + [ + 536870912, 268435456, 402653184, 335544320, 905969664, 218103808, 25165824, 524288000, 853540864, 1064304640, 992477184, 336330752, 241041408, 136642560, 752058368, 935280640, 869392384, 87904256, 739604480, 186450944, 96705024, 824702720, 190315136, 1039984448, 347529952, 319484688, 685531192, 568791076, 804722878, 535761945 + ], + [ + 536870912, 805306368, 134217728, 201326592, 33554432, 419430400, 964689920, 163577856, 576716800, 131072000, 214433792, 815005696, 1039007744, 946143232, 718766080, 860438528, 777428992, 1024028672, 385292288, 876411904, 799834624, 986019072, 1055299712, 1033157824, 845914656, 782517552, 641114248, 534343844, 700389574, 409533463 + ], + [ + 536870912, 805306368, 402653184, 738197504, 301989888, 117440512, 830472192, 281018368, 568328192, 63963136, 936902656, 577503232, 262275072, 125108224, 590249984, 243515392, 1027907584, 992333824, 154249216, 395076608, 40936960, 1034858752, 466071168, 845284800, 202383584, 197070960, 595167272, 513766572, 390803086, 194299231 + ], + [ + 536870912, 805306368, 134217728, 67108864, 234881024, 150994944, 729808896, 1010827264, 52428800, 227540992, 109576192, 670302208, 297664512, 464322560, 459440128, 817283072, 169385984, 251146240, 67987456, 3617792, 652003840, 287014144, 511658112, 416138432, 399966752, 950630672, 132410040, 645090788, 452599822, 839839777 + ], + [ + 536870912, 268435456, 939524096, 335544320, 100663296, 318767104, 1031798784, 272629760, 815792128, 806354944, 434634752, 400818176, 322043904, 113180672, 288260096, 830914560, 306667520, 497168384, 177227776, 841790464, 604492288, 772048128, 1057087616, 796979264, 88418528, 505513040, 500242968, 957018444, 391336566, 986268929 + ], + [ + 536870912, 268435456, 671088640, 738197504, 1040187392, 620756992, 427819008, 163577856, 115343360, 674234368, 438829056, 927727616, 498991104, 368246784, 919240704, 8077312, 688971776, 704598016, 416425984, 723162112, 585531904, 708218624, 690512512, 667606848, 871942688, 1071057904, 26781912, 1000461412, 43409982, 725212931 + ], + [ + 536870912, 268435456, 939524096, 469762048, 503316480, 721420288, 545259520, 499122176, 975175680, 1003487232, 264765440, 1039400960, 974782464, 557514752, 997031936, 417513472, 192143360, 953896960, 26908672, 880538624, 948744704, 454268160, 174684288, 23110720, 993405664, 146301296, 590203640, 210186732, 734352098, 891536711 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 503316480, 385875968, 142606336, 826277888, 425721856, 363855872, 756547584, 761528320, 665976832, 203227136, 249790464, 7454720, 859824128, 179474432, 161474560, 706792448, 366355968, 254626560, 96460928, 1022529600, 813688992, 852544752, 1068377720, 553208668, 127262882, 751538309 + ], + [ + 536870912, 268435456, 402653184, 67108864, 570425344, 989855744, 243269632, 759169024, 782237696, 661651456, 80216064, 72613888, 343539712, 964624384, 654213120, 574177280, 156950528, 885526528, 206768128, 142517248, 528233984, 1073517824, 398190720, 714978368, 925613664, 92565776, 734248456, 534802860, 802275034, 985362917 + ], + [ + 536870912, 805306368, 939524096, 603979776, 503316480, 352321536, 947912704, 46137344, 983564288, 550502400, 292028416, 827588608, 556662784, 976420864, 853180416, 801685504, 1065623552, 491114496, 400652288, 255263744, 979182080, 353159424, 556234880, 596640960, 327787232, 115804560, 431085816, 362353812, 858454530, 489872795 + ], + [ + 536870912, 805306368, 939524096, 603979776, 1040187392, 587202560, 276824064, 1010827264, 106954752, 328204288, 307757056, 304873472, 136445952, 619773952, 273383424, 364331008, 766353408, 921006080, 534190080, 742360064, 633232896, 612362496, 366929536, 149429696, 218505312, 998387792, 818067480, 539423772, 150161082, 843935101 + ], + [ + 536870912, 268435456, 939524096, 67108864, 503316480, 956301312, 880803840, 843055104, 824180736, 326107136, 728236032, 548667392, 780795904, 732102656, 808615936, 315408384, 461611008, 331829248, 367421440, 856699904, 448783872, 661154048, 313976960, 898364480, 1009043168, 301005072, 472490232, 1058295972, 683468850, 1013511385 + ], + [ + 536870912, 268435456, 939524096, 201326592, 838860800, 721420288, 796917760, 901775360, 652214272, 17825792, 396886016, 97255424, 916324352, 101777408, 439123968, 588038144, 872194048, 13094912, 6465536, 139940864, 654894592, 637328128, 767706752, 988154688, 185757280, 816619376, 407546024, 677074140, 259450518, 788388683 + ], + [ + 536870912, 805306368, 402653184, 201326592, 973078528, 50331648, 343932928, 423624704, 509607936, 164626432, 553123840, 729546752, 884604928, 614006784, 296255488, 415744000, 446930944, 24588288, 915347456, 1064391680, 730672640, 116412672, 323956352, 743788992, 171814624, 383488496, 256806408, 1045914108, 490223194, 878183833 + ], + [ + 536870912, 268435456, 402653184, 738197504, 167772160, 889192448, 209715200, 62914560, 618659840, 313524224, 491257856, 697565184, 689569792, 661585920, 927170560, 455098368, 609230848, 385699840, 844863488, 911059968, 639024640, 22793472, 365443200, 72399936, 117245536, 710619568, 441261736, 739433876, 878280914, 424624383 + ], + [ + 536870912, 805306368, 939524096, 469762048, 704643072, 318767104, 1031798784, 683671552, 572522496, 519045120, 861405184, 1065091072, 881459200, 995426304, 510296064, 931512320, 197304320, 665292800, 708003840, 997960704, 848093696, 978600192, 753812096, 147050944, 304417376, 653557168, 794552520, 360267004, 663562942, 114699679 + ], + [ + 536870912, 268435456, 134217728, 335544320, 704643072, 419430400, 1065353216, 708837376, 996147200, 386924544, 271056896, 875298816, 103677952, 53411840, 44924928, 468238336, 101441536, 81530880, 97605632, 495596544, 480171520, 1001902848, 186570368, 368563008, 310302368, 266851088, 399955464, 143381364, 353949430, 922014685 + ], + [ + 536870912, 805306368, 939524096, 469762048, 33554432, 822083584, 209715200, 138412032, 119537664, 1045430272, 45613056, 362545152, 600440832, 91553792, 250249216, 505462784, 651419648, 754511872, 1035548672, 572144640, 839714304, 412117248, 215934592, 409508288, 191356512, 393389488, 938137704, 916638836, 815021786, 416961941 + ], + [ + 536870912, 268435456, 671088640, 469762048, 369098752, 889192448, 192937984, 239075328, 421527552, 529530880, 1042808832, 467402752, 214302720, 451346432, 368476160, 790183936, 572547072, 85315584, 435009536, 868051968, 586421760, 194877184, 753356416, 821062464, 211320864, 811745328, 170975480, 863735972, 101931126, 929955053 + ], + [ + 536870912, 268435456, 671088640, 67108864, 838860800, 855638016, 595591168, 876609536, 1050673152, 521142272, 631767040, 926679040, 467009536, 483328000, 180977664, 466141184, 592125952, 814321664, 141506560, 450558976, 65267200, 624037632, 930799232, 796390208, 483964960, 987839568, 431441512, 381444060, 613893830, 770465629 + ], + [ + 536870912, 268435456, 671088640, 201326592, 637534208, 419430400, 897581056, 641728512, 2097152, 829423616, 211288064, 557580288, 34471936, 213057536, 805208064, 736903168, 211836928, 850808832, 50190336, 476789760, 434307584, 940910848, 961372800, 51411264, 802044448, 131532144, 690837688, 54819860, 732291822, 708000205 + ], + [ + 536870912, 268435456, 671088640, 469762048, 838860800, 117440512, 343932928, 926941184, 1050673152, 768606208, 697827328, 793509888, 408289280, 861863936, 791314432, 870563840, 410099712, 181202944, 714455040, 792566784, 916004352, 533295360, 689219200, 620293440, 595310624, 1052679216, 710778472, 917090668, 589399578, 722787713 + ], + [ + 536870912, 805306368, 134217728, 603979776, 570425344, 788529152, 125829120, 826277888, 295698432, 976224256, 988282880, 619446272, 904527872, 325779456, 212828160, 650887168, 345907200, 858181632, 938801152, 931712000, 893028864, 18306816, 689605248, 828856256, 802327200, 368793424, 351308328, 101472236, 24971830, 472946473 + ], + [ + 536870912, 805306368, 671088640, 872415232, 436207616, 822083584, 998244352, 432013312, 111149056, 93323264, 1055391744, 874250240, 297926656, 44236800, 932413440, 1005436928, 362373120, 956518400, 1065830400, 734030848, 61187584, 605163264, 371723904, 154989504, 227770400, 988659728, 102326472, 348344340, 589777030, 525364387 + ], + [ + 536870912, 805306368, 671088640, 67108864, 838860800, 520093696, 847249408, 767557632, 882900992, 791674880, 410517504, 353107968, 563216384, 474677248, 636583936, 39370752, 167550976, 609169408, 972204032, 475745280, 553312768, 1003254016, 968084096, 934870464, 380504096, 941915344, 468732520, 458964332, 1048258690, 537889803 + ], + [ + 536870912, 805306368, 939524096, 469762048, 301989888, 218103808, 528482304, 549453824, 752877568, 691011584, 148373504, 10223616, 171573248, 112001024, 677806080, 628146176, 1014980608, 722440192, 712378368, 653972480, 810537472, 676755712, 1009472128, 52935104, 525382240, 984213936, 174414376, 275869060, 1073569878, 432967687 + ], + [ + 536870912, 268435456, 134217728, 469762048, 503316480, 318767104, 528482304, 926941184, 828375040, 630194176, 78118912, 914096128, 330694656, 140181504, 54951936, 593641472, 546349056, 338300928, 12244992, 110404608, 53112320, 356273920, 550909568, 550153024, 191690912, 1037890608, 889198168, 142801724, 583434374, 388120785 + ], + [ + 536870912, 805306368, 939524096, 201326592, 838860800, 721420288, 1065353216, 364904448, 908066816, 907018240, 445120512, 436469760, 788922368, 965148672, 12681216, 279330816, 928342016, 116387840, 267827200, 901301248, 253608448, 793301248, 471859328, 554696896, 789053664, 683933744, 346423496, 827785388, 334070014, 695353431 + ], + [ + 536870912, 268435456, 134217728, 872415232, 838860800, 50331648, 1048576000, 373293056, 681574400, 986710016, 144179200, 285999104, 649461760, 447414272, 853770240, 208846848, 1062150144, 571813888, 779704320, 1065008128, 318578176, 842907904, 954189440, 413777216, 702806176, 251022480, 789112552, 1001426396, 690790578, 522711061 + ], + [ + 536870912, 268435456, 671088640, 469762048, 771751936, 520093696, 41943040, 20971520, 551550976, 516947968, 586678272, 937164800, 867041280, 937623552, 273973248, 633028608, 339320832, 33058816, 190355456, 99410944, 159559168, 566311168, 950111872, 1068566848, 300693024, 729996592, 952213656, 958689356, 309762066, 793764873 + ], + [ + 536870912, 268435456, 402653184, 67108864, 301989888, 251658240, 1031798784, 381681664, 715128832, 466616320, 845676544, 173801472, 411435008, 809566208, 199458816, 749912064, 748396544, 975327232, 932669440, 797740032, 1005235712, 110720768, 556000896, 1338176, 843972832, 1053622352, 76382248, 74432556, 123609278, 838963303 + ], + [ + 536870912, 805306368, 671088640, 335544320, 369098752, 385875968, 360710144, 289406976, 23068672, 588251136, 43515904, 1054605312, 658112512, 1039073280, 802521088, 918241280, 581672960, 95555584, 36419584, 812766208, 948606464, 46601472, 522655360, 200299968, 852407840, 1008813456, 947031672, 478728652, 1019492398, 472224905 + ], + [ + 536870912, 268435456, 134217728, 738197504, 838860800, 687865856, 847249408, 826277888, 425721856, 825229312, 798490624, 154402816, 463077376, 523567104, 748650496, 917716992, 106602496, 739577856, 525109248, 735984640, 148286976, 384683776, 88901760, 1054751808, 5680672, 581816240, 481069128, 397294820, 70168298, 736743285 + ], + [ + 536870912, 268435456, 671088640, 335544320, 1040187392, 251658240, 964689920, 859832320, 631242752, 30408704, 631767040, 746323968, 232128512, 934215680, 561741824, 290668544, 208216064, 18698240, 1071781888, 1056177152, 750640640, 976525056, 224380544, 466053952, 811735072, 112458768, 647880280, 329553772, 181913246, 170617777 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 637534208, 150994944, 461373440, 792723456, 710934528, 881852416, 153616384, 22806528, 36044800, 946929664, 192708608, 509034496, 688906240, 976048128, 635377664, 669082624, 450133504, 483165952, 9078400, 242070336, 523985120, 884347056, 576649464, 1050752212, 565307126, 266052505 + ], + [ + 536870912, 268435456, 134217728, 603979776, 100663296, 654311424, 796917760, 289406976, 484442112, 279969792, 765984768, 416546816, 970588160, 903675904, 131760128, 786415616, 39804928, 983478272, 272467968, 870960128, 531787264, 908742912, 126937216, 641629248, 217015840, 472997264, 91186840, 980508124, 1041196574, 528571797 + ], + [ + 536870912, 805306368, 939524096, 201326592, 33554432, 989855744, 394264576, 440401920, 195035136, 328204288, 538443776, 54788096, 388366336, 643235840, 1039761408, 427048960, 531193856, 311029760, 869844992, 597963776, 395678208, 370684672, 910262400, 966803648, 278356192, 1000009776, 453462024, 663188716, 574976606, 128287593 + ], + [ + 536870912, 805306368, 939524096, 469762048, 234881024, 620756992, 713031680, 633339904, 115343360, 61865984, 698875904, 558104576, 908460032, 399966208, 333152256, 901120, 836149248, 584863744, 9189376, 588291072, 633083392, 696009984, 52265088, 610975936, 866459872, 529895536, 159160376, 857459860, 476819114, 799086999 + ], + [ + 536870912, 805306368, 939524096, 738197504, 771751936, 452984832, 159383552, 415236096, 488636416, 422576128, 426246144, 927727616, 66715648, 945094656, 188514304, 762527744, 101523456, 907841536, 71747584, 660950016, 760379904, 700112640, 70736512, 803884992, 470520416, 521798512, 12937432, 19110940, 255267454, 778650559 + ], + [ + 536870912, 268435456, 939524096, 67108864, 973078528, 855638016, 58720256, 4194304, 195035136, 175112192, 120061952, 987496448, 800456704, 298647552, 160137216, 371834880, 509091840, 779587584, 757774336, 836492288, 674753024, 730723072, 824922752, 534458176, 423049312, 521083984, 149703176, 658482140, 459786854, 303457165 + ], + [ + 536870912, 268435456, 134217728, 335544320, 905969664, 553648128, 645922816, 675282944, 807403520, 785383424, 242745344, 156499968, 280625152, 422903808, 440958976, 261865472, 1012965376, 821104640, 497723392, 61510656, 648819200, 1042823936, 594061440, 63673408, 610185760, 1015479120, 859867224, 497108164, 588561082, 664633329 + ], + [ + 536870912, 805306368, 939524096, 872415232, 704643072, 587202560, 914358272, 29360128, 836763648, 353370112, 329777152, 226754560, 860225536, 572981248, 871792640, 440221696, 1021861888, 967102464, 95500288, 866106368, 828203520, 104420608, 720240768, 1017315520, 238059744, 232407248, 352247976, 361336972, 477190362, 109014023 + ], + [ + 536870912, 805306368, 939524096, 67108864, 234881024, 16777216, 41943040, 297795584, 639631360, 495976448, 580386816, 908853248, 983695360, 89194496, 977240064, 813514752, 823910400, 762146816, 826796032, 887536640, 170989056, 659476736, 785718912, 628694464, 899276896, 28078288, 534800600, 934804500, 218691122, 531800387 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 704643072, 83886080, 864026624, 1019215872, 199229440, 36700160, 446169088, 189005824, 958529536, 315686912, 942637056, 832126976, 868655104, 761622528, 91297792, 297516032, 680633856, 613384960, 814579840, 914899008, 294199328, 453783792, 1045412008, 208325652, 909819598, 307314675 + ], + [ + 536870912, 805306368, 939524096, 469762048, 503316480, 855638016, 125829120, 1027604480, 1038090240, 858783744, 484966400, 829685760, 814612480, 671285248, 335904768, 973389824, 822468608, 713240576, 163694592, 120015872, 865193472, 305930496, 514607232, 488082624, 704261856, 210506096, 100663544, 520093708, 562036990, 306184325 + ], + [ + 536870912, 805306368, 939524096, 738197504, 100663296, 419430400, 260046848, 1052770304, 165675008, 705691648, 212336640, 348913664, 85590016, 836042752, 80510976, 220086272, 634675200, 785059840, 303794176, 860902400, 529090048, 624540416, 279389824, 959949760, 1029189216, 24493936, 234817656, 138548244, 145172166, 624405295 + ], + [ + 536870912, 805306368, 134217728, 738197504, 637534208, 520093696, 1015021568, 1027604480, 257949696, 258998272, 268959744, 819200000, 176291840, 440598528, 400588800, 942850048, 644505600, 472248320, 457820160, 414503936, 494040576, 1024014080, 290971776, 507657536, 769785888, 154337328, 703102984, 1004978220, 912810022, 606531615 + ], + [ + 536870912, 805306368, 939524096, 603979776, 369098752, 486539264, 729808896, 641728512, 983564288, 460324864, 102236160, 596377600, 313393152, 530382848, 455507968, 131645440, 91201536, 612331520, 108349440, 947055616, 479749632, 609116416, 558688384, 516901952, 378357920, 355286128, 870219928, 243732564, 1009337998, 330694985 + ], + [ + 536870912, 268435456, 939524096, 469762048, 704643072, 754974720, 142606336, 96468992, 924844032, 179306496, 663224320, 914096128, 724434944, 230096896, 489717760, 197869568, 505208832, 578793472, 892336128, 783713280, 246605312, 25847040, 159355264, 313429056, 720636320, 47249488, 1054603160, 920955212, 78247986, 583894049 + ], + [ + 536870912, 805306368, 671088640, 335544320, 905969664, 419430400, 1065353216, 994050048, 845152256, 877658112, 527958016, 659816448, 678297600, 903413760, 136675328, 908443648, 187113472, 715485184, 484747264, 654699520, 823435776, 596617984, 197840512, 247388352, 677637280, 391164912, 871891464, 412490532, 835503774, 774603981 + ], + [ + 536870912, 268435456, 671088640, 67108864, 33554432, 452984832, 411041792, 725614592, 455081984, 890241024, 138936320, 915668992, 192806912, 45809664, 892305408, 30457856, 514416640, 115806208, 679901184, 599006208, 862926336, 594717440, 796557696, 541921216, 40032160, 221492432, 165260808, 329148180, 1070280618, 1062693087 + ], + [ + 536870912, 268435456, 134217728, 201326592, 369098752, 352321536, 260046848, 205520896, 597688320, 862978048, 992477184, 823918592, 5111808, 89587712, 826507264, 807485440, 556867584, 25751552, 468502528, 573008896, 409536000, 238831872, 771555200, 303903808, 181344160, 244688976, 312564136, 921947484, 1013678142, 71122953 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 704643072, 150994944, 92274688, 968884224, 656408576, 124780544, 395837440, 175374336, 485359616, 119078912, 741769216, 319569920, 516448256, 790409216, 549488640, 178365440, 447897088, 649661696, 772041344, 133603520, 825111712, 775663088, 876895800, 571739404, 570223282, 680780021 + ], + [ + 536870912, 805306368, 134217728, 67108864, 100663296, 620756992, 109051904, 448790528, 530579456, 781189120, 603455488, 967049216, 413007872, 43581440, 1050116096, 955695104, 440737792, 57651200, 408156160, 240804864, 1010214400, 484903680, 561914496, 107629504, 232719520, 863731952, 1046742568, 230587188, 885586574, 567255009 + ], + [ + 536870912, 805306368, 671088640, 872415232, 771751936, 50331648, 260046848, 331350016, 10485760, 552599552, 892862464, 446431232, 485621760, 523960320, 530481152, 611401728, 762961920, 268349440, 195147776, 728816640, 553302528, 759019264, 495095680, 985830336, 169981984, 196140080, 131775016, 705541940, 102404014, 61772739 + ], + [ + 536870912, 268435456, 402653184, 335544320, 1040187392, 1023410176, 880803840, 314572800, 341835776, 380633088, 642252800, 3932160, 83492864, 141885440, 566722560, 739131392, 91316224, 615124992, 189556736, 357719040, 1002126848, 206921472, 14026368, 370533056, 611800608, 466027280, 923613336, 418430420, 1021923486, 820961773 + ], + [ + 536870912, 805306368, 134217728, 201326592, 436207616, 218103808, 897581056, 272629760, 559939584, 948961280, 653787136, 221511680, 985006080, 334823424, 420839424, 717570048, 266133504, 314060800, 173369344, 488991744, 26016256, 736310016, 743586944, 811114432, 92552352, 708681712, 501857448, 478994428, 644046002, 940699633 + ], + [ + 536870912, 805306368, 134217728, 872415232, 637534208, 989855744, 595591168, 121634816, 1025507328, 233832448, 9961472, 797704192, 565575680, 1015611392, 478642176, 275890176, 819601408, 724389888, 33867776, 1068575744, 557553152, 683603200, 340755072, 643167040, 202912928, 491738736, 685047336, 467290372, 816676014, 960936527 + ], + [ + 536870912, 268435456, 939524096, 335544320, 234881024, 184549376, 41943040, 188743680, 912261120, 516947968, 181927936, 117702656, 254672896, 96665600, 925007872, 364036096, 160014336, 169627648, 1040881664, 551394304, 766136832, 422497024, 180363392, 60829120, 32754336, 862579408, 344752152, 3260420, 843784246, 507416607 + ], + [ + 536870912, 268435456, 402653184, 469762048, 369098752, 16777216, 461373440, 415236096, 333447168, 101711872, 563609600, 529793024, 832962560, 491716608, 890404864, 555302912, 332734464, 1007071232, 503302144, 414884864, 291785216, 45085440, 1023473280, 495176128, 29400736, 342007248, 147864760, 863664844, 34064430, 150905869 + ], + [ + 536870912, 805306368, 671088640, 872415232, 167772160, 83886080, 1048576000, 641728512, 694157312, 896532480, 8912896, 255590400, 622460928, 587661312, 957120512, 41041920, 386473984, 33394688, 289015808, 244683776, 288730624, 1013226240, 125819520, 460956352, 838108704, 524787504, 225377448, 360836596, 264327850, 681735925 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 838860800, 855638016, 92274688, 113246208, 710934528, 9437184, 591921152, 205783040, 1013579776, 762773504, 693338112, 245940224, 555130880, 214102016, 358643712, 789765120, 713637376, 296174848, 154772096, 568300864, 591797792, 1005221168, 11860632, 984840572, 989591570, 457055235 + ], + [ + 536870912, 268435456, 134217728, 603979776, 33554432, 419430400, 545259520, 759169024, 551550976, 378535936, 16252928, 165937152, 733347840, 376373248, 213614592, 898088960, 1046798336, 158658560, 676083712, 168332288, 214774272, 893960960, 1026527360, 660214976, 311830688, 392059088, 254966440, 747285492, 713994794, 606798637 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 503316480, 1023410176, 494927872, 222298112, 748683264, 846200832, 543686656, 293339136, 566362112, 711000064, 177307648, 20692992, 757456896, 485871616, 946788352, 12211200, 778406400, 357992192, 731707008, 865107904, 784039968, 459718672, 752246808, 81727548, 1009956894, 1011369021 + ], + [ + 536870912, 805306368, 134217728, 201326592, 33554432, 721420288, 243269632, 88080384, 668991488, 1045430272, 277348352, 752091136, 629538816, 26017792, 119111680, 100614144, 375545856, 59854848, 522909696, 518441984, 698147328, 988970752, 473693056, 764163264, 890831776, 654244080, 350478760, 80840700, 331979306, 775353111 + ], + [ + 536870912, 805306368, 939524096, 603979776, 301989888, 520093696, 830472192, 666894336, 702545920, 567279616, 429391872, 504102912, 740163584, 107282432, 985300992, 146718720, 974577664, 735285248, 312166400, 93148160, 819894784, 201797376, 598307456, 155566144, 570997408, 934696048, 723566744, 179497812, 537590282, 548830987 + ], + [ + 536870912, 805306368, 402653184, 201326592, 301989888, 184549376, 427819008, 465567744, 455081984, 344981504, 592969728, 79429632, 583925760, 891617280, 131104768, 356139008, 256663552, 15159296, 502335488, 522851328, 1012192768, 263890688, 688676480, 101031744, 121747104, 677550960, 317720760, 816412796, 714573866, 404313143 + ], + [ + 536870912, 805306368, 939524096, 872415232, 704643072, 587202560, 981467136, 1052770304, 392167424, 78643200, 1057488896, 823394304, 979501056, 1060306944, 340492288, 1010253824, 510697472, 174665728, 446965760, 569027584, 971298304, 550238976, 66328704, 479452480, 345546784, 84750384, 447621176, 1014869044, 944068138, 253475619 + ], + [ + 536870912, 268435456, 939524096, 335544320, 637534208, 251658240, 947912704, 843055104, 106954752, 154140672, 837287936, 902037504, 808845312, 721354752, 283672576, 1044889600, 821469184, 601673728, 238655488, 56597504, 947546624, 456982784, 709587840, 877972928, 583822240, 981701072, 859840920, 501317828, 837970494, 751370507 + ], + [ + 536870912, 805306368, 939524096, 67108864, 973078528, 855638016, 494927872, 675282944, 1033895936, 972029952, 873988096, 803995648, 119668736, 1043529728, 788234240, 138166272, 730439680, 920924160, 168056832, 282575872, 285145600, 451571456, 209058176, 193800896, 489922592, 997929008, 478009400, 673743876, 102029882, 278798131 + ], + [ + 536870912, 805306368, 134217728, 872415232, 1040187392, 285212672, 276824064, 591396864, 677380096, 315621376, 490209280, 1039400960, 380764160, 1038811136, 869040128, 549797888, 932896768, 75927552, 444123136, 328569856, 694351360, 978416896, 41521024, 529874240, 727853088, 559088688, 1039810056, 1028972852, 818117054, 950028369 + ], + [ + 536870912, 268435456, 671088640, 67108864, 838860800, 352321536, 595591168, 541065216, 601882624, 30408704, 634912768, 600571904, 298188800, 550699008, 207323136, 982433792, 665149440, 641822720, 1021372416, 458423296, 270227968, 124539648, 91695232, 119233856, 166501024, 716567120, 850978824, 215940116, 943544858, 930042641 + ], + [ + 536870912, 805306368, 671088640, 738197504, 1040187392, 654311424, 998244352, 1027604480, 253755392, 1028653056, 1050148864, 885260288, 1063911424, 374276096, 739540992, 733200384, 1042964480, 1064185856, 843356160, 1017857024, 783071744, 329644288, 530116480, 474250048, 61358624, 288329008, 1021595048, 163120748, 1033271198, 1005600599 + ], + [ + 536870912, 805306368, 939524096, 469762048, 1040187392, 16777216, 494927872, 650117120, 673185792, 1062207488, 285736960, 878444544, 915013632, 27197440, 69828608, 412008448, 943874048, 476237824, 355579904, 557562880, 719632896, 95389952, 814959232, 816471232, 936294944, 748718384, 672320184, 434674908, 1043257886, 995186993 + ], + [ + 536870912, 268435456, 402653184, 201326592, 301989888, 855638016, 914358272, 801112064, 60817408, 1039138816, 310902784, 939261952, 364511232, 760545280, 1073184768, 260554752, 273653760, 366047232, 523896832, 412462080, 458719744, 452418304, 201668224, 604982976, 775031328, 187250448, 755963032, 800089548, 342406322, 745346531 + ], + [ + 536870912, 805306368, 134217728, 67108864, 570425344, 520093696, 914358272, 339738624, 467664896, 550502400, 284688384, 323747840, 210370560, 403111936, 246317056, 559497216, 696098816, 992161792, 7473152, 357176320, 858220032, 920387840, 940639616, 1012559808, 821972512, 299918640, 198429576, 209210052, 470590850, 65626095 + ], + [ + 536870912, 805306368, 939524096, 872415232, 570425344, 352321536, 713031680, 641728512, 65011712, 462422016, 366477312, 975962112, 997326848, 600506368, 238518272, 981286912, 76226560, 894816256, 715941888, 204604416, 279694848, 317096192, 617017728, 376932544, 849299488, 245093424, 793617976, 681805108, 921747362, 839600597 + ], + [ + 536870912, 268435456, 671088640, 738197504, 905969664, 1056964608, 864026624, 188743680, 10485760, 217055232, 167247872, 744751104, 1024589824, 480837632, 233734144, 206356480, 809263104, 520515584, 729839616, 524456960, 849402368, 703702784, 863732608, 732344384, 91396128, 465052688, 138723880, 622936876, 682697142, 316179327 + ], + [ + 536870912, 805306368, 671088640, 469762048, 637534208, 654311424, 159383552, 230686720, 748683264, 512753664, 956825600, 120324096, 837156864, 526974976, 211648512, 868040704, 300851200, 46632960, 54044672, 213279744, 29574656, 312568576, 227585408, 176872512, 200174496, 868677488, 95970824, 351779628, 111191438, 127019131 + ], + [ + 536870912, 268435456, 671088640, 335544320, 1040187392, 486539264, 696254464, 1002438656, 98566144, 193986560, 829947904, 431226880, 599654400, 90374144, 936607744, 979091456, 709271552, 479473664, 894191616, 801678336, 373105152, 77776640, 959569536, 289973440, 931009696, 637728720, 822124552, 730017796, 214026262, 257975305 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 570425344, 150994944, 813694976, 985661440, 123731968, 87031808, 382205952, 516161536, 891944960, 255262720, 125992960, 289456128, 203595776, 873680896, 207169536, 56572928, 144014848, 148045568, 607820416, 703528768, 52289056, 808890160, 268513928, 939590524, 872546306, 503513145 + ], + [ + 536870912, 268435456, 134217728, 201326592, 33554432, 385875968, 243269632, 490733568, 488636416, 927989760, 849870848, 1025245184, 561643520, 435486720, 96894976, 161464320, 1060872192, 206843904, 920029184, 1033323520, 834136576, 291797248, 621585536, 32682688, 423322144, 89537808, 626380424, 894766028, 1029072546, 827703239 + ], + [ + 536870912, 805306368, 671088640, 872415232, 1040187392, 654311424, 494927872, 373293056, 983564288, 208666624, 361234432, 443809792, 415891456, 123142144, 871923712, 654065664, 272588800, 542912512, 642627584, 81253376, 851005952, 702477056, 1041070720, 829819968, 390713888, 337031984, 970463912, 944585844, 332720670, 121186071 + ], + [ + 536870912, 805306368, 402653184, 67108864, 637534208, 150994944, 998244352, 641728512, 824180736, 242221056, 894959616, 898891776, 745144320, 1047461888, 265256960, 461193216, 398909440, 583028736, 232986624, 1049711616, 239737344, 278907648, 274140032, 252211264, 1061061152, 971497264, 103936408, 561572676, 979702150, 343128953 + ], + [ + 536870912, 268435456, 939524096, 67108864, 100663296, 83886080, 880803840, 1002438656, 723517440, 126877696, 35127296, 151257088, 458358784, 247005184, 1020755968, 959070208, 382558208, 204328960, 261883904, 26696704, 46801408, 939364608, 82210176, 392305216, 250841120, 501816336, 510476856, 1073561860, 686286214, 761398853 + ], + [ + 536870912, 805306368, 402653184, 335544320, 100663296, 721420288, 327155712, 876609536, 119537664, 651165696, 3670016, 1027866624, 179437568, 72024064, 485326848, 930037760, 657285120, 1041117184, 668792832, 845603840, 274948608, 242369792, 413691776, 56511040, 799283232, 33788976, 83950104, 880906516, 901936518, 509717355 + ], + [ + 536870912, 805306368, 134217728, 67108864, 503316480, 587202560, 58720256, 767557632, 870318080, 860880896, 812122112, 28049408, 1058406400, 806420480, 919306240, 593281024, 940548096, 1013370880, 734758912, 870130688, 508477952, 642161408, 897211264, 333711424, 738791840, 893302640, 161351720, 644670516, 167043606, 801213223 + ], + [ + 536870912, 805306368, 671088640, 872415232, 905969664, 788529152, 327155712, 549453824, 291504128, 491782144, 45613056, 590086144, 249692160, 663945216, 383418368, 16728064, 639197184, 161345536, 659142656, 153504768, 493286912, 994403584, 162919296, 473829056, 91971616, 634318896, 762525736, 793316404, 220698166, 56923439 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 234881024, 654311424, 75497472, 952107008, 463470592, 753926144, 868745216, 73138176, 983433216, 305987584, 273448960, 239550464, 1010540544, 823644160, 922916864, 746689536, 482438656, 698417408, 99839360, 273281088, 941616544, 436121712, 627854776, 259350604, 969987510, 49935467 + ], + [ + 536870912, 805306368, 939524096, 335544320, 838860800, 318767104, 998244352, 381681664, 274726912, 338690048, 628621312, 621019136, 320733184, 296288256, 487358464, 532725760, 618749952, 661753856, 383502336, 1003877376, 471292416, 754384128, 965015680, 1012842944, 1007338144, 920497392, 172749336, 671062308, 1054534282, 668207303 + ], + [ + 536870912, 805306368, 134217728, 335544320, 167772160, 150994944, 411041792, 62914560, 979369984, 617611264, 804782080, 200015872, 997851136, 774832128, 505053184, 92160000, 698490880, 649252864, 388605952, 974515200, 865373696, 81256704, 729108864, 583405504, 846106144, 70836528, 361746824, 497569748, 483700266, 125186361 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 503316480, 587202560, 713031680, 96468992, 761266176, 904921088, 594018304, 1055653888, 452329472, 783482880, 30048256, 528236544, 669786112, 561303552, 82843648, 485209088, 917449216, 987207936, 249762176, 867408960, 407511968, 138195280, 860657688, 669316140, 829000230, 737085727 + ], + [ + 536870912, 268435456, 671088640, 67108864, 704643072, 117440512, 109051904, 406847488, 811597824, 951058432, 526909440, 159121408, 704512000, 146735104, 995983360, 506314752, 99049472, 453709824, 600668160, 496499712, 692288000, 669004032, 661792640, 415948864, 845948832, 663085136, 146384776, 337911892, 564709282, 828125267 + ], + [ + 536870912, 805306368, 402653184, 67108864, 637534208, 486539264, 1031798784, 692060160, 203423744, 63963136, 961019904, 660340736, 456785920, 478609408, 353337344, 20004864, 284745728, 258215936, 188741632, 659039232, 240929280, 414888192, 751100544, 45005504, 916541984, 403801392, 44617880, 627929028, 524360326, 958504685 + ], + [ + 536870912, 805306368, 402653184, 201326592, 369098752, 788529152, 159383552, 650117120, 127926272, 198180864, 141033472, 6553600, 75890688, 137691136, 992772096, 1030766592, 20652032, 625922048, 276940800, 809657344, 820116992, 649261824, 303779200, 752793536, 84602272, 706029552, 809272760, 96064508, 252679086, 425956563 + ], + [ + 536870912, 268435456, 939524096, 603979776, 234881024, 1023410176, 377487360, 692060160, 1000341504, 766509056, 515375104, 530317312, 942800896, 880345088, 134184960, 761282560, 265412608, 15224832, 733423616, 249852928, 491743744, 106640128, 714063744, 414802880, 782051360, 1018262544, 171633208, 434008868, 34856846, 352875517 + ], + [ + 536870912, 805306368, 939524096, 201326592, 167772160, 956301312, 578813952, 817889280, 106954752, 1072693248, 582483968, 319553536, 432668672, 41353216, 790986752, 973979648, 860495872, 112709632, 793233408, 922614784, 175373824, 133761792, 2918784, 219698624, 941504032, 205780784, 966981560, 269524684, 973774762, 798454473 + ], + [ + 536870912, 268435456, 671088640, 201326592, 369098752, 1023410176, 914358272, 834666496, 333447168, 179306496, 820510720, 593231872, 735182848, 26804224, 56000512, 96387072, 199385088, 1051742208, 48834560, 73317376, 911314432, 1004081920, 401996416, 758044608, 576276512, 666364944, 982394408, 222916364, 525210774, 1017877757 + ], + [ + 536870912, 268435456, 939524096, 201326592, 838860800, 184549376, 880803840, 1035993088, 740294656, 328204288, 814219264, 1011089408, 107872256, 259719168, 423526400, 139542528, 967499776, 441716736, 950351872, 610055168, 371273216, 1016263424, 34180480, 881155776, 667698080, 514375120, 215381528, 912529180, 822082442, 175196615 + ], + [ + 536870912, 268435456, 939524096, 469762048, 436207616, 150994944, 209715200, 4194304, 1042284544, 594542592, 275251200, 122421248, 547487744, 506527744, 483098624, 729661440, 292265984, 1070436352, 518080512, 789627904, 540656128, 1054304000, 616984192, 41935040, 233414688, 126652432, 1019398200, 375456796, 961569306, 891025161 + ], + [ + 536870912, 805306368, 134217728, 738197504, 905969664, 184549376, 226492416, 1010827264, 891289600, 774897664, 73924608, 320077824, 168165376, 157089792, 178356224, 863059968, 164175872, 736432128, 1015875584, 907717632, 308268544, 1059206400, 724785024, 652788928, 953647008, 1046968560, 349026728, 289137116, 762257438, 197660695 + ], + [ + 536870912, 805306368, 402653184, 738197504, 973078528, 352321536, 696254464, 406847488, 555745280, 384827392, 608698368, 661913600, 854458368, 539033600, 426934272, 185286656, 383082496, 803008512, 671795200, 542481408, 320787968, 350952704, 902257536, 361151424, 681977248, 475319024, 18702392, 904458268, 172279842, 583310393 + ], + [ + 536870912, 805306368, 134217728, 201326592, 704643072, 956301312, 192937984, 29360128, 899678208, 709885952, 67633152, 444858368, 252313600, 470220800, 726302720, 929546240, 741875712, 712790016, 223647744, 566381568, 94552576, 575760640, 134857344, 814096704, 906674720, 394619184, 713802376, 46473548, 107627018, 779462921 + ], + [ + 536870912, 805306368, 134217728, 738197504, 167772160, 520093696, 75497472, 692060160, 161480704, 537919488, 616038400, 871104512, 532021248, 434700288, 16220160, 1028145152, 526737408, 305385472, 426276864, 1068956672, 703282688, 150303488, 290041472, 358901568, 221278368, 501908592, 385140264, 541839132, 686289026, 905102451 + ], + [ + 536870912, 268435456, 939524096, 603979776, 369098752, 285212672, 998244352, 650117120, 60817408, 326107136, 236453888, 619970560, 748290048, 901054464, 66682880, 107429888, 571531264, 550129664, 882726912, 267860992, 471458304, 871680768, 1041802112, 217527360, 815522336, 129354512, 83567544, 753235044, 1062371894, 94952193 + ], + [ + 536870912, 268435456, 134217728, 201326592, 301989888, 452984832, 394264576, 457179136, 627048448, 288358400, 421003264, 141295616, 901120000, 536543232, 69042176, 80625664, 338092032, 762515456, 570001408, 488483840, 5091840, 350596352, 22183552, 246074688, 45370528, 175775824, 207442472, 976076060, 206993050, 168370519 + ], + [ + 536870912, 268435456, 402653184, 67108864, 570425344, 285212672, 1031798784, 499122176, 727711744, 779091968, 206045184, 509870080, 960888832, 261554176, 701399040, 521322496, 658169856, 363786240, 803383296, 36713472, 82321920, 745936128, 368929152, 754672576, 97454496, 823153616, 138002872, 522999764, 1017228186, 403736261 + ], + [ + 536870912, 805306368, 939524096, 67108864, 167772160, 184549376, 176160768, 364904448, 123731968, 619708416, 311951360, 915668992, 461242368, 590413824, 720928768, 719831040, 321314816, 306515968, 196515840, 380580864, 1048267264, 908519680, 700849792, 670491840, 177065120, 36321776, 204347416, 599323700, 222669362, 53999887 + ], + [ + 536870912, 268435456, 402653184, 335544320, 100663296, 50331648, 679477248, 884998144, 832569344, 407896064, 434634752, 613679104, 150339584, 143065088, 142508032, 266584064, 271687680, 395874304, 728733696, 904631296, 647491072, 368368384, 923143552, 306161856, 159460768, 289470672, 585176504, 665910468, 31056830, 1057977287 + ], + [ + 536870912, 805306368, 671088640, 67108864, 704643072, 150994944, 461373440, 834666496, 513802240, 865075200, 875036672, 826015744, 467271680, 581369856, 723288064, 1024016384, 762257408, 978341888, 914905088, 78621696, 150110720, 723008768, 327656576, 726546624, 444693024, 507674928, 761290408, 540211652, 909804682, 1037396217 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 33554432, 419430400, 545259520, 650117120, 585105408, 68157440, 876085248, 440139776, 253886464, 661848064, 40402944, 338149376, 686694400, 569937920, 224233472, 124988416, 845860352, 472215808, 351083392, 603514816, 341745696, 670257200, 346662920, 1053080636, 285066754, 398630169 + ], + [ + 536870912, 805306368, 134217728, 201326592, 838860800, 1023410176, 679477248, 734003200, 249561088, 309329920, 554172416, 825491456, 991297536, 33882112, 977108992, 52510720, 663773184, 284733440, 276740096, 142787584, 465570304, 115440896, 510764416, 319548096, 204752288, 328604400, 700751272, 886927100, 290566042, 110794689 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 301989888, 50331648, 528482304, 1002438656, 962592768, 271581184, 1060634624, 813957120, 608043008, 293273600, 891781120, 351223808, 682745856, 226136064, 925140992, 1072604160, 187841024, 616094976, 222688384, 811348416, 264883872, 761261264, 961264136, 505191724, 174822586, 495837695 + ], + [ + 536870912, 268435456, 939524096, 335544320, 167772160, 788529152, 494927872, 574619648, 1038090240, 122683392, 379060224, 422838272, 71958528, 300744704, 110985216, 603340800, 963125248, 748498944, 485865472, 485110784, 450811392, 722843904, 884714368, 298110016, 274820640, 219319568, 125369784, 6763860, 936568234, 979071359 + ], + [ + 536870912, 268435456, 134217728, 603979776, 570425344, 721420288, 25165824, 901775360, 828375040, 533725184, 421003264, 420741120, 1071251456, 368377856, 466255872, 277823488, 361537536, 688910336, 474855424, 376187904, 782036480, 133689600, 684445568, 1024227392, 642674208, 292335888, 689794952, 993429604, 858347010, 379575611 + ], + [ + 536870912, 268435456, 402653184, 872415232, 838860800, 754974720, 41943040, 440401920, 828375040, 556793856, 818413568, 714342400, 354287616, 678100992, 738492416, 482656256, 199712768, 95907840, 1062156288, 949185536, 853049856, 638459136, 678437760, 942395328, 342106528, 359994064, 946692664, 784510244, 1008925610, 332403673 + ], + [ + 536870912, 268435456, 939524096, 67108864, 167772160, 352321536, 142606336, 641728512, 178257920, 523239424, 2621440, 743702528, 481165312, 650313728, 14843904, 596885504, 68739072, 1006497792, 188471296, 504359936, 368266752, 919083264, 348574080, 255186880, 654059424, 800592592, 239894552, 72400916, 1048207410, 791556113 + ], + [ + 536870912, 805306368, 402653184, 469762048, 167772160, 150994944, 931135488, 910163968, 543162368, 617611264, 374865920, 794558464, 866779136, 1027014656, 683638784, 154714112, 252583936, 892522496, 801708032, 602330112, 803614208, 233304320, 14948224, 560236224, 338073120, 180827440, 802619800, 799831004, 71317418, 90265337 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 167772160, 318767104, 931135488, 759169024, 627048448, 393216000, 661127168, 424411136, 948043776, 549650432, 589529088, 965984256, 391684096, 138752000, 20805632, 309056512, 1070519808, 893597440, 694294144, 628327616, 141164576, 617545776, 113344568, 841007164, 420683786, 1000009747 + ], + [ + 536870912, 268435456, 134217728, 335544320, 167772160, 1023410176, 511705088, 314572800, 383778816, 263192576, 258473984, 626262016, 603062272, 457768960, 872710144, 925581312, 997564416, 262230016, 286369792, 116984832, 443547136, 318747392, 1027934848, 562647872, 652683296, 983256080, 488562184, 1047896852, 488702602, 366022525 + ], + [ + 536870912, 268435456, 939524096, 469762048, 570425344, 889192448, 981467136, 247463936, 769654784, 458227712, 967311360, 655622144, 674627584, 344391680, 662470656, 1027686400, 731996160, 896741376, 698030080, 690893824, 778619392, 980758272, 749051264, 72106176, 49839520, 247345360, 924976536, 548615372, 301586362, 792473593 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 369098752, 721420288, 796917760, 792723456, 484442112, 1039138816, 443023360, 444858368, 175505408, 211615744, 47939584, 286146560, 25305088, 541265920, 828614656, 330398720, 336110080, 213275904, 205475712, 407381440, 869590944, 546134512, 163726728, 757206220, 886082078, 750348583 + ], + [ + 536870912, 268435456, 402653184, 67108864, 704643072, 184549376, 545259520, 255852544, 555745280, 196083712, 695730176, 810287104, 26345472, 306774016, 242581504, 352206848, 845783040, 1044656128, 172345344, 675615744, 1061585408, 834978560, 528747392, 354759360, 827615264, 911025168, 747719192, 264820484, 79104426, 991932875 + ], + [ + 536870912, 805306368, 134217728, 738197504, 1040187392, 889192448, 142606336, 247463936, 85983232, 349175808, 755499008, 760479744, 1019346944, 1042481152, 558923776, 122339328, 414703616, 405884928, 259753984, 801926144, 335319552, 243772672, 709361792, 70720832, 217088032, 760922160, 950001672, 229986348, 548505662, 163277877 + ], + [ + 536870912, 268435456, 402653184, 67108864, 100663296, 452984832, 293601280, 977272832, 65011712, 439353344, 1061683200, 356777984, 230817792, 849412096, 273776640, 456671232, 804020224, 431468544, 296359936, 234300416, 88866304, 474252032, 423732352, 107002944, 1047756832, 598294544, 418766872, 332132356, 897873926, 1038193691 + ], + [ + 536870912, 805306368, 402653184, 738197504, 973078528, 385875968, 612368384, 113246208, 765460480, 846200832, 543686656, 760479744, 1042415616, 540213248, 319389696, 512147456, 372875264, 974024704, 620611584, 106408960, 144833024, 99751680, 203992704, 121022784, 678666272, 124350512, 299255832, 350383148, 932305466, 914007831 + ], + [ + 536870912, 805306368, 939524096, 201326592, 436207616, 117440512, 159383552, 775946240, 429916160, 219152384, 856162304, 189005824, 940703744, 965410816, 42434560, 519225344, 968531968, 476049408, 417224704, 807289856, 981428736, 378407168, 741749888, 401260096, 813062176, 222970928, 451242552, 16845068, 478393498, 348356167 + ], + [ + 536870912, 268435456, 939524096, 872415232, 704643072, 587202560, 327155712, 46137344, 526385152, 498073600, 283639808, 734265344, 848166912, 563806208, 89030656, 947568640, 213704704, 464588800, 1038698496, 155464704, 885959168, 95991040, 643582336, 968998080, 685802400, 225630672, 411656728, 267796772, 61211538, 112990679 + ], + [ + 536870912, 805306368, 671088640, 603979776, 704643072, 251658240, 343932928, 910163968, 23068672, 602931200, 405274624, 765722624, 851836928, 741670912, 597655552, 586792960, 35479552, 389582848, 767449088, 233372672, 839354880, 1451264, 395280256, 73472448, 141696928, 317295088, 1048856456, 978679252, 418237858, 43143387 + ], + [ + 536870912, 805306368, 402653184, 469762048, 1040187392, 956301312, 1048576000, 4194304, 161480704, 36700160, 980942848, 633602048, 5636096, 689766400, 203456512, 200491008, 740007936, 211136512, 268277760, 70351872, 796521984, 1027931392, 622280320, 540846272, 928056992, 111699184, 195913912, 1058661868, 18194438, 842838037 + ], + [ + 536870912, 268435456, 402653184, 201326592, 771751936, 285212672, 192937984, 339738624, 505413632, 783286272, 651689984, 611057664, 171573248, 758972416, 221478912, 916045824, 5201920, 395038720, 1063737344, 664785920, 1027774976, 161599232, 217309056, 637154752, 794589728, 698539792, 485648280, 1039856076, 593319950, 128111617 + ], + [ + 536870912, 805306368, 671088640, 872415232, 771751936, 889192448, 713031680, 448790528, 677380096, 451936256, 129499136, 994312192, 49676288, 745340928, 335249408, 1072087040, 426057728, 27783168, 784635904, 833917952, 491758080, 187430144, 185502336, 143332544, 354390688, 234897648, 83923080, 42173892, 784474662, 106968369 + ], + [ + 536870912, 805306368, 134217728, 67108864, 637534208, 587202560, 142606336, 381681664, 580911104, 1060110336, 931659776, 14417920, 672792576, 1030160384, 1020166144, 266420224, 1003610112, 819654656, 147236864, 629095424, 162107904, 925734656, 305331840, 671675584, 815716896, 997743408, 242599048, 28729284, 311932550, 988166355 + ], + [ + 536870912, 805306368, 939524096, 738197504, 704643072, 318767104, 494927872, 1044381696, 501219328, 923795456, 227016704, 983302144, 888274944, 530251776, 731348992, 313311232, 1061920768, 868069376, 63084544, 329286656, 317836800, 379148544, 487867520, 493790144, 921253920, 172831792, 618354232, 452320556, 25135786, 182516435 + ], + [ + 536870912, 268435456, 402653184, 603979776, 436207616, 318767104, 25165824, 910163968, 417333248, 680525824, 125304832, 578551808, 189923328, 1004077056, 1024294912, 456671232, 563912704, 507686912, 887314432, 244532224, 712703488, 721367296, 797975424, 351973824, 993843232, 741475344, 738975256, 806732068, 639097754, 51856851 + ], + [ + 536870912, 268435456, 939524096, 603979776, 503316480, 687865856, 897581056, 1027604480, 346030080, 628097024, 411566080, 1038876672, 1966080, 509018112, 458784768, 991215616, 1006247936, 946089984, 779200512, 772365312, 976201216, 293476608, 960966016, 641844544, 438338976, 112433488, 401187736, 872300660, 142880262, 35878173 + ], + [ + 536870912, 805306368, 134217728, 738197504, 905969664, 553648128, 226492416, 499122176, 702545920, 955252736, 571998208, 30146560, 755630080, 640090112, 1029603328, 438550528, 605085696, 90722304, 85293056, 531016704, 43865600, 12782336, 710943616, 540028352, 477679136, 872281904, 175115656, 257526508, 107985814, 752472529 + ], + [ + 536870912, 268435456, 939524096, 67108864, 637534208, 822083584, 629145600, 364904448, 786432000, 684720128, 655884288, 648282112, 872022016, 225771520, 509706240, 781271040, 356114432, 18305024, 267532288, 321604608, 107951616, 583373056, 241827712, 718108480, 506910240, 1069728016, 367249336, 642923332, 73129990, 788942881 + ], + [ + 536870912, 268435456, 402653184, 603979776, 1040187392, 687865856, 243269632, 1010827264, 467664896, 617611264, 449314816, 659816448, 597557248, 1036713984, 148144128, 761118720, 6987776, 551940096, 885504000, 255167488, 59607552, 362892032, 70380928, 463147968, 1012688800, 988436688, 983927352, 572869428, 459795878, 201593805 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 234881024, 553648128, 595591168, 859832320, 987758592, 53477376, 251133952, 452198400, 585236480, 120651776, 351961088, 167231488, 778231808, 921899008, 1054390272, 56947712, 424234496, 567223040, 137779072, 1010981696, 677568544, 1005785104, 995670056, 757396540, 237587982, 817832737 + ], + [ + 536870912, 268435456, 402653184, 335544320, 570425344, 855638016, 478150656, 666894336, 471859200, 472907776, 702021632, 11272192, 793116672, 825425920, 945324032, 653049856, 220553216, 459411456, 433223680, 885748736, 751099392, 745738496, 179873408, 494707520, 562954400, 989120080, 715814968, 949449732, 284876346, 18616615 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 369098752, 218103808, 411041792, 46137344, 165675008, 569376768, 955777024, 1021575168, 354025472, 253165568, 48398336, 208715776, 381280256, 499585024, 638248960, 60816384, 482317824, 783086336, 614986112, 154878272, 747009568, 816571184, 231545224, 412401020, 262266934, 215158845 + ], + [ + 536870912, 805306368, 939524096, 603979776, 234881024, 318767104, 75497472, 356515840, 157286400, 963641344, 881328128, 528220160, 548274176, 712310784, 689078272, 612024320, 288694272, 57774080, 562731008, 352300032, 460179968, 727168256, 243530112, 943956032, 652263840, 213015664, 648557464, 1013781844, 702003222, 348273671 + ], + [ + 536870912, 268435456, 402653184, 201326592, 1040187392, 285212672, 864026624, 130023424, 379584512, 498073600, 913833984, 983826432, 210108416, 41353216, 334397440, 605700096, 1027055616, 437104640, 541722624, 387789824, 109084160, 239195392, 710990464, 462591168, 814316192, 1060906192, 158593720, 878203100, 374647942, 706573773 + ], + [ + 536870912, 805306368, 402653184, 67108864, 503316480, 16777216, 1031798784, 297795584, 316669952, 389021696, 718798848, 833880064, 382861312, 862650368, 875397120, 46546944, 321445888, 84840448, 68425728, 138525696, 757227008, 483621632, 74041728, 347003200, 881129504, 252390448, 1012680216, 364758788, 269227934, 261415489 + ], + [ + 536870912, 805306368, 402653184, 469762048, 503316480, 721420288, 696254464, 1069547520, 631242752, 800063488, 786956288, 682885120, 294518784, 415301632, 975339520, 1064321024, 549986304, 231165952, 407250944, 159671296, 522528256, 85319936, 171750784, 740980160, 999627680, 847044848, 88768568, 67387436, 317071366, 230051895 + ], + [ + 536870912, 268435456, 671088640, 335544320, 1040187392, 989855744, 293601280, 213909504, 73400320, 904921088, 412614656, 747896832, 1045823488, 288817152, 491094016, 488423424, 199958528, 995004416, 593528832, 510772224, 962281984, 376716544, 686204032, 973874624, 298001568, 48293328, 716178568, 20608452, 159812790, 897364479 + ], + [ + 536870912, 268435456, 939524096, 603979776, 234881024, 587202560, 1048576000, 767557632, 752877568, 554696704, 858259456, 142868480, 1071775744, 932249600, 48988160, 241582080, 871555072, 423309312, 422340608, 816225280, 160509440, 166371584, 753212032, 875754560, 416997408, 633286672, 281962552, 3644452, 1006284302, 156033315 + ], + [ + 536870912, 805306368, 671088640, 469762048, 503316480, 1023410176, 847249408, 306184192, 769654784, 282066944, 189267968, 358350848, 241827840, 372178944, 235962368, 971685888, 854548480, 464523264, 1004128256, 955544576, 409351680, 768395520, 264387200, 908275904, 351524384, 347674928, 308548264, 583898332, 910379070, 937538573 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 436207616, 184549376, 243269632, 297795584, 840957952, 623902720, 1041760256, 487849984, 697958400, 89587712, 922255360, 881115136, 191963136, 678981632, 1028114432, 760245248, 726231552, 308117248, 902163328, 496123456, 887843360, 338591536, 843017128, 479592060, 148425274, 599117627 + ], + [ + 536870912, 268435456, 671088640, 872415232, 1040187392, 989855744, 763363328, 515899392, 488636416, 737148928, 345505792, 860094464, 386269184, 191299584, 980779008, 79609856, 1053892608, 459837440, 836716544, 725754880, 266581504, 349268224, 241848448, 257891520, 738316448, 839048400, 419655816, 478383332, 910203062, 358873311 + ], + [ + 536870912, 805306368, 939524096, 335544320, 771751936, 687865856, 1048576000, 624951296, 81788928, 967835648, 338165760, 56360960, 201719808, 206635008, 924352512, 607567872, 918134784, 694644736, 589363200, 705952768, 41646592, 54789376, 129094016, 891990848, 299684768, 323390064, 263280664, 422087716, 735937046, 340195645 + ], + [ + 536870912, 805306368, 939524096, 603979776, 637534208, 16777216, 729808896, 373293056, 291504128, 776994816, 276299776, 524550144, 912130048, 726204416, 929857536, 6537216, 231940096, 440004608, 203745280, 1057995776, 296837632, 367643392, 824133248, 430687680, 326960288, 58457840, 466004504, 379553556, 99273886, 958247653 + ], + [ + 536870912, 805306368, 134217728, 469762048, 1040187392, 352321536, 427819008, 884998144, 216006656, 588251136, 369623040, 732692480, 463863808, 17367040, 690978816, 736575488, 1017847808, 203239424, 119506944, 1000207360, 517779968, 989755136, 722347392, 186034240, 791844768, 737730416, 1035252264, 914519852, 574629302, 514041929 + ], + [ + 536870912, 805306368, 402653184, 738197504, 838860800, 452984832, 260046848, 130023424, 748683264, 623902720, 637009920, 963379200, 252837888, 596312064, 544571392, 338477056, 854728704, 559624192, 677361664, 887856128, 870799872, 1004837632, 1071979392, 971407552, 1021810720, 443001904, 153575960, 767870764, 597156274, 268364763 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 905969664, 553648128, 1031798784, 666894336, 1029701632, 894435328, 758644736, 606339072, 220332032, 686882816, 25919488, 437239808, 681402368, 684003328, 28530688, 497761280, 662500864, 181921024, 95124352, 192902720, 81059872, 413913104, 16627768, 34991164, 407424566, 309119265 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 436207616, 251658240, 780140544, 759169024, 1008730112, 542113792, 122159104, 514064384, 442368000, 948109312, 541163520, 698564608, 93478912, 53039104, 592844800, 1048984576, 806229504, 952780544, 744763776, 79527616, 238149536, 767038928, 553517096, 429064236, 153714706, 609697843 + ], + [ + 536870912, 268435456, 402653184, 738197504, 33554432, 117440512, 696254464, 1061158912, 937426944, 907018240, 495452160, 573833216, 512884736, 709427200, 840269824, 547405824, 636559360, 496627712, 381442048, 270914560, 622333440, 964524288, 738684032, 422100288, 835082272, 705221648, 276270616, 871414060, 614059138, 574393671 + ], + [ + 536870912, 268435456, 134217728, 335544320, 100663296, 553648128, 662700032, 943718400, 769654784, 294649856, 308805632, 537657344, 299499520, 643104768, 399409152, 8011776, 338026496, 557174784, 329013248, 1018328064, 484079104, 198526208, 344804480, 958058432, 1031228960, 545104144, 270533256, 993160916, 882494630, 775262193 + ], + [ + 536870912, 268435456, 939524096, 335544320, 33554432, 218103808, 260046848, 1061158912, 111149056, 613416960, 882376704, 786694144, 209846272, 1002504192, 23298048, 200359936, 610803712, 168611840, 995031040, 921498624, 721218048, 933726464, 757246336, 835837504, 322568224, 334823440, 140083256, 285491220, 431071234, 1028165645 + ], + [ + 536870912, 268435456, 134217728, 335544320, 838860800, 956301312, 310378496, 88080384, 354418688, 177209344, 998768640, 671350784, 1032978432, 638124032, 1019510784, 309542912, 477765632, 616501248, 214853632, 1035236352, 965296640, 151339264, 856886400, 88810048, 585525280, 861959184, 808665608, 483934484, 787319986, 715481721 + ], + [ + 536870912, 805306368, 939524096, 872415232, 503316480, 989855744, 343932928, 155189248, 148897792, 277872640, 671612928, 459014144, 758775808, 86441984, 234717184, 1003110400, 704471040, 768176128, 519890944, 323699712, 851326464, 875083008, 1072523904, 495000256, 1019362848, 136364336, 179492024, 867933172, 426085054, 312355531 + ], + [ + 536870912, 268435456, 939524096, 67108864, 167772160, 251658240, 796917760, 515899392, 585105408, 269484032, 491257856, 941359104, 555089920, 766181376, 856588288, 568180736, 7856128, 360239104, 228902912, 592606208, 40555008, 325977856, 864907648, 10276672, 72819616, 596117584, 184365592, 151443220, 887208370, 18004811 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 100663296, 1056964608, 444596224, 482344960, 1067450368, 244318208, 823656448, 313262080, 206438400, 1061093376, 836075520, 642924544, 616046592, 222220288, 618133504, 768668672, 570158592, 853423872, 908357248, 930723904, 270519968, 579217488, 426481288, 80039020, 705306766, 502734675 + ], + [ + 536870912, 805306368, 939524096, 335544320, 771751936, 419430400, 914358272, 515899392, 429916160, 617611264, 429391872, 1069809664, 779747328, 427229184, 1041334272, 641351680, 773152768, 996331520, 259164160, 642513920, 870298112, 251609344, 535597952, 844388672, 570511904, 318820656, 964885432, 625161556, 534972430, 984726569 + ], + [ + 536870912, 268435456, 939524096, 335544320, 503316480, 285212672, 528482304, 390070272, 18874368, 108003328, 246939648, 386138112, 270401536, 480968704, 770605056, 860930048, 113876992, 817852416, 211527680, 99904512, 560330240, 122670336, 744528000, 542333376, 709545632, 461169872, 511278616, 90444036, 827287206, 291735749 + ], + [ + 536870912, 805306368, 402653184, 335544320, 1040187392, 385875968, 125829120, 1010827264, 543162368, 781189120, 11010048, 554958848, 70123520, 537985024, 476741632, 582270976, 580689920, 273387520, 71796736, 10845184, 469131776, 142540544, 874130304, 474843072, 713277856, 985793776, 10586168, 523271204, 454746662, 1070546691 + ], + [ + 536870912, 805306368, 134217728, 67108864, 637534208, 486539264, 947912704, 130023424, 610271232, 250609664, 691535872, 152305664, 891158528, 726728704, 782991360, 509394944, 384835584, 356036608, 588699648, 169718784, 684808704, 216594688, 92091520, 1000496832, 378615456, 231461872, 523073576, 1065993268, 1007657518, 517602585 + ], + [ + 536870912, 268435456, 402653184, 469762048, 503316480, 1023410176, 612368384, 281018368, 585105408, 506462208, 279445504, 871104512, 149028864, 691077120, 321486848, 950910976, 1027858432, 480432128, 185845760, 939052032, 708300288, 275200, 447496832, 239121088, 488890400, 592629776, 467388440, 736414748, 706596382, 690565949 + ], + [ + 536870912, 805306368, 402653184, 872415232, 838860800, 318767104, 645922816, 532676608, 195035136, 200278016, 250085376, 202113024, 280363008, 983629824, 376602624, 464175104, 510418944, 837029888, 171595776, 768939008, 326206976, 875259136, 405782912, 84293184, 883457952, 384587632, 589586488, 840437764, 1046763562, 1014502439 + ], + [ + 536870912, 268435456, 402653184, 738197504, 905969664, 553648128, 1048576000, 952107008, 383778816, 892338176, 14155776, 33816576, 566624256, 245825536, 81166336, 950812672, 398139392, 880226304, 868210688, 749786112, 798554624, 648481024, 550892672, 984607936, 750482592, 502770896, 352212152, 1007918332, 881396878, 95160541 + ], + [ + 536870912, 805306368, 402653184, 603979776, 973078528, 1023410176, 176160768, 20971520, 262144000, 569376768, 505937920, 219938816, 34734080, 318439424, 260407296, 8667136, 990289920, 919031808, 455501824, 955610112, 837700096, 649594624, 111537792, 641017792, 160253984, 397042736, 836534808, 594617124, 325602490, 79435005 + ], + [ + 536870912, 268435456, 402653184, 603979776, 33554432, 822083584, 864026624, 834666496, 106954752, 32505856, 640155648, 436994048, 596246528, 614268928, 198410240, 259735552, 120954880, 186601472, 202381312, 572034048, 541367808, 762798848, 280900736, 897783744, 314752544, 484668176, 666078360, 327732196, 748435490, 936483873 + ], + [ + 536870912, 268435456, 134217728, 201326592, 100663296, 218103808, 746586112, 230686720, 958398464, 363855872, 58195968, 298057728, 199622656, 601292800, 267354112, 734740480, 641540096, 333639680, 454277120, 847913984, 115185152, 1030929664, 182186624, 129346240, 817812128, 220420816, 129198760, 209354460, 977763502, 564429777 + ], + [ + 536870912, 805306368, 402653184, 335544320, 1040187392, 956301312, 478150656, 197132288, 887095296, 821035008, 301465600, 65798144, 435814400, 1072627712, 737902592, 753811456, 813195264, 44945408, 333031424, 226323456, 103998976, 798647040, 232651136, 174284224, 3335712, 848978736, 928905624, 748903892, 374531614, 816472841 + ], + [ + 536870912, 268435456, 939524096, 67108864, 838860800, 855638016, 260046848, 1019215872, 270532608, 36700160, 588775424, 1002700800, 14548992, 790298624, 633765888, 1037942784, 630743040, 394694656, 767428608, 80434176, 441212416, 661858560, 519784064, 760533952, 381098144, 690485968, 1070358040, 1018374420, 190531210, 614781943 + ], + [ + 536870912, 805306368, 134217728, 335544320, 838860800, 989855744, 796917760, 314572800, 912261120, 439353344, 954728448, 104071168, 215351296, 262471680, 703430656, 747159552, 520478720, 129978368, 1028794368, 442024960, 765379072, 859926784, 161740672, 47243456, 815273888, 134131952, 259112872, 944485604, 275193242, 17651167 + ], + [ + 536870912, 805306368, 939524096, 67108864, 1040187392, 520093696, 360710144, 734003200, 996147200, 881852416, 1017643008, 161218560, 753532928, 239009792, 177831936, 398934016, 634281984, 211857408, 99760128, 288918528, 1001737728, 624289024, 762696832, 517387456, 1051119136, 1012770096, 948581560, 388842692, 435197470, 456825135 + ], + [ + 536870912, 805306368, 671088640, 738197504, 369098752, 587202560, 796917760, 624951296, 648019968, 97517568, 844627968, 644612096, 318111744, 293142528, 738033664, 244203520, 33988608, 1034997760, 376145920, 105221120, 898870784, 678993664, 25126016, 256853312, 40323744, 763402864, 608374280, 941707036, 370240702, 725125455 + ], + [ + 536870912, 268435456, 939524096, 872415232, 771751936, 352321536, 578813952, 616562688, 278921216, 458227712, 105381888, 940834816, 617742336, 470351872, 779583488, 539049984, 412344320, 57331712, 704997376, 259697664, 1017993728, 22945024, 759588992, 664333120, 1050634272, 443001872, 42523192, 951475508, 125962414, 776174421 + ], + [ + 536870912, 268435456, 134217728, 67108864, 838860800, 788529152, 998244352, 440401920, 882900992, 632291328, 354942976, 28573696, 614858752, 1044316160, 161710080, 556908544, 1022091264, 727027712, 129263616, 564653056, 650040832, 509834496, 315794304, 964297408, 973941664, 1036549840, 363304360, 213706708, 1029955610, 525439035 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 704643072, 654311424, 209715200, 20971520, 769654784, 405798912, 618135552, 1050935296, 546701312, 827129856, 275349504, 725368832, 1003741184, 904400896, 805083136, 586378240, 1023123968, 1043708160, 664541312, 1040421056, 16810144, 159448304, 381887144, 169952716, 328284674, 495703339 + ], + [ + 536870912, 805306368, 939524096, 201326592, 1040187392, 486539264, 142606336, 1035993088, 589299712, 573571072, 336068608, 26476544, 170786816, 787546112, 833126400, 996622336, 965025792, 244789248, 296736768, 1051792384, 734678528, 968188160, 832510848, 834223552, 870092192, 953698544, 479156248, 159536188, 54619654, 937644305 + ], + [ + 536870912, 805306368, 134217728, 335544320, 637534208, 117440512, 92274688, 432013312, 48234496, 598736896, 186122240, 18087936, 441319424, 175702016, 208109568, 506970112, 622731264, 970166272, 837478400, 1034839040, 893968896, 4152576, 864140928, 650316480, 459332768, 141727728, 687391272, 539348260, 219469486, 273592019 + ], + [ + 536870912, 805306368, 671088640, 603979776, 973078528, 855638016, 444596224, 457179136, 115343360, 594542592, 247988224, 796655616, 362938368, 831717376, 1069187072, 917913600, 442343424, 208809984, 306718720, 826110976, 616795648, 438413056, 89191552, 1033415616, 1072111648, 969175088, 982878248, 34554916, 174827066, 996987699 + ], + [ + 536870912, 805306368, 671088640, 469762048, 369098752, 654311424, 964689920, 742391808, 320864256, 47185920, 946339840, 859570176, 694812672, 499056640, 346587136, 1054785536, 324657152, 593801216, 562984960, 359691264, 108677632, 515365120, 342330496, 1034944, 221399584, 526113072, 761629864, 848087772, 653314614, 456792343 + ], + [ + 536870912, 268435456, 939524096, 738197504, 1040187392, 520093696, 377487360, 750780416, 18874368, 776994816, 379060224, 205783040, 560070656, 649134080, 443252736, 63881216, 568188928, 27717632, 504489984, 645565440, 750170624, 283653376, 957288832, 738136128, 729047072, 88682512, 580880440, 432454700, 220248638, 5327135 + ], + [ + 536870912, 805306368, 402653184, 872415232, 704643072, 251658240, 478150656, 817889280, 790626304, 680525824, 684195840, 1025769472, 199098368, 635502592, 548569088, 819642368, 992862208, 1020809216, 355350528, 31015936, 850247168, 127490816, 575452544, 480884416, 315937696, 644151792, 213868600, 546476036, 885774386, 992285755 + ], + [ + 536870912, 268435456, 402653184, 201326592, 838860800, 318767104, 578813952, 281018368, 136314880, 812646400, 629669888, 787218432, 83755008, 434569216, 852656128, 20463616, 625369088, 929091584, 990984192, 614175744, 225928704, 353085696, 1026420096, 912136512, 894842272, 762977616, 212110264, 649244764, 279533578, 85738511 + ], + [ + 536870912, 805306368, 939524096, 201326592, 167772160, 922746880, 713031680, 1027604480, 962592768, 571473920, 105381888, 697040896, 193069056, 583204864, 765689856, 179355648, 494444544, 691499008, 294955008, 44487680, 907875840, 705192192, 929858688, 827328704, 103415840, 673120304, 722042936, 418365452, 496050186, 579383351 + ], + [ + 536870912, 805306368, 939524096, 335544320, 301989888, 318767104, 293601280, 339738624, 505413632, 204472320, 1017643008, 968622080, 859963392, 369164288, 151093248, 780255232, 62955520, 190877696, 277911552, 894995456, 259301888, 418312448, 366698880, 437609792, 763334112, 134478352, 396361736, 1013973004, 143130638, 848035845 + ], + [ + 536870912, 268435456, 402653184, 201326592, 369098752, 218103808, 1015021568, 465567744, 236978176, 867172352, 594018304, 163315712, 58589184, 866582528, 158564352, 464601088, 661135360, 196874240, 343848960, 338050048, 590533120, 852495104, 20517504, 356837312, 219837216, 1032679760, 441850152, 192628308, 543021486, 552577687 + ], + [ + 536870912, 268435456, 402653184, 603979776, 704643072, 721420288, 427819008, 624951296, 815792128, 934281216, 344457216, 1066663936, 775553024, 662241280, 960266240, 48152576, 740958208, 213962752, 501291008, 990981120, 758733312, 706579712, 590227840, 897729088, 195351456, 1022560592, 231522824, 200696068, 9393030, 800202569 + ], + [ + 536870912, 805306368, 402653184, 603979776, 905969664, 687865856, 125829120, 566231040, 731906048, 521142272, 556269568, 181141504, 191234048, 19988480, 821657600, 918863872, 486219776, 387887104, 649447424, 887323648, 556527104, 286739712, 304627840, 508304704, 237450336, 936431664, 1023993864, 740084748, 636462598, 585953545 + ], + [ + 536870912, 805306368, 671088640, 335544320, 570425344, 654311424, 327155712, 943718400, 421527552, 544210944, 465043456, 123469824, 706084864, 339542016, 742883328, 7618560, 1055072256, 824135680, 339286016, 958221312, 506927616, 348972288, 1044343168, 21622976, 1042630496, 648730224, 1035717000, 877846732, 88571754, 452250229 + ], + [ + 536870912, 805306368, 402653184, 335544320, 1040187392, 654311424, 947912704, 398458880, 916455424, 521142272, 382205952, 87818240, 813039616, 149356544, 359563264, 389169152, 1039458304, 977932288, 202483712, 541600768, 771584512, 710366976, 1043777408, 302448064, 899569184, 210483856, 20053544, 907581084, 693373998, 5931417 + ], + [ + 536870912, 805306368, 939524096, 603979776, 1040187392, 520093696, 360710144, 12582912, 182452224, 751828992, 1049100288, 921960448, 855506944, 20512768, 913145856, 224641024, 962732032, 258174976, 207861760, 65195008, 572757504, 574832384, 466788992, 796538432, 1069425312, 521757808, 375131656, 607879948, 446631054, 346555721 + ], + [ + 536870912, 268435456, 402653184, 67108864, 570425344, 285212672, 75497472, 1027604480, 94371840, 508559360, 452460544, 315883520, 280363008, 853213184, 312049664, 509886464, 482271232, 103165952, 71440384, 1056828416, 198946304, 437860096, 489023360, 773806400, 804661088, 914055184, 273280744, 1037913684, 701156878, 432031493 + ], + [ + 536870912, 268435456, 134217728, 469762048, 637534208, 1056964608, 226492416, 1010827264, 748683264, 149946368, 508035072, 947650560, 170786816, 139395072, 232751104, 59228160, 501424128, 520622080, 73197568, 1042154496, 241608192, 959685376, 1030788224, 638090944, 651976992, 132016720, 42385704, 996325972, 348686634, 230452819 + ], + [ + 536870912, 805306368, 671088640, 469762048, 167772160, 419430400, 394264576, 473956352, 799014912, 233832448, 455606272, 1033633792, 866516992, 761331712, 831619072, 288964608, 316989440, 199380992, 921946112, 420101120, 227484160, 1031560448, 796270464, 410575168, 952412384, 928127792, 66805768, 640028684, 69249034, 732965895 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 369098752, 587202560, 511705088, 859832320, 970981376, 347078656, 179830784, 371458048, 851836928, 756088832, 560562176, 795688960, 1035722752, 675524608, 159881216, 418460672, 198752768, 987094784, 589229440, 180619712, 66537248, 510228272, 401471496, 100385804, 857915914, 947280655 + ], + [ + 536870912, 268435456, 402653184, 335544320, 100663296, 721420288, 562036736, 264241152, 102760448, 164626432, 955777024, 354680832, 66453504, 693567488, 902266880, 1029652480, 1011605504, 246796288, 686786560, 310576128, 530135552, 982805248, 473838976, 955996736, 821921632, 914561744, 295200616, 496356052, 801009518, 440045265 + ], + [ + 536870912, 268435456, 671088640, 335544320, 838860800, 150994944, 109051904, 843055104, 824180736, 768606208, 275251200, 156499968, 243138560, 134152192, 406814720, 1021231104, 15622144, 204992512, 16496640, 1021938688, 504700416, 937301760, 930036096, 83335872, 630915168, 454663056, 741146728, 438475668, 858030178, 294083473 + ], + [ + 536870912, 805306368, 939524096, 872415232, 838860800, 654311424, 92274688, 1010827264, 736100352, 714080256, 769130496, 917766144, 925761536, 15269888, 303923200, 181649408, 715825152, 107941888, 227047424, 189647872, 598348288, 720328448, 759779456, 946723008, 236668064, 411525360, 244664840, 689851148, 599890574, 211833805 + ], + [ + 536870912, 805306368, 939524096, 469762048, 100663296, 1023410176, 411041792, 851443712, 312475648, 600834048, 159907840, 355205120, 160563200, 504430592, 749305856, 62767104, 536535040, 722284544, 176318464, 439878656, 634713600, 317154560, 287774336, 352729152, 488085344, 79674768, 998500360, 213500940, 236197390, 46617863 + ], + [ + 536870912, 268435456, 402653184, 469762048, 100663296, 989855744, 494927872, 1010827264, 937426944, 19922944, 481820672, 278134784, 15335424, 26673152, 455180288, 605044736, 262676480, 482136064, 119007232, 719336448, 934383104, 628661504, 120936064, 809163840, 656324960, 177074160, 137341416, 959728308, 121348110, 614436867 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 570425344, 889192448, 176160768, 666894336, 891289600, 982515712, 77070336, 873725952, 916586496, 293404672, 132087808, 648200192, 427646976, 64966656, 950175744, 243016704, 1012909568, 367228160, 480038528, 871254976, 736821536, 739336016, 827941000, 204835532, 984768942, 270849439 + ], + [ + 536870912, 268435456, 671088640, 469762048, 771751936, 385875968, 914358272, 700448768, 60817408, 590348288, 832045056, 379846656, 480378880, 693043200, 402751488, 604094464, 436314112, 620859392, 260163584, 138480640, 484506112, 156324608, 285803648, 67933504, 1000290784, 592007216, 770518888, 357485172, 637534210, 452984835 + ], + [ + 536870912, 805306368, 402653184, 872415232, 503316480, 587202560, 679477248, 171966464, 106954752, 439353344, 946339840, 82575360, 607780864, 233242624, 389316608, 796868608, 110125056, 712560640, 651503616, 361757696, 601417216, 323287296, 1064789632, 592306368, 715826976, 1000279856, 65071528, 871437308, 818456718, 956163521 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 838860800, 687865856, 411041792, 79691776, 627048448, 89128960, 326631424, 610009088, 581042176, 739835904, 1007517696, 526106624, 730128384, 944640000, 55805952, 1037149184, 666498560, 960250624, 468885120, 224486848, 827327968, 628628880, 56432136, 555897612, 425268878, 86819279 + ], + [ + 536870912, 268435456, 134217728, 738197504, 436207616, 285212672, 1048576000, 1035993088, 589299712, 709885952, 950534144, 73662464, 486146048, 318701568, 867532800, 169000960, 620371968, 654192640, 230004736, 756210688, 293267968, 884887296, 768878464, 430155200, 547493216, 572774768, 233018088, 331582644, 487833482, 159021519 + ], + [ + 536870912, 805306368, 939524096, 67108864, 234881024, 788529152, 343932928, 1027604480, 224395264, 504365056, 996671488, 272367616, 700055552, 426442752, 178421760, 112148480, 571301888, 1000476672, 892332032, 936184832, 25298432, 123649280, 691340672, 51897024, 251198752, 177502704, 900175144, 698430972, 397439782, 484038909 + ], + [ + 536870912, 805306368, 402653184, 603979776, 369098752, 352321536, 377487360, 658505728, 442499072, 449839104, 483917824, 214171648, 178913280, 460259328, 189038592, 493568000, 726589440, 963973120, 706959360, 875756544, 860528128, 8368384, 851278208, 891252288, 837652960, 654719728, 831055976, 534598844, 307198350, 905211461 + ], + [ + 536870912, 805306368, 402653184, 872415232, 838860800, 788529152, 444596224, 448790528, 547356672, 179306496, 845676544, 764149760, 480903168, 428277760, 329023488, 645087232, 828530688, 205172736, 194947072, 886590464, 702902784, 874928896, 78498944, 945466560, 546258976, 662830000, 524348584, 954328956, 80807054, 712528065 + ], + [ + 536870912, 805306368, 671088640, 872415232, 1040187392, 889192448, 377487360, 1027604480, 786432000, 418381824, 1004011520, 623116288, 124649472, 114753536, 155353088, 781565952, 1062690816, 830607360, 45447168, 679881728, 168498688, 165214464, 35963520, 116363840, 303447648, 123898256, 105138280, 425681052, 607089378, 758587089 + ], + [ + 536870912, 805306368, 671088640, 603979776, 1040187392, 520093696, 310378496, 549453824, 312475648, 428867584, 986185728, 145489920, 858128384, 540344320, 660832256, 837697536, 345612288, 642068480, 349870080, 8078336, 988450304, 547567872, 231718528, 533288256, 187495648, 912752624, 617883784, 848521292, 521561194, 770515897 + ], + [ + 536870912, 268435456, 134217728, 603979776, 905969664, 788529152, 8388608, 381681664, 245366784, 466616320, 904396800, 617873408, 983695360, 835911680, 82542592, 727171072, 685826048, 464539648, 211396608, 418245632, 849246720, 2408192, 433756544, 101642944, 304906848, 910094960, 787860072, 296963700, 765073514, 527310205 + ], + [ + 536870912, 268435456, 939524096, 738197504, 33554432, 16777216, 461373440, 1010827264, 362807296, 227540992, 653787136, 161218560, 833224704, 923598848, 634552320, 223395840, 328851456, 560844800, 128149504, 614059008, 99445248, 459518208, 1006235264, 941427392, 418113632, 388761232, 386041480, 612943556, 810844782, 534689691 + ], + [ + 536870912, 268435456, 671088640, 201326592, 369098752, 721420288, 562036736, 792723456, 1054867456, 632291328, 134742016, 1055129600, 611188736, 542310400, 606175232, 370262016, 173613056, 64802816, 558098432, 569988096, 898430464, 779865344, 366328448, 682057152, 437694304, 496908368, 54209512, 573844628, 899063810, 769527815 + ], + [ + 536870912, 268435456, 134217728, 603979776, 704643072, 922746880, 645922816, 725614592, 635437056, 1009778688, 585629696, 798228480, 1008336896, 97845248, 511344640, 86327296, 766746624, 597692416, 273684480, 1058546688, 232636928, 392121088, 915800960, 454200384, 108005152, 143145104, 191136648, 634637380, 340895522, 85534873 + ], + [ + 536870912, 268435456, 134217728, 67108864, 100663296, 150994944, 343932928, 264241152, 383778816, 636485632, 881328128, 657719296, 540672000, 501678080, 584679424, 980205568, 504782848, 256970752, 30996480, 904702976, 39254528, 267516160, 797528192, 884240320, 914015200, 373800816, 386468200, 695482804, 664527370, 708281605 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 503316480, 687865856, 478150656, 624951296, 861929472, 890241024, 506986496, 163315712, 814350336, 801439744, 483885056, 471842816, 164323328, 849653760, 415754240, 581317632, 993522176, 407799552, 512921216, 84538560, 502549600, 337590800, 499842184, 145011660, 331850470, 153583327 + ], + [ + 536870912, 268435456, 402653184, 603979776, 301989888, 889192448, 729808896, 188743680, 132120576, 500170752, 192413696, 654049280, 1041629184, 109379584, 946503680, 55820288, 449748992, 650760192, 487901184, 728902656, 960446976, 960617216, 585105536, 777028288, 607652960, 857490160, 382157448, 645749188, 366349542, 983941177 + ], + [ + 536870912, 805306368, 939524096, 335544320, 100663296, 956301312, 1015021568, 373293056, 501219328, 166723584, 361234432, 1052508160, 125435904, 878641152, 870350848, 753942528, 50946048, 66883584, 421263360, 779037696, 290051584, 270277888, 99336320, 359101376, 112468384, 252158512, 310685480, 951021820, 15294470, 386699273 + ], + [ + 536870912, 268435456, 671088640, 738197504, 838860800, 117440512, 998244352, 331350016, 119537664, 898629632, 566755328, 693895168, 142213120, 693567488, 81100800, 1002946560, 245178368, 693792768, 768075776, 127730688, 266015232, 780648192, 452802944, 699028672, 108968352, 876124080, 778356776, 1000241012, 805940098, 293415887 + ], + [ + 536870912, 805306368, 134217728, 201326592, 973078528, 251658240, 310378496, 1069547520, 190840832, 907018240, 1073217536, 698613760, 332005376, 784531456, 416186368, 91799552, 711303168, 715911168, 466798592, 263699456, 471716352, 542019840, 230221184, 931421248, 360349280, 441081520, 226673768, 493847484, 327793642, 1003303679 + ], + [ + 536870912, 268435456, 671088640, 469762048, 1040187392, 452984832, 914358272, 994050048, 656408576, 143654912, 146276352, 97779712, 395968512, 912326656, 112230400, 1000947712, 128770048, 112193536, 772528128, 559428608, 61086208, 30578944, 767317120, 123203008, 33489568, 265532112, 247226376, 97955844, 415184906, 234079239 + ], + [ + 536870912, 805306368, 939524096, 67108864, 503316480, 117440512, 159383552, 29360128, 639631360, 667942912, 577241088, 338427904, 212992000, 1058340864, 45580288, 946520064, 887136256, 510701568, 1064949760, 65313792, 663668224, 963527936, 102759552, 870804544, 641978080, 556652624, 271770248, 307541324, 836203630, 685453585 + ], + [ + 536870912, 805306368, 939524096, 335544320, 301989888, 251658240, 931135488, 549453824, 392167424, 313524224, 272105472, 238288896, 640811008, 698023936, 570851328, 615071744, 370991104, 1030746112, 5588992, 369284096, 232915456, 705831168, 982186112, 317667136, 76851680, 727896048, 72582120, 531335932, 461263206, 339605689 + ], + [ + 536870912, 805306368, 134217728, 201326592, 301989888, 285212672, 411041792, 37748736, 295698432, 324009984, 225968128, 764674048, 827981824, 912982016, 404914176, 905887744, 578330624, 102051840, 848967680, 822852608, 177360384, 729158400, 155476352, 367222336, 161360096, 1028139824, 475803880, 155674428, 697067242, 897464383 + ], + [ + 536870912, 268435456, 402653184, 67108864, 570425344, 587202560, 847249408, 138412032, 1063256064, 384827392, 457703424, 946601984, 560332800, 809304064, 1031700480, 147439616, 833396736, 1019727872, 367802368, 765854720, 505190912, 24039168, 498083200, 111712576, 1054683360, 21932912, 1017134472, 609324356, 840544998, 636842097 + ], + [ + 536870912, 805306368, 671088640, 469762048, 570425344, 218103808, 142606336, 952107008, 698351616, 783286272, 919076864, 404488192, 100007936, 654114816, 329744384, 761544704, 329474048, 735531008, 84674560, 344953856, 380177920, 93157632, 5147520, 889796416, 977053536, 470170352, 416574344, 518727500, 747261802, 337362679 + ], + [ + 536870912, 805306368, 134217728, 738197504, 33554432, 922746880, 343932928, 113246208, 681574400, 328204288, 303562752, 745275392, 1057882112, 207290368, 937984000, 289783808, 887824384, 337670144, 156248064, 817454080, 620622336, 999777024, 301425024, 885401664, 139396512, 968523280, 983086632, 279725404, 78543370, 625708807 + ], + [ + 536870912, 268435456, 671088640, 738197504, 905969664, 587202560, 494927872, 4194304, 467664896, 902823936, 299368448, 437518336, 5373952, 851247104, 439255040, 498221056, 476897280, 309751808, 501626880, 316652544, 731539968, 198216448, 249057408, 429185984, 252871968, 47998160, 213803656, 168549572, 870868906, 404551707 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 771751936, 922746880, 864026624, 289406976, 123731968, 1034944512, 1036517376, 395051008, 934412288, 124059648, 1064206336, 49168384, 883843072, 676311040, 952014848, 739757056, 824926720, 147869440, 158864256, 113552192, 1056920800, 150428496, 903582088, 242816068, 222674794, 1002343455 + ], + [ + 536870912, 805306368, 134217728, 738197504, 973078528, 318767104, 1065353216, 759169024, 350224384, 829423616, 755499008, 246153216, 360054784, 69140480, 251822080, 802996224, 8298496, 783544320, 208971776, 46363648, 603729408, 330236160, 900353664, 165724352, 871370912, 852083600, 227319464, 187052700, 222754858, 469124695 + ], + [ + 536870912, 268435456, 402653184, 469762048, 234881024, 587202560, 1031798784, 130023424, 991952896, 877658112, 769130496, 533987328, 580255744, 735117312, 253263872, 1047838720, 1049026560, 401174528, 20813824, 1059793920, 465296896, 717367552, 797440640, 392766144, 8130720, 575374768, 487299080, 728378372, 341532166, 3336455 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 838860800, 822083584, 343932928, 826277888, 752877568, 544210944, 459800576, 43778048, 1035075584, 636157952, 838828032, 304136192, 475013120, 339292160, 455473152, 1062648832, 891135488, 963823872, 80457344, 808378304, 936942624, 349473328, 620708392, 815808308, 974219938, 324606459 + ], + [ + 536870912, 805306368, 939524096, 335544320, 570425344, 16777216, 796917760, 708837376, 509607936, 212860928, 601358336, 130809856, 49414144, 481886208, 352157696, 862699520, 286629888, 952012800, 218810368, 765811712, 593887744, 516332288, 223750528, 1054741696, 632969568, 343714832, 833331720, 297011980, 984539534, 465717445 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 301989888, 318767104, 327155712, 490733568, 178257920, 611319808, 491257856, 821821440, 929693696, 94437376, 904953856, 722059264, 366862336, 475697152, 21600256, 855383040, 476785152, 706786560, 984691584, 849982016, 573373408, 475251024, 991289352, 568758276, 75733006, 791485455 + ], + [ + 536870912, 805306368, 134217728, 872415232, 905969664, 251658240, 763363328, 784334848, 828375040, 986710016, 182976512, 302252032, 507379712, 56557568, 59670528, 208060416, 1055088640, 446484480, 618899456, 798770176, 207876608, 568137984, 121773952, 640475328, 89896160, 464647952, 137942248, 619521820, 238779626, 610362129 + ], + [ + 536870912, 268435456, 402653184, 603979776, 301989888, 989855744, 1048576000, 1061158912, 375390208, 34603008, 115867648, 197918720, 417202176, 519766016, 996769792, 1040990208, 1006624768, 361410560, 319866880, 929590272, 912896, 788461824, 638249856, 1003588544, 466102048, 364654992, 52896424, 1063207764, 742125070, 281671949 + ], + [ + 536870912, 268435456, 134217728, 872415232, 1040187392, 1023410176, 763363328, 876609536, 10485760, 999292928, 749207552, 509870080, 331481088, 508231680, 503283712, 490061824, 1007378432, 73338880, 1025783808, 769897472, 152815104, 473373440, 841065344, 89217216, 1053332704, 898963312, 597308136, 519445620, 708847978, 765538489 + ], + [ + 536870912, 805306368, 402653184, 201326592, 100663296, 654311424, 394264576, 230686720, 748683264, 303038464, 295174144, 747372544, 924975104, 1022820352, 846757888, 360529920, 994746368, 236146688, 448759808, 936231936, 381940224, 432896, 479206784, 282650688, 74228384, 793983600, 39832872, 935070012, 611045902, 63146767 + ], + [ + 536870912, 805306368, 402653184, 201326592, 100663296, 352321536, 645922816, 884998144, 257949696, 261095424, 946339840, 356253696, 635043840, 660537344, 997228544, 28917760, 83140608, 789991424, 16619520, 909777920, 386880000, 871972096, 257259392, 937932736, 990187168, 493828400, 854078248, 402518012, 666581006, 38751247 + ], + [ + 536870912, 268435456, 939524096, 67108864, 33554432, 117440512, 75497472, 247463936, 622854144, 592445440, 426246144, 207355904, 679608320, 841285632, 1062633472, 755679232, 344563712, 523063296, 691787776, 693179392, 845733376, 920450304, 658729088, 377783360, 289859936, 453145040, 275050120, 683058500, 763002862, 733057169 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 436207616, 822083584, 260046848, 71303168, 861929472, 842006528, 137887744, 1040973824, 129368064, 637337600, 766410752, 992034816, 55664640, 1057525760, 531916800, 385526784, 799713792, 832726784, 697725824, 120453824, 31953376, 863339632, 492477320, 540743364, 353033186, 833762175 + ], + [ + 536870912, 805306368, 671088640, 335544320, 100663296, 855638016, 612368384, 717225984, 304087040, 95420416, 1041760256, 1042546688, 770310144, 373227520, 707559424, 522633216, 780722176, 386732032, 471263232, 659627008, 948552192, 1007492864, 77019264, 529644352, 531138784, 775739376, 886036584, 425046204, 634581634, 61581385 + ], + [ + 536870912, 805306368, 939524096, 738197504, 905969664, 486539264, 662700032, 398458880, 987758592, 1005584384, 446169088, 356253696, 959315968, 212402176, 776306688, 358858752, 861822976, 754003968, 504932352, 746429440, 697200128, 830050048, 256740224, 292984512, 687186144, 224129520, 615728648, 341299980, 233145742, 238168523 + ], + [ + 536870912, 268435456, 402653184, 872415232, 838860800, 520093696, 696254464, 750780416, 1033895936, 464519168, 113770496, 409206784, 978714624, 318308352, 258768896, 823312384, 39755776, 943460352, 520796160, 1038298112, 452384256, 935970048, 551848320, 1041689664, 857309216, 20727344, 193621512, 1067706628, 370597766, 253356365 + ], + [ + 536870912, 268435456, 939524096, 469762048, 100663296, 452984832, 276824064, 121634816, 631242752, 265289728, 315097088, 797179904, 623771648, 695533568, 695631872, 312000512, 546070528, 223080448, 833304576, 215692288, 1061331456, 38734080, 1002755200, 604959552, 65359520, 522160432, 1062046856, 464205636, 970609838, 281244727 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 33554432, 620756992, 914358272, 71303168, 664797184, 883949568, 182976512, 1021575168, 825360384, 27852800, 80052224, 1027751936, 832626688, 531730432, 325675008, 388256768, 642920960, 871961856, 733843840, 1002321216, 289290784, 662617104, 769634824, 334451980, 524775810, 553821519 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 167772160, 989855744, 125829120, 4194304, 392167424, 632291328, 272105472, 275513344, 790233088, 917831680, 864518144, 913719296, 19881984, 485724160, 533854208, 856247296, 345319936, 332852992, 557816704, 484138176, 664071136, 408374672, 58708360, 213590988, 262473834, 858725727 + ], + [ + 536870912, 268435456, 402653184, 872415232, 167772160, 251658240, 478150656, 708837376, 530579456, 187695104, 1062731776, 624689152, 45481984, 530513920, 685473792, 857817088, 695328768, 217657344, 269322240, 955173888, 690146816, 481086208, 425703040, 356204096, 196147872, 588820112, 329006248, 604498324, 319202350, 730213593 + ], + [ + 536870912, 268435456, 671088640, 872415232, 436207616, 721420288, 998244352, 884998144, 333447168, 709885952, 974651392, 815529984, 802291712, 735772672, 100630528, 197181440, 576741376, 495988736, 645408768, 873223168, 757801472, 177726720, 620096384, 57138496, 572319392, 127064752, 830106792, 227453876, 48842018, 653616121 + ], + [ + 536870912, 268435456, 134217728, 469762048, 838860800, 922746880, 612368384, 197132288, 148897792, 164626432, 864550912, 608960512, 1029308416, 83558400, 319520768, 640925696, 963059712, 366522368, 444860416, 624405504, 1094144, 342463744, 488409984, 722603968, 760641952, 872506736, 1040243112, 218174836, 260075946, 490850675 + ], + [ + 536870912, 268435456, 402653184, 335544320, 637534208, 83886080, 679477248, 717225984, 740294656, 1028653056, 722993152, 146014208, 939917312, 237961216, 255033344, 124338176, 847044608, 258691072, 62699520, 181066752, 44956160, 909333248, 367603072, 935189312, 1019888608, 531366736, 179462632, 422091860, 513633902, 689625105 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 33554432, 822083584, 713031680, 297795584, 933232640, 311427072, 362283008, 428081152, 940441600, 928710656, 1026392064, 142786560, 944283648, 209547264, 62642176, 769408000, 237718016, 700840704, 569318784, 522970688, 323237344, 942546128, 344682600, 64226964, 481767306, 663703883 + ], + [ + 536870912, 268435456, 134217728, 201326592, 100663296, 956301312, 461373440, 549453824, 639631360, 653262848, 1009254400, 40632320, 852885504, 729088000, 506626048, 931086336, 718921728, 642052096, 884729856, 329485312, 172457472, 198042880, 652627328, 175949376, 305073632, 1036067952, 664820616, 825356100, 881450594, 433977139 + ], + [ + 536870912, 268435456, 134217728, 67108864, 973078528, 150994944, 142606336, 851443712, 912261120, 355467264, 376963072, 857997312, 859701248, 732495872, 632061952, 327303168, 163782656, 492982272, 909346816, 830186496, 774350336, 658361088, 925603200, 200251840, 195149856, 80742768, 101256712, 511524612, 705379202, 520074945 + ], + [ + 536870912, 268435456, 671088640, 335544320, 704643072, 83886080, 562036736, 297795584, 882900992, 506462208, 403177472, 877920256, 652869632, 644153344, 954368000, 19939328, 76029952, 940838912, 1032488960, 603282432, 442115584, 489482496, 861298560, 302675264, 624188192, 913992464, 224188296, 557787460, 676232490, 900104725 + ], + [ + 536870912, 268435456, 939524096, 872415232, 570425344, 150994944, 25165824, 809500672, 446693376, 340787200, 739770368, 15466496, 251527168, 403374080, 991526912, 913129472, 406740992, 745254912, 791205888, 742720512, 201059840, 818996992, 467251072, 957105728, 1016023456, 864237456, 873269288, 923768532, 113503750, 959244041 + ], + [ + 536870912, 805306368, 671088640, 603979776, 973078528, 16777216, 813694976, 834666496, 589299712, 600834048, 383254528, 88342528, 599392256, 849149952, 645890048, 149307392, 331587584, 927469568, 217966592, 290337792, 701396480, 202360064, 1026481280, 1006585280, 665228192, 304256144, 574139016, 45383884, 288509738, 1061212505 + ], + [ + 536870912, 805306368, 402653184, 872415232, 973078528, 16777216, 310378496, 725614592, 1012924416, 164626432, 586678272, 863240192, 347471872, 811663360, 936476672, 33079296, 351641600, 393728000, 641796096, 283186176, 26319360, 957891328, 962961024, 544153536, 606343072, 588152752, 477470728, 221761548, 278988806, 108073997 + ], + [ + 536870912, 805306368, 939524096, 738197504, 301989888, 452984832, 696254464, 675282944, 102760448, 835715072, 1045954560, 914096128, 439484416, 139526144, 504987648, 610123776, 367222784, 1057591296, 451237888, 1068403712, 869474816, 383787264, 825300608, 577248960, 546636256, 510044304, 416765960, 738167820, 130720270, 96329995 + ], + [ + 536870912, 805306368, 134217728, 603979776, 905969664, 687865856, 58720256, 88080384, 216006656, 97517568, 668467200, 83623936, 123076608, 337051648, 32931840, 262586368, 155181056, 924995584, 480581632, 753533952, 748727808, 682625280, 810076032, 558180672, 918214304, 339281936, 464279208, 776980508, 1028372138, 965842965 + ], + [ + 536870912, 805306368, 402653184, 335544320, 436207616, 452984832, 327155712, 339738624, 824180736, 74448896, 906493952, 537657344, 100270080, 389349376, 39813120, 1030995968, 234364928, 1011191808, 232175616, 171961344, 1050814976, 557944064, 329383296, 11545408, 350749408, 454895632, 497217416, 381782604, 98694502, 1049632341 + ], + [ + 536870912, 268435456, 671088640, 67108864, 301989888, 150994944, 1031798784, 390070272, 417333248, 655360000, 749207552, 515112960, 680919040, 887554048, 656375808, 56803328, 898686976, 627666944, 160806912, 732369920, 738102784, 510810368, 339241344, 341688512, 1061396320, 975181008, 1018218344, 693727444, 403468642, 889912789 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 704643072, 150994944, 192937984, 88080384, 459276288, 869269504, 783810560, 971767808, 61997056, 84738048, 656637952, 232079360, 815685632, 111022080, 362752000, 522177536, 769606144, 436139776, 944737408, 782748352, 1018306528, 495844688, 686025864, 611637964, 930002914, 160919903 + ], + [ + 536870912, 268435456, 671088640, 872415232, 100663296, 452984832, 243269632, 952107008, 161480704, 498073600, 645398528, 737935360, 212205568, 18808832, 163807232, 236240896, 265445376, 954060800, 1071106048, 499571712, 84888064, 436932352, 932241024, 780777280, 778391456, 965441552, 584156584, 224966420, 817183522, 384028761 + ], + [ + 536870912, 268435456, 671088640, 335544320, 905969664, 721420288, 645922816, 616562688, 174063616, 355467264, 495452160, 894697472, 55443456, 679936000, 359890944, 174899200, 416505856, 935153664, 715835392, 704748544, 419523072, 327201024, 1027613824, 1042322112, 277975392, 609762192, 422411112, 569592468, 195936226, 590497873 + ], + [ + 536870912, 805306368, 402653184, 67108864, 570425344, 285212672, 511705088, 725614592, 480247808, 275775488, 167247872, 892600320, 541982720, 674824192, 148209664, 564051968, 154214400, 744001536, 667174912, 620155904, 850217472, 929819904, 899659648, 53589440, 559488160, 524675568, 1018612232, 562834700, 316348294, 193455553 + ], + [ + 536870912, 268435456, 671088640, 469762048, 838860800, 788529152, 880803840, 1002438656, 958398464, 831520768, 1042808832, 435421184, 790495232, 938409984, 909606912, 379240448, 954736640, 726970368, 969885696, 388410368, 359862784, 423365376, 475733888, 273242816, 243659616, 528991888, 547560296, 393484948, 937353570, 542100883 + ], + [ + 536870912, 805306368, 671088640, 872415232, 436207616, 251658240, 394264576, 423624704, 144703488, 978321408, 790102016, 1062469632, 900333568, 919273472, 502956032, 315867136, 120479744, 87601152, 885377024, 886240256, 372145664, 800594688, 17127808, 682785088, 849326048, 634425520, 844713960, 99934396, 888825826, 340944049 + ], + [ + 536870912, 268435456, 402653184, 872415232, 167772160, 654311424, 310378496, 843055104, 56623104, 441450496, 8912896, 802947072, 38141952, 970784768, 323387392, 710787072, 713498624, 620597248, 880154624, 495256576, 810781184, 698818304, 1053579392, 774806336, 328296032, 103410032, 489445512, 87989060, 284780134, 317057405 + ], + [ + 536870912, 805306368, 134217728, 201326592, 570425344, 520093696, 494927872, 448790528, 270532608, 984612864, 957874176, 1006895104, 411172864, 254738432, 783319040, 790216704, 84156416, 872640512, 896460800, 651203584, 46791168, 206337792, 462300288, 306246976, 878820576, 131161648, 440961640, 269305980, 586082314, 521180175 + ], + [ + 536870912, 268435456, 939524096, 469762048, 905969664, 452984832, 998244352, 926941184, 606076928, 858783744, 480772096, 214695936, 898236416, 560660480, 658210816, 260194304, 190226432, 804851712, 150259712, 866096128, 296021504, 447131392, 925943424, 648567744, 432927136, 151760880, 464179624, 794558452, 588462502, 328154099 + ], + [ + 536870912, 268435456, 134217728, 335544320, 369098752, 520093696, 75497472, 390070272, 60817408, 621805568, 731381760, 538181632, 991559680, 391708672, 678723584, 384450560, 410099712, 266874880, 1039972352, 132547584, 524225024, 847996160, 796970112, 365004480, 65097120, 909121616, 264866312, 388769028, 983559298, 278591173 + ], + [ + 536870912, 268435456, 134217728, 872415232, 234881024, 855638016, 360710144, 717225984, 111149056, 1049624576, 642252800, 861143040, 181534720, 335216640, 488603648, 768983040, 429088768, 228233216, 741328896, 495748096, 13566464, 234708736, 670457728, 219215808, 461905504, 645202288, 428080232, 680726132, 152767466, 309259705 + ], + [ + 536870912, 268435456, 939524096, 469762048, 771751936, 452984832, 427819008, 683671552, 81788928, 1041235968, 230162432, 43253760, 856031232, 711000064, 156270592, 513392640, 333766656, 493842432, 590206976, 932334592, 644318720, 145835776, 168411264, 186488256, 31148192, 534410800, 752541704, 291139588, 194729998, 981109767 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 369098752, 754974720, 444596224, 515899392, 119537664, 613416960, 566755328, 656146432, 54657024, 670892032, 947027968, 56934400, 604463104, 1021997056, 252774400, 596190208, 738049536, 108248320, 711264896, 344329024, 422248032, 1068612432, 56158856, 332708676, 48141934, 746581855 + ], + [ + 536870912, 268435456, 134217728, 738197504, 301989888, 788529152, 763363328, 289406976, 257949696, 579862528, 935854080, 562298880, 372113408, 629342208, 813268992, 809287680, 716382208, 369160192, 16869376, 411063296, 1069581824, 564158720, 330307456, 934921920, 630995040, 251905616, 817465832, 874353044, 71519754, 1020790031 + ], + [ + 536870912, 268435456, 402653184, 67108864, 369098752, 654311424, 125829120, 884998144, 471859200, 294649856, 344457216, 985399296, 210370560, 1042481152, 672104448, 445464576, 408051712, 582438912, 535308288, 97383424, 716325376, 34007808, 678544256, 700026304, 350521120, 241091312, 329557288, 952072692, 622153390, 673644597 + ], + [ + 536870912, 268435456, 134217728, 335544320, 637534208, 855638016, 612368384, 843055104, 216006656, 1051721728, 359137280, 450625536, 492175360, 995295232, 858882048, 313049088, 503111680, 516395008, 749447168, 261438464, 379221504, 951850240, 145130112, 257603264, 10346912, 364345936, 736279848, 22603156, 183871498, 32128001 + ], + [ + 536870912, 268435456, 939524096, 201326592, 369098752, 184549376, 528482304, 406847488, 362807296, 802160640, 115867648, 892600320, 431882240, 608239616, 731938816, 282181632, 57171968, 812953600, 413030400, 206699520, 547897856, 529886464, 871308928, 669615936, 531984800, 562033136, 740327432, 345096196, 952655886, 413446147 + ], + [ + 536870912, 805306368, 939524096, 872415232, 704643072, 822083584, 964689920, 104857600, 1042284544, 11534336, 133693440, 150208512, 86638592, 458424320, 635863040, 653082624, 152035328, 17838080, 503904256, 732746752, 934270464, 845176576, 1066520192, 113887040, 1028517856, 436138032, 801651176, 13479740, 230651750, 350824561 + ], + [ + 536870912, 805306368, 939524096, 201326592, 167772160, 218103808, 612368384, 943718400, 576716800, 1007681536, 172490752, 342097920, 851050496, 609550336, 696483840, 468238336, 534110208, 71536640, 390662144, 954528768, 1056598528, 3495680, 311685760, 941746496, 393316256, 752457104, 762092168, 658394444, 993985966, 960472723 + ], + [ + 536870912, 268435456, 939524096, 67108864, 637534208, 922746880, 612368384, 373293056, 618659840, 1055916032, 323485696, 254017536, 664403968, 664993792, 705658880, 177225728, 905535488, 864866304, 281978880, 338734080, 904441344, 188051712, 958546560, 961444544, 603008224, 180992944, 283454184, 616261300, 510805606, 647441781 + ], + [ + 536870912, 268435456, 671088640, 201326592, 436207616, 452984832, 830472192, 759169024, 903872512, 667942912, 336068608, 1036255232, 512098304, 362217472, 557809664, 717930496, 294952960, 751792128, 70395904, 958948352, 78982656, 834580736, 1024182144, 280286144, 532630496, 403325648, 741663720, 41936596, 707456482, 583329751 + ], + [ + 536870912, 805306368, 134217728, 738197504, 167772160, 318767104, 92274688, 96468992, 203423744, 420478976, 642252800, 369885184, 900071424, 803667968, 218529792, 968278016, 623878144, 4976640, 745629696, 272122880, 758508032, 957598464, 892691328, 756187584, 456419744, 403851408, 129296808, 190023836, 198560170, 463648919 + ], + [ + 536870912, 805306368, 402653184, 469762048, 637534208, 587202560, 1065353216, 868220928, 811597824, 334495744, 354942976, 639369216, 446562304, 80281600, 153976832, 1045872640, 1038475264, 796569600, 531814400, 882875392, 331935232, 346897152, 345404288, 923074368, 332064736, 918221168, 47386120, 1072597772, 815868806, 873571143 + ], + [ + 536870912, 268435456, 402653184, 872415232, 167772160, 620756992, 494927872, 507510784, 425721856, 487587840, 465043456, 249823232, 261750784, 1018494976, 180518912, 201441280, 771825664, 922783744, 209750016, 163625984, 572643840, 435169024, 417864320, 205264576, 477011872, 681025808, 949097096, 156854980, 515138982, 331486749 + ], + [ + 536870912, 268435456, 402653184, 335544320, 33554432, 251658240, 578813952, 784334848, 1063256064, 770703360, 352845824, 627834880, 512884736, 6225920, 526221312, 192561152, 327376896, 870789120, 270084096, 450202624, 131469824, 485573888, 646539392, 674045376, 884128288, 328150384, 461714088, 634339508, 19251342, 266260929 + ], + [ + 536870912, 805306368, 671088640, 603979776, 100663296, 654311424, 25165824, 381681664, 379584512, 510656512, 258473984, 557056000, 638451712, 130744320, 99385344, 695386112, 121724928, 408981504, 80758784, 857216000, 257722880, 565918464, 914705024, 38256320, 609191904, 1059809872, 830244200, 462143644, 369952898, 1046630853 + ], + [ + 536870912, 805306368, 939524096, 738197504, 704643072, 822083584, 478150656, 1019215872, 908066816, 680525824, 239599616, 620494848, 377356288, 890044416, 566722560, 38322176, 1056759808, 528388096, 93186048, 923153408, 90746368, 183350528, 771109504, 391129920, 166221664, 1043165104, 265730696, 968970060, 480276846, 928104123 + ], + [ + 536870912, 268435456, 939524096, 469762048, 436207616, 788529152, 847249408, 180355072, 698351616, 951058432, 326631424, 600571904, 14811136, 887422976, 973504512, 266518528, 375742464, 147296256, 977491968, 886318080, 884915712, 722436352, 1056421760, 704276672, 700046048, 577629008, 475246984, 563977668, 751463278, 310408855 + ], + [ + 536870912, 268435456, 134217728, 738197504, 637534208, 620756992, 343932928, 297795584, 786432000, 466616320, 1048051712, 710148096, 200146944, 485556224, 1061715968, 234635264, 818110464, 717893632, 135702528, 98919424, 646393344, 482109184, 501425792, 955912128, 373207200, 394916464, 161302536, 1003688964, 617801218, 726872843 + ], + [ + 536870912, 268435456, 402653184, 201326592, 436207616, 620756992, 578813952, 138412032, 559939584, 397410304, 394788864, 208928768, 819068928, 19333120, 775258112, 1018314752, 538419200, 670904320, 782743552, 16096256, 462644736, 633827584, 977562240, 983287744, 938680032, 351696816, 730690664, 613331060, 219277966, 228165575 + ], + [ + 536870912, 268435456, 134217728, 67108864, 33554432, 452984832, 780140544, 960495616, 1038090240, 298844160, 633864192, 184811520, 79560704, 605356032, 139886592, 417415168, 978362368, 654856192, 1009055744, 642737152, 556536320, 493492992, 669123712, 403136832, 820577952, 586494896, 654736520, 208160068, 146093218, 812071089 + ], + [ + 536870912, 805306368, 134217728, 67108864, 369098752, 218103808, 780140544, 507510784, 278921216, 642777088, 246939648, 431751168, 426901504, 558039040, 1045069824, 792641536, 274259968, 390942720, 1033549824, 608603136, 629530112, 881765120, 1066488192, 148381760, 873306016, 196771120, 408375208, 765223228, 107104682, 115070525 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 973078528, 50331648, 1065353216, 180355072, 782237696, 1028653056, 93847552, 636747776, 354287616, 335347712, 97746944, 860241920, 1009344512, 215814144, 121812992, 922668032, 785194496, 1035620608, 729538688, 266059712, 428587040, 529705648, 178767496, 840524492, 590620330, 700339327 + ], + [ + 536870912, 805306368, 939524096, 335544320, 33554432, 922746880, 8388608, 213909504, 1038090240, 219152384, 889716736, 971767808, 802553856, 766705664, 642285568, 340541440, 1038573568, 155955200, 305997824, 205519872, 936247808, 290961664, 141782912, 36281536, 874312992, 206565584, 991402152, 877843740, 291013126, 38074633 + ], + [ + 536870912, 268435456, 671088640, 469762048, 771751936, 989855744, 226492416, 1002438656, 631242752, 9437184, 739770368, 808189952, 275120128, 873398272, 726368256, 300466176, 277159936, 755159040, 352143360, 656294912, 1066543616, 1038483200, 162678656, 95760704, 965450016, 1019827344, 894720808, 251395988, 337764002, 89155027 + ], + [ + 536870912, 805306368, 939524096, 603979776, 436207616, 553648128, 1048576000, 926941184, 396361728, 200278016, 315097088, 20709376, 339607552, 291569664, 647069696, 978960384, 946151424, 400216064, 360318976, 839611392, 713226752, 1017044224, 789639040, 613953088, 17090016, 491395056, 690135048, 359534604, 953722894, 19227657 + ], + [ + 536870912, 805306368, 134217728, 201326592, 100663296, 922746880, 276824064, 633339904, 169869312, 1041235968, 284688384, 1059848192, 95551488, 395771904, 1069580288, 52543488, 495984640, 800608256, 567117824, 369310720, 205433344, 1073086208, 227434880, 559699776, 674934432, 666049776, 446123304, 373299388, 224428042, 619823119 + ], + [ + 536870912, 268435456, 939524096, 738197504, 33554432, 989855744, 25165824, 801112064, 1012924416, 116391936, 1033371648, 574357504, 158203904, 555286528, 830242816, 911196160, 550002688, 557092864, 104470528, 584215552, 62320128, 973372160, 348265344, 329196224, 914479840, 1010890992, 278982152, 387021572, 380148622, 415621835 + ], + [ + 536870912, 268435456, 671088640, 469762048, 570425344, 922746880, 8388608, 675282944, 807403520, 831520768, 688390144, 520880128, 487194624, 161021952, 126124032, 197607424, 91480064, 845975552, 993687552, 297837568, 903885312, 712009984, 1048105088, 183836224, 490701664, 1002955216, 1030900232, 107793668, 87745162, 79722311 + ], + [ + 536870912, 805306368, 671088640, 469762048, 771751936, 486539264, 8388608, 171966464, 106954752, 714080256, 390594560, 181141504, 65667072, 547291136, 392200192, 470859776, 873046016, 1043173376, 272340992, 741862400, 1039980032, 76718336, 850118528, 394198720, 825275424, 108561712, 1018535336, 392079100, 734109698, 312578059 + ], + [ + 536870912, 268435456, 671088640, 469762048, 301989888, 989855744, 645922816, 608174080, 1050673152, 758120448, 46661632, 952369152, 423231488, 275841024, 434667520, 590692352, 252895232, 304451584, 850089984, 193557504, 769999360, 734668032, 467227008, 427635264, 311852064, 876603600, 522967048, 826815492, 50700810, 911914247 + ], + [ + 536870912, 805306368, 134217728, 603979776, 301989888, 1023410176, 880803840, 1019215872, 966787072, 888143872, 376963072, 373555200, 315752448, 419627008, 172654592, 257343488, 670162944, 301494272, 486807552, 674495488, 856832512, 606267136, 175827072, 76472128, 390404960, 676505840, 650306408, 208282876, 484852074, 1030356981 + ], + [ + 536870912, 805306368, 939524096, 335544320, 234881024, 687865856, 260046848, 297795584, 715128832, 105906176, 754450432, 538181632, 1029832704, 255000576, 499810304, 752828416, 171827200, 449744896, 77944832, 564814848, 380570112, 114609920, 960734592, 992192064, 273886432, 121325808, 997618920, 122760444, 1064926950, 332784633 + ], + [ + 536870912, 805306368, 671088640, 469762048, 234881024, 117440512, 729808896, 918552576, 824180736, 47185920, 344457216, 915144704, 600440832, 176750592, 697139200, 1011564544, 776593408, 296611840, 303790080, 662748160, 549471744, 35713280, 995207808, 726229568, 724305248, 1012552912, 434128392, 753987852, 165259914, 113599047 + ], + [ + 536870912, 805306368, 939524096, 201326592, 905969664, 1023410176, 746586112, 482344960, 23068672, 1051721728, 742916096, 203685888, 603324416, 266141696, 689668096, 969850880, 617668608, 192540672, 606881792, 141734912, 419151360, 633210624, 16332672, 795717440, 1012109216, 459976816, 484884872, 574954572, 1053230638, 752097331 + ], + [ + 536870912, 268435456, 134217728, 603979776, 33554432, 922746880, 260046848, 222298112, 434110464, 363855872, 462946304, 94633984, 951975936, 209256448, 286556160, 296108032, 404496384, 814387200, 734984192, 289463296, 669039104, 212866816, 85582208, 845487808, 345974304, 48791152, 194812424, 63604484, 724507010, 443663049 + ], + [ + 536870912, 805306368, 134217728, 469762048, 973078528, 1056964608, 545259520, 658505728, 291504128, 347078656, 74973184, 742129664, 878051328, 482017280, 967081984, 463192064, 905289728, 26390528, 672229376, 568957952, 420851200, 165849344, 348781184, 910541888, 157977888, 292338896, 668975016, 194925724, 746583178, 311352651 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 973078528, 788529152, 394264576, 88080384, 601882624, 829423616, 285736960, 883163136, 672792576, 36110336, 308379648, 825311232, 845684736, 722743296, 632465408, 185779200, 226694656, 335246592, 525808768, 23688128, 378873184, 938660336, 57905128, 62006068, 236068870, 218312715 + ], + [ + 536870912, 805306368, 671088640, 872415232, 234881024, 385875968, 360710144, 104857600, 148897792, 1037041664, 46661632, 418119680, 920780800, 948895744, 598507520, 713211904, 497016832, 4542464, 404621312, 503706624, 218025472, 433388800, 389520768, 62478016, 840186912, 899106288, 612999592, 537727804, 590552450, 239572673 + ], + [ + 536870912, 805306368, 402653184, 738197504, 503316480, 184549376, 1031798784, 4194304, 1059061760, 391118848, 318242816, 585367552, 377356288, 630784000, 244678656, 970375168, 746872832, 311390208, 1022466048, 90770432, 234631680, 321569024, 472819328, 98586048, 1001407008, 701082480, 166580744, 796094732, 937123462, 893792715 + ], + [ + 536870912, 805306368, 671088640, 67108864, 301989888, 184549376, 310378496, 1002438656, 6291456, 32505856, 688390144, 108265472, 908460032, 653066240, 749436928, 95830016, 890544128, 961957888, 170145792, 935306240, 971068928, 414281472, 984126848, 65334592, 215890720, 43020528, 242834312, 784102988, 1060356266, 297424561 + ], + [ + 536870912, 805306368, 671088640, 603979776, 301989888, 218103808, 327155712, 440401920, 329252864, 384827392, 936902656, 61603840, 242876416, 816644096, 385581056, 241975296, 630890496, 285003776, 5425152, 844647424, 921442816, 727437568, 194784640, 985837504, 93343968, 424242192, 241446280, 148811724, 336744682, 49835033 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 771751936, 788529152, 696254464, 364904448, 819986432, 821035008, 940048384, 1024196608, 1018822656, 731316224, 247234560, 538132480, 659169280, 404623360, 1064323072, 382243840, 778940928, 613073152, 201213056, 268459456, 671157536, 604078896, 302115240, 16813820, 109087886, 1010862531 + ], + [ + 536870912, 805306368, 671088640, 67108864, 100663296, 1023410176, 964689920, 339738624, 102760448, 948961280, 400031744, 144441344, 582615040, 983629824, 156336128, 800669696, 153886720, 259141632, 891611136, 144067584, 491971072, 330600704, 240071808, 776943296, 508500192, 911192016, 843980808, 877604876, 156198922, 818809857 + ], + [ + 536870912, 268435456, 402653184, 738197504, 838860800, 587202560, 142606336, 767557632, 547356672, 380633088, 1054343168, 586416128, 779223040, 722141184, 735019008, 1017462784, 452665344, 863449088, 348153856, 790662144, 905024000, 246996736, 224679552, 5970496, 851869408, 1016625648, 823446760, 279156468, 373486190, 353566911 + ], + [ + 536870912, 268435456, 939524096, 738197504, 771751936, 721420288, 578813952, 884998144, 723517440, 317718528, 92798976, 157548544, 506068992, 356843520, 677019648, 453820416, 715120640, 639086592, 418625536, 60302336, 129818112, 217554176, 10713472, 379701568, 380663456, 661231120, 355768712, 823294276, 759811758, 608481819 + ], + [ + 536870912, 805306368, 402653184, 603979776, 503316480, 1023410176, 1031798784, 281018368, 492830720, 103809024, 87556096, 672923648, 709754880, 355139584, 274235392, 573390848, 225959936, 976670720, 613914624, 658916352, 755894784, 327941376, 931701376, 912559168, 250805024, 599042960, 901436328, 45193948, 108653070, 12397829 + ], + [ + 536870912, 805306368, 939524096, 469762048, 301989888, 754974720, 578813952, 423624704, 870318080, 967835648, 845676544, 827588608, 532545536, 112001024, 160661504, 192856064, 730619904, 469946368, 604456960, 501343232, 917598720, 99140352, 378823552, 656358976, 570205216, 550174000, 285456776, 914819404, 1017191854, 424735863 + ], + [ + 536870912, 805306368, 402653184, 469762048, 771751936, 285212672, 578813952, 322961408, 559939584, 797966336, 904396800, 469499904, 700841984, 482934784, 613253120, 629063680, 796778496, 126283776, 690571264, 358380544, 1031219712, 424698624, 407410816, 315456832, 211689696, 816634032, 244271624, 1032082188, 433205382, 670234951 + ], + [ + 536870912, 805306368, 134217728, 335544320, 301989888, 117440512, 931135488, 197132288, 861929472, 204472320, 801636352, 595329024, 24772608, 929366016, 532643840, 218841088, 369893376, 512970752, 185194496, 60558336, 478852608, 953007872, 359830400, 796508992, 116686176, 128424464, 768597384, 627187788, 564134114, 835824213 + ], + [ + 536870912, 268435456, 671088640, 335544320, 234881024, 520093696, 260046848, 977272832, 60817408, 412090368, 26738688, 309592064, 381550592, 810745856, 303661056, 573947904, 740286464, 742641664, 675350528, 379667456, 772820480, 1062805248, 705974656, 684608576, 628765024, 589588816, 616967912, 1522196, 422465026, 977936129 + ], + [ + 536870912, 805306368, 939524096, 738197504, 771751936, 721420288, 914358272, 20971520, 195035136, 1018167296, 134742016, 365690880, 584187904, 432734208, 851345408, 480854016, 771563520, 379310080, 908478464, 891100160, 747283968, 186532608, 488186496, 343249088, 446121888, 890590896, 759597480, 734910908, 30623014, 994776695 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 100663296, 385875968, 192937984, 373293056, 350224384, 554696704, 905445376, 735313920, 736231424, 212271104, 603750400, 602816512, 547430400, 686837760, 912869376, 686621696, 253156864, 334867712, 617771904, 695129408, 576796256, 634485040, 802688488, 971352188, 749430150, 1006320707 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 436207616, 855638016, 931135488, 12582912, 195035136, 483393536, 339214336, 456392704, 830603264, 504430592, 681082880, 1046822912, 813424640, 268816384, 25892864, 145619968, 342320640, 480955648, 1010638464, 247336384, 523167648, 594992400, 817076232, 890813444, 899974666, 408624399 + ], + [ + 536870912, 268435456, 402653184, 738197504, 704643072, 318767104, 260046848, 197132288, 794820608, 321912832, 503840768, 952369152, 85590016, 590807040, 370769920, 425476096, 730308608, 366030848, 804866048, 220996608, 112148992, 914715904, 582744704, 149411264, 1021413472, 988906992, 375951592, 578098484, 701639182, 672342287 + ], + [ + 536870912, 268435456, 134217728, 872415232, 369098752, 150994944, 8388608, 541065216, 811597824, 200278016, 242745344, 994836480, 642121728, 625016832, 182484992, 145768448, 362389504, 259829760, 832456704, 89981952, 957317632, 592757504, 133922688, 838828992, 380482144, 192366128, 974684168, 1052524548, 490708994, 1015918605 + ], + [ + 536870912, 268435456, 134217728, 872415232, 570425344, 184549376, 1031798784, 4194304, 891289600, 324009984, 365428736, 988545024, 798359552, 772734976, 850100224, 848412672, 648634368, 1033695232, 730785792, 518759424, 430978560, 687376128, 1020580224, 665005504, 966634400, 294597008, 703296936, 842011284, 28938794, 1064613977 + ], + [ + 536870912, 805306368, 671088640, 738197504, 436207616, 520093696, 310378496, 985661440, 996147200, 399507456, 846725120, 1033633792, 818020352, 575078400, 633896960, 213172224, 686170112, 905490432, 316516352, 669199360, 37167616, 1040211200, 419519872, 1065457984, 457185568, 153197040, 158353064, 206106044, 586459650, 71811335 + ], + [ + 536870912, 805306368, 939524096, 872415232, 838860800, 486539264, 1031798784, 499122176, 593494016, 529530880, 1006108672, 254541824, 182059008, 225378304, 520650752, 793001984, 873357312, 563687424, 389871616, 1038271488, 446931456, 948102400, 439504768, 469380928, 22952096, 494972080, 767669544, 459364092, 730937862, 167317761 + ], + [ + 536870912, 268435456, 402653184, 738197504, 234881024, 922746880, 260046848, 960495616, 878706688, 66060288, 824705024, 379322368, 458620928, 676790272, 232226816, 966213632, 393617408, 457592832, 533719040, 134452224, 749493760, 350158080, 639328896, 188263360, 872726304, 671348112, 1017954088, 216003988, 169525038, 87618975 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 301989888, 150994944, 746586112, 910163968, 236978176, 839909376, 657981440, 1007419392, 121503744, 948109312, 760578048, 201539584, 924131328, 673443840, 805574656, 832195584, 860390912, 335866624, 261870976, 273265472, 226876576, 123368208, 556347688, 490044500, 607384454, 876472395 + ], + [ + 536870912, 805306368, 402653184, 67108864, 234881024, 1056964608, 411041792, 859832320, 216006656, 657457152, 772276224, 824967168, 887488512, 609943552, 518291456, 996884480, 82698240, 474468352, 185223168, 782081024, 430861824, 26731776, 154356352, 1060641728, 337953312, 189454800, 419209384, 551538204, 251634830, 99598029 + ], + [ + 536870912, 805306368, 402653184, 201326592, 637534208, 50331648, 1048576000, 624951296, 392167424, 495976448, 1041760256, 214171648, 553517056, 805896192, 236814336, 312131584, 373776384, 293449728, 722163712, 442389504, 884537856, 276091648, 848797824, 906329792, 761224992, 272202864, 137732616, 343377676, 374659718, 577138115 + ], + [ + 536870912, 268435456, 671088640, 603979776, 704643072, 889192448, 511705088, 952107008, 1042284544, 567279616, 49807360, 477364224, 706871296, 1063714816, 122519552, 83345408, 894787584, 343076864, 434026496, 215612416, 94740992, 618397440, 756251520, 846178112, 269523296, 341405232, 375765736, 863634804, 998463874, 49780813 + ], + [ + 536870912, 805306368, 134217728, 201326592, 1040187392, 218103808, 260046848, 817889280, 673185792, 523239424, 648544256, 1065091072, 775028736, 321323008, 541622272, 896385024, 271196160, 909283328, 656873472, 440980480, 174873088, 749410048, 74662016, 809937088, 496606368, 466981232, 709756456, 865463996, 841939466, 12863247 + ], + [ + 536870912, 805306368, 939524096, 335544320, 33554432, 218103808, 159383552, 801112064, 736100352, 200278016, 447217664, 1026293760, 897712128, 663158784, 518553600, 67911680, 605249536, 220180480, 277673984, 173171712, 624906752, 647762176, 336279680, 104517312, 141704736, 36658288, 524571816, 63865788, 95801862, 1055346953 + ], + [ + 536870912, 268435456, 671088640, 738197504, 704643072, 620756992, 176160768, 130023424, 413138944, 770703360, 836239360, 758382592, 322306048, 1638400, 43286528, 356990976, 981491712, 1069666304, 480274432, 737227776, 1054436864, 45477120, 511130496, 528003264, 935668896, 158250544, 644738568, 29535492, 261053322, 696082635 + ], + [ + 536870912, 268435456, 671088640, 201326592, 369098752, 822083584, 494927872, 255852544, 455081984, 290455552, 112721920, 527171584, 169738240, 745996288, 1021542400, 733003776, 218734592, 40210432, 544954368, 840704, 720346624, 811470592, 551012736, 770840128, 380202016, 133522000, 732146216, 76593492, 777551266, 802971671 + ], + [ + 536870912, 268435456, 134217728, 201326592, 973078528, 922746880, 864026624, 29360128, 287309824, 462422016, 750256128, 860094464, 390987776, 263651328, 957579264, 611172352, 414359552, 599584768, 770344960, 684241920, 852281856, 753044224, 388268928, 935328832, 746509664, 442413200, 978296680, 456588180, 55721194, 948713431 + ], + [ + 536870912, 268435456, 134217728, 738197504, 771751936, 855638016, 696254464, 281018368, 606076928, 185597952, 184025088, 472121344, 853147648, 376635392, 38764544, 344047616, 440508416, 358633472, 334596096, 197764096, 785142272, 226945792, 676134784, 46640704, 195931744, 108445744, 126219368, 772493108, 455834090, 884710015 + ], + [ + 536870912, 268435456, 939524096, 201326592, 167772160, 855638016, 343932928, 398458880, 207618048, 336592896, 35127296, 299106304, 626917376, 787808256, 49184768, 10272768, 53665792, 252612608, 1053587456, 84653056, 166430208, 473659136, 323196544, 1023897536, 318784544, 75566896, 801240712, 6307780, 504388654, 823716659 + ], + [ + 536870912, 805306368, 402653184, 872415232, 771751936, 754974720, 260046848, 817889280, 350224384, 477102080, 833093632, 122945536, 980549632, 271777792, 1066565632, 834813952, 301719552, 452366336, 196737024, 1036813312, 78545408, 1065739520, 990520960, 169778112, 499984736, 883922672, 663071080, 252368636, 605997422, 818743025 + ], + [ + 536870912, 805306368, 671088640, 67108864, 973078528, 587202560, 729808896, 675282944, 199229440, 336592896, 498597888, 888930304, 899284992, 515047424, 255229952, 712097792, 149479424, 35958784, 313976832, 791712768, 428377600, 854917376, 1026530688, 259834432, 98267808, 961805040, 623320232, 784953340, 882149154, 880700605 + ], + [ + 536870912, 268435456, 671088640, 67108864, 167772160, 989855744, 746586112, 935329792, 962592768, 460324864, 268959744, 777256960, 1029308416, 378208256, 764641280, 859750400, 628678656, 526233600, 747563008, 881970176, 1069142528, 129861888, 834660992, 867794624, 431864416, 683599792, 540553832, 150756276, 488630370, 782872245 + ], + [ + 536870912, 805306368, 402653184, 335544320, 436207616, 654311424, 931135488, 331350016, 14680064, 105906176, 363331584, 884736000, 1042415616, 875233280, 73826304, 194789376, 110354432, 47427584, 569624576, 1061295104, 951777792, 61805824, 775005056, 330902720, 808816672, 1060017328, 879757864, 630813116, 839188910, 311867769 + ], + [ + 536870912, 268435456, 671088640, 469762048, 167772160, 50331648, 411041792, 784334848, 941621248, 1009778688, 175636480, 748945408, 51511296, 78577664, 726237184, 995999744, 955752448, 383627264, 397854720, 867998720, 971493888, 420783872, 405428352, 409691712, 395000032, 538634416, 1007850088, 103700980, 780737026, 133970691 + ], + [ + 536870912, 268435456, 939524096, 335544320, 167772160, 855638016, 109051904, 692060160, 736100352, 17825792, 79167488, 18612224, 975831040, 411631616, 596934656, 46120960, 817340416, 610521088, 876468224, 807130112, 1057061376, 142653184, 675296384, 174089152, 617642464, 890787024, 762151432, 381842180, 919451278, 431100101 + ], + [ + 536870912, 805306368, 671088640, 872415232, 167772160, 956301312, 662700032, 88080384, 257949696, 361758720, 361234432, 594804736, 438960128, 523304960, 783908864, 533544960, 552050688, 643256320, 1051674624, 813890560, 657738240, 516639488, 434164864, 860891200, 1034474912, 881185872, 934504456, 361622540, 1057432074, 168208141 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 637534208, 1056964608, 612368384, 473956352, 715128832, 275775488, 777519104, 1029439488, 736755712, 123535360, 585793536, 886849536, 640376832, 608006144, 603625472, 1049908224, 750680576, 42139904, 276429184, 158200768, 991089504, 812747920, 1046083976, 358478788, 401265514, 559778975 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 503316480, 922746880, 444596224, 507510784, 836763648, 691011584, 558366720, 287047680, 709230592, 7929856, 475299840, 224083968, 557768704, 414019584, 944666624, 117797888, 249782784, 810190592, 124142976, 48831552, 801926624, 20910256, 145562120, 273675012, 990193546, 283351887 + ], + [ + 536870912, 805306368, 671088640, 738197504, 301989888, 117440512, 897581056, 406847488, 106954752, 179306496, 274202624, 259784704, 362414080, 261816320, 345669632, 454803456, 677027840, 163196928, 474613760, 1072931840, 578774528, 568153344, 730464384, 986841664, 556710304, 141833584, 357480872, 902051196, 412531106, 251147639 + ], + [ + 536870912, 268435456, 671088640, 469762048, 33554432, 822083584, 1031798784, 440401920, 555745280, 745537536, 56098816, 208404480, 732299264, 270336000, 285114368, 678445056, 626548736, 191713280, 958883840, 81591296, 656398848, 48276736, 823251328, 151536576, 834955488, 810728432, 3586440, 30719940, 1021031146, 531767031 + ], + [ + 536870912, 268435456, 134217728, 67108864, 771751936, 889192448, 310378496, 213909504, 878706688, 112197632, 1035468800, 61079552, 834273280, 110559232, 57769984, 693682176, 517234688, 904089600, 113498112, 273857536, 16462336, 800466176, 383846016, 309452864, 98163936, 789945072, 386019432, 582214580, 747264010, 393116677 + ], + [ + 536870912, 268435456, 671088640, 67108864, 33554432, 16777216, 243269632, 1002438656, 757071872, 191889408, 163053568, 917241856, 619315200, 1045233664, 1035632640, 486817792, 820944896, 337793024, 945399808, 226337792, 979547648, 490220800, 812457344, 692721856, 167601376, 346246544, 345587080, 98306244, 22179050, 249608593 + ], + [ + 536870912, 268435456, 671088640, 469762048, 33554432, 922746880, 612368384, 322961408, 1046478848, 737148928, 694681600, 470548480, 310509568, 347275264, 66813952, 417775616, 851189760, 1015754752, 449775616, 617737216, 469358080, 303322368, 682091136, 643683776, 423304096, 38248112, 653104040, 976466612, 733734306, 671487923 + ], + [ + 536870912, 805306368, 402653184, 469762048, 905969664, 117440512, 1048576000, 943718400, 908066816, 862978048, 174587904, 28573696, 371064832, 68878336, 957120512, 57884672, 121184256, 212652032, 801327104, 1051732992, 612894208, 1067748096, 229064320, 905362112, 728717280, 628265680, 674865512, 908870684, 1032016014, 965856715 + ], + [ + 536870912, 805306368, 134217728, 603979776, 905969664, 822083584, 209715200, 834666496, 987758592, 76546048, 548929536, 367788032, 308412416, 369426432, 483885056, 295387136, 768188416, 38039552, 125233152, 69989376, 268514816, 939653888, 738242176, 302107840, 117531872, 1031822928, 1027666056, 186680268, 1047616610, 606607769 + ], + [ + 536870912, 268435456, 939524096, 603979776, 973078528, 956301312, 461373440, 666894336, 102760448, 466616320, 434634752, 671350784, 575537152, 105971712, 153649152, 245743616, 417275904, 534302720, 572344320, 863181824, 326311424, 57827584, 997414528, 527659840, 628280864, 477256560, 133384200, 540154884, 638819854, 1036230921 + ], + [ + 536870912, 805306368, 134217728, 335544320, 301989888, 318767104, 964689920, 675282944, 836763648, 542113792, 779616256, 210501632, 719978496, 700252160, 402882560, 912867328, 722804736, 439799808, 724514816, 1010031616, 771824128, 620831488, 813707392, 381703360, 840999648, 720384656, 105392264, 719608012, 973013218, 797609365 + ], + [ + 536870912, 805306368, 402653184, 335544320, 838860800, 419430400, 830472192, 88080384, 1046478848, 951058432, 410517504, 22806528, 420872192, 279117824, 448823296, 740376576, 273702912, 722022400, 948262912, 861619200, 601662976, 282482944, 805566080, 340862528, 822614304, 763652688, 618328488, 228335900, 104235022, 1014120457 + ], + [ + 536870912, 268435456, 402653184, 872415232, 167772160, 687865856, 662700032, 826277888, 551550976, 504365056, 688390144, 988020736, 392822784, 675872768, 302284800, 628801536, 1061199872, 199282688, 1016170496, 29924352, 138795520, 656035584, 160484480, 273171008, 906235936, 930868176, 574708232, 643862276, 617639046, 111710797 + ], + [ + 536870912, 805306368, 134217728, 469762048, 436207616, 419430400, 92274688, 675282944, 94371840, 898629632, 608698368, 94109696, 232128512, 878116864, 907444224, 582402048, 245768192, 414117888, 26359808, 1012143104, 67786240, 841022208, 684824448, 912889280, 491637024, 868179856, 891013416, 531128220, 246237482, 344891291 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 570425344, 889192448, 343932928, 264241152, 199229440, 95420416, 244842496, 1020002304, 264896512, 634322944, 518029312, 556875776, 425271296, 187494400, 679131136, 508955648, 917264896, 557539584, 930501248, 276572480, 131230368, 1002615856, 843840040, 747569276, 935403534, 132182019 + ], + [ + 536870912, 268435456, 402653184, 603979776, 503316480, 352321536, 159383552, 884998144, 761266176, 510656512, 452460544, 328466432, 862322688, 595263488, 938573824, 1043873792, 653647872, 152555520, 662919168, 828728320, 81766912, 827206912, 327665792, 130759744, 224972640, 509443472, 632026600, 26806484, 887445518, 35546125 + ], + [ + 536870912, 805306368, 939524096, 67108864, 704643072, 352321536, 444596224, 868220928, 962592768, 739246080, 820510720, 679215104, 928382976, 291831808, 51609600, 507953152, 856465408, 615452672, 1047545856, 829957120, 416654848, 554407680, 1065515648, 946862656, 9469024, 136881008, 211629192, 587618636, 464283886, 417212977 + ], + [ + 536870912, 268435456, 671088640, 872415232, 704643072, 520093696, 662700032, 71303168, 572522496, 99614720, 813170688, 615776256, 396754944, 198901760, 470908928, 535412736, 85778432, 127594496, 439396352, 404308992, 509894144, 783192832, 383217280, 375575616, 63265376, 589290128, 848249576, 908532180, 916178946, 816935945 + ], + [ + 536870912, 268435456, 134217728, 469762048, 436207616, 218103808, 847249408, 348127232, 232783872, 59768832, 775421952, 349437952, 457834496, 920322048, 65241088, 985120768, 381493248, 298250240, 93657088, 770395136, 384485888, 728388864, 338317696, 965405760, 876331232, 737292208, 885971176, 206136244, 997987050, 950482611 + ], + [ + 536870912, 268435456, 134217728, 469762048, 234881024, 687865856, 260046848, 415236096, 245366784, 573571072, 375914496, 80478208, 155582464, 244645888, 719486976, 413089792, 670130176, 357085184, 289269760, 722398208, 824770048, 179159296, 836234112, 684580928, 524792544, 865460464, 929234312, 660524356, 265332578, 540656055 + ], + [ + 536870912, 805306368, 134217728, 335544320, 167772160, 117440512, 746586112, 633339904, 1063256064, 191889408, 970457088, 62128128, 491126784, 680853504, 521633792, 807223296, 715857920, 774311936, 98834432, 936309760, 103347712, 867036928, 932404608, 664979904, 802872352, 587139568, 835845512, 1036622284, 958161954, 858435061 + ], + [ + 536870912, 268435456, 402653184, 469762048, 771751936, 587202560, 696254464, 281018368, 6291456, 774897664, 851968000, 25952256, 360316928, 426442752, 817070080, 191315968, 1007263744, 720228352, 382355456, 157467648, 1012802048, 984453376, 787093632, 192033472, 646439072, 821568624, 356878504, 871854196, 395428526, 874100083 + ], + [ + 536870912, 805306368, 671088640, 67108864, 905969664, 419430400, 360710144, 20971520, 1000341504, 875560960, 1062731776, 200540160, 192806912, 272695296, 438403072, 728842240, 435691520, 474329088, 744933376, 899001344, 607095296, 1070177536, 1008468352, 51579584, 774616992, 948946928, 863600648, 159727628, 788930570, 155496449 + ], + [ + 536870912, 805306368, 402653184, 872415232, 167772160, 50331648, 998244352, 834666496, 639631360, 36700160, 956825600, 702808064, 329121792, 340066304, 275742720, 325959680, 263856128, 872124416, 823867392, 193711104, 133330432, 847207680, 626276224, 903318848, 885073056, 278945712, 426776456, 577314124, 230005926, 1011241917 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 301989888, 419430400, 394264576, 968884224, 543162368, 359661568, 72876032, 348389376, 420610048, 669057024, 347176960, 272121856, 800448512, 373985280, 1034274816, 602094592, 779652608, 236282624, 391805824, 42732224, 947849760, 758025872, 514318344, 1034653708, 856967170, 383482895 + ], + [ + 536870912, 805306368, 939524096, 469762048, 234881024, 1056964608, 897581056, 1019215872, 367001600, 292552704, 1051197440, 874250240, 912392192, 363003904, 96632832, 275988480, 658219008, 207081472, 1000089600, 799179776, 549708288, 821234944, 58369664, 569885632, 156101408, 484117552, 304573224, 146033724, 998165286, 222338107 + ], + [ + 536870912, 805306368, 671088640, 603979776, 369098752, 318767104, 209715200, 213909504, 622854144, 567279616, 913833984, 721158144, 1027735552, 6356992, 665944064, 449396736, 817176576, 859222016, 326604800, 177660928, 644326912, 365938944, 525033088, 469072832, 710343648, 21405712, 421437448, 313716748, 659109898, 770970633 + ], + [ + 536870912, 268435456, 134217728, 738197504, 570425344, 889192448, 461373440, 230686720, 224395264, 550502400, 594018304, 972292096, 296353792, 787546112, 144211968, 854343680, 176644096, 655757312, 408823808, 660282368, 40422912, 880073472, 795516544, 51453760, 688473504, 1067826256, 142854152, 899959812, 25363970, 69506827 + ], + [ + 536870912, 805306368, 134217728, 201326592, 637534208, 956301312, 679477248, 364904448, 1063256064, 655360000, 739770368, 130809856, 579469312, 708640768, 247693312, 1011433472, 779476992, 616001536, 855549952, 59438080, 918398464, 956505856, 271156864, 1055228864, 216988384, 924006032, 749784712, 686360524, 990147810, 624860563 + ], + [ + 536870912, 268435456, 402653184, 335544320, 1040187392, 889192448, 427819008, 71303168, 652214272, 15728640, 231211008, 656670720, 924975104, 994902016, 513179648, 983023616, 211230720, 899067904, 102123520, 156687360, 53975552, 503726848, 829378944, 811208512, 172056480, 467710416, 359754632, 596196420, 180708902, 458478229 + ], + [ + 536870912, 805306368, 939524096, 201326592, 570425344, 989855744, 897581056, 46137344, 887095296, 808452096, 417857536, 491520000, 97386496, 764346368, 137265152, 591347712, 528949248, 72495104, 1016719360, 973423616, 76730880, 58307840, 129291392, 314262464, 148165024, 155886544, 308040104, 527885276, 459010470, 275026911 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 100663296, 956301312, 243269632, 683671552, 1067450368, 103809024, 359137280, 635699200, 172097536, 858718208, 634945536, 340606976, 235347968, 979161088, 186546176, 95452160, 556356096, 696535808, 1045685376, 959962816, 901089888, 607892528, 861052136, 632730108, 108341774, 370882307 + ], + [ + 536870912, 805306368, 671088640, 67108864, 905969664, 83886080, 796917760, 322961408, 660602880, 51380224, 129499136, 1069285376, 185466880, 94830592, 312639488, 378650624, 335077376, 744280064, 903854080, 801104896, 523193856, 299310336, 1040865664, 714427968, 290103456, 670374992, 224024232, 953017692, 1025982754, 761509405 + ], + [ + 536870912, 805306368, 671088640, 603979776, 838860800, 553648128, 713031680, 222298112, 186646528, 456130560, 235405312, 623640576, 931790848, 27197440, 372277248, 42516480, 325869568, 321564672, 258971648, 1062788096, 490077696, 1017008896, 850473088, 281653696, 97273120, 1020955440, 210178984, 765834748, 971479042, 104127493 + ], + [ + 536870912, 268435456, 671088640, 469762048, 771751936, 419430400, 662700032, 54525952, 165675008, 756023296, 582483968, 580124672, 80347136, 264175616, 912621568, 862175232, 999464960, 574230528, 253196288, 1019859968, 66942464, 222711040, 26231680, 561537856, 1052041312, 419156848, 615908328, 196714548, 1024826242, 864790339 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 436207616, 285212672, 209715200, 423624704, 450887680, 292552704, 702021632, 600047616, 1014366208, 419495936, 411140096, 658554880, 769777664, 384880640, 756582400, 753165312, 782682624, 994694912, 65866624, 288067264, 726924832, 721925040, 198705160, 1053032460, 854982662, 759234575 + ], + [ + 536870912, 805306368, 939524096, 603979776, 838860800, 452984832, 662700032, 113246208, 874512384, 512753664, 237502464, 166461440, 921829376, 297467904, 304513024, 290275328, 19095552, 829583360, 662366208, 503788544, 735949312, 1024088832, 597674880, 906555584, 159172768, 232463024, 852925096, 747991484, 244734246, 418743669 + ], + [ + 536870912, 805306368, 671088640, 738197504, 1040187392, 620756992, 310378496, 482344960, 425721856, 691011584, 196608000, 704905216, 942800896, 922550272, 588742656, 56508416, 780394496, 788803584, 447907840, 37504000, 376888832, 342804224, 3928960, 394319040, 1044429984, 765549264, 475049352, 478761932, 79507242, 11992603 + ], + [ + 536870912, 805306368, 939524096, 872415232, 369098752, 50331648, 864026624, 599785472, 681574400, 252706816, 370671616, 128712704, 192544768, 212926464, 378109952, 678805504, 91725824, 777760768, 526424064, 28433408, 571047424, 372528384, 957796480, 745157824, 648560480, 186925264, 34551816, 793144332, 731112974, 267684109 + ], + [ + 536870912, 268435456, 134217728, 469762048, 570425344, 318767104, 562036736, 633339904, 228589568, 5242880, 529006592, 350486528, 56754176, 187105280, 714440704, 846905344, 946577408, 646082560, 420890624, 1072477184, 650580480, 614820608, 84052864, 1070994624, 466480224, 525803952, 344770536, 45565300, 45966218, 567267523 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 637534208, 452984832, 411041792, 977272832, 811597824, 533725184, 228065280, 462684160, 882245632, 1069350912, 910852096, 229064704, 548691968, 648540160, 540309504, 686199808, 173373952, 171376384, 72194176, 862160320, 989533472, 594435312, 519633544, 952377028, 290426786, 357151295 + ], + [ + 536870912, 268435456, 134217728, 603979776, 301989888, 218103808, 645922816, 591396864, 819986432, 508559360, 580386816, 240386048, 814088192, 223412224, 790134784, 479477760, 749150208, 874614784, 225503232, 946435072, 234633728, 366679808, 263953024, 346792128, 299018400, 240575280, 193521672, 372077572, 25311746, 265164553 + ], + [ + 536870912, 268435456, 134217728, 603979776, 570425344, 956301312, 914358272, 230686720, 929038336, 244318208, 694681600, 803471360, 499515392, 272695296, 757104640, 783302656, 458825728, 612175872, 442222592, 810202112, 904130048, 937851648, 795907200, 976862016, 971818784, 414360112, 116293640, 730152964, 685219842, 677924873 + ], + [ + 536870912, 805306368, 134217728, 872415232, 369098752, 855638016, 679477248, 591396864, 425721856, 330301440, 669515776, 706478080, 533069824, 1054277632, 11436032, 260751360, 973692928, 15519744, 944687104, 1056623616, 373421568, 987811072, 611444864, 1070162880, 97325344, 807325712, 954349864, 257231900, 608888618, 808000785 + ], + [ + 536870912, 805306368, 939524096, 872415232, 369098752, 922746880, 444596224, 658505728, 589299712, 657457152, 770179072, 482607104, 173670400, 421724160, 410943488, 942227456, 614850560, 340447232, 117155840, 315841536, 611784192, 691803904, 910576256, 257238976, 407063776, 804257200, 875565800, 694773436, 8676966, 301615729 + ], + [ + 536870912, 268435456, 402653184, 335544320, 100663296, 50331648, 478150656, 490733568, 912261120, 95420416, 641204224, 947126272, 725221376, 1010892800, 669024256, 191938560, 60334080, 333721600, 559028224, 645784576, 968256000, 397308672, 277548416, 494420416, 487930784, 705424848, 322469896, 804569092, 653959174, 90255365 + ], + [ + 536870912, 268435456, 939524096, 335544320, 637534208, 184549376, 998244352, 901775360, 85983232, 300941312, 785907712, 603717632, 733085696, 992018432, 519077888, 190431232, 154968064, 856895488, 336680960, 243883008, 211054080, 158763264, 977190784, 260746944, 487359456, 820712336, 169648136, 971190276, 961107982, 213212165 + ], + [ + 536870912, 805306368, 134217728, 603979776, 369098752, 318767104, 360710144, 331350016, 354418688, 953155584, 645398528, 380895232, 339345408, 493158400, 398688256, 269565952, 853057536, 598011904, 274970624, 813767680, 625051136, 459293952, 439384192, 495528640, 454945568, 829898256, 204193928, 196884172, 577137954, 326269721 + ], + [ + 536870912, 805306368, 939524096, 67108864, 570425344, 352321536, 981467136, 717225984, 320864256, 646971392, 6815744, 128188416, 813563904, 492240896, 361922560, 614285312, 1058168832, 106819584, 271718400, 114076672, 660310528, 787073792, 124121984, 173976256, 659018976, 138109072, 530112232, 968682396, 579063142, 934670685 + ], + [ + 536870912, 805306368, 402653184, 201326592, 704643072, 889192448, 142606336, 918552576, 719323136, 705691648, 497549312, 557580288, 295043072, 940244992, 497844224, 436158464, 1012375552, 560705536, 50116608, 66505728, 1020985856, 652540160, 953416576, 90720192, 819851680, 939920592, 149105192, 926006044, 64570254, 658869199 + ], + [ + 536870912, 805306368, 671088640, 201326592, 905969664, 150994944, 243269632, 12582912, 983564288, 923795456, 1019740160, 528744448, 236322816, 828440576, 674332672, 513359872, 615276544, 761507840, 156190720, 971830272, 377669120, 734000384, 181725312, 247389760, 39116832, 796807856, 980803592, 783216652, 891103242, 146424835 + ], + [ + 536870912, 268435456, 134217728, 738197504, 100663296, 117440512, 360710144, 264241152, 555745280, 177209344, 752353280, 921436160, 536215552, 485687296, 434208768, 640729088, 227090432, 286609408, 579471360, 1029542912, 700338688, 247871232, 486260096, 590660160, 261835168, 994440400, 116624936, 14730644, 280010762, 1036619791 + ], + [ + 536870912, 805306368, 402653184, 469762048, 369098752, 16777216, 494927872, 457179136, 144703488, 91226112, 838336512, 345767936, 572391424, 1060700160, 863862784, 1036959744, 11657216, 479801344, 210552832, 334892032, 105736704, 1041747200, 245172096, 488519104, 666472928, 1069306736, 959375880, 299896076, 785475462, 973718983 + ], + [ + 536870912, 268435456, 939524096, 469762048, 234881024, 620756992, 411041792, 373293056, 463470592, 288358400, 820510720, 156499968, 36044800, 968032256, 678789120, 106381312, 192552960, 751898624, 309860352, 210553856, 698017280, 432027392, 778123392, 424720576, 683229920, 728530704, 336329320, 194545620, 1008539782, 121809091 + ], + [ + 536870912, 268435456, 402653184, 67108864, 100663296, 687865856, 645922816, 448790528, 123731968, 911212544, 143130624, 304873472, 694550528, 434044928, 61571072, 849952768, 324820992, 270454784, 424302592, 263834624, 234154496, 155400448, 978603904, 460469696, 286055328, 378985488, 1046874536, 39778580, 569046062, 34159061 + ], + [ + 536870912, 805306368, 671088640, 738197504, 570425344, 1056964608, 343932928, 264241152, 165675008, 886046720, 580386816, 640942080, 152698880, 685834240, 626098176, 47792128, 982867968, 652939264, 482932736, 242033664, 156188160, 6958848, 872953472, 386673856, 1012905376, 907232976, 225271816, 667881484, 883619850, 661136395 + ], + [ + 536870912, 805306368, 402653184, 603979776, 100663296, 184549376, 864026624, 775946240, 371195904, 112197632, 174587904, 828637184, 572653568, 228261888, 1032224768, 811089920, 281829376, 942133248, 682117120, 344224768, 737310208, 115506944, 595281536, 131518400, 358683104, 403827568, 152686568, 661418108, 97965934, 677405877 + ], + [ + 536870912, 805306368, 134217728, 335544320, 33554432, 788529152, 1065353216, 381681664, 295698432, 569376768, 1022885888, 585891840, 538836992, 658440192, 982417408, 227983360, 543842304, 924610560, 786827264, 584283136, 823132672, 1047097088, 608522368, 620470080, 615885856, 646149840, 505007144, 125568732, 221725738, 924496601 + ], + [ + 536870912, 805306368, 939524096, 67108864, 771751936, 1023410176, 8388608, 784334848, 857735168, 556793856, 953679872, 129236992, 1054736384, 204800000, 429883392, 122994688, 474980352, 52277248, 298993664, 823112704, 729562624, 293776640, 520583040, 352422848, 209754656, 1019323696, 606173064, 850430924, 731453998, 450127153 + ], + [ + 536870912, 268435456, 402653184, 872415232, 369098752, 922746880, 595591168, 205520896, 81788928, 900726784, 43515904, 50069504, 548798464, 132972544, 931037184, 1010417664, 346890240, 740192256, 1070143488, 131410944, 433265152, 86481664, 702873472, 856411072, 221955680, 1071899504, 66996104, 66672580, 68019302, 693052541 + ], + [ + 536870912, 268435456, 671088640, 67108864, 1040187392, 419430400, 511705088, 62914560, 404750336, 414187520, 534249472, 259784704, 1061027840, 909443072, 304775168, 355352576, 882745344, 799944704, 425502720, 110076928, 460154368, 613833984, 355573632, 496519616, 1058814816, 418329776, 230551944, 94339268, 1061448426, 919766129 + ], + [ + 536870912, 805306368, 402653184, 603979776, 100663296, 855638016, 377487360, 507510784, 467664896, 537919488, 890765312, 831258624, 1001521152, 53411840, 973373440, 761741312, 686874624, 864587776, 47540224, 903744512, 512587264, 1060254976, 812559232, 543554112, 62360480, 726149488, 796149800, 841998140, 696563086, 245809989 + ], + [ + 536870912, 268435456, 134217728, 335544320, 33554432, 620756992, 696254464, 146800640, 115343360, 376438784, 953679872, 56885248, 540672000, 759496704, 548044800, 200097792, 253108224, 716394496, 661129216, 249404416, 82808320, 214354688, 926567808, 969168320, 501990048, 332219920, 948366728, 144328132, 1033235106, 597920277 + ], + [ + 536870912, 268435456, 134217728, 335544320, 570425344, 620756992, 696254464, 356515840, 1059061760, 407896064, 209190912, 959184896, 222429184, 612433920, 952139776, 6307840, 376479744, 531173376, 85272576, 584010752, 617851392, 790132992, 433848960, 388662208, 343243104, 792646160, 54132744, 682426372, 335708162, 631324677 + ], + [ + 536870912, 805306368, 134217728, 872415232, 905969664, 654311424, 897581056, 901775360, 685768704, 225443840, 261619712, 938737664, 870973440, 891748352, 912818176, 657309696, 281010176, 345837568, 944179200, 920245248, 1012146688, 674961664, 971945088, 672435008, 857380192, 863906800, 729637864, 146172348, 947989002, 356633857 + ], + [ + 536870912, 268435456, 134217728, 335544320, 570425344, 218103808, 998244352, 272629760, 727711744, 489684992, 709361664, 662437888, 600965120, 401670144, 82345984, 845955072, 1061855232, 53743616, 665774080, 1017289728, 64594432, 421825280, 498491776, 195444288, 264192480, 62534032, 459040776, 654564356, 558465538, 738056965 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 234881024, 486539264, 964689920, 331350016, 371195904, 783286272, 556269568, 652476416, 354811904, 981663744, 650477568, 177684480, 338370560, 853544960, 1041356800, 249103360, 447529472, 789755648, 954065024, 446410432, 63492448, 552942224, 671003112, 774820948, 349618310, 197902027 + ], + [ + 536870912, 805306368, 402653184, 67108864, 234881024, 989855744, 92274688, 230686720, 673185792, 277872640, 542638080, 188481536, 252051456, 938934272, 249462784, 252329984, 184049664, 703401984, 666847232, 1056613376, 928082432, 226073344, 1026385792, 589232448, 388642464, 40424336, 230006440, 578955164, 184376494, 86395037 + ], + [ + 536870912, 268435456, 671088640, 67108864, 503316480, 788529152, 880803840, 205520896, 362807296, 286261248, 837287936, 14942208, 629538816, 233897984, 148406272, 467484672, 602546176, 291762176, 242677760, 103375872, 1032159744, 91700480, 1017651328, 918889280, 542636320, 1073309488, 1032607752, 86234116, 668424714, 624470273 + ], + [ + 536870912, 805306368, 939524096, 469762048, 234881024, 285212672, 1031798784, 4194304, 178257920, 273678336, 272105472, 613154816, 931790848, 1069744128, 132546560, 196689920, 567058432, 715870208, 752031744, 1073714176, 329524736, 824122112, 726959488, 376950336, 794882848, 917512176, 1019833640, 702857468, 817780390, 1032176059 + ], + [ + 536870912, 268435456, 939524096, 335544320, 771751936, 754974720, 176160768, 54525952, 1063256064, 955252736, 370671616, 903610368, 633470976, 844824576, 524779520, 237256704, 800055296, 685838336, 422590464, 104434688, 139298304, 137020672, 907955840, 110712896, 631079840, 86158128, 392824232, 461336116, 292145958, 772109937 + ], + [ + 536870912, 268435456, 939524096, 738197504, 1040187392, 989855744, 528482304, 322961408, 610271232, 869269504, 730333184, 1046740992, 286392320, 931594240, 212697088, 840384512, 935698432, 190976000, 377415680, 724681728, 681104896, 617398528, 801558912, 525168832, 109455456, 707543856, 64369128, 140879860, 773031814, 34009551 + ], + [ + 536870912, 805306368, 134217728, 469762048, 1040187392, 419430400, 662700032, 968884224, 174063616, 856686592, 624427008, 1003749376, 460718080, 129040384, 315195392, 1002192896, 708501504, 543354880, 19286016, 397016064, 439152128, 658703104, 756498560, 983674304, 653272224, 1005116080, 915220488, 884165644, 125715970, 820842247 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 637534208, 889192448, 746586112, 222298112, 715128832, 896532480, 292028416, 846462976, 457048064, 5308416, 551059456, 545013760, 131850240, 869675008, 65284096, 336045056, 66898432, 622527744, 95843200, 32778048, 838823328, 170979056, 80332808, 813995012, 580280834, 524673295 + ], + [ + 536870912, 268435456, 134217728, 67108864, 33554432, 587202560, 880803840, 624951296, 845152256, 217055232, 209190912, 481034240, 283508736, 514785280, 870023168, 155303936, 610328576, 636514304, 536422400, 258780160, 617059840, 348003584, 370368128, 737433408, 618266912, 666988944, 773930792, 621871252, 390633386, 653654741 + ], + [ + 536870912, 268435456, 134217728, 603979776, 167772160, 788529152, 662700032, 297795584, 1067450368, 193986560, 698875904, 770965504, 129105920, 336527360, 649691136, 203210752, 690446336, 185364480, 751806464, 798557184, 483136000, 40854272, 780728704, 136641984, 746296544, 600552240, 640917352, 349150708, 328841738, 986539789 + ], + [ + 536870912, 805306368, 402653184, 469762048, 503316480, 83886080, 981467136, 641728512, 828375040, 244318208, 188219392, 447479808, 220332032, 676659200, 170885120, 617070592, 179462144, 804040704, 935561216, 537134080, 288786944, 538658560, 469293696, 999064768, 869404896, 360516432, 654037128, 1034486732, 1033185894, 294649751 + ], + [ + 536870912, 268435456, 671088640, 335544320, 436207616, 520093696, 109051904, 322961408, 232783872, 506462208, 537395200, 661389312, 847380480, 69271552, 512786432, 517554176, 349478912, 975622144, 275773440, 1029944320, 688937472, 504958720, 1005961600, 674728000, 720775008, 920011280, 71704584, 1017024516, 961271818, 15475717 + ], + [ + 536870912, 268435456, 939524096, 603979776, 637534208, 117440512, 394264576, 650117120, 278921216, 898629632, 651689984, 245104640, 695074816, 966721536, 603422720, 65159168, 132734976, 735399936, 1043064832, 770544640, 868614656, 237762304, 99353472, 801593664, 204190624, 619481552, 1061600168, 1030360532, 311177638, 443956957 + ], + [ + 536870912, 268435456, 939524096, 67108864, 167772160, 385875968, 159383552, 1027604480, 970981376, 240123904, 746061824, 333185024, 791019520, 507445248, 141787136, 973881344, 857694208, 310554624, 432359424, 116122624, 134348288, 738236672, 906067840, 419433024, 343964064, 599791888, 220260264, 183578644, 466178086, 838180437 + ], + [ + 536870912, 805306368, 671088640, 603979776, 771751936, 520093696, 478150656, 599785472, 979369984, 770703360, 778567680, 419692544, 953548800, 11206656, 522223616, 491831296, 913858560, 802967552, 656115712, 896080896, 461666816, 739740928, 38444160, 1058139328, 374965088, 504203920, 446860776, 81110876, 1064230914, 672632837 + ], + [ + 536870912, 805306368, 134217728, 872415232, 1040187392, 352321536, 58720256, 146800640, 765460480, 722468864, 1013448704, 752091136, 138805248, 866713600, 636846080, 1058422784, 908107776, 802189312, 331933696, 415611904, 481277440, 20759808, 189973632, 47113536, 688728992, 728443568, 1024603656, 539919628, 293364866, 817075533 + ], + [ + 536870912, 805306368, 939524096, 335544320, 436207616, 251658240, 394264576, 918552576, 337641472, 976224256, 465043456, 372506624, 936247296, 831062016, 93159424, 234602496, 138911744, 553930752, 284571648, 620551168, 195184128, 534956288, 360920448, 584206272, 901398176, 203899632, 55868936, 522065164, 1008825230, 640716485 + ], + [ + 536870912, 268435456, 134217728, 603979776, 838860800, 251658240, 947912704, 616562688, 341835776, 93323264, 700973056, 90963968, 940965888, 236388352, 588742656, 479707136, 618061824, 645361664, 948373504, 744410112, 607906304, 220285184, 1051747712, 981052352, 9814176, 12787728, 209043624, 831725588, 970834090, 359604253 + ], + [ + 536870912, 268435456, 939524096, 872415232, 704643072, 620756992, 461373440, 440401920, 325058560, 560988160, 623378432, 884736000, 486670336, 889782272, 724336640, 1818624, 394043392, 757321728, 983164928, 238418944, 376324608, 997397248, 849414016, 944870208, 792298208, 82166160, 647389704, 968295172, 413552526, 75415373 + ], + [ + 536870912, 268435456, 671088640, 469762048, 503316480, 251658240, 964689920, 88080384, 249561088, 737148928, 102236160, 190578688, 728629248, 575340544, 457801728, 953532416, 169582592, 876679168, 677382144, 1060172800, 297338368, 810331392, 159862912, 378512192, 1044103200, 1058125456, 417871528, 298100948, 301149698, 704940291 + ], + [ + 536870912, 805306368, 671088640, 603979776, 167772160, 285212672, 645922816, 314572800, 387973120, 661651456, 274202624, 293339136, 589168640, 269287424, 1011318784, 351289344, 504930304, 765267968, 298821632, 1071932416, 994287104, 660851968, 798100864, 126593984, 1024972896, 894967344, 637379976, 752865228, 262948458, 318231353 + ], + [ + 536870912, 805306368, 402653184, 872415232, 570425344, 318767104, 243269632, 541065216, 211812352, 435159040, 788004864, 564396032, 414056448, 212664320, 15958016, 19382272, 330375168, 760762368, 953546752, 320259072, 506038784, 1013778688, 18053504, 133607616, 259536800, 828679472, 693046152, 310214092, 674939942, 1058741501 + ], + [ + 536870912, 268435456, 939524096, 872415232, 1040187392, 419430400, 310378496, 121634816, 350224384, 760217600, 23592960, 300679168, 321781760, 75038720, 333742080, 139706368, 379494400, 171995136, 677480448, 185660416, 856189440, 100507392, 531052160, 709207360, 115511904, 153588976, 990208520, 117615364, 1022885006, 439175757 + ], + [ + 536870912, 805306368, 671088640, 872415232, 1040187392, 117440512, 209715200, 1035993088, 304087040, 953155584, 1000865792, 921436160, 771358720, 392626176, 220495872, 648462336, 218488832, 997707776, 925730816, 98204672, 1052129792, 151807744, 520749952, 136195520, 174083872, 78772272, 1008215208, 276134396, 860838274, 76044993 + ], + [ + 536870912, 268435456, 671088640, 738197504, 1040187392, 452984832, 25165824, 440401920, 601882624, 168820736, 401080320, 560726016, 605683712, 225902592, 359497728, 236699648, 746004480, 502075392, 819652608, 257422336, 803065344, 344139008, 270711680, 928195008, 191598880, 223219760, 88681128, 823996916, 664976258, 169025999 + ], + [ + 536870912, 805306368, 671088640, 469762048, 436207616, 251658240, 914358272, 381681664, 828375040, 479199232, 158859264, 488374272, 634781696, 622657536, 567771136, 186400768, 685203456, 681349120, 127342592, 968696832, 1017622016, 489991936, 877873792, 747037888, 696558176, 228280944, 642992776, 260498636, 755278442, 140200567 + ], + [ + 536870912, 805306368, 402653184, 603979776, 369098752, 117440512, 327155712, 541065216, 924844032, 464519168, 907542528, 349962240, 305004544, 961740800, 17596416, 271007744, 434561024, 327618560, 26658816, 721404928, 500846080, 58282752, 21827712, 386374464, 441948448, 27182352, 55208360, 1070681692, 923383950, 573837125 + ], + [ + 536870912, 805306368, 402653184, 469762048, 234881024, 385875968, 796917760, 230686720, 228589568, 764411904, 864550912, 31195136, 1051328512, 758448128, 80183296, 172474368, 319184896, 719728640, 202774528, 1043311616, 992609792, 368408832, 669456000, 244779840, 24032608, 298513040, 243593352, 18842188, 1051974630, 543253975 + ], + [ + 536870912, 268435456, 134217728, 872415232, 301989888, 184549376, 1048576000, 859832320, 635437056, 1032847360, 315097088, 554958848, 309723136, 978649088, 328630272, 499466240, 1046421504, 273797120, 342456320, 828711936, 154034688, 461982464, 737455744, 191237440, 618520096, 1004747504, 174206600, 228805956, 738393634, 754117373 + ], + [ + 536870912, 268435456, 134217728, 335544320, 973078528, 486539264, 343932928, 767557632, 534773760, 609222656, 465043456, 44826624, 467271680, 1043136512, 840597504, 332218368, 524951552, 653561856, 757516288, 911094784, 446342656, 805632, 799720576, 522499776, 903823840, 465707024, 779142280, 738834116, 457556450, 835674133 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 1040187392, 687865856, 461373440, 1027604480, 643825664, 204472320, 783810560, 605290496, 3801088, 227344384, 8355840, 239026176, 551510016, 690958336, 741763072, 330435584, 413168128, 319911680, 250105728, 765208768, 102235168, 644044944, 224976264, 350040012, 712424354, 22170719 + ], + [ + 536870912, 268435456, 671088640, 603979776, 838860800, 654311424, 360710144, 775946240, 945815552, 122683392, 141033472, 383516672, 298975232, 384368640, 723288064, 989020160, 1062739968, 769986560, 359036928, 317099008, 195518976, 239483648, 56063616, 23019840, 936525280, 1005146128, 362635784, 389233412, 1014625930, 542441801 + ], + [ + 536870912, 268435456, 134217728, 603979776, 1040187392, 318767104, 1048576000, 977272832, 522190848, 485490688, 139984896, 107741184, 20054016, 84606976, 53968896, 158187520, 1035198464, 1045139456, 731367424, 1012751360, 1024155136, 1060589312, 460063872, 884080704, 768231456, 1012397872, 666727976, 77260852, 884955818, 162079869 + ], + [ + 536870912, 268435456, 939524096, 469762048, 369098752, 352321536, 595591168, 826277888, 627048448, 611319808, 860356608, 471072768, 162922496, 685309952, 669810688, 63684608, 367779840, 603664384, 809691136, 316652544, 870160896, 342004480, 1003358080, 14971968, 826148256, 762075952, 386568712, 751509252, 493614478, 3906375 + ], + [ + 536870912, 805306368, 134217728, 738197504, 838860800, 50331648, 1015021568, 608174080, 274726912, 30408704, 567803904, 532938752, 880410624, 290783232, 625180672, 285294592, 260104192, 281137152, 404846592, 598766592, 587807232, 43869952, 268381312, 894340544, 902197408, 362442000, 21353608, 725334476, 431336098, 517200411 + ], + [ + 536870912, 805306368, 671088640, 738197504, 973078528, 50331648, 327155712, 171966464, 908066816, 902823936, 486014976, 871628800, 716046336, 609550336, 171933696, 252461056, 693821440, 654020608, 40630272, 1060277248, 626452992, 471883008, 785486976, 192422592, 800347936, 630130096, 17134728, 252097228, 9973546, 379323 + ], + [ + 536870912, 805306368, 671088640, 738197504, 301989888, 855638016, 713031680, 683671552, 115343360, 858783744, 1023934464, 975962112, 616169472, 694878208, 324173824, 41402368, 299933696, 397488128, 482945024, 156056576, 130750976, 155368704, 909065344, 3457216, 961427360, 692401520, 778551208, 414792060, 635800994, 796309623 + ], + [ + 536870912, 268435456, 402653184, 872415232, 1040187392, 620756992, 58720256, 239075328, 660602880, 49283072, 532152320, 1057226752, 247595008, 449249280, 981827584, 25313280, 405168128, 657838080, 81434624, 244536320, 313507328, 766038272, 34470016, 874386496, 510670048, 24700592, 480627816, 747827956, 900724878, 422122569 + ], + [ + 536870912, 805306368, 134217728, 67108864, 637534208, 587202560, 209715200, 918552576, 283115520, 152043520, 993525760, 349437952, 326500352, 280952832, 264404992, 572047360, 463855616, 513757184, 573769728, 1043385344, 323553792, 868037888, 876243328, 1026309696, 21220320, 567899856, 751053288, 701489116, 422199914, 269818013 + ], + [ + 536870912, 805306368, 402653184, 335544320, 436207616, 452984832, 360710144, 633339904, 517996544, 818937856, 401080320, 8650752, 154796032, 1020854272, 457015296, 957792256, 365404160, 607014912, 699045888, 537938944, 763895296, 51683072, 611549824, 766260544, 819865888, 938703440, 896345608, 918455052, 576914566, 220587589 + ], + [ + 536870912, 268435456, 939524096, 67108864, 301989888, 486539264, 125829120, 910163968, 354418688, 97517568, 730333184, 707526656, 700317696, 1021902848, 14450688, 652722176, 751640576, 974000128, 1007691776, 619224064, 350020096, 216424704, 902660736, 797869632, 391185504, 910717296, 659374600, 844083460, 439388814, 767035969 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 369098752, 721420288, 746586112, 926941184, 429916160, 282066944, 581435392, 475267072, 832176128, 145948672, 690388992, 626868224, 874487808, 234983424, 654411776, 42028032, 541091328, 589341440, 210807168, 394803904, 1002752864, 177387056, 70692200, 974460220, 834307302, 748908531 + ], + [ + 536870912, 805306368, 939524096, 201326592, 771751936, 553648128, 427819008, 138412032, 715128832, 32505856, 14155776, 802947072, 973471744, 264962048, 1002733568, 79314944, 769433600, 84316160, 256555008, 637871104, 140230144, 663535360, 498009728, 672068416, 427755808, 1013325648, 324704168, 218961948, 997079174, 1047465039 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 100663296, 50331648, 58720256, 88080384, 337641472, 535822336, 409468928, 238288896, 4063232, 76873728, 504266752, 471613440, 665542656, 152727552, 793933824, 328657920, 927011328, 1025551616, 829447552, 564770368, 450138144, 229526960, 346897800, 316851780, 509503530, 851829183 + ], + [ + 536870912, 805306368, 671088640, 469762048, 704643072, 1056964608, 897581056, 952107008, 908066816, 537919488, 290979840, 673447936, 237109248, 993722368, 226394112, 254656512, 574496768, 315486208, 59754496, 944063488, 324203008, 965921536, 884141952, 1059260224, 532403552, 557832176, 1028499304, 743431420, 669378786, 562293691 + ], + [ + 536870912, 805306368, 402653184, 67108864, 167772160, 218103808, 578813952, 952107008, 85983232, 688914432, 479723520, 211025920, 345374720, 1055457280, 654147584, 967491584, 1071849472, 592367616, 320612352, 966423552, 476739072, 809677056, 782115968, 77872832, 455061408, 1004919600, 410975752, 555078924, 802609798, 931720129 + ], + [ + 536870912, 805306368, 134217728, 469762048, 704643072, 956301312, 226492416, 205520896, 765460480, 999292928, 1054343168, 637272064, 527826944, 514523136, 940343296, 853524480, 373268480, 395259904, 797333504, 142836736, 802782720, 75282176, 825681280, 369843264, 605921824, 960979920, 333637544, 1059590044, 576036234, 786638923 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 301989888, 419430400, 796917760, 868220928, 698351616, 110100480, 67633152, 12845056, 448397312, 213319680, 887652352, 297058304, 860004352, 885682176, 231659520, 869561344, 947110400, 810803968, 1040335232, 220917952, 725494880, 1038994672, 128921576, 82059068, 787210754, 446583555 + ], + [ + 536870912, 805306368, 671088640, 469762048, 369098752, 788529152, 494927872, 121634816, 115343360, 930086912, 30932992, 539230208, 812253184, 951910400, 363823104, 472268800, 411721728, 617443328, 737630208, 507706368, 176263680, 516018944, 597800320, 345030592, 304709536, 339580176, 208643976, 1040657612, 492481066, 520379095 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 838860800, 654311424, 1048576000, 499122176, 782237696, 640679936, 620232704, 688652288, 393871360, 96272384, 272859136, 1058029568, 76046336, 253022208, 698800128, 292512768, 932926976, 762134784, 963313536, 246702784, 1024897504, 844529680, 724969352, 279316172, 586049514, 668696863 + ], + [ + 536870912, 268435456, 671088640, 469762048, 369098752, 452984832, 981467136, 884998144, 241172480, 202375168, 261619712, 797179904, 794689536, 355139584, 1019052032, 564903936, 930914304, 927649792, 514598912, 20147200, 678986240, 567635200, 610678656, 1071546944, 1022072800, 996005968, 1073424488, 340125204, 29332866, 150667075 + ], + [ + 536870912, 805306368, 939524096, 603979776, 704643072, 721420288, 461373440, 356515840, 283115520, 248512512, 197656576, 689700864, 628752384, 577830912, 158957568, 348504064, 655302656, 715542528, 783013888, 54107136, 1034275328, 194983680, 604921472, 489032256, 233514720, 920238800, 703952904, 630590476, 322122254, 858651401 + ], + [ + 536870912, 268435456, 939524096, 738197504, 503316480, 989855744, 109051904, 314572800, 849346560, 697303040, 397934592, 453771264, 269615104, 134021120, 152731648, 580435968, 131981312, 273362944, 444708864, 616580096, 497061376, 487637248, 544811648, 338489536, 767795424, 807775056, 153612936, 212026564, 211121902, 307175003 + ], + [ + 536870912, 805306368, 671088640, 67108864, 369098752, 50331648, 8388608, 666894336, 505413632, 40894464, 98041856, 647757824, 674365440, 702742528, 1040875520, 439336960, 672260096, 650661888, 886425600, 86412288, 904172032, 522081024, 606705792, 872698432, 525207712, 427913264, 104865960, 73444412, 1007811234, 684241725 + ], + [ + 536870912, 805306368, 939524096, 603979776, 570425344, 989855744, 830472192, 943718400, 471859200, 766509056, 1010302976, 619970560, 22151168, 267714560, 953384960, 733265920, 586326016, 520474624, 340490240, 842030080, 829995520, 206945536, 404903808, 1059888320, 527945760, 781076048, 1008359304, 265854156, 69586990, 1048266329 + ], + [ + 536870912, 805306368, 134217728, 67108864, 100663296, 16777216, 343932928, 901775360, 211812352, 550502400, 611844096, 4980736, 574488576, 111083520, 307134464, 943112192, 1031462912, 231002112, 1067177984, 905313280, 416453120, 225449728, 539607424, 435501632, 718521376, 40945616, 833168424, 1051989980, 313719850, 981593053 + ], + [ + 536870912, 268435456, 134217728, 872415232, 436207616, 788529152, 998244352, 742391808, 421527552, 540016640, 680001536, 46399488, 1058406400, 360120320, 266829824, 387956736, 175267840, 579907584, 888719360, 997037056, 702723584, 417914624, 928288384, 477000384, 609966304, 1042559568, 558282984, 762266196, 853151978, 988112473 + ], + [ + 536870912, 268435456, 402653184, 738197504, 503316480, 922746880, 8388608, 247463936, 702545920, 116391936, 276299776, 546045952, 47841280, 750452736, 738951168, 793985024, 315498496, 798806016, 72509440, 72346624, 576576000, 523384064, 629019264, 742758720, 923762976, 285079024, 258187560, 257304052, 601901358, 334596607 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 234881024, 16777216, 1015021568, 12582912, 429916160, 630194176, 918028288, 583270400, 114688000, 696320000, 104955904, 308396032, 867295232, 543715328, 815532032, 610526208, 622790144, 126635264, 588999808, 452629952, 403310112, 730009264, 451805192, 109379596, 330792974, 598786063 + ], + [ + 536870912, 268435456, 134217728, 603979776, 905969664, 654311424, 478150656, 960495616, 132120576, 344981504, 167247872, 142344192, 656539648, 939982848, 338264064, 509919232, 399466496, 81629184, 894568448, 384736256, 342724096, 966427904, 1016841088, 689643328, 131763744, 939162096, 214573992, 767734708, 487982602, 84990221 + ], + [ + 536870912, 268435456, 134217728, 67108864, 905969664, 687865856, 562036736, 37748736, 245366784, 118489088, 139984896, 170655744, 634781696, 204668928, 777093120, 544784384, 201089024, 854560768, 317716480, 49267712, 183426560, 250578688, 955129216, 300900928, 812517280, 841972176, 1016020008, 1000298644, 868644874, 971703301 + ], + [ + 536870912, 805306368, 939524096, 469762048, 100663296, 822083584, 159383552, 725614592, 480247808, 53477376, 150470656, 772538368, 802029568, 219742208, 312311808, 1049083904, 573431808, 440381440, 268519424, 134294528, 604023296, 436309248, 922772864, 947951040, 583129440, 937442800, 529582600, 197786892, 653577614, 29493703 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 100663296, 50331648, 192937984, 918552576, 715128832, 164626432, 915931136, 993787904, 223739904, 710737920, 849772544, 710197248, 442720256, 835645440, 1012955136, 863054848, 122260992, 832887040, 812372096, 604743104, 326892896, 775126384, 446050440, 578655684, 993453422, 875405695 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 33554432, 117440512, 780140544, 1010827264, 228589568, 258998272, 984088576, 672399360, 710541312, 555679744, 542932992, 136232960, 333291520, 165572608, 851208192, 844049408, 591709696, 1027856128, 709046912, 482546880, 880958688, 119772144, 223520360, 511367996, 615437442, 1058304963 + ], + [ + 536870912, 268435456, 402653184, 335544320, 33554432, 184549376, 729808896, 859832320, 132120576, 470810624, 33030144, 297533440, 802029568, 283574272, 990085120, 788611072, 562094080, 876638208, 979429376, 642847744, 647536128, 359463168, 446121344, 447467584, 153477792, 799259728, 619713704, 610799956, 805613358, 101845009 + ], + [ + 536870912, 268435456, 939524096, 872415232, 637534208, 1056964608, 864026624, 432013312, 127926272, 693108736, 721944576, 998506496, 347996160, 445972480, 282492928, 257998848, 1047601152, 35188736, 602691584, 726313984, 422721024, 925769984, 129877120, 985892160, 267830944, 980489648, 202972296, 283961668, 181096622, 435356861 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 33554432, 822083584, 310378496, 608174080, 199229440, 800063488, 382205952, 503054336, 305004544, 872873984, 835354624, 636239872, 750166016, 176304128, 634451968, 246959104, 773135872, 868358400, 380672128, 273221824, 532435488, 382621136, 976743464, 549616860, 87133358, 1049114643 + ], + [ + 536870912, 805306368, 134217728, 603979776, 704643072, 150994944, 159383552, 415236096, 492830720, 714080256, 715653120, 948174848, 956956672, 192872448, 701267968, 224378880, 1073504256, 294121472, 998266880, 230728704, 316774912, 894518528, 491299712, 173313984, 528627296, 483041008, 228503016, 1050494268, 1024940426, 371800773 + ], + [ + 536870912, 805306368, 939524096, 201326592, 838860800, 520093696, 75497472, 717225984, 874512384, 210763776, 98041856, 786169856, 982646784, 561184768, 105021440, 659243008, 867115008, 919646208, 356075520, 57469952, 609909248, 372685568, 334286720, 10148160, 924281760, 150747440, 419613608, 405522748, 241083302, 469275967 + ], + [ + 536870912, 805306368, 671088640, 201326592, 905969664, 184549376, 243269632, 490733568, 576716800, 697303040, 959971328, 218365952, 756154368, 1046937600, 136085504, 426164224, 10231808, 656822272, 545105920, 636996608, 807759360, 266486016, 961534848, 518051648, 902936288, 14278192, 810935656, 327914876, 785520002, 424019535 + ], + [ + 536870912, 805306368, 134217728, 201326592, 905969664, 620756992, 276824064, 348127232, 48234496, 707788800, 648544256, 561250304, 467533824, 713621504, 715489280, 717635584, 622157824, 808333312, 373319680, 958489600, 592532992, 567893760, 930899328, 599440192, 799971488, 956410224, 511817224, 901852940, 677473666, 770830147 + ], + [ + 536870912, 268435456, 671088640, 335544320, 771751936, 721420288, 864026624, 507510784, 65011712, 533725184, 1018691584, 55836672, 436338688, 266928128, 741113856, 133644288, 777756672, 820834304, 1020696576, 481000448, 698655232, 793507584, 242539136, 804510656, 924884896, 821089680, 541604360, 824019716, 975108234, 58092741 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 838860800, 855638016, 578813952, 448790528, 278921216, 644874240, 135790592, 243007488, 549584896, 671416320, 778993664, 867057664, 529424384, 171921408, 1057404928, 491496448, 217185792, 1054456064, 81549696, 162721728, 815599456, 164768336, 558712712, 188368580, 1021939434, 614740383 + ], + [ + 536870912, 805306368, 402653184, 201326592, 838860800, 654311424, 461373440, 616562688, 811597824, 296747008, 848822272, 856424448, 414056448, 297467904, 190349312, 468533248, 274636800, 780333056, 386148352, 942318592, 256924160, 191419648, 380987008, 582131008, 677209760, 768032784, 302930472, 359270492, 217111054, 691639567 + ], + [ + 536870912, 268435456, 671088640, 603979776, 637534208, 16777216, 696254464, 205520896, 1029701632, 909115392, 217579520, 817102848, 589955072, 121700352, 132153344, 485572608, 827924480, 941961216, 700581888, 433867776, 586605056, 968338176, 341250432, 195532736, 880700832, 681215312, 435716104, 120930308, 577445898, 295710729 + ], + [ + 536870912, 805306368, 671088640, 67108864, 33554432, 1056964608, 578813952, 817889280, 174063616, 267386880, 915931136, 1046740992, 660209664, 267190272, 546799616, 36323328, 1035247616, 1049808896, 293705728, 608216064, 799092224, 470851328, 690552192, 224238016, 1043254176, 555644816, 770108296, 879915724, 565248042, 305763665 + ], + [ + 536870912, 268435456, 939524096, 738197504, 234881024, 956301312, 880803840, 784334848, 350224384, 122683392, 1070071808, 714342400, 875167744, 223805440, 89751552, 104677376, 548315136, 320081920, 476788736, 947301376, 929575424, 719642880, 919860608, 714764480, 860873952, 834961136, 769852264, 180600628, 670206470, 313199887 + ], + [ + 536870912, 268435456, 671088640, 872415232, 838860800, 620756992, 327155712, 247463936, 379584512, 124780544, 216530944, 476839936, 490864640, 27066368, 854228992, 244334592, 251207680, 248827904, 41322496, 234490880, 61398528, 822995200, 923970944, 818274880, 114221280, 768571728, 223225224, 789507652, 904838890, 192925789 + ], + [ + 536870912, 268435456, 939524096, 67108864, 369098752, 251658240, 176160768, 130023424, 773849088, 594542592, 260571136, 201064448, 735707136, 574685184, 861962240, 848412672, 114827264, 822390784, 548304896, 149378048, 1027325440, 227619072, 609778560, 180694080, 479115232, 848741072, 926056456, 187482116, 643997710, 634679297 + ], + [ + 536870912, 268435456, 939524096, 469762048, 637534208, 117440512, 562036736, 4194304, 1012924416, 1016070144, 469237760, 9175040, 948830208, 1033961472, 280002560, 587841536, 1004855296, 100347904, 44251136, 874417152, 240665088, 876364544, 562558080, 658782144, 868909152, 6959728, 869949448, 190050308, 301422606, 250379271 + ], + [ + 536870912, 805306368, 671088640, 469762048, 436207616, 385875968, 578813952, 968884224, 463470592, 607125504, 734527488, 270270464, 774504448, 720306176, 836796416, 433111040, 806985728, 50606080, 162424832, 394308608, 138500608, 786453248, 391191680, 1004056512, 329606816, 354346416, 310962216, 561874300, 490414082, 232255499 + ], + [ + 536870912, 268435456, 134217728, 872415232, 234881024, 553648128, 142606336, 910163968, 740294656, 1001390080, 838336512, 534511616, 347471872, 630915072, 662011904, 188923904, 10018816, 936202240, 1027553280, 593488896, 583927296, 897981184, 690133120, 990507072, 260311072, 136010448, 263465128, 203654804, 629720714, 616863561 + ], + [ + 536870912, 268435456, 671088640, 872415232, 436207616, 16777216, 427819008, 356515840, 627048448, 330301440, 410517504, 583270400, 853671936, 865271808, 952860672, 677298176, 867524608, 297447424, 386349056, 958411776, 189890048, 747218176, 719102080, 1509184, 222930784, 360462704, 612835176, 358731124, 732987746, 74979449 + ], + [ + 536870912, 268435456, 134217728, 335544320, 905969664, 587202560, 595591168, 322961408, 631242752, 760217600, 1027080192, 572784640, 137756672, 782172160, 1013153792, 553762816, 645947392, 465653760, 23070720, 766620672, 382246400, 298625792, 74112384, 556576320, 932909664, 247855440, 432407656, 343287380, 314550250, 192066321 + ], + [ + 536870912, 268435456, 939524096, 201326592, 234881024, 520093696, 1015021568, 624951296, 467664896, 781189120, 794296320, 56885248, 843448320, 567738368, 856653824, 246038528, 852238336, 220942336, 990652416, 193694720, 41715200, 71436544, 826398080, 165798720, 126918240, 14169424, 346338920, 333953364, 673591398, 394702935 + ], + [ + 536870912, 805306368, 939524096, 201326592, 503316480, 150994944, 880803840, 784334848, 119537664, 267386880, 310902784, 298057728, 789708800, 341377024, 230522880, 752861184, 374300672, 651587584, 122357760, 1071940608, 610510336, 269492480, 391676800, 306003520, 429804832, 237902864, 709348872, 986895628, 16264590, 688757571 + ], + [ + 536870912, 805306368, 939524096, 469762048, 570425344, 721420288, 360710144, 826277888, 35651584, 963641344, 876085248, 472645632, 724959232, 243859456, 620068864, 839630848, 22536192, 56201216, 696064000, 394234880, 69040640, 355457280, 265617280, 100394944, 699312736, 806730544, 454812168, 1069454604, 494790030, 561999559 + ], + [ + 536870912, 805306368, 402653184, 201326592, 973078528, 654311424, 511705088, 138412032, 442499072, 110100480, 1009254400, 794034176, 2228224, 648740864, 810450944, 825507840, 414392320, 327315456, 278530048, 987126784, 364490240, 704419072, 154594688, 770210496, 334852448, 210962416, 175341416, 530752252, 90847982, 267301951 + ], + [ + 536870912, 268435456, 671088640, 872415232, 167772160, 486539264, 796917760, 373293056, 115343360, 630194176, 626524160, 434372608, 788135936, 134021120, 645824512, 114704384, 1010442240, 199004160, 63866880, 272550912, 271985152, 833303296, 444951168, 271246272, 600063648, 944480912, 26591368, 447975620, 159478826, 222351709 + ], + [ + 536870912, 805306368, 402653184, 738197504, 369098752, 50331648, 998244352, 968884224, 1029701632, 516947968, 106430464, 149159936, 789708800, 1039335424, 283279360, 651837440, 611262464, 426086400, 735217664, 202626048, 913529344, 824381696, 934950784, 750693696, 473771616, 414663920, 448794216, 920769788, 1058014830, 389562615 + ], + [ + 536870912, 805306368, 402653184, 738197504, 771751936, 50331648, 260046848, 297795584, 287309824, 802160640, 83361792, 532414464, 122028032, 32571392, 581533696, 1032110080, 73097216, 363229184, 973117440, 822164480, 981544448, 826317056, 559945344, 741360576, 898109408, 626277680, 220461064, 920341516, 552056326, 23110923 + ], + [ + 536870912, 268435456, 671088640, 603979776, 905969664, 956301312, 947912704, 759169024, 966787072, 1064304640, 565706752, 637272064, 501350400, 721092608, 569868288, 543997952, 529195008, 323932160, 1041291264, 1017674752, 450168320, 905442048, 778839168, 713799488, 969881504, 475056688, 76075432, 811985204, 11414818, 222372477 + ], + [ + 536870912, 268435456, 939524096, 872415232, 33554432, 855638016, 847249408, 926941184, 241172480, 242221056, 1018691584, 105119744, 128581632, 290914304, 918126592, 692404224, 992632832, 588689408, 995624960, 301288448, 204623360, 302217472, 5900416, 875551296, 131865056, 738145904, 456417128, 429102388, 408047110, 192117001 + ], + [ + 536870912, 268435456, 939524096, 335544320, 973078528, 16777216, 562036736, 12582912, 689963008, 684720128, 120061952, 60030976, 295567360, 415039488, 336232448, 505593856, 37167104, 275353600, 360048640, 854572032, 50626048, 584523008, 202933376, 743201344, 812778784, 593433136, 211614344, 190531396, 919241134, 839075957 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 838860800, 520093696, 377487360, 633339904, 950009856, 59768832, 190316544, 1035730944, 241041408, 14352384, 361267200, 914702336, 424878080, 151875584, 215410688, 887065600, 1058732544, 371800832, 764772736, 449462848, 93393184, 844629520, 574474920, 740249436, 641372686, 49870595 + ], + [ + 536870912, 268435456, 134217728, 872415232, 369098752, 822083584, 545259520, 994050048, 148897792, 919601152, 211288064, 6553600, 983433216, 424345600, 945651712, 88784896, 173858816, 709595136, 802977792, 663464960, 763178496, 960181504, 745866624, 1025941568, 543085792, 308941648, 19745128, 367234836, 393300874, 229164361 + ], + [ + 536870912, 805306368, 134217728, 67108864, 33554432, 285212672, 1048576000, 683671552, 316669952, 277872640, 470286336, 2359296, 507904000, 297992192, 917798912, 558874624, 912744448, 984788992, 145512448, 329423872, 702923264, 170322176, 630341504, 1046281920, 586880096, 464014992, 1024773096, 444514396, 559835018, 632185549 + ], + [ + 536870912, 805306368, 134217728, 469762048, 369098752, 788529152, 310378496, 289406976, 165675008, 600834048, 145227776, 549191680, 155582464, 923467776, 991199232, 494649344, 135110656, 192925696, 50235392, 994020352, 312372736, 422550784, 664229248, 941767104, 694711200, 756852560, 16158248, 749863580, 253836170, 552707275 + ], + [ + 536870912, 805306368, 939524096, 738197504, 167772160, 1023410176, 461373440, 616562688, 975175680, 355467264, 647495680, 175898624, 413532160, 815464448, 492601344, 504774656, 650354688, 184659968, 612497408, 373396480, 593545728, 1020350208, 789073024, 110389056, 715362336, 223407696, 113859752, 523618588, 928246918, 468309831 + ], + [ + 536870912, 805306368, 402653184, 67108864, 838860800, 822083584, 562036736, 926941184, 207618048, 835715072, 873988096, 307494912, 158728192, 312541184, 653361152, 665370624, 278667264, 230395904, 776112128, 663194624, 420084224, 409797376, 756219520, 475961536, 234686112, 770323888, 891002888, 1035096076, 330246150, 265608193 + ], + [ + 536870912, 805306368, 939524096, 67108864, 234881024, 385875968, 578813952, 717225984, 601882624, 149946368, 871890944, 563347456, 17432576, 520028160, 323256320, 90324992, 27451392, 88264704, 389253120, 168479744, 109007360, 411427072, 386065536, 252949056, 681289312, 1060607600, 449422056, 688780348, 598674566, 1047391821 + ], + [ + 536870912, 805306368, 939524096, 201326592, 503316480, 385875968, 92274688, 717225984, 157286400, 19922944, 296222720, 531890176, 857866240, 808910848, 180649984, 715800576, 571645952, 698224640, 561055744, 193508352, 455354880, 836449536, 614147712, 171689664, 988414432, 3362864, 554633064, 1032374012, 136621702, 509227727 + ], + [ + 536870912, 268435456, 402653184, 603979776, 973078528, 83886080, 327155712, 213909504, 1012924416, 665845760, 416808960, 105119744, 609615872, 1052966912, 125665280, 442646528, 783081472, 470446080, 1034958848, 232330240, 231074304, 211193088, 950178432, 634139968, 289131488, 606645008, 71139688, 616823380, 310220942, 300140621 + ], + [ + 536870912, 805306368, 402653184, 872415232, 301989888, 50331648, 931135488, 381681664, 723517440, 68157440, 68681728, 1044119552, 719716352, 135069696, 40861696, 761905152, 240394240, 103960576, 645838848, 426880000, 678030848, 416646400, 1014212224, 404681152, 847312224, 4275696, 291585672, 980487628, 803840870, 370414845 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 436207616, 150994944, 377487360, 658505728, 136314880, 261095424, 258473984, 1011613696, 663355392, 242024448, 823820288, 260423680, 370630656, 976162816, 518662144, 316482560, 174248448, 727713024, 833666688, 200857152, 279296224, 805722128, 260562568, 776455748, 422023398, 580353055 + ], + [ + 536870912, 805306368, 671088640, 872415232, 167772160, 251658240, 511705088, 205520896, 652214272, 495976448, 827850752, 515112960, 598081536, 445710336, 735674368, 821379072, 1044881408, 327241728, 432142336, 371307520, 204587520, 514418432, 826053760, 875265728, 911447968, 89565744, 43644936, 932557836, 420987402, 1014523661 + ], + [ + 536870912, 805306368, 402653184, 872415232, 771751936, 318767104, 1048576000, 364904448, 14680064, 32505856, 119013376, 595329024, 257556480, 361299968, 903184384, 748601344, 931045376, 336588800, 81188864, 776606720, 593509888, 162598656, 884568960, 61680320, 659795680, 589082704, 543835656, 15854348, 412620166, 423489997 + ], + [ + 536870912, 805306368, 671088640, 872415232, 1040187392, 452984832, 494927872, 432013312, 803209216, 477102080, 173539328, 40632320, 453115904, 5439488, 823820288, 304070656, 512253952, 333746176, 459786240, 838165504, 110004736, 790742272, 252812928, 527020096, 211068192, 280978992, 542739752, 393040444, 897756962, 806511409 + ], + [ + 536870912, 805306368, 671088640, 469762048, 369098752, 16777216, 25165824, 339738624, 195035136, 726663168, 346554368, 424411136, 317849600, 756482048, 900235264, 684507136, 783523840, 985092096, 150484992, 1030013952, 914296320, 1007005440, 776880000, 597539776, 169582880, 200954608, 101355688, 108152380, 47648258, 357150475 + ], + [ + 536870912, 805306368, 939524096, 872415232, 301989888, 218103808, 662700032, 968884224, 908066816, 588251136, 866648064, 325844992, 256245760, 278069248, 286294016, 245907456, 216817664, 42414080, 884209664, 1057084416, 444641792, 641736448, 1004640640, 120618432, 498618912, 121901904, 636125608, 703964572, 580122630, 739365889 + ], + [ + 536870912, 268435456, 939524096, 335544320, 100663296, 184549376, 276824064, 29360128, 899678208, 326107136, 299368448, 559153152, 516292608, 158793728, 177176576, 65683456, 563404800, 854052864, 1044776960, 548916224, 321823232, 43753216, 1028484224, 137510464, 834682592, 497101776, 1064417000, 64530388, 743830758, 88598737 + ], + [ + 536870912, 805306368, 402653184, 603979776, 234881024, 754974720, 612368384, 331350016, 807403520, 212860928, 746061824, 647757824, 920256512, 374800384, 377782272, 580337664, 287629312, 744935424, 507303936, 732621824, 353241600, 522835712, 745926784, 193925184, 132686368, 701817264, 444557992, 728813052, 978950798, 992761669 + ], + [ + 536870912, 268435456, 671088640, 603979776, 905969664, 520093696, 645922816, 348127232, 685768704, 737148928, 296222720, 143917056, 1063124992, 911015936, 597852160, 484851712, 553689088, 226521088, 742430720, 119645184, 328330752, 832080640, 391957888, 150694976, 811293728, 915122224, 296991624, 54477636, 813498282, 191500153 + ], + [ + 536870912, 268435456, 134217728, 335544320, 436207616, 419430400, 645922816, 1019215872, 455081984, 655360000, 704118784, 64749568, 41549824, 374538240, 542605312, 727826432, 32530432, 793260032, 1073002496, 813640704, 258284032, 130452224, 962152320, 881626688, 493025696, 457059056, 168090536, 355880436, 563144234, 87586993 + ], + [ + 536870912, 805306368, 134217728, 67108864, 167772160, 318767104, 645922816, 314572800, 379584512, 13631488, 580386816, 100925440, 666501120, 760938496, 501907456, 721600512, 407822336, 937996288, 986523648, 501718016, 340019712, 249192192, 212519296, 484615488, 662671712, 776000176, 794947944, 1022468796, 1049147754, 725372605 + ], + [ + 536870912, 268435456, 939524096, 201326592, 771751936, 83886080, 746586112, 322961408, 81788928, 577765376, 320339968, 300154880, 6946816, 455409664, 323649536, 452247552, 79880192, 293187584, 802473984, 605279232, 812765696, 270054144, 207905152, 497793984, 663058080, 475665552, 341631368, 295599044, 644290222, 99771539 + ], + [ + 536870912, 268435456, 939524096, 67108864, 33554432, 218103808, 92274688, 62914560, 878706688, 17825792, 199753728, 262930432, 893517824, 371392512, 196313088, 1008353280, 219570176, 178548736, 415176704, 648590336, 579660288, 863119616, 721080704, 994465472, 896384928, 782462896, 636739496, 935010228, 1046923174, 257731509 + ], + [ + 536870912, 805306368, 134217728, 67108864, 1040187392, 352321536, 713031680, 1035993088, 929038336, 189792256, 709361664, 443809792, 834273280, 591724544, 35880960, 582565888, 613261312, 269987840, 270764032, 1035478016, 755795456, 374771456, 235103360, 692662592, 301249824, 284820880, 954551432, 714253644, 727825186, 156348049 + ], + [ + 536870912, 268435456, 671088640, 335544320, 436207616, 721420288, 998244352, 608174080, 887095296, 542113792, 623378432, 190578688, 358481920, 1033043968, 54886400, 943439872, 802742272, 29683712, 150652928, 922297344, 238333440, 417504512, 933026176, 981424576, 1063505056, 232590992, 396254504, 464761684, 758407042, 660803777 + ], + [ + 536870912, 805306368, 671088640, 603979776, 436207616, 184549376, 1031798784, 331350016, 593494016, 609222656, 463994880, 751566848, 1020657664, 992280576, 398163968, 725762048, 900177920, 75304960, 267368448, 547380224, 523286016, 871972608, 157624448, 18506816, 829594080, 48131696, 207101576, 433331020, 237212010, 1022843449 + ], + [ + 536870912, 268435456, 939524096, 335544320, 436207616, 385875968, 159383552, 918552576, 228589568, 823132160, 213385216, 327417856, 251002880, 445579264, 430669824, 13385728, 1035722752, 385134592, 863913984, 543351808, 113271296, 631244544, 487689088, 45726784, 512012128, 276174672, 634342760, 583684180, 1014834918, 1268753 + ], + [ + 536870912, 268435456, 134217728, 469762048, 503316480, 587202560, 696254464, 1010827264, 333447168, 611319808, 73924608, 192675840, 276168704, 630784000, 894730240, 1072316416, 975167488, 367357952, 413390848, 607316992, 564818432, 83801856, 856971136, 353000768, 519007968, 625802032, 687843848, 890592004, 571123074, 896444999 + ], + [ + 536870912, 268435456, 134217728, 335544320, 973078528, 452984832, 176160768, 96468992, 656408576, 15728640, 620232704, 942407680, 669122560, 1054539776, 769097728, 751157248, 65429504, 1033646080, 586885120, 933633024, 100499968, 149574400, 546187392, 601406784, 685573920, 186289328, 318178600, 808787892, 153046442, 615617265 + ], + [ + 536870912, 268435456, 402653184, 335544320, 704643072, 385875968, 914358272, 994050048, 346030080, 653262848, 699924480, 867434496, 506855424, 1057161216, 947224576, 148258816, 517169152, 972845056, 565946368, 759196672, 899751424, 561010432, 225984128, 399852608, 916920160, 690637456, 728312296, 1052511956, 52149902, 984613953 + ], + [ + 536870912, 268435456, 402653184, 469762048, 503316480, 16777216, 847249408, 1035993088, 98566144, 818937856, 1023934464, 364118016, 648151040, 977076224, 517373952, 25149440, 138108928, 1017229312, 502310912, 549012480, 648934912, 645874432, 934999168, 903888192, 953199136, 956912848, 397738632, 966950468, 163372710, 295086487 + ], + [ + 536870912, 268435456, 402653184, 67108864, 369098752, 150994944, 394264576, 113246208, 987758592, 433061888, 434634752, 743178240, 796000256, 985726976, 954236928, 516997120, 57155584, 722251776, 441600000, 242334720, 1041806848, 294983424, 428273280, 660045632, 876522080, 120752016, 425754632, 17874948, 906502150, 807186433 + ], + [ + 536870912, 268435456, 402653184, 603979776, 637534208, 520093696, 880803840, 633339904, 652214272, 730857472, 198705152, 924581888, 262275072, 146341888, 1053589504, 702201856, 169091072, 977776640, 947337216, 807339008, 187391488, 220049152, 44214400, 490232000, 344802272, 947561360, 1034255880, 141500164, 182653062, 630758601 + ], + [ + 536870912, 268435456, 402653184, 469762048, 33554432, 956301312, 662700032, 264241152, 1004535808, 995098624, 425197568, 830734336, 1043464192, 96927744, 396197888, 789987328, 772087808, 1039298560, 606476288, 164467712, 332337664, 692144384, 530663808, 359691840, 1021873632, 906818864, 539982952, 370222964, 419027854, 536117059 + ], + [ + 536870912, 805306368, 939524096, 201326592, 369098752, 553648128, 729808896, 683671552, 1004535808, 716177408, 847773696, 684982272, 951975936, 655425536, 177831936, 751681536, 892493824, 973320192, 1028360192, 738073600, 1009804800, 801722112, 787828096, 409931840, 552199328, 564431088, 357984264, 188050444, 772673038, 999826179 + ], + [ + 536870912, 268435456, 134217728, 738197504, 234881024, 83886080, 780140544, 1052770304, 534773760, 749731840, 720896000, 111935488, 858390528, 150274048, 60194816, 976699392, 111599616, 462401536, 44730368, 666215424, 590745088, 1042805504, 72310656, 298496704, 1053140448, 1034814992, 75182472, 1018999236, 750916194, 137421019 + ], + [ + 536870912, 805306368, 402653184, 469762048, 100663296, 419430400, 864026624, 574619648, 39845888, 160432128, 854065152, 844365824, 616693760, 227082240, 574980096, 862633984, 188604416, 416788480, 892012544, 593361920, 373711360, 826538752, 113868928, 195378496, 79361440, 1035220112, 974357000, 276843276, 1052805254, 312590663 + ], + [ + 536870912, 268435456, 939524096, 469762048, 905969664, 654311424, 897581056, 222298112, 186646528, 252706816, 1069023232, 69468160, 705560576, 733806592, 851083264, 743096320, 1065574400, 11530240, 736991232, 857979904, 536789504, 66329856, 1003910784, 262765248, 35395232, 762031664, 831771784, 362190788, 185202734, 692873463 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 905969664, 620756992, 813694976, 1069547520, 98566144, 808452096, 599261184, 394526720, 442892288, 726597632, 962822144, 485081088, 818749440, 171577344, 333215744, 47422464, 957354496, 334050560, 55419008, 679115584, 628954208, 1052976336, 175758952, 660954580, 316060906, 188112795 + ], + [ + 536870912, 805306368, 671088640, 738197504, 369098752, 83886080, 947912704, 1052770304, 153092096, 275775488, 392691712, 274464768, 683278336, 958201856, 752582656, 655114240, 513990656, 346615808, 368887808, 336212992, 408272384, 125222144, 463412608, 948098624, 928548704, 97795984, 825662856, 75470412, 231991146, 641830811 + ], + [ + 536870912, 268435456, 939524096, 738197504, 838860800, 1056964608, 92274688, 79691776, 450887680, 814743552, 918028288, 877920256, 374996992, 671547392, 968982528, 140591104, 634429440, 915992576, 321153024, 720622592, 732629504, 99578112, 474813312, 842928448, 97789792, 479893616, 132609768, 533830708, 228163590, 816136207 + ], + [ + 536870912, 268435456, 402653184, 738197504, 503316480, 385875968, 427819008, 171966464, 547356672, 519045120, 227016704, 871628800, 530186240, 175177728, 860389376, 1033158656, 386621440, 594145280, 933509120, 836897792, 143405568, 99054848, 203394944, 60964928, 338460064, 488006096, 982923272, 936840196, 385266182, 776385803 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 1040187392, 721420288, 1065353216, 306184192, 257949696, 938475520, 827850752, 452198400, 197525504, 814809088, 178880512, 1034764288, 104062976, 987164672, 58316800, 132463616, 506343936, 48065280, 346724224, 1040412352, 867096992, 496797488, 457848840, 640928780, 181922314, 729306895 + ], + [ + 536870912, 268435456, 134217728, 67108864, 1040187392, 218103808, 92274688, 239075328, 568328192, 1060110336, 217579520, 44826624, 932315136, 296550400, 789741568, 309149696, 78815232, 851226624, 981125120, 963156992, 17086976, 1052152576, 9094016, 254883008, 351876832, 246192208, 227722120, 581776580, 663959266, 430807121 + ], + [ + 536870912, 268435456, 939524096, 738197504, 33554432, 184549376, 142606336, 1010827264, 677380096, 711983104, 376963072, 445906944, 366608384, 962265088, 52133888, 913981440, 831201280, 439562240, 386361344, 873278464, 629132800, 681118976, 765730432, 1010994496, 327150048, 496561968, 338029032, 797175604, 232679910, 684306239 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 436207616, 352321536, 176160768, 994050048, 773849088, 781189120, 640155648, 909377536, 239206400, 891224064, 994607104, 981778432, 888840192, 201469952, 331282432, 798571520, 504147456, 404675328, 365469056, 264628672, 702211808, 655613104, 290870632, 105655932, 733908482, 194521859 + ], + [ + 536870912, 268435456, 671088640, 201326592, 570425344, 520093696, 612368384, 54525952, 153092096, 311427072, 222822400, 790888448, 165019648, 500760576, 762085376, 712196096, 458186752, 462721024, 177158144, 418710528, 750774784, 300802304, 489924736, 342754368, 939799072, 507995952, 252760584, 193520900, 348406410, 648537411 + ], + [ + 536870912, 268435456, 939524096, 738197504, 771751936, 218103808, 25165824, 943718400, 610271232, 128974848, 470286336, 1061421056, 387842048, 632356864, 789086208, 197509120, 48193536, 395341824, 30992384, 301845504, 433234432, 464212736, 885511552, 122465344, 39458848, 95374320, 70838280, 1041091588, 431661582, 257905419 + ], + [ + 536870912, 805306368, 939524096, 738197504, 33554432, 285212672, 847249408, 574619648, 782237696, 101711872, 746061824, 800325632, 376832000, 3211264, 86605824, 636338176, 546529280, 606015488, 536610816, 116118528, 246067712, 353010944, 932964480, 111304640, 641190816, 932211888, 632907784, 97895436, 847723022, 402166027 + ], + [ + 536870912, 805306368, 134217728, 603979776, 167772160, 788529152, 8388608, 759169024, 836763648, 267386880, 782761984, 762052608, 520749056, 182255616, 532905984, 226574336, 381722624, 505417728, 407918592, 439899136, 242487808, 766479104, 436868480, 358382144, 973264096, 891415824, 584174984, 276393548, 454321890, 85947929 + ], + [ + 536870912, 268435456, 402653184, 469762048, 301989888, 956301312, 796917760, 130023424, 895483904, 32505856, 266862592, 231473152, 551944192, 77791232, 855212032, 991182848, 388112384, 926511104, 796252160, 626160640, 756064768, 786007296, 734309504, 563866816, 613269280, 835160656, 1039372712, 746623892, 88168974, 186745091 + ], + [ + 536870912, 805306368, 134217728, 872415232, 100663296, 788529152, 746586112, 104857600, 480247808, 735051776, 1018691584, 972292096, 977928192, 226820096, 195264512, 461979648, 624697344, 72773632, 113498112, 809096192, 263490048, 787112192, 307625088, 823904448, 226348320, 871842192, 261227656, 297823436, 6332194, 372372637 + ], + [ + 536870912, 268435456, 671088640, 469762048, 1040187392, 989855744, 746586112, 624951296, 312475648, 397410304, 484966400, 859570176, 503185408, 984023040, 326336512, 850444288, 459874304, 318525440, 907986944, 28724224, 589960704, 837032704, 283779712, 654680000, 142314272, 1016896848, 969889064, 630114900, 246374818, 64966291 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 234881024, 620756992, 880803840, 79691776, 450887680, 1020264448, 749207552, 1067188224, 522321920, 294322176, 488013824, 129351680, 343875584, 1011470336, 206387200, 940293120, 156649984, 60138752, 625934208, 867193024, 171526432, 840216496, 621740840, 93391548, 269089954, 745364083 + ], + [ + 536870912, 805306368, 939524096, 67108864, 436207616, 150994944, 746586112, 205520896, 44040192, 238026752, 956825600, 252968960, 48103424, 671940608, 364085248, 65978368, 444899328, 291934208, 777037824, 81269760, 873282048, 1001593088, 686729088, 990213952, 732379168, 699477296, 617190792, 259385932, 252677550, 722835313 + ], + [ + 536870912, 268435456, 671088640, 603979776, 234881024, 956301312, 260046848, 289406976, 211812352, 95420416, 428343296, 869531648, 1029308416, 377028608, 712802304, 184500224, 1036656640, 369225728, 620759040, 226499584, 37870080, 874634496, 577870208, 199768640, 730165664, 767795792, 966087176, 1031438596, 302539658, 1016403785 + ], + [ + 536870912, 268435456, 671088640, 335544320, 234881024, 83886080, 243269632, 381681664, 379584512, 248512512, 842530816, 819200000, 1007550464, 666173440, 637435904, 538722304, 955392000, 586559488, 448858112, 883016704, 970030592, 599265536, 596940928, 938440896, 662975008, 427225776, 981481608, 146868420, 1000413738, 340788917 + ], + [ + 536870912, 805306368, 134217728, 67108864, 301989888, 855638016, 310378496, 683671552, 908066816, 856686592, 849870848, 614727680, 621412352, 448593920, 240615424, 760954880, 661954560, 495144960, 319354880, 1022731264, 549588480, 90807552, 637885056, 400210496, 1001699488, 832795536, 387517576, 249353036, 531010594, 79933649 + ], + [ + 536870912, 268435456, 939524096, 335544320, 100663296, 620756992, 377487360, 792723456, 580911104, 412090368, 306708480, 547094528, 815661056, 247922688, 408125440, 896548864, 947511296, 306532352, 374061056, 415542272, 51013120, 895752960, 974818176, 1038988224, 619076128, 243422800, 756646952, 506847572, 45279654, 717228433 + ], + [ + 536870912, 805306368, 671088640, 469762048, 570425344, 1023410176, 75497472, 985661440, 190840832, 877658112, 215482368, 780402688, 669122560, 195756032, 630620160, 354533376, 904929280, 468234240, 168564736, 666819584, 1070406144, 224274688, 31223680, 237436736, 258596960, 684500464, 417227368, 899518716, 512178146, 383383227 + ], + [ + 536870912, 268435456, 939524096, 67108864, 637534208, 385875968, 142606336, 775946240, 740294656, 743440384, 292028416, 851181568, 742785024, 565903360, 777879552, 1031225344, 69394432, 764973056, 801425408, 145955840, 965813760, 763960064, 864894848, 836698048, 645873056, 451923024, 652706344, 413823892, 26500998, 953823173 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 503316480, 83886080, 226492416, 935329792, 610271232, 338690048, 683147264, 314834944, 132775936, 634454016, 256409600, 337461248, 639623168, 470020096, 119384064, 44018688, 272768512, 767406848, 558872960, 504013248, 1042404384, 395426384, 820529160, 307059716, 597112330, 905928463 + ], + [ + 536870912, 805306368, 939524096, 67108864, 234881024, 587202560, 478150656, 171966464, 526385152, 126877696, 974651392, 121372672, 595722240, 426442752, 400457728, 1064910848, 632053760, 438013952, 43403264, 209521664, 23326208, 423275776, 224806272, 460668736, 285624736, 811914032, 425693096, 741925436, 860646438, 743079037 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 301989888, 352321536, 75497472, 79691776, 576716800, 846200832, 155713536, 814481408, 835846144, 462225408, 710115328, 449593344, 645029888, 152883200, 782944256, 48821248, 1895936, 137029376, 992607616, 452750656, 748411360, 83891152, 478281096, 281046348, 207739370, 896603103 + ], + [ + 536870912, 268435456, 939524096, 738197504, 905969664, 419430400, 8388608, 750780416, 115343360, 735051776, 498597888, 602669056, 977403904, 512688128, 58556416, 274415616, 504602624, 645353472, 842086400, 132705280, 102003200, 697256192, 654120320, 840603968, 20080544, 1036395248, 832131624, 1071426484, 413904262, 370816335 + ], + [ + 536870912, 268435456, 671088640, 738197504, 637534208, 922746880, 327155712, 1002438656, 1000341504, 703594496, 555220992, 378798080, 420610048, 816644096, 439779328, 717635584, 324984832, 596373504, 569907200, 914689024, 681276928, 502376704, 320341376, 60125120, 932316192, 166509776, 1054315400, 282474180, 467048874, 106405659 + ], + [ + 536870912, 805306368, 939524096, 201326592, 905969664, 285212672, 1031798784, 331350016, 815792128, 552599552, 600309760, 746848256, 980287488, 522649600, 853704704, 862797824, 676995072, 501288960, 487643136, 249107456, 442341888, 741558016, 85300352, 653783232, 672867296, 327207952, 1052817896, 52464412, 775007590, 417938399 + ], + [ + 536870912, 805306368, 134217728, 469762048, 570425344, 1023410176, 914358272, 650117120, 450887680, 439353344, 511180800, 948174848, 310509568, 652935168, 449216512, 495501312, 127737856, 678932480, 170989568, 645450752, 746924544, 746763520, 971710592, 289905984, 231248480, 1002288624, 682033256, 242793724, 8729322, 109242555 + ], + [ + 536870912, 805306368, 402653184, 67108864, 905969664, 184549376, 1048576000, 1069547520, 710934528, 732954624, 347602944, 588513280, 897187840, 387121152, 932085760, 798507008, 889544704, 1007898624, 957270016, 140024832, 459608576, 564377856, 649552000, 365806400, 299764960, 483523760, 982038248, 787319228, 130944110, 364408829 + ], + [ + 536870912, 805306368, 939524096, 201326592, 234881024, 318767104, 847249408, 658505728, 367001600, 357564416, 784859136, 663486464, 759824384, 497352704, 941064192, 753319936, 2023424, 55259136, 1051047936, 848806912, 128414208, 469709568, 85699712, 585944896, 844875744, 1057844112, 319438472, 331664460, 696767342, 521101523 + ], + [ + 536870912, 805306368, 134217728, 67108864, 637534208, 16777216, 713031680, 801112064, 937426944, 611319808, 765984768, 741605376, 847118336, 532348928, 808222720, 520339456, 604069888, 369135616, 151091200, 780237824, 163650048, 920701184, 250726528, 40448192, 466990048, 370135504, 840106856, 471375132, 763177610, 1002128845 + ], + [ + 536870912, 268435456, 402653184, 201326592, 369098752, 956301312, 830472192, 180355072, 408944640, 397410304, 668467200, 848560128, 959315968, 159711232, 740720640, 955891712, 696573952, 1009152000, 553166848, 629521408, 707223040, 435695360, 335862656, 552007104, 26854688, 62165424, 121508744, 856488388, 983225126, 247165619 + ], + [ + 536870912, 268435456, 671088640, 67108864, 570425344, 285212672, 8388608, 859832320, 421527552, 609222656, 973602816, 1015808000, 457572352, 417923072, 649887744, 373243904, 792535040, 436178944, 190629888, 328115200, 646236672, 936042752, 732853888, 978674240, 310638944, 671255216, 910387720, 568537348, 32710282, 291182145 + ], + [ + 536870912, 805306368, 402653184, 335544320, 838860800, 553648128, 713031680, 901775360, 882900992, 1053818880, 717750272, 815005696, 485359616, 987037696, 890208256, 1013301248, 725032960, 522735616, 941893632, 500564992, 874055168, 710729984, 880513152, 842663744, 1037749280, 678124592, 1037176968, 31377228, 330066982, 455330869 + ], + [ + 536870912, 268435456, 402653184, 67108864, 33554432, 318767104, 209715200, 46137344, 815792128, 462422016, 445120512, 242483200, 168165376, 1005256704, 1020362752, 594034688, 822403072, 780021760, 178751488, 679181312, 978924032, 723383040, 704883072, 169189568, 943115232, 963840400, 544069736, 75179604, 878184462, 639384581 + ], + [ + 536870912, 268435456, 134217728, 603979776, 100663296, 1023410176, 897581056, 1027604480, 65011712, 122683392, 805830656, 253493248, 997851136, 459997184, 797147136, 89112576, 436002816, 1034670080, 404994048, 981390336, 182738432, 853430528, 726938496, 470169536, 184609056, 276830192, 616616232, 480314356, 1068527402, 1071153917 + ], + [ + 536870912, 268435456, 939524096, 603979776, 1040187392, 486539264, 780140544, 859832320, 442499072, 670040064, 936902656, 298582016, 450232320, 728039424, 562200576, 522108928, 1027645440, 794865664, 359663616, 513385472, 682394112, 245845760, 24957312, 426670016, 945398496, 101578736, 687233928, 24485060, 309031278, 220860217 + ], + [ + 536870912, 805306368, 402653184, 469762048, 973078528, 822083584, 964689920, 792723456, 136314880, 420478976, 924319744, 108265472, 37093376, 106496000, 693469184, 833011712, 176283648, 197152768, 1021396992, 326183936, 631810560, 910018816, 50005120, 877380288, 302183072, 30316848, 660417032, 818612492, 381871238, 330273479 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 167772160, 419430400, 226492416, 79691776, 845152256, 504365056, 844627968, 49545216, 1036648448, 776929280, 340623360, 628047872, 352133120, 1061629952, 205543424, 555860992, 162650624, 799579392, 545087360, 638028864, 48331360, 827436912, 804871656, 100980532, 314811782, 826483019 + ], + [ + 536870912, 805306368, 671088640, 469762048, 234881024, 1023410176, 662700032, 876609536, 358612992, 812646400, 142082048, 392953856, 1057095680, 24444928, 111116288, 533610496, 514220032, 398700544, 383043584, 374303744, 669424128, 220360448, 249906560, 89636544, 1039916512, 500746576, 750632840, 699032012, 321933418, 228137879 + ], + [ + 536870912, 268435456, 939524096, 67108864, 771751936, 285212672, 696254464, 272629760, 685768704, 321912832, 167247872, 381943808, 236060672, 683868160, 428572672, 368459776, 926965760, 73404416, 1022367744, 609784832, 714356224, 362414336, 916394112, 36475712, 306079584, 66908400, 267788136, 541095156, 14692710, 791798261 + ], + [ + 536870912, 268435456, 134217728, 201326592, 369098752, 520093696, 109051904, 71303168, 1054867456, 309329920, 154664960, 866910208, 514457600, 601817088, 489259008, 799326208, 39723008, 199872512, 117753856, 734956544, 522286592, 542237952, 988404864, 176459328, 990856864, 545351472, 54643752, 1013046388, 204578314, 1054456071 + ], + [ + 536870912, 268435456, 939524096, 872415232, 369098752, 285212672, 562036736, 792723456, 1004535808, 28311552, 608698368, 995360768, 274071552, 418971648, 211582976, 994295808, 936288256, 219492352, 372754432, 738749440, 540338688, 656811776, 470886784, 463037504, 535574432, 296483888, 97198600, 507136772, 236176270, 1052132173 + ], + [ + 536870912, 805306368, 402653184, 738197504, 167772160, 83886080, 394264576, 826277888, 689963008, 97517568, 152567808, 675020800, 310509568, 235208704, 7307264, 522174464, 748150784, 529666048, 343738368, 673369088, 76894720, 56061184, 712155264, 349044672, 910819424, 455129424, 483398280, 211321548, 813541606, 639863451 + ], + [ + 536870912, 805306368, 671088640, 872415232, 369098752, 620756992, 645922816, 557842432, 593494016, 118489088, 639107072, 157548544, 869400576, 678625280, 348291072, 1047248896, 900096000, 968413184, 198506496, 142232576, 322897408, 480001280, 166131072, 274320704, 663077472, 167976688, 147530344, 731320060, 206649954, 846811889 + ], + [ + 536870912, 805306368, 134217728, 872415232, 503316480, 520093696, 813694976, 381681664, 224395264, 942669824, 493355008, 941359104, 529399808, 652935168, 922779648, 880918528, 12705792, 643911680, 380635136, 346651648, 100479488, 830397696, 920824448, 925739712, 912714656, 506977424, 250485544, 81413980, 594018314, 387710977 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 436207616, 989855744, 578813952, 801112064, 610271232, 9437184, 771227648, 675545088, 839778304, 193134592, 138510336, 606158848, 816848896, 55128064, 906823680, 126012416, 977365504, 455138560, 875620224, 227052352, 200080864, 173214288, 471455848, 395698196, 727154694, 62275595 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 167772160, 251658240, 612368384, 440401920, 480247808, 61865984, 208142336, 1054081024, 1001521152, 1056636928, 744390656, 417611776, 1744896, 1062105088, 87902208, 27675648, 346664448, 355803904, 723698304, 971188160, 486714976, 689063792, 877371496, 431363196, 737192686, 331890611 + ], + [ + 536870912, 268435456, 134217728, 872415232, 369098752, 16777216, 578813952, 197132288, 316669952, 879755264, 126353408, 575930368, 642908160, 890568704, 443711488, 788873216, 390799360, 750383104, 771565568, 135783424, 528414208, 240825088, 67122560, 234938176, 1023524640, 8421840, 482391432, 828415812, 489692962, 514339293 + ], + [ + 536870912, 268435456, 402653184, 738197504, 436207616, 754974720, 142606336, 876609536, 182452224, 479199232, 987234304, 749993984, 491388928, 887422976, 624066560, 203538432, 523362304, 1009258496, 314312704, 465998848, 881576448, 1053135616, 84084352, 562635200, 122466592, 776881296, 365399688, 1066104260, 423893798, 952240027 + ], + [ + 536870912, 268435456, 671088640, 738197504, 436207616, 16777216, 864026624, 574619648, 1059061760, 951058432, 314048512, 448004096, 960364544, 785317888, 987201536, 328384512, 414556160, 742289408, 55572480, 798467072, 70424064, 818208512, 275169920, 1009402688, 58841312, 440523280, 992059624, 246464020, 163092194, 674566431 + ], + [ + 536870912, 268435456, 402653184, 469762048, 905969664, 754974720, 662700032, 926941184, 803209216, 238026752, 771227648, 528744448, 54657024, 597229568, 66355200, 584761344, 795729920, 430911488, 443983872, 316824576, 533285376, 343717632, 700898688, 459009472, 556656416, 600819088, 604416520, 746227460, 868021638, 99054023 + ], + [ + 536870912, 805306368, 671088640, 738197504, 436207616, 620756992, 528482304, 46137344, 987758592, 986710016, 522715136, 504102912, 62259200, 401276928, 724860928, 24297472, 486612992, 729821184, 482392064, 702592000, 441465344, 661186816, 967638400, 21445056, 150134304, 281131856, 65051560, 391198364, 350814082, 560833735 + ], + [ + 536870912, 268435456, 402653184, 67108864, 637534208, 520093696, 964689920, 1044381696, 492830720, 860880896, 192413696, 44302336, 456523776, 88539136, 856653824, 167985152, 464084992, 446517248, 477308928, 836838400, 26310144, 886631680, 374697856, 12576832, 980076384, 135610832, 232722280, 289043924, 124531054, 695921877 + ], + [ + 536870912, 268435456, 134217728, 738197504, 33554432, 889192448, 226492416, 12582912, 538968064, 531628032, 83361792, 287047680, 838991872, 392888320, 843022336, 156876800, 510500864, 517681152, 902289408, 113529856, 976159232, 332483328, 2624128, 968106816, 251066016, 360465712, 450071720, 1036151348, 1003183146, 114251391 + ], + [ + 536870912, 268435456, 671088640, 201326592, 905969664, 654311424, 578813952, 440401920, 207618048, 493879296, 806879232, 719585280, 559808512, 557252608, 810254336, 3194880, 251240448, 97816576, 287762432, 547527680, 101547520, 694314240, 95189632, 682776640, 853865568, 358551824, 859267688, 759949332, 867198690, 288937303 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 973078528, 452984832, 377487360, 339738624, 513802240, 303038464, 880279552, 742129664, 679346176, 1030422528, 1030782976, 906608640, 850763776, 462041088, 868222976, 1063382016, 980440576, 713668352, 905295232, 799796032, 261191200, 247005200, 316415400, 584020060, 973285386, 682957827 + ], + [ + 536870912, 805306368, 402653184, 738197504, 503316480, 855638016, 612368384, 566231040, 1025507328, 80740352, 265814016, 714342400, 1032454144, 506134528, 305823744, 490881024, 927408128, 276156416, 729499648, 933424128, 162963968, 234679040, 49700224, 169724736, 730227680, 315917744, 518734824, 379213244, 936545262, 754907575 + ], + [ + 536870912, 805306368, 939524096, 738197504, 167772160, 855638016, 1031798784, 180355072, 761266176, 1047527424, 282591232, 1048313856, 222691328, 875888640, 22249472, 1001832448, 447602688, 772673536, 1050687488, 764500992, 568876544, 621051648, 707402112, 618341312, 641861472, 52300144, 889823112, 1068830924, 982776046, 207014331 + ], + [ + 536870912, 805306368, 939524096, 201326592, 369098752, 452984832, 914358272, 490733568, 954204160, 133169152, 285736960, 789839872, 183369728, 979173376, 446398464, 696434688, 904847360, 517861376, 1054537728, 652452864, 350118400, 133520128, 85956992, 525599040, 797958688, 778845104, 573733768, 797416012, 855153582, 740084467 + ], + [ + 536870912, 805306368, 939524096, 603979776, 570425344, 117440512, 662700032, 432013312, 891289600, 355467264, 361234432, 709623808, 1036386304, 567214080, 457342976, 220545024, 110845952, 640741376, 403277824, 680383488, 694610432, 138300160, 460027520, 203018432, 37026208, 228739344, 1043600296, 1000538652, 590734630, 1059295957 + ], + [ + 536870912, 805306368, 671088640, 67108864, 838860800, 318767104, 763363328, 532676608, 664797184, 735051776, 973602816, 217317376, 265945088, 423034880, 766541824, 595116032, 967663616, 476557312, 1039665152, 1005351936, 201773568, 898163456, 406090624, 704337600, 455605216, 286914416, 987615848, 1044313788, 835053570, 333644813 + ], + [ + 536870912, 805306368, 134217728, 872415232, 167772160, 251658240, 813694976, 230686720, 652214272, 735051776, 486014976, 838074368, 7733248, 699203584, 972259328, 164839424, 241377280, 864718848, 1021777920, 561296384, 1035347456, 122452736, 639810688, 522932928, 815223840, 58587120, 411712136, 1047001548, 531910818, 366395709 + ], + [ + 536870912, 268435456, 402653184, 872415232, 771751936, 117440512, 176160768, 826277888, 337641472, 776994816, 678952960, 551813120, 158728192, 764870656, 640122880, 879706112, 1057153024, 91852800, 191145984, 431389696, 410400256, 68663040, 736589184, 571452992, 569609568, 890270928, 492367208, 792044756, 13575534, 17959129 + ], + [ + 536870912, 805306368, 939524096, 201326592, 167772160, 822083584, 914358272, 339738624, 819986432, 787480576, 716701696, 434372608, 1011744768, 923729920, 242122752, 224346112, 46604288, 485715968, 131397632, 1062620160, 880438784, 522823936, 90996352, 582130496, 909462624, 522613264, 109300840, 1009594908, 651357286, 159728159 + ], + [ + 536870912, 805306368, 939524096, 872415232, 637534208, 251658240, 176160768, 734003200, 1021313024, 428867584, 571998208, 131334144, 257032192, 359596032, 94404608, 179322880, 426270720, 123506688, 102713344, 958999552, 704416256, 674199808, 142707584, 180448320, 895522400, 718385200, 473481192, 656742780, 362471430, 662949889 + ], + [ + 536870912, 268435456, 402653184, 738197504, 1040187392, 989855744, 864026624, 977272832, 857735168, 149946368, 887619584, 936116224, 438173696, 526450688, 617644032, 93896704, 275079168, 678686720, 1062131712, 901258240, 387289600, 14301440, 748935040, 718671680, 1037875808, 325566192, 26599432, 572207108, 239319046, 122153995 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 503316480, 1023410176, 847249408, 499122176, 908066816, 890241024, 706215936, 512491520, 62783488, 128122880, 289767424, 998916096, 373301248, 727814144, 636606464, 447323136, 818252288, 566933248, 723553664, 395351616, 802739616, 346857744, 682590248, 280669012, 1028218766, 636878155 + ], + [ + 536870912, 805306368, 402653184, 67108864, 973078528, 419430400, 8388608, 473956352, 367001600, 544210944, 662175744, 274989056, 917897216, 329449472, 351043584, 879443968, 609345536, 472412160, 466475008, 180022272, 221787648, 176489728, 692545664, 253491776, 782780384, 848149776, 970651496, 369666908, 463242894, 479400781 + ], + [ + 536870912, 268435456, 939524096, 67108864, 301989888, 855638016, 880803840, 608174080, 14680064, 141557760, 153616384, 512491520, 993656832, 914292736, 79265792, 441794560, 929030144, 132755456, 925730816, 439090176, 48735744, 574371072, 347249792, 727928512, 240824096, 231629488, 632321448, 738765172, 534629894, 490895621 + ], + [ + 536870912, 268435456, 939524096, 67108864, 905969664, 654311424, 478150656, 490733568, 1038090240, 95420416, 682098688, 373555200, 278790144, 193265664, 306085888, 450150400, 10919936, 335114240, 31299584, 741512192, 675213824, 668285696, 824622976, 121155136, 754804128, 849569456, 956710792, 1009348164, 654656942, 662623921 + ], + [ + 536870912, 268435456, 671088640, 738197504, 973078528, 620756992, 528482304, 364904448, 111149056, 793772032, 122159104, 41680896, 447610880, 125108224, 934445056, 640303104, 299819008, 825036800, 535267328, 604507136, 614315520, 731869440, 441213056, 840371520, 437295712, 1051245744, 164451976, 232209476, 296786666, 578347515 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 33554432, 218103808, 964689920, 406847488, 664797184, 550502400, 133693440, 354680832, 673841152, 692387840, 505053184, 642596864, 123166720, 228282368, 520882176, 326573056, 67766784, 81035520, 868449408, 905447104, 2478496, 631945616, 251960456, 918230724, 840710562, 560969119 + ], + [ + 536870912, 805306368, 671088640, 603979776, 1040187392, 822083584, 897581056, 960495616, 648019968, 984612864, 479723520, 152829952, 660209664, 557252608, 613711872, 1072611328, 698966016, 331698176, 610744320, 337380352, 953816576, 1064777472, 582282368, 933219136, 466710816, 860380080, 475276712, 101602556, 146317954, 443394117 + ], + [ + 536870912, 805306368, 939524096, 335544320, 1040187392, 184549376, 931135488, 557842432, 731906048, 330301440, 295174144, 413401088, 334364672, 254738432, 13533184, 1012875264, 1018683392, 23728128, 959465472, 274265088, 935624192, 733930240, 606592640, 126034496, 468483936, 562232336, 887947112, 268614684, 179150694, 841215001 + ], + [ + 536870912, 805306368, 671088640, 469762048, 33554432, 922746880, 796917760, 507510784, 224395264, 714080256, 176685056, 1026293760, 644743168, 30998528, 1015382016, 145965056, 430956544, 1073254400, 938833920, 124443648, 137036288, 466305792, 26890368, 515045952, 11419744, 226002160, 758512136, 969662220, 110834314, 422734151 + ], + [ + 536870912, 805306368, 402653184, 469762048, 503316480, 922746880, 847249408, 62914560, 878706688, 546308096, 879230976, 732168192, 351928320, 429850624, 176455680, 835403776, 134684672, 744001536, 364644352, 778439680, 231250432, 542471424, 914508672, 127061440, 683357024, 431924592, 506853608, 185804988, 746318734, 123608523 + ], + [ + 536870912, 268435456, 134217728, 201326592, 33554432, 150994944, 411041792, 717225984, 799014912, 598736896, 1063780352, 194248704, 497156096, 240844800, 668434432, 657047552, 469016576, 53620736, 1027815424, 638262272, 829299200, 4542208, 677086848, 819389376, 1017759328, 750010608, 483542120, 311632884, 234053866, 216159031 + ], + [ + 536870912, 268435456, 671088640, 335544320, 838860800, 83886080, 629145600, 482344960, 404750336, 674234368, 1019740160, 669777920, 539623424, 272171008, 788824064, 569851904, 802922496, 173019136, 312076288, 1064619008, 643814912, 904296704, 824427904, 678751296, 383678560, 614986192, 566410760, 711324932, 120042378, 436372805 + ], + [ + 536870912, 805306368, 671088640, 469762048, 704643072, 16777216, 545259520, 650117120, 1012924416, 860880896, 277348352, 304873472, 914751488, 304807936, 426541056, 1051115520, 249208832, 274018304, 43227136, 655993856, 331612672, 897240320, 266638720, 797703360, 98338848, 775895248, 6167976, 907002908, 403051906, 468335819 + ], + [ + 536870912, 268435456, 402653184, 335544320, 369098752, 218103808, 58720256, 952107008, 383778816, 852492288, 868745216, 483655680, 854458368, 666828800, 850886656, 964902912, 943579136, 260722688, 965326848, 997516288, 958382592, 1019651328, 255576960, 80761280, 784901472, 122973968, 506404200, 660572948, 224878446, 164261393 + ], + [ + 536870912, 805306368, 134217728, 872415232, 771751936, 822083584, 1031798784, 893386752, 836763648, 879755264, 250085376, 237240320, 284033024, 356974592, 595755008, 110936064, 846356480, 825593856, 532076544, 1051350016, 647556608, 718108928, 164359808, 1026058176, 268793824, 280963600, 218044904, 211718940, 531535722, 195519697 + ], + [ + 536870912, 268435456, 939524096, 469762048, 167772160, 251658240, 796917760, 851443712, 991952896, 844103680, 699924480, 758382592, 367132672, 728694784, 884572160, 28655616, 983769088, 831500288, 407480320, 664552448, 714066432, 164232960, 878502784, 657333056, 601435744, 881154480, 506071016, 607305204, 303548934, 162397955 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 369098752, 989855744, 25165824, 926941184, 685768704, 596639744, 792199168, 614203392, 720502784, 493027328, 274366464, 499597312, 666148864, 555159552, 342640640, 874185728, 10886656, 560220416, 936320384, 1071669312, 1007737504, 662242352, 670864040, 320995388, 540708006, 563497267 + ], + [ + 536870912, 268435456, 671088640, 872415232, 33554432, 385875968, 293601280, 574619648, 417333248, 988807168, 522715136, 781451264, 325976064, 697106432, 619872256, 245776384, 652746752, 657838080, 184440832, 219429888, 506411520, 1022145280, 172190080, 477068352, 873266208, 414378416, 927370120, 412660548, 484183978, 256620285 + ], + [ + 536870912, 268435456, 939524096, 738197504, 973078528, 184549376, 880803840, 96468992, 513802240, 439353344, 885522432, 870055936, 81133568, 198115328, 9142272, 978862080, 1042554880, 591622144, 788916224, 540191744, 346886656, 25075456, 260250240, 841300672, 155442464, 470140944, 951224104, 728615700, 350144422, 557052639 + ], + [ + 536870912, 268435456, 134217728, 872415232, 301989888, 50331648, 1065353216, 423624704, 81788928, 923795456, 84410368, 478937088, 97386496, 1008795648, 397443072, 611860480, 760586240, 795512832, 861083648, 1046903808, 1021118976, 824657664, 826132608, 112689216, 888459360, 379199600, 1045110792, 1046728708, 769538050, 816360461 + ], + [ + 536870912, 268435456, 402653184, 872415232, 771751936, 956301312, 343932928, 1002438656, 975175680, 271581184, 1010302976, 494141440, 180224000, 226689024, 588349440, 814235648, 915234816, 938135552, 899072, 1059843072, 564967936, 224079616, 653648000, 956270656, 786636384, 1069582416, 471891176, 87065364, 850974734, 833960969 + ], + [ + 536870912, 268435456, 671088640, 335544320, 33554432, 520093696, 494927872, 171966464, 1050673152, 258998272, 150470656, 1002176512, 226361344, 712704000, 991526912, 1005436928, 1052237824, 782217216, 36399104, 483447808, 1024056832, 411326208, 337888896, 198522944, 342580256, 611368208, 125355176, 117183060, 979353090, 759834369 + ], + [ + 536870912, 268435456, 671088640, 872415232, 771751936, 956301312, 8388608, 1010827264, 157286400, 267386880, 742916096, 486801408, 767688704, 305987584, 47087616, 546979840, 289415168, 937472000, 582035456, 296276992, 11885056, 837519104, 4757888, 1057246016, 650353824, 834458576, 688843656, 742004804, 722525994, 561602461 + ], + [ + 536870912, 805306368, 671088640, 603979776, 301989888, 587202560, 897581056, 423624704, 970981376, 877658112, 966262784, 914620416, 282460160, 623968256, 67731456, 54345728, 2301952, 1057984512, 433428480, 550464512, 351644160, 943718144, 383543936, 846452928, 529924640, 500251568, 249083912, 845544460, 67613194, 23646985 + ], + [ + 536870912, 268435456, 402653184, 603979776, 33554432, 1056964608, 847249408, 473956352, 723517440, 74448896, 471334912, 690749440, 541982720, 455409664, 665485312, 1022345216, 982818816, 609374208, 1037244416, 420684800, 762464768, 379802880, 797648256, 1008653248, 533475296, 266223408, 892098440, 374289092, 1042610278, 237751801 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 570425344, 184549376, 1031798784, 910163968, 169869312, 546308096, 914882560, 114032640, 20054016, 33882112, 601849856, 312983552, 500391936, 511004672, 958855168, 378723328, 617978368, 125285632, 150676096, 141151040, 297589216, 642415696, 812726408, 284802636, 724867942, 445048607 + ], + [ + 536870912, 268435456, 671088640, 469762048, 973078528, 620756992, 109051904, 205520896, 656408576, 198180864, 728236032, 772538368, 296615936, 400883712, 98729984, 376061952, 643260416, 136384512, 273680384, 363348992, 594311680, 576713984, 349970560, 172405824, 44578272, 216846768, 983456392, 113000772, 439784810, 189801975 + ], + [ + 536870912, 805306368, 671088640, 67108864, 570425344, 251658240, 394264576, 4194304, 48234496, 540016640, 1043857408, 282853376, 408027136, 74514432, 786006016, 401424384, 904536064, 921440256, 996931584, 606927872, 625713664, 859653888, 920836480, 680009152, 539319520, 414071184, 573732872, 58833932, 977371658, 568416001 + ], + [ + 536870912, 805306368, 939524096, 335544320, 234881024, 956301312, 612368384, 79691776, 291504128, 303038464, 641204224, 564920320, 702676992, 750321664, 745373696, 604225536, 778674176, 355856384, 784205824, 87196672, 484496896, 978387712, 530109568, 954058688, 717897312, 917255056, 73586184, 888668940, 768431246, 695338949 + ], + [ + 536870912, 805306368, 671088640, 335544320, 436207616, 50331648, 679477248, 918552576, 929038336, 1041235968, 900202496, 951320576, 270925824, 708902912, 732004352, 577847296, 926457856, 568119296, 485627904, 754336768, 42546688, 101022464, 998117504, 151838016, 775589280, 39034160, 856129544, 250626060, 66658314, 700289029 + ], + [ + 536870912, 268435456, 939524096, 201326592, 503316480, 889192448, 679477248, 708837376, 656408576, 133169152, 574095360, 176422912, 724959232, 16318464, 400850944, 870825984, 691101696, 559443968, 659843072, 712975360, 470065664, 611717376, 928627584, 911516608, 687758624, 289779248, 14033416, 124309764, 831282062, 686494659 + ], + [ + 536870912, 805306368, 939524096, 603979776, 436207616, 150994944, 360710144, 926941184, 241172480, 808452096, 724041728, 1035730944, 1039532032, 273350656, 633110528, 704004096, 843833344, 146632704, 645322752, 202048512, 324822528, 554111232, 692254336, 516996800, 937010592, 79033552, 110842664, 241519132, 323155590, 667991749 + ], + [ + 536870912, 268435456, 671088640, 603979776, 973078528, 956301312, 696254464, 289406976, 333447168, 363855872, 188219392, 529793024, 648937472, 1051656192, 581926912, 346996736, 867164160, 422457344, 418379776, 869184512, 618544640, 699834624, 682232960, 447239488, 490580448, 663886992, 792570344, 714218644, 347974114, 651304093 + ], + [ + 536870912, 805306368, 939524096, 872415232, 301989888, 318767104, 58720256, 968884224, 715128832, 619708416, 585629696, 776208384, 998113280, 792395776, 994344960, 167657472, 1048272896, 530952192, 745424896, 29615104, 880304640, 578605824, 291673728, 1065996992, 487945824, 870817616, 752345320, 1067339164, 984258182, 1023267521 + ], + [ + 536870912, 805306368, 939524096, 67108864, 301989888, 553648128, 427819008, 935329792, 966787072, 19922944, 896008192, 400818176, 428474368, 660537344, 129794048, 419840000, 808509440, 619261952, 472143872, 908846080, 359588352, 173406976, 547571840, 668662976, 992405856, 801153776, 228719080, 724679228, 275378822, 476373965 + ], + [ + 536870912, 268435456, 134217728, 738197504, 33554432, 50331648, 360710144, 398458880, 35651584, 221249536, 983040000, 557056000, 915537920, 687931392, 713064448, 138428416, 987848704, 412094464, 594024448, 202157056, 223788544, 657133824, 797305216, 785061056, 982854048, 1046627472, 448266248, 1057226756, 294256642, 871694347 + ], + [ + 536870912, 268435456, 134217728, 469762048, 1040187392, 1056964608, 494927872, 524288000, 828375040, 468713472, 378011648, 430178304, 524156928, 322240512, 38174720, 337199104, 417095680, 638824448, 917379072, 768384000, 623624704, 576898816, 778483072, 797505344, 1059399328, 939461552, 538234248, 878172996, 614530210, 609308855 + ], + [ + 536870912, 805306368, 402653184, 738197504, 503316480, 16777216, 998244352, 247463936, 941621248, 277872640, 819462144, 1029439488, 841613312, 1037631488, 685604864, 636141568, 309878784, 680357888, 739428352, 70630400, 616498688, 347474176, 240302208, 206913728, 323879904, 824089040, 266798600, 388630796, 475576454, 219955403 + ], + [ + 536870912, 268435456, 671088640, 603979776, 100663296, 956301312, 864026624, 356515840, 195035136, 426770432, 159907840, 284426240, 932839424, 103350272, 528777216, 789790720, 22814720, 996061184, 463177728, 875117568, 142957056, 26473728, 563955584, 482319936, 986369696, 831578448, 442071560, 1066222852, 430362506, 367436361 + ], + [ + 536870912, 268435456, 134217728, 67108864, 301989888, 989855744, 1015021568, 272629760, 350224384, 831520768, 953679872, 705429504, 126746624, 777584640, 491552768, 837697536, 579411968, 619974656, 1035180032, 637453312, 361861632, 987348736, 420219008, 1058010304, 739884896, 850201840, 1023382024, 168869636, 437815426, 195933377 + ], + [ + 536870912, 805306368, 939524096, 335544320, 234881024, 956301312, 746586112, 750780416, 408944640, 368050176, 584581120, 523501568, 1015939072, 780861440, 381452288, 871514112, 60317696, 588599296, 736000000, 750980096, 471921152, 659565824, 977823872, 513544000, 446862432, 13639248, 285738216, 498949404, 879886982, 416824905 + ], + [ + 536870912, 268435456, 134217728, 335544320, 100663296, 318767104, 864026624, 398458880, 794820608, 619708416, 714604544, 859045888, 980549632, 281608192, 289177600, 1018052608, 819437568, 567521280, 819550208, 345373696, 409103872, 140538624, 24155008, 643346112, 1003839648, 256049424, 103814664, 897089284, 998507906, 1011519941 + ], + [ + 536870912, 268435456, 134217728, 67108864, 704643072, 989855744, 629145600, 1061158912, 643825664, 179306496, 851968000, 710672384, 1007026176, 439418880, 688422912, 637288448, 236331008, 292048896, 642603008, 778005504, 267704832, 308994816, 104779136, 71637568, 908277984, 849505072, 191059976, 1002597380, 106060290, 155951873 + ], + [ + 536870912, 805306368, 134217728, 201326592, 369098752, 1023410176, 109051904, 926941184, 119537664, 321912832, 530055168, 131334144, 568983552, 66387968, 895188992, 866992128, 871358464, 383250432, 921896960, 979387392, 118616576, 858299648, 864820096, 1029679552, 227524896, 197575824, 786168712, 845961676, 193906978, 247955603 + ], + [ + 536870912, 268435456, 939524096, 738197504, 167772160, 1056964608, 696254464, 901775360, 10485760, 821035008, 38273024, 446955520, 843186176, 234160128, 360349696, 316194816, 775806976, 1042255872, 1044092928, 171482112, 900535808, 352839936, 178657664, 64372544, 207595168, 978993744, 854090120, 39138116, 604711086, 827340635 + ], + [ + 536870912, 805306368, 671088640, 335544320, 301989888, 486539264, 176160768, 834666496, 933232640, 921698304, 129499136, 296484864, 1056833536, 280297472, 220430336, 724713472, 706355200, 442454016, 130385920, 383427584, 1065293312, 1022734592, 549639552, 388125376, 305393120, 446428848, 580903816, 686076876, 216707178, 98959477 + ], + [ + 536870912, 268435456, 134217728, 738197504, 503316480, 50331648, 780140544, 859832320, 736100352, 554696704, 539492352, 1038876672, 719192064, 469434368, 559513600, 370458624, 993730560, 75010048, 153380864, 245574656, 223120896, 472823040, 214110080, 329096640, 833045536, 979361424, 1002169768, 741893716, 675661322, 787613967 + ], + [ + 536870912, 268435456, 939524096, 335544320, 234881024, 218103808, 377487360, 88080384, 845152256, 223346688, 936902656, 923533312, 114163712, 786366464, 996638720, 960118784, 472702976, 201297920, 995522560, 976456704, 406373888, 412910848, 850818944, 883152192, 549507872, 77720656, 15805224, 396894292, 1021644070, 281752913 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 503316480, 1023410176, 494927872, 390070272, 1029701632, 319815680, 1010302976, 144441344, 232390656, 327221248, 843153408, 887177216, 642899968, 576253952, 990767104, 992144384, 826128896, 300575488, 138991744, 548766144, 335541472, 50816720, 951713800, 210829324, 947486730, 1031618575 + ], + [ + 536870912, 268435456, 939524096, 67108864, 704643072, 385875968, 562036736, 448790528, 866123776, 265289728, 699924480, 988020736, 523632640, 332595200, 635797504, 313999360, 521330688, 793047040, 31893504, 451630080, 490809856, 945939200, 485603200, 606705984, 649869792, 904100112, 577605224, 64675924, 122271622, 500013381 + ], + [ + 536870912, 268435456, 671088640, 469762048, 503316480, 1056964608, 947912704, 985661440, 1012924416, 357564416, 952631296, 69468160, 280625152, 834469888, 139886592, 253902848, 340877312, 793325568, 778328064, 169595904, 109960704, 449797888, 189724800, 974033728, 841963680, 48115984, 900169352, 433723460, 829193770, 1004535127 + ], + [ + 536870912, 805306368, 671088640, 335544320, 771751936, 117440512, 931135488, 801112064, 975175680, 869269504, 1004011520, 1059323904, 1049755648, 250413056, 189759488, 420102144, 304619520, 120434688, 309319680, 458976256, 355513856, 464033024, 938261632, 600744384, 1028390560, 1036562640, 668750472, 719788236, 132633642, 23540757 + ], + [ + 536870912, 805306368, 402653184, 738197504, 100663296, 352321536, 444596224, 994050048, 618659840, 147849216, 533200896, 584843264, 174718976, 686227456, 151289856, 912211968, 622895104, 661704704, 737695744, 432348160, 830422528, 357651712, 822621568, 754819776, 1050390432, 1021195056, 912376360, 932285948, 153736078, 353217479 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 704643072, 486539264, 411041792, 549453824, 102760448, 506462208, 309854208, 412876800, 545652736, 467206144, 871137280, 882884608, 127197184, 855887872, 647112704, 110797824, 77469184, 798324992, 922994048, 814943680, 832301536, 18862000, 399832584, 300132612, 679701902, 1037265359 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 503316480, 654311424, 629145600, 759169024, 513802240, 638582784, 390594560, 434896896, 862846976, 787546112, 75005952, 720650240, 988536832, 287567872, 923711488, 436268032, 486558208, 679585024, 230758528, 794844736, 393326944, 658057328, 458610696, 91970564, 892015106, 390314255 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 704643072, 16777216, 746586112, 801112064, 195035136, 66060288, 680001536, 312213504, 11665408, 865140736, 114917376, 451166208, 724033536, 150884352, 278562816, 192783360, 866344448, 143240448, 580724608, 145963072, 261121760, 752390800, 467986440, 128431116, 658388482, 456808719 + ], + [ + 536870912, 268435456, 939524096, 335544320, 704643072, 956301312, 427819008, 331350016, 52428800, 420478976, 279445504, 171704320, 516292608, 806682624, 934969344, 531808256, 442441728, 143724544, 1063790592, 253557760, 14067200, 708660480, 247976576, 135532096, 599408224, 900936432, 593458312, 286278468, 749300974, 205323445 + ], + [ + 536870912, 268435456, 402653184, 469762048, 771751936, 16777216, 75497472, 683671552, 65011712, 483393536, 870842368, 18087936, 562954240, 535363584, 655654912, 613335040, 694804480, 550891520, 586074112, 435799040, 941405696, 1019926272, 391062144, 352856384, 994336672, 229109488, 77379080, 403363588, 581902982, 349710663 + ], + [ + 536870912, 805306368, 134217728, 603979776, 167772160, 83886080, 813694976, 188743680, 375390208, 475004928, 656932864, 202113024, 6422528, 592117760, 356941824, 405061632, 804184064, 1005072384, 816633856, 865319936, 605279744, 248757504, 561177472, 16977088, 379212192, 799961392, 571049896, 440257596, 488334378, 594460917 + ], + [ + 536870912, 268435456, 939524096, 67108864, 637534208, 218103808, 696254464, 205520896, 954204160, 1043333120, 728236032, 324796416, 413794304, 60358656, 1007976448, 921157632, 868950016, 250130432, 354232320, 927640576, 992506368, 431759104, 899356032, 141645120, 747147232, 401431504, 520346120, 736391940, 590268302, 826751553 + ], + [ + 536870912, 268435456, 402653184, 469762048, 905969664, 1023410176, 713031680, 88080384, 6291456, 110100480, 120061952, 711196672, 33685504, 156565504, 496664576, 761905152, 126115840, 944992256, 14419968, 684614656, 384958976, 267138816, 156757632, 198111808, 359850912, 304946000, 460785288, 750724676, 101321126, 281147479 + ], + [ + 536870912, 268435456, 671088640, 201326592, 973078528, 855638016, 545259520, 784334848, 375390208, 263192576, 558366720, 419168256, 187301888, 729088000, 129400832, 955138048, 453763072, 6623232, 758003712, 837481472, 857005568, 621166336, 1009235840, 79166272, 544208736, 298557840, 537258376, 731874372, 52666602, 631851731 + ], + [ + 536870912, 805306368, 134217728, 738197504, 637534208, 922746880, 125829120, 322961408, 1067450368, 959447040, 474480640, 163315712, 982646784, 626720768, 94797824, 429178880, 427728896, 844173312, 966289408, 459600896, 978746880, 742222592, 617780864, 75213504, 861281312, 146634288, 840065576, 362487100, 591819946, 235173879 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 637534208, 50331648, 260046848, 62914560, 249561088, 883949568, 1066926080, 833880064, 257556480, 1032650752, 33456128, 375341056, 994992128, 113700864, 729430016, 895314944, 831919616, 13861632, 422612864, 1029177792, 567641376, 782952080, 632584584, 89862852, 277729954, 830421855 + ], + [ + 536870912, 805306368, 134217728, 603979776, 503316480, 1056964608, 1015021568, 1010827264, 673185792, 441450496, 893911040, 120324096, 931004416, 869597184, 1034649600, 301940736, 513122304, 504049664, 795842560, 566014976, 341256704, 193543424, 474776704, 831406400, 76388064, 972010800, 83629704, 334936140, 723091554, 476384633 + ], + [ + 536870912, 268435456, 134217728, 603979776, 33554432, 1056964608, 830472192, 104857600, 383778816, 477102080, 696778752, 821297152, 604897280, 321323008, 541294592, 892715008, 330293248, 70676480, 905660416, 128558080, 363177472, 760641792, 650882688, 1010891968, 367046240, 66159248, 919169128, 714361748, 817786602, 462381917 + ], + [ + 536870912, 805306368, 134217728, 603979776, 436207616, 117440512, 813694976, 943718400, 639631360, 776994816, 943194112, 330039296, 109707264, 105185280, 132087808, 637747200, 31563776, 347148288, 436819968, 14971904, 701442560, 337349888, 35501184, 922940096, 945864416, 158398224, 401196680, 441715660, 650616930, 125815001 + ], + [ + 536870912, 805306368, 402653184, 603979776, 905969664, 889192448, 528482304, 910163968, 652214272, 508559360, 79167488, 648806400, 895090688, 219348992, 615940096, 522731520, 146038784, 340152320, 438319104, 561079296, 306718208, 1051023616, 1059047296, 794642496, 634560032, 899074160, 416833576, 960292220, 490985902, 17809461 + ], + [ + 536870912, 268435456, 671088640, 201326592, 33554432, 50331648, 696254464, 390070272, 543162368, 1039138816, 1023934464, 900464640, 174981120, 343474176, 258244608, 107167744, 860315648, 767922176, 917755904, 887057408, 1058097664, 574147328, 361077632, 760376896, 896474208, 133721072, 1059361288, 25339652, 418795914, 439149891 + ], + [ + 536870912, 268435456, 402653184, 872415232, 1040187392, 553648128, 1031798784, 876609536, 551550976, 544210944, 164102144, 732692480, 572653568, 332070912, 959938560, 168640512, 825483264, 926126080, 842192896, 699552768, 150185472, 731011328, 514047616, 168541888, 899040928, 1050497840, 646676648, 878107188, 104629806, 739959033 + ], + [ + 536870912, 268435456, 134217728, 738197504, 973078528, 452984832, 192937984, 20971520, 811597824, 873463808, 607649792, 848560128, 357433344, 686751744, 73367552, 441958400, 353017856, 45707264, 156542976, 1022260224, 174013952, 525819136, 327904640, 695858240, 687140064, 845026448, 727174376, 227255444, 611861738, 41181343 + ], + [ + 536870912, 805306368, 939524096, 872415232, 33554432, 318767104, 813694976, 213909504, 488636416, 384827392, 145227776, 356777984, 101580800, 144637952, 413564928, 1021001728, 86564864, 1007022080, 242149376, 403680256, 631237120, 891736832, 630938752, 893947328, 412473824, 827786384, 49500648, 900536476, 816460774, 776066961 + ], + [ + 536870912, 805306368, 939524096, 738197504, 973078528, 117440512, 931135488, 583008256, 488636416, 999292928, 847773696, 854327296, 387055616, 990838784, 577011712, 1056849920, 429760512, 279654400, 205203456, 959603712, 287193600, 925755136, 229800320, 442439360, 567107104, 226750832, 990326696, 784921532, 462177158, 568521159 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 704643072, 587202560, 981467136, 507510784, 723517440, 571473920, 537395200, 255590400, 98959360, 234553344, 135036928, 50216960, 693051392, 957755392, 788727808, 415788032, 543020544, 400016128, 157496704, 326762176, 286368, 969087312, 44583720, 32298908, 344923526, 502768323 + ], + [ + 536870912, 268435456, 402653184, 201326592, 838860800, 922746880, 729808896, 457179136, 903872512, 514850816, 484966400, 820248576, 133562368, 69140480, 461078528, 567099392, 422715392, 846737408, 144492544, 611038208, 569728512, 449788160, 392427648, 1017184704, 206610400, 836364496, 994951656, 821219796, 710424942, 671928343 + ], + [ + 536870912, 805306368, 402653184, 67108864, 436207616, 452984832, 142606336, 213909504, 492830720, 907018240, 289931264, 138674176, 178126848, 122224640, 625311744, 522108928, 101261312, 1030049792, 724441088, 946955264, 64566784, 332198656, 448517248, 843529280, 738521376, 725540976, 876164616, 102560524, 471061638, 533937217 + ], + [ + 536870912, 805306368, 402653184, 469762048, 905969664, 754974720, 595591168, 683671552, 509607936, 309329920, 640155648, 954990592, 249167872, 1047461888, 678461440, 355024896, 845946880, 798707712, 332388352, 719385600, 707860992, 436835584, 364720256, 388201152, 574325280, 559901616, 234385576, 508915836, 372234254, 1011938315 + ], + [ + 536870912, 805306368, 402653184, 335544320, 100663296, 117440512, 830472192, 851443712, 480247808, 386924544, 997720064, 299630592, 1064173568, 571408384, 775847936, 798375936, 1007869952, 829476864, 214558720, 934667264, 13283840, 1010693888, 924843904, 1011244096, 80395936, 305955792, 1008656040, 533074908, 923522734, 941369305 + ], + [ + 536870912, 805306368, 134217728, 67108864, 301989888, 788529152, 360710144, 784334848, 748683264, 508559360, 395837440, 594804736, 855244800, 297336832, 1046839296, 721567744, 373104640, 945229824, 886454272, 43387904, 846669312, 1070005504, 644755072, 259179200, 45472416, 1004189520, 690488840, 22867212, 69703298, 476024513 + ], + [ + 536870912, 805306368, 402653184, 335544320, 436207616, 184549376, 1031798784, 4194304, 10485760, 412090368, 619184128, 436469760, 566099968, 718077952, 837517312, 284934144, 106045440, 469143552, 291026944, 238869504, 334686720, 132563200, 259072640, 660198464, 993894304, 661821744, 623372424, 672171340, 875136294, 979718517 + ], + [ + 536870912, 805306368, 939524096, 872415232, 100663296, 721420288, 125829120, 507510784, 249561088, 909115392, 552075264, 271319040, 779485184, 834469888, 869236736, 1007206400, 991698944, 438300672, 206698496, 186223616, 509897216, 428600064, 143815552, 133605440, 956058848, 816801520, 225979272, 1066669132, 247725806, 368046589 + ], + [ + 536870912, 805306368, 134217728, 335544320, 1040187392, 150994944, 662700032, 549453824, 207618048, 321912832, 696778752, 1057226752, 739901440, 654901248, 138772480, 146423808, 744071168, 217870336, 389416960, 415669248, 657356288, 874179328, 185189760, 709155392, 733659936, 1020845392, 45905416, 471329548, 659965314, 301439557 + ], + [ + 536870912, 268435456, 134217728, 335544320, 838860800, 754974720, 411041792, 180355072, 601882624, 389021696, 876085248, 311689216, 716046336, 488701952, 382763008, 101203968, 707567616, 16486400, 963536896, 71386112, 773887488, 491912960, 390695296, 277699008, 963328160, 113690480, 75243528, 473157636, 950192130, 126538757 + ], + [ + 536870912, 805306368, 671088640, 738197504, 704643072, 83886080, 947912704, 104857600, 408944640, 653262848, 92798976, 395051008, 420347904, 1055457280, 385712128, 256327680, 600072192, 488820736, 263612416, 961291264, 523215360, 75090688, 864371584, 843195968, 281539424, 67492336, 964936200, 510073612, 282405770, 681247307 + ], + [ + 536870912, 268435456, 939524096, 201326592, 973078528, 989855744, 192937984, 20971520, 668991488, 382730240, 29884416, 384565248, 789446656, 670629888, 544505856, 980140032, 1048272896, 85086208, 550475776, 802716672, 780466688, 223516416, 330269312, 1036636224, 82658912, 537855984, 444072456, 540326660, 755687566, 577387331 + ], + [ + 536870912, 268435456, 134217728, 738197504, 637534208, 218103808, 981467136, 633339904, 299892736, 296747008, 565706752, 23855104, 825622528, 590020608, 600145920, 175292416, 462954496, 809291776, 364845056, 121625600, 519981568, 555616512, 296711808, 748109376, 87716256, 527246160, 137862952, 464191764, 17138826, 169081679 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 771751936, 83886080, 58720256, 532676608, 568328192, 663748608, 58195968, 211025920, 154533888, 8978432, 113016832, 783990784, 712695808, 85651456, 449538048, 898808832, 343354880, 1059649280, 739104896, 288522688, 809906592, 954220592, 437298696, 28949252, 318054022, 526781135 + ], + [ + 536870912, 805306368, 134217728, 201326592, 234881024, 83886080, 494927872, 155189248, 970981376, 152043520, 887619584, 906231808, 506331136, 20119552, 895516672, 668057600, 189276160, 477368320, 1008097280, 738182144, 964306432, 898974976, 218507136, 454475712, 226406240, 549139792, 347395816, 985078684, 437133322, 453185551 + ], + [ + 536870912, 805306368, 939524096, 469762048, 301989888, 754974720, 679477248, 524288000, 966787072, 584056832, 573046784, 882114560, 934936576, 104136704, 384532480, 148684800, 253714432, 752242688, 716376064, 3183616, 123286016, 862796032, 948368512, 551247936, 746906656, 737320848, 244421768, 67711052, 679865390, 368249751 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 905969664, 83886080, 813694976, 817889280, 866123776, 217055232, 311951360, 125566976, 843972608, 897122304, 183271424, 143048704, 334290944, 503787520, 1043195904, 556196864, 874378752, 85906688, 252810112, 352869056, 246764256, 559660016, 567514632, 1059464452, 85728134, 664751823 + ], + [ + 536870912, 268435456, 402653184, 469762048, 234881024, 318767104, 478150656, 281018368, 1063256064, 47185920, 678952960, 485752832, 299237376, 102432768, 639205376, 396640256, 586031104, 1003458560, 129984512, 200752128, 1055638016, 647015680, 333030784, 725973312, 981454432, 857085968, 880421352, 860392532, 798876174, 532364547 + ], + [ + 536870912, 805306368, 671088640, 335544320, 704643072, 788529152, 327155712, 281018368, 77594624, 831520768, 232259584, 691273728, 46268416, 1003290624, 782729216, 846610432, 919478272, 709529600, 696260608, 667003904, 723602944, 525349120, 209305216, 606415296, 207288864, 110647120, 424988808, 905087180, 1015340202, 868913813 + ], + [ + 536870912, 805306368, 402653184, 469762048, 234881024, 654311424, 662700032, 356515840, 937426944, 563085312, 34078720, 588513280, 786825216, 894763008, 478642176, 814071808, 904880128, 247574528, 480270336, 695307264, 404320768, 979170048, 487759488, 497259328, 1050295840, 955684976, 169680520, 208819020, 770924070, 733096055 + ], + [ + 536870912, 805306368, 402653184, 603979776, 301989888, 285212672, 343932928, 373293056, 996147200, 804257792, 835190784, 394002432, 353239040, 672989184, 419397632, 282443776, 1057136640, 26955776, 1031743488, 571765760, 170023424, 822808320, 826701184, 362850624, 483474016, 442080048, 985978248, 846985548, 47059558, 868085561 + ], + [ + 536870912, 805306368, 134217728, 872415232, 301989888, 184549376, 427819008, 750780416, 392167424, 628097024, 865599488, 567017472, 237895680, 278462464, 1011712000, 955138048, 955817984, 314380288, 750131200, 399797248, 354579968, 416785152, 790939520, 276540096, 293277024, 268052208, 347764232, 35365644, 814401410, 404925133 + ], + [ + 536870912, 268435456, 939524096, 872415232, 838860800, 855638016, 109051904, 222298112, 354418688, 391118848, 571998208, 168034304, 846331904, 883228672, 199393280, 828162048, 257368064, 445075456, 803190784, 268166144, 710414848, 816180480, 300071040, 240985536, 265698464, 382151760, 260020360, 325809604, 270599342, 953223261 + ], + [ + 536870912, 805306368, 671088640, 335544320, 369098752, 956301312, 545259520, 583008256, 631242752, 919601152, 650641408, 955514880, 1010171904, 512557056, 905674752, 378945536, 31203328, 963801088, 1023617024, 949720064, 250064384, 910459136, 135230592, 136353088, 311427104, 816401264, 520376968, 418361420, 470930090, 661240629 + ], + [ + 536870912, 268435456, 134217728, 1006632960, 637534208, 50331648, 25165824, 29360128, 681574400, 116391936, 215482368, 691273728, 923402240, 449380352, 779911168, 783695872, 400482304, 47362048, 125687808, 305605632, 547331584, 808586496, 233624448, 843013312, 63151776, 196447440, 659170824, 1000919300, 1009579394, 43945423 + ], + [ + 536870912, 268435456, 134217728, 335544320, 167772160, 16777216, 562036736, 977272832, 1029701632, 934281216, 196608000, 251396096, 278265856, 984285184, 396197888, 891731968, 739500032, 652308480, 351311872, 190440448, 487337472, 760111360, 593908352, 393395776, 106025760, 566805968, 358875560, 708557716, 116765322, 265539137 + ], + [ + 536870912, 268435456, 671088640, 603979776, 570425344, 989855744, 494927872, 255852544, 547356672, 506462208, 647495680, 974389248, 1019871232, 883228672, 697466880, 198197248, 1057595392, 826036224, 302446592, 375061504, 369893888, 35531008, 378530688, 556237248, 707471648, 1018431120, 737874824, 482115012, 625445674, 989556633 + ], + [ + 536870912, 805306368, 671088640, 738197504, 704643072, 956301312, 780140544, 700448768, 782237696, 789577728, 520617984, 659816448, 302120960, 125501440, 462848000, 844742656, 599629824, 539455488, 591460352, 828402688, 984658432, 194522880, 354161536, 188169664, 977849952, 87399664, 1060349032, 195260412, 166354402, 954163511 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 637534208, 50331648, 260046848, 364904448, 81788928, 741343232, 748158976, 644087808, 523894784, 997261312, 87588864, 385138688, 397664256, 870068224, 630102016, 652459008, 766823936, 1267456, 1011702144, 75974848, 948925728, 107141840, 166991880, 775060484, 1025355270, 317630223 + ], + [ + 536870912, 268435456, 134217728, 469762048, 167772160, 50331648, 746586112, 507510784, 517996544, 682622976, 364380160, 697040896, 402522112, 283312128, 699760640, 397590528, 1061003264, 122040320, 351209472, 327818240, 560989696, 1033387264, 530327168, 555201088, 568801952, 868136976, 352465960, 965011028, 172630154, 22056771 + ], + [ + 536870912, 268435456, 402653184, 738197504, 503316480, 654311424, 1031798784, 79691776, 396361728, 168820736, 489160704, 75759616, 1069678592, 706019328, 749371392, 410107904, 639229952, 754724864, 1041127424, 794958848, 226795008, 759369984, 659871360, 231425088, 1019247776, 731915088, 202411656, 371742788, 654598822, 470020699 + ], + [ + 536870912, 268435456, 939524096, 67108864, 905969664, 218103808, 444596224, 88080384, 1042284544, 957349888, 927465472, 537133056, 923926528, 745603072, 695762944, 987611136, 740171776, 700887040, 55306240, 742167552, 602884608, 25075968, 871870592, 798160448, 976352800, 1020815248, 772622344, 456647684, 426934798, 633373953 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 1040187392, 788529152, 327155712, 381681664, 262144000, 955252736, 641204224, 4456448, 599392256, 885325824, 855277568, 396673024, 682319872, 200093696, 613816320, 586394624, 309964288, 899961088, 699017600, 258785472, 500661152, 93549840, 170404232, 955105476, 421002158, 590525727 + ], + [ + 536870912, 805306368, 671088640, 469762048, 100663296, 1056964608, 931135488, 801112064, 304087040, 934281216, 404226048, 640942080, 510263296, 230621184, 440696832, 374521856, 289054720, 246829056, 479725568, 544498688, 680219136, 95405824, 590207104, 853444416, 110428768, 949665904, 147258088, 497080124, 477188226, 943203147 + ], + [ + 536870912, 805306368, 939524096, 603979776, 838860800, 620756992, 578813952, 390070272, 987758592, 300941312, 219676672, 513540096, 259129344, 20381696, 293109760, 439107584, 629858304, 148615168, 911357952, 442989568, 150064640, 161062144, 652017792, 370305856, 386304544, 348216944, 220251304, 559015996, 545861126, 657796357 + ], + [ + 536870912, 805306368, 402653184, 872415232, 503316480, 150994944, 897581056, 624951296, 1000341504, 923795456, 890765312, 482607104, 564527104, 295895040, 753172480, 183975936, 848977920, 376557568, 1005189120, 32277504, 464246272, 423186176, 93585792, 564024896, 162994656, 71040656, 316774504, 380758236, 218653070, 559711809 + ], + [ + 536870912, 805306368, 939524096, 335544320, 973078528, 486539264, 696254464, 1010827264, 945815552, 380633088, 348651520, 185860096, 620625920, 259325952, 340754432, 280805376, 98246656, 109252608, 974047232, 702405632, 753658368, 487276288, 133844864, 324161856, 452414240, 281074864, 161574792, 277954892, 857309998, 451739829 + ], + [ + 536870912, 805306368, 671088640, 469762048, 167772160, 553648128, 125829120, 1069547520, 325058560, 286261248, 974651392, 226230272, 724434944, 894107648, 949518336, 993837056, 412065792, 129740800, 13752320, 108655616, 82600448, 511169792, 940985216, 143060032, 241154336, 717453200, 582848680, 542002908, 274358786, 343987467 + ], + [ + 536870912, 268435456, 134217728, 603979776, 301989888, 721420288, 461373440, 557842432, 811597824, 814743552, 576192512, 26476544, 913702912, 792788992, 895516672, 1041252352, 93921280, 842305536, 658987008, 925490176, 924682752, 727433984, 267625600, 1034814144, 882152608, 553029552, 612401160, 817905668, 371269634, 762351625 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 503316480, 184549376, 75497472, 432013312, 329252864, 898629632, 1572864, 692846592, 622198784, 491978752, 416382976, 578371584, 192684032, 849285120, 554149888, 453770240, 125610496, 77525760, 772202880, 1032545344, 196970144, 415133904, 114713896, 938679188, 79702022, 136428555 + ], + [ + 536870912, 805306368, 939524096, 603979776, 905969664, 654311424, 444596224, 348127232, 392167424, 254803968, 786956288, 545521664, 609353728, 639565824, 366510080, 812400640, 1071046656, 181243904, 906430464, 257240064, 248173056, 408120576, 69098112, 1020865216, 703368544, 127343024, 778855912, 886541948, 978180614, 398868741 + ], + [ + 536870912, 268435456, 134217728, 67108864, 637534208, 855638016, 461373440, 440401920, 668991488, 141557760, 902299648, 958660608, 482213888, 345571328, 415006720, 1015169024, 568008704, 13021184, 903108608, 448150528, 219972096, 118699776, 845379456, 992712768, 768477216, 1003565936, 1029274120, 823982852, 1024593282, 727933761 + ], + [ + 536870912, 268435456, 402653184, 469762048, 167772160, 150994944, 58720256, 88080384, 685768704, 403701760, 671612928, 671875072, 796524544, 330235904, 208764928, 634929152, 1059332096, 759607296, 728569856, 640340992, 491255296, 594283776, 573282176, 189196480, 544025632, 682248624, 227005864, 231553140, 408631310, 1033856003 + ], + [ + 536870912, 805306368, 939524096, 469762048, 771751936, 117440512, 729808896, 398458880, 744488960, 653262848, 1572864, 563871744, 873070592, 354877440, 664043520, 1061044224, 50864128, 833884160, 829327360, 671122432, 335614464, 167781632, 889317504, 42006848, 994072352, 270583600, 491894696, 176814716, 125063814, 361711691 + ], + [ + 536870912, 805306368, 134217728, 67108864, 301989888, 654311424, 75497472, 725614592, 736100352, 210763776, 378011648, 899940352, 326238208, 362610688, 1030717440, 993214464, 419209216, 901730304, 114972672, 411571200, 1017459200, 787620608, 190622336, 206477632, 344115872, 113612112, 446881928, 301317708, 836381218, 604580625 + ], + [ + 536870912, 805306368, 134217728, 603979776, 1040187392, 16777216, 226492416, 750780416, 727711744, 745537536, 509083648, 473694208, 776601600, 1012203520, 219119616, 527646720, 35233792, 874262528, 379283456, 865975296, 1029381632, 947683072, 711641472, 511999936, 1036415328, 598097680, 72826760, 466615500, 991135458, 719867865 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 33554432, 218103808, 125829120, 239075328, 656408576, 594542592, 301465600, 375652352, 23986176, 509542400, 495419392, 991084544, 465903616, 1004417024, 247977984, 867312640, 183825920, 252133120, 919854208, 614778688, 210737760, 885959184, 821019240, 857624084, 438703202, 547569947 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 234881024, 620756992, 830472192, 499122176, 966787072, 149946368, 251133952, 999030784, 830341120, 370081792, 406224896, 530235392, 164962304, 58871808, 1011480576, 806663168, 807565824, 733570816, 409802880, 216955712, 707218720, 326269392, 917550376, 832163292, 375148330, 657877715 + ], + [ + 536870912, 268435456, 402653184, 67108864, 301989888, 419430400, 394264576, 155189248, 996147200, 179306496, 232259584, 673447936, 241565696, 173735936, 179929088, 613695488, 280944640, 687845376, 136304640, 99562496, 1012372992, 37904640, 104642176, 31637312, 1034707424, 795535120, 438354280, 1037138260, 157906446, 721277189 + ], + [ + 536870912, 268435456, 939524096, 469762048, 369098752, 486539264, 947912704, 650117120, 903872512, 959447040, 562561024, 1007943680, 511049728, 963575808, 753106944, 215498752, 552443904, 600543232, 777893888, 453188608, 183032320, 384122112, 379461760, 277504704, 771608928, 353534288, 766546792, 961048660, 821424614, 365421459 + ], + [ + 536870912, 268435456, 134217728, 201326592, 905969664, 83886080, 629145600, 566231040, 429916160, 726663168, 689438720, 664535040, 611450880, 364576768, 805273600, 405913600, 795385856, 328568832, 764934144, 841331712, 490637824, 823242496, 142113152, 250425152, 251356832, 287230896, 595596456, 1019334836, 941713194, 814780663 + ], + [ + 536870912, 268435456, 671088640, 67108864, 905969664, 218103808, 142606336, 247463936, 182452224, 634388480, 986185728, 303300608, 380764160, 688979968, 858292224, 507854848, 406462464, 69513216, 254470144, 772539392, 133092864, 838313728, 933947008, 416080448, 554659488, 640120464, 912418824, 257508356, 838661642, 186062593 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 570425344, 1056964608, 192937984, 683671552, 916455424, 416284672, 790102016, 738983936, 82968576, 487260160, 238518272, 74268672, 58957824, 407056384, 258115584, 611578880, 675955200, 693575424, 10255744, 168501056, 834079776, 715921456, 337866280, 370308916, 1010547630, 497020027 + ], + [ + 536870912, 805306368, 134217728, 335544320, 369098752, 1056964608, 897581056, 817889280, 325058560, 588251136, 62390272, 886308864, 406716416, 781778944, 803569664, 943079424, 503685120, 979841024, 538753024, 365071360, 990541312, 66536192, 518308992, 515310528, 289784224, 616970096, 216815112, 254489356, 440818818, 799932357 + ], + [ + 536870912, 268435456, 134217728, 67108864, 570425344, 419430400, 528482304, 373293056, 853540864, 787480576, 1028128768, 67895296, 539361280, 218038272, 202080256, 873054208, 40689664, 370634752, 244774912, 542548992, 746014208, 111556864, 356426368, 548090560, 739801504, 869645584, 911419304, 893210644, 449821482, 509820885 + ], + [ + 536870912, 805306368, 402653184, 469762048, 704643072, 520093696, 947912704, 574619648, 153092096, 814743552, 876085248, 1056702464, 654704640, 215416832, 340688896, 467812352, 758947840, 837218304, 682002432, 520489984, 550977024, 642696960, 417524608, 1069315648, 212228000, 419869840, 232153000, 500103324, 673431982, 199085979 + ], + [ + 536870912, 268435456, 939524096, 872415232, 167772160, 587202560, 176160768, 859832320, 425721856, 439353344, 454557696, 714342400, 1030619136, 82640896, 600473600, 865779712, 271720448, 519966720, 778369024, 618062848, 829010432, 846001920, 109811584, 268068288, 495144992, 354937648, 122684808, 589857476, 512507822, 595290877 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 369098752, 352321536, 562036736, 633339904, 769654784, 946864128, 715653120, 356253696, 881983488, 1049952256, 439320576, 617037824, 31154176, 349728768, 311724032, 875437056, 96982528, 173734656, 840534400, 200554560, 136199008, 659465552, 183918472, 340968268, 183874274, 866098463 + ], + [ + 536870912, 268435456, 402653184, 1006632960, 301989888, 117440512, 964689920, 197132288, 840957952, 735051776, 589824000, 272367616, 586809344, 244908032, 2392064, 10403840, 803659776, 171118592, 274036736, 195456000, 181595648, 1025857792, 169769600, 732336960, 449999584, 623144528, 908064264, 967304452, 500403334, 480540239 + ], + [ + 536870912, 268435456, 939524096, 335544320, 100663296, 218103808, 1065353216, 448790528, 924844032, 611319808, 932708352, 180617216, 675151872, 726859776, 928088064, 1038696448, 475881472, 259690496, 313350144, 430117888, 193587712, 1003310848, 179530368, 637622080, 486581984, 125856208, 247529064, 824255892, 695220230, 135889921 + ], + [ + 536870912, 268435456, 402653184, 872415232, 234881024, 50331648, 662700032, 624951296, 35651584, 470810624, 491257856, 805568512, 68812800, 406126592, 574783488, 83476480, 69017600, 863416320, 70957056, 757386240, 227242496, 20794624, 249993856, 322130752, 41968800, 1036053648, 585171592, 40972100, 704229030, 815623581 + ], + [ + 536870912, 805306368, 402653184, 603979776, 503316480, 654311424, 159383552, 88080384, 446693376, 242221056, 977797120, 448528384, 503185408, 365756416, 490176512, 95535104, 472424448, 321662976, 392566784, 625589248, 121410048, 515791104, 208435584, 80115520, 498622048, 364237232, 98722184, 574868300, 749915238, 624593081 + ], + [ + 536870912, 268435456, 671088640, 603979776, 436207616, 50331648, 360710144, 314572800, 249561088, 842006528, 50855936, 689176576, 256507904, 176095232, 31817728, 916701184, 593190912, 715550720, 440928256, 1010062336, 219843072, 403048704, 769131136, 791440320, 47676896, 434156144, 95526760, 516516276, 209029762, 918290381 + ], + [ + 536870912, 268435456, 671088640, 872415232, 234881024, 855638016, 1048576000, 406847488, 840957952, 26214400, 136839168, 505675776, 414056448, 221184000, 670007296, 529448960, 624910336, 788992000, 751470592, 1050770432, 13680128, 294235904, 1047847808, 174523072, 200967136, 978935440, 494699496, 1045585556, 985465826, 867409561 + ], + [ + 536870912, 268435456, 671088640, 201326592, 100663296, 754974720, 729808896, 901775360, 635437056, 5242880, 912785408, 142868480, 506855424, 728170496, 42958848, 499826688, 18653184, 715886592, 755857408, 65201152, 213510656, 514610432, 261271424, 828455104, 17905376, 46694992, 343166696, 950953556, 58434786, 430256983 + ], + [ + 536870912, 268435456, 939524096, 872415232, 436207616, 822083584, 176160768, 708837376, 127926272, 30408704, 967311360, 439091200, 869924864, 72810496, 794656768, 337854464, 622026752, 776663040, 895424512, 757087232, 999372288, 101209856, 805085056, 276012480, 796569376, 369621552, 976572584, 233740276, 1001973638, 702894537 + ], + [ + 536870912, 805306368, 402653184, 603979776, 973078528, 822083584, 192937984, 339738624, 442499072, 686817280, 355991552, 791412736, 33161216, 887029760, 353402880, 529088512, 393601024, 581365760, 886921216, 977425408, 640892416, 265015552, 675677312, 451741248, 383401120, 835677360, 580443688, 889040892, 735229966, 494642181 + ], + [ + 536870912, 268435456, 134217728, 469762048, 1040187392, 855638016, 864026624, 272629760, 526385152, 663748608, 665321472, 423362560, 816185344, 553451520, 914784256, 848117760, 75390976, 1035513856, 97908736, 293219328, 92994048, 598939392, 975693440, 37583424, 254191456, 113085296, 115828360, 412957252, 9848674, 140802935 + ], + [ + 536870912, 268435456, 402653184, 738197504, 771751936, 822083584, 377487360, 490733568, 1025507328, 202375168, 544735232, 641990656, 190185472, 332464128, 303595520, 276086784, 750739456, 808218624, 778766336, 792949760, 475924992, 157145344, 866306176, 187590592, 630571040, 22003632, 799377416, 279360516, 291105286, 341141771 + ], + [ + 536870912, 805306368, 671088640, 469762048, 33554432, 50331648, 830472192, 339738624, 576716800, 911212544, 461897728, 518782976, 874905600, 44367872, 803962880, 993148928, 148267008, 836620288, 746469376, 629226496, 977390080, 190961408, 416310400, 1011413312, 734850272, 295063792, 993799816, 149841484, 665413738, 635253175 + ], + [ + 536870912, 268435456, 939524096, 335544320, 704643072, 687865856, 377487360, 415236096, 597688320, 326107136, 454557696, 273416192, 345636864, 625410048, 727023616, 349650944, 165437440, 437481472, 360896512, 873126912, 89088512, 391148288, 36274816, 573963584, 151473056, 87414576, 881324328, 242599540, 661053574, 627412545 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 838860800, 419430400, 847249408, 54525952, 950009856, 386924544, 54001664, 239337472, 1054736384, 785580032, 771784704, 453001216, 327163904, 230715392, 165763072, 917593088, 648646144, 238935808, 138116480, 119382336, 65792992, 994395344, 912187496, 814962332, 706740230, 609222659 + ], + [ + 536870912, 268435456, 671088640, 201326592, 100663296, 1056964608, 92274688, 884998144, 601882624, 999292928, 932708352, 561774592, 499777536, 921894912, 406814720, 27049984, 500932608, 782897152, 354560000, 705111040, 97571328, 490276096, 701336960, 941816640, 579217824, 697349232, 983096232, 972841332, 428564002, 492006967 + ], + [ + 536870912, 268435456, 671088640, 1006632960, 570425344, 687865856, 1015021568, 675282944, 794820608, 856686592, 608698368, 553910272, 421658624, 601161728, 483033088, 199245824, 525426688, 1026052096, 622110720, 183170048, 1058081280, 1044913920, 470129280, 1000585536, 9732256, 640295760, 741454472, 1010306372, 6056618, 728706143 + ], + [ + 536870912, 268435456, 402653184, 67108864, 973078528, 318767104, 226492416, 742391808, 174063616, 206569472, 303562752, 141295616, 312606720, 182517760, 345014272, 850968576, 731652096, 281792512, 94738432, 496430080, 483303936, 625210112, 586216064, 283666624, 142942048, 36085520, 214310920, 576114692, 66000902, 636693505 + ], + [ + 536870912, 268435456, 939524096, 67108864, 234881024, 956301312, 209715200, 1027604480, 421527552, 137363456, 675807232, 683409408, 629538816, 488177664, 224690176, 671334400, 625680384, 460845056, 212961280, 956892160, 60586496, 515330304, 248552832, 756646976, 627426016, 335703728, 793399816, 745956612, 959467406, 147398977 + ], + [ + 536870912, 805306368, 402653184, 738197504, 973078528, 587202560, 696254464, 767557632, 270532608, 711983104, 634912768, 823918592, 317849600, 917700608, 995262464, 419577856, 984293376, 342814720, 344057856, 423732224, 962677248, 185666304, 46741632, 165004864, 942102176, 655723824, 830985896, 950324540, 679376558, 432569655 + ], + [ + 536870912, 268435456, 939524096, 335544320, 973078528, 587202560, 746586112, 700448768, 383778816, 896532480, 300417024, 721682432, 684064768, 893452288, 388005888, 261210112, 177774592, 602787840, 205723648, 415654912, 490786304, 992081664, 563137408, 328859456, 745377824, 151206448, 669417480, 1053868036, 532160526, 461115397 + ], + [ + 536870912, 805306368, 402653184, 67108864, 570425344, 788529152, 897581056, 239075328, 559939584, 57671680, 817364992, 164364288, 612499456, 351207424, 666664960, 1052459008, 1055121408, 673165312, 709109760, 93828096, 441527808, 933802240, 1015288960, 3610688, 461442720, 792785136, 98597416, 833624252, 655899790, 1058843725 + ], + [ + 536870912, 805306368, 671088640, 872415232, 905969664, 486539264, 109051904, 750780416, 891289600, 894435328, 698875904, 696516608, 230817792, 932118528, 368607232, 11321344, 1032249344, 1038946304, 233232384, 350002176, 662663680, 146882304, 455134080, 877667264, 757608288, 776277808, 593753832, 681493500, 632400386, 693740289 + ], + [ + 536870912, 805306368, 402653184, 738197504, 637534208, 117440512, 310378496, 289406976, 652214272, 686817280, 970457088, 408682496, 648937472, 32571392, 676954112, 161267712, 470769664, 1012936704, 1035057152, 221795328, 1034807808, 754321152, 493649792, 735500992, 389908704, 60744304, 1015658504, 647255052, 240904710, 253429515 + ], + [ + 536870912, 268435456, 671088640, 603979776, 905969664, 318767104, 125829120, 574619648, 786432000, 781189120, 498597888, 129761280, 557711360, 821231616, 568688640, 613662720, 632643584, 134877184, 20539392, 377291776, 866115072, 126016768, 592187264, 265802560, 710343456, 353780368, 595000488, 975603156, 238989698, 494083661 + ], + [ + 536870912, 268435456, 939524096, 335544320, 167772160, 218103808, 931135488, 398458880, 291504128, 256901120, 617086976, 203685888, 363462656, 234160128, 186810368, 846249984, 590880768, 165515264, 479643648, 452127744, 351884800, 146568960, 734504064, 708468032, 316515232, 269950736, 296971400, 920236356, 835483054, 1014933525 + ], + [ + 536870912, 268435456, 402653184, 469762048, 704643072, 855638016, 394264576, 826277888, 610271232, 774897664, 536346624, 952893440, 657850368, 416874496, 228360192, 863944704, 565043200, 193449984, 551573504, 418438144, 316152320, 781998848, 1023319424, 216919488, 99015008, 1037042224, 277445128, 458574596, 768288134, 169271751 + ], + [ + 536870912, 805306368, 402653184, 738197504, 234881024, 822083584, 343932928, 155189248, 241172480, 101711872, 42467328, 364118016, 996802560, 936181760, 84377600, 284934144, 746971136, 764620800, 820062208, 877671424, 325677568, 493108992, 356691584, 113812800, 693488160, 825980304, 228922504, 551722572, 49856166, 355212251 + ], + [ + 536870912, 805306368, 134217728, 335544320, 838860800, 687865856, 780140544, 4194304, 979369984, 818937856, 782761984, 569638912, 114950144, 255000576, 86409216, 250396672, 114778112, 880046080, 823916544, 328395776, 467017216, 418772224, 274366336, 326247616, 424085088, 624751408, 805279848, 994166332, 232818666, 370184953 + ], + [ + 536870912, 805306368, 402653184, 469762048, 100663296, 285212672, 578813952, 650117120, 299892736, 324009984, 734527488, 570163200, 995753984, 811794432, 1059487744, 913850368, 518365184, 925765632, 384129024, 53357568, 350579200, 137350400, 560255872, 493790144, 885272352, 958354800, 498941224, 544990332, 752024750, 180287163 + ], + [ + 536870912, 268435456, 671088640, 335544320, 33554432, 486539264, 377487360, 775946240, 849346560, 196083712, 372768768, 225705984, 546963456, 141623296, 995655680, 765804544, 561160192, 460132352, 840853504, 762508288, 896291328, 287196416, 821187968, 313341376, 108929440, 824323536, 331671560, 606254084, 21262858, 543364357 + ], + [ + 536870912, 268435456, 134217728, 201326592, 301989888, 218103808, 1065353216, 801112064, 44040192, 674234368, 287834112, 1000603648, 452329472, 145948672, 731217920, 534691840, 622272512, 576942080, 938293248, 331559936, 794636800, 397112064, 169414784, 437109440, 873665376, 212084752, 880190440, 49502932, 133441674, 416216775 + ], + [ + 536870912, 805306368, 671088640, 335544320, 503316480, 385875968, 511705088, 549453824, 916455424, 72351744, 488112128, 96731136, 996540416, 996999168, 587956224, 686178304, 338436096, 15347712, 777410560, 302261248, 591891968, 939333888, 481427584, 930239424, 626251168, 549704560, 385513096, 925769420, 271688490, 48876981 + ], + [ + 536870912, 805306368, 402653184, 67108864, 570425344, 83886080, 578813952, 1052770304, 819986432, 428867584, 483917824, 630980608, 756416512, 338231296, 731217920, 636665856, 764616704, 1002672128, 259680256, 213349376, 219710976, 519954176, 382075008, 634395840, 586740192, 351021360, 744476168, 258751244, 639594118, 1045264321 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 167772160, 352321536, 226492416, 390070272, 648019968, 747634688, 586678272, 400818176, 352714752, 1015611392, 497909760, 189415424, 485679104, 884396032, 44066816, 579881984, 167332352, 962866432, 281538688, 367552960, 224189472, 885130160, 601768456, 943517964, 506606210, 22534351 + ], + [ + 536870912, 268435456, 134217728, 335544320, 771751936, 419430400, 159383552, 809500672, 589299712, 791674880, 543686656, 237764608, 727842816, 374669312, 337018880, 41107456, 982327296, 890482688, 10299392, 1061886976, 492403200, 491109632, 332367744, 167178304, 916631008, 859155408, 486995336, 1051451716, 327776354, 603847317 + ], + [ + 536870912, 805306368, 671088640, 603979776, 704643072, 553648128, 595591168, 834666496, 119537664, 288358400, 306708480, 172752896, 33947648, 893976576, 919437312, 860307456, 623386624, 412930048, 668878848, 146619392, 577723904, 263549184, 306394496, 48368704, 269665120, 679155120, 512187912, 873033996, 246232458, 957811785 + ], + [ + 536870912, 805306368, 134217728, 872415232, 704643072, 989855744, 780140544, 96468992, 677380096, 972029952, 73924608, 985923584, 829554688, 1063321600, 829521920, 749223936, 421896192, 851660800, 53008384, 828699648, 232943104, 158982912, 899489664, 524270400, 770048544, 753563024, 835559432, 851922956, 381343746, 1026946061 + ], + [ + 536870912, 805306368, 939524096, 201326592, 301989888, 620756992, 276824064, 448790528, 740294656, 749731840, 730333184, 532414464, 708968448, 928448512, 244875264, 449069056, 479698944, 473559040, 599013376, 582904832, 930427392, 832481024, 440790144, 240606656, 68757408, 285476592, 1043749160, 491260988, 295479814, 468859663 + ], + [ + 536870912, 268435456, 671088640, 603979776, 771751936, 318767104, 696254464, 641728512, 983564288, 829423616, 358088704, 749993984, 244973568, 223412224, 434667520, 336412672, 427761664, 354578432, 188028928, 735742976, 913330688, 718865664, 368386944, 398089920, 660695968, 210799568, 101201928, 509475844, 1058523658, 946850057 + ], + [ + 536870912, 805306368, 671088640, 872415232, 838860800, 721420288, 243269632, 457179136, 236978176, 179306496, 520617984, 181665792, 530448384, 639827968, 578322432, 868007936, 56287232, 826617856, 111626240, 733965312, 60001792, 703658752, 1026038912, 778414528, 764878048, 997680976, 52883048, 243254684, 1056065026, 425744129 + ], + [ + 536870912, 268435456, 939524096, 603979776, 436207616, 452984832, 998244352, 616562688, 501219328, 982515712, 39321600, 357826560, 280625152, 104529920, 343638016, 198852608, 384524288, 763604992, 431974400, 641250304, 604279296, 377683200, 843049344, 989354816, 501539296, 907222064, 728162792, 338435124, 698311142, 768171069 + ], + [ + 536870912, 268435456, 134217728, 201326592, 301989888, 486539264, 931135488, 507510784, 589299712, 1064304640, 1067974656, 149684224, 306053120, 392888320, 910262272, 1059110912, 628105216, 782823424, 762083328, 293557248, 63589888, 393243392, 598221440, 317466304, 54479392, 854306448, 889257640, 729843540, 71401482, 841007111 + ], + [ + 536870912, 268435456, 134217728, 335544320, 369098752, 1056964608, 713031680, 801112064, 610271232, 982515712, 354942976, 638844928, 720764928, 830275584, 566394880, 549142528, 644292608, 190148608, 626497536, 831259648, 628758016, 788954880, 977610368, 507498560, 548970784, 29150576, 1059303560, 1038872388, 53356450, 30420277 + ], + [ + 536870912, 805306368, 939524096, 201326592, 234881024, 419430400, 427819008, 432013312, 316669952, 946864128, 690487296, 698613760, 448921600, 902234112, 777289728, 925515776, 755146752, 237408256, 933623808, 197272576, 407294464, 898892032, 852189312, 368238784, 659423584, 354548144, 999375336, 1020840316, 458004614, 914867407 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 1040187392, 117440512, 327155712, 994050048, 543162368, 856686592, 117964800, 764674048, 265420800, 619511808, 954171392, 610484224, 869621760, 892481536, 809277440, 192351232, 533156352, 796837632, 466873984, 384694592, 165591840, 216230992, 622150792, 689046092, 818716578, 70147615 + ], + [ + 536870912, 268435456, 671088640, 872415232, 838860800, 989855744, 897581056, 725614592, 866123776, 852492288, 343408640, 176422912, 198574080, 559611904, 505511936, 361873408, 165208064, 89403392, 590235648, 236942336, 949450240, 519702272, 49376128, 1021887808, 1071407072, 725765776, 789899880, 974112980, 940498946, 990851081 + ], + [ + 536870912, 805306368, 134217728, 335544320, 973078528, 855638016, 729808896, 46137344, 106954752, 456130560, 792199168, 835977216, 325713920, 58654720, 99909632, 58441728, 30924800, 558493696, 72189952, 1055794176, 681392640, 187165952, 328298112, 610912832, 282935904, 990300016, 25210088, 163630396, 836767370, 938539593 + ], + [ + 536870912, 805306368, 671088640, 67108864, 234881024, 318767104, 142606336, 918552576, 329252864, 110100480, 20447232, 293863424, 676462592, 192086016, 656572416, 398180352, 430956544, 625315840, 317851648, 811781120, 257669632, 635324160, 17572736, 851427904, 356323936, 211182320, 583070312, 94434044, 965769826, 62521085 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 503316480, 117440512, 914358272, 960495616, 350224384, 533725184, 718798848, 126615552, 108134400, 834994176, 180781056, 946520064, 594042880, 29732864, 583407616, 1013687296, 23626240, 415525632, 323395712, 866790336, 751381984, 334845904, 642693768, 520037572, 758607726, 608347935 + ], + [ + 536870912, 268435456, 134217728, 335544320, 704643072, 285212672, 260046848, 130023424, 480247808, 416284672, 614989824, 185335808, 987365376, 787808256, 767459328, 1057177600, 738271232, 637636608, 654338048, 545360896, 859956736, 98570496, 204506240, 656014912, 735345632, 229520656, 998967944, 849175364, 110336354, 273193557 + ], + [ + 536870912, 268435456, 671088640, 469762048, 503316480, 218103808, 931135488, 364904448, 199229440, 135266304, 750256128, 588513280, 198836224, 461701120, 438468608, 707805184, 558391296, 582856704, 804685824, 948587520, 211633664, 335946496, 673336960, 19966656, 801636384, 50155280, 584500872, 33285828, 175490602, 92941335 + ], + [ + 536870912, 805306368, 671088640, 67108864, 234881024, 50331648, 461373440, 440401920, 44040192, 1066401792, 43515904, 158597120, 332267520, 714932224, 303267840, 816726016, 1038917632, 96120832, 13793280, 734923776, 916290048, 806498560, 967828096, 728505280, 125556256, 62062640, 213893256, 154457804, 74421930, 562927345 + ], + [ + 536870912, 268435456, 671088640, 738197504, 301989888, 822083584, 830472192, 432013312, 316669952, 810549248, 180879360, 781451264, 208535552, 1006567424, 282558464, 647151616, 611688448, 675164160, 657864704, 826438656, 947689984, 113966336, 38397824, 987067840, 1028645728, 72247568, 164518760, 705617172, 636445026, 910037023 + ], + [ + 536870912, 268435456, 134217728, 872415232, 301989888, 553648128, 578813952, 700448768, 874512384, 959447040, 432537600, 180617216, 1038483456, 544800768, 63733760, 495075328, 728670208, 1029509120, 775669760, 428078080, 560987648, 543029504, 716879232, 54715456, 382664992, 304925616, 781334024, 77008132, 198298498, 559504717 + ], + [ + 536870912, 805306368, 671088640, 335544320, 369098752, 587202560, 713031680, 406847488, 387973120, 978321408, 192413696, 52166656, 573440000, 285147136, 113672192, 863748096, 231038976, 253939712, 76105728, 242605056, 57376256, 1016960768, 66047360, 488548928, 670456992, 57881296, 485561512, 266989276, 755296930, 759413209 + ], + [ + 536870912, 268435456, 134217728, 469762048, 838860800, 721420288, 209715200, 281018368, 799014912, 779091968, 603455488, 529268736, 891420672, 524877824, 550797312, 475938816, 928243712, 380637184, 5871616, 201114624, 568063488, 1044690176, 775344000, 540458432, 691431264, 112719760, 116846088, 194392324, 558291330, 541989063 + ] + ], + + "md_c" : [ + [[ 1.0000000 , 0.6000000 , 0.8000000 ], + [ 0.6000000 , 0.8000000 , 0.1500000 ], + [ 0.8000000 , 0.1500000 , 0.5809475 ]] + ], + + "md_vols" : [ + [[ 0.0000000 , 0.0000000 , 0.0000000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ]] + ], + + "md_drifts" : [ + [[ 0.0000000000000000 , 0.0000000000000000 , 0.0000000000000000 ], + [ -0.0000769148269844 , 0.0000327749731970 , -0.0000051340050666 ], + [ -0.0000769148269844 , 0.0000327749731970 , -0.0000051340050666 ], + [ -0.0000769148269844 , 0.0000327749731970 , -0.0000051340050666 ], + [ -0.0000769117410220 , 0.0000327819160986 , -0.0000051309191042 ], + [ -0.0000769117410220 , 0.0000327819160986 , -0.0000051309191042 ], + [ -0.0000769197006278 , 0.0000342555768863 , -0.0000036470215480 ], + [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], + [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], + [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], + [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], + [ -0.0000769231082238 , 0.0000348871540378 , -0.0000030110617889 ], + [ -0.0000769364349073 , 0.0000371477302492 , -0.0000007324359000 ], + [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], + [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], + [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], + [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], + [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], + [ -0.0000769436108138 , 0.0000383649635937 , 0.0000004945165018 ], + [ -0.0000769609069770 , 0.0000476737925826 , 0.0000098342203061 ], + [ -0.0000769695550586 , 0.0000523282070770 , 0.0000145040722083 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000769782031402 , 0.0000569826215715 , 0.0000191739241105 ], + [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], + [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], + [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], + [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], + [ -0.0000770387184138 , 0.0000525750483138 , 0.0000148283938103 ], + [ -0.0000770387184138 , 0.0000516935336623 , 0.0000148283938103 ], + [ -0.0000770931821601 , 0.0000481674750561 , 0.0000109174165401 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000481674750561 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000486764057747 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000486764057747 , 0.0000104828635101 ], + [ -0.0000770992336875 , 0.0000486764057747 , 0.0000104828635101 ], + [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000486764057747 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000489308711339 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000491853364932 , 0.0000112366493239 ], + [ -0.0000772189449197 , 0.0000491853364932 , 0.0000112366493239 ], + [ -0.0000773147139055 , 0.0000491853364932 , 0.0000118396779749 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351376 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351377 ], + [ -0.0000773386561520 , 0.0000491853364932 , 0.0000119904351376 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000774788281904 , 0.0000502714491067 , 0.0000132707320858 ], + [ -0.0000775909658212 , 0.0000511403391975 , 0.0000142949696444 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000776190002289 , 0.0000513575617202 , 0.0000145510290340 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000777566242513 , 0.0000494090965224 , 0.0000128043798313 ], + [ -0.0000778667234691 , 0.0000478503243642 , 0.0000114070604692 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ], + [ -0.0000778942482736 , 0.0000474606313246 , 0.0000110577306286 ] + ] + ], + + "md_starts" : [ + [ 3758.0500000000001819, + 11840.0000000000000000, + 1200.0000000000000000 ] + ], + + "md_deterministic_values" : [ + [ ] + ], + + "md_discounts" : [ + [ 0.9800680293073579 , 0.9800680293073579 ] + ], + + "bb_inds" : + [[ 367, 183, 91, 45, 22, 11, 5, 2, 1, 3, 4, 8, 6, 7, 9, 10, 16, 13, 12, 14, 15, 19, 17, 18, 20, 21, 33, 27, 24, 23, 25, 26, 30, 28, 29, 31, 32, 39, 36, 34, 35, 37, 38, 42, 40, 41, 43, 44, 68, 56, 50, 47, 46, 48, 49, 53, 51, 52, 54, 55, 62, 59, 57, 58, 60, 61, 65, 63, 64, 66, 67, 79, 73, 70, 69, 71, 72, 76, 74, 75, 77, 78, 85, 82, 80, 81, 83, 84, 88, 86, 87, 89, 90, 137, 114, 102, 96, 93, 92, 94, 95, 99, 97, 98, 100, 101, 108, 105, 103, 104, 106, 107, 111, 109, 110, 112, 113, 125, 119, 116, 115, 117, 118, 122, 120, 121, 123, 124, 131, 128, 126, 127, 129, 130, 134, 132, 133, 135, 136, 160, 148, 142, 139, 138, 140, 141, 145, 143, 144, 146, 147, 154, 151, 149, 150, 152, 153, 157, 155, 156, 158, 159, 171, 165, 162, 161, 163, 164, 168, 166, 167, 169, 170, 177, 174, 172, 173, 175, 176, 180, 178, 179, 181, 182, 275, 229, 206, 194, 188, 185, 184, 186, 187, 191, 189, 190, 192, 193, 200, 197, 195, 196, 198, 199, 203, 201, 202, 204, 205, 217, 211, 208, 207, 209, 210, 214, 212, 213, 215, 216, 223, 220, 218, 219, 221, 222, 226, 224, 225, 227, 228, 252, 240, 234, 231, 230, 232, 233, 237, 235, 236, 238, 239, 246, 243, 241, 242, 244, 245, 249, 247, 248, 250, 251, 263, 257, 254, 253, 255, 256, 260, 258, 259, 261, 262, 269, 266, 264, 265, 267, 268, 272, 270, 271, 273, 274, 321, 298, 286, 280, 277, 276, 278, 279, 283, 281, 282, 284, 285, 292, 289, 287, 288, 290, 291, 295, 293, 294, 296, 297, 309, 303, 300, 299, 301, 302, 306, 304, 305, 307, 308, 315, 312, 310, 311, 313, 314, 318, 316, 317, 319, 320, 344, 332, 326, 323, 322, 324, 325, 329, 327, 328, 330, 331, 338, 335, 333, 334, 336, 337, 341, 339, 340, 342, 343, 355, 349, 346, 345, 347, 348, 352, 350, 351, 353, 354, 361, 358, 356, 357, 359, 360, 364, 362, 363, 365, 366 ], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 5, 6, 8, 9, 11, 11, 11, 13, 14, 16, 16, 17, 19, 20, 22, 22, 22, 22, 24, 25, 27, 27, 28, 30, 31, 33, 33, 33, 34, 36, 37, 39, 39, 40, 42, 43, 45, 45, 45, 45, 45, 47, 48, 50, 50, 51, 53, 54, 56, 56, 56, 57, 59, 60, 62, 62, 63, 65, 66, 68, 68, 68, 68, 70, 71, 73, 73, 74, 76, 77, 79, 79, 79, 80, 82, 83, 85, 85, 86, 88, 89, 91, 91, 91, 91, 91, 91, 93, 94, 96, 96, 97, 99, 100, 102, 102, 102, 103, 105, 106, 108, 108, 109, 111, 112, 114, 114, 114, 114, 116, 117, 119, 119, 120, 122, 123, 125, 125, 125, 126, 128, 129, 131, 131, 132, 134, 135, 137, 137, 137, 137, 137, 139, 140, 142, 142, 143, 145, 146, 148, 148, 148, 149, 151, 152, 154, 154, 155, 157, 158, 160, 160, 160, 160, 162, 163, 165, 165, 166, 168, 169, 171, 171, 171, 172, 174, 175, 177, 177, 178, 180, 181, 183, 183, 183, 183, 183, 183, 183, 185, 186, 188, 188, 189, 191, 192, 194, 194, 194, 195, 197, 198, 200, 200, 201, 203, 204, 206, 206, 206, 206, 208, 209, 211, 211, 212, 214, 215, 217, 217, 217, 218, 220, 221, 223, 223, 224, 226, 227, 229, 229, 229, 229, 229, 231, 232, 234, 234, 235, 237, 238, 240, 240, 240, 241, 243, 244, 246, 246, 247, 249, 250, 252, 252, 252, 252, 254, 255, 257, 257, 258, 260, 261, 263, 263, 263, 264, 266, 267, 269, 269, 270, 272, 273, 275, 275, 275, 275, 275, 275, 277, 278, 280, 280, 281, 283, 284, 286, 286, 286, 287, 289, 290, 292, 292, 293, 295, 296, 298, 298, 298, 298, 300, 301, 303, 303, 304, 306, 307, 309, 309, 309, 310, 312, 313, 315, 315, 316, 318, 319, 321, 321, 321, 321, 321, 323, 324, 326, 326, 327, 329, 330, 332, 332, 332, 333, 335, 336, 338, 338, 339, 341, 342, 344, 344, 344, 344, 346, 347, 349, 349, 350, 352, 353, 355, 355, 355, 356, 358, 359, 361, 361, 362, 364, 365 ], + [ 0, 367, 183, 91, 45, 22, 11, 5, 2, 5, 5, 11, 8, 8, 11, 11, 22, 16, 13, 16, 16, 22, 19, 19, 22, 22, 45, 33, 27, 24, 27, 27, 33, 30, 30, 33, 33, 45, 39, 36, 36, 39, 39, 45, 42, 42, 45, 45, 91, 68, 56, 50, 47, 50, 50, 56, 53, 53, 56, 56, 68, 62, 59, 59, 62, 62, 68, 65, 65, 68, 68, 91, 79, 73, 70, 73, 73, 79, 76, 76, 79, 79, 91, 85, 82, 82, 85, 85, 91, 88, 88, 91, 91, 183, 137, 114, 102, 96, 93, 96, 96, 102, 99, 99, 102, 102, 114, 108, 105, 105, 108, 108, 114, 111, 111, 114, 114, 137, 125, 119, 116, 119, 119, 125, 122, 122, 125, 125, 137, 131, 128, 128, 131, 131, 137, 134, 134, 137, 137, 183, 160, 148, 142, 139, 142, 142, 148, 145, 145, 148, 148, 160, 154, 151, 151, 154, 154, 160, 157, 157, 160, 160, 183, 171, 165, 162, 165, 165, 171, 168, 168, 171, 171, 183, 177, 174, 174, 177, 177, 183, 180, 180, 183, 183, 367, 275, 229, 206, 194, 188, 185, 188, 188, 194, 191, 191, 194, 194, 206, 200, 197, 197, 200, 200, 206, 203, 203, 206, 206, 229, 217, 211, 208, 211, 211, 217, 214, 214, 217, 217, 229, 223, 220, 220, 223, 223, 229, 226, 226, 229, 229, 275, 252, 240, 234, 231, 234, 234, 240, 237, 237, 240, 240, 252, 246, 243, 243, 246, 246, 252, 249, 249, 252, 252, 275, 263, 257, 254, 257, 257, 263, 260, 260, 263, 263, 275, 269, 266, 266, 269, 269, 275, 272, 272, 275, 275, 367, 321, 298, 286, 280, 277, 280, 280, 286, 283, 283, 286, 286, 298, 292, 289, 289, 292, 292, 298, 295, 295, 298, 298, 321, 309, 303, 300, 303, 303, 309, 306, 306, 309, 309, 321, 315, 312, 312, 315, 315, 321, 318, 318, 321, 321, 367, 344, 332, 326, 323, 326, 326, 332, 329, 329, 332, 332, 344, 338, 335, 335, 338, 338, 344, 341, 341, 344, 344, 367, 355, 349, 346, 349, 349, 355, 352, 352, 355, 355, 367, 361, 358, 358, 361, 361, 367, 364, 364, 367, 367 ] + ], + + "bb_data" : + [[ 1.0013689260344547, 0.5006769876043941, 0.3530474200541117, 0.2482204548705323, 0.1734206441019846, 0.1197954333762150, 0.0810884854079383, 0.0453298413911625, 0.0000000000000000, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0864406158858196, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.1253939592915132, 0.0864406158858196, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0906596827823249, 0.0641060764756032, 0.0427373843170688, 0.0370116605098802, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098802, 0.0427373843170688, 0.0370116605098803, 0.1775016882034323, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0906596827823249, 0.0641060764756033, 0.0427373843170689, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.1253939592915132, 0.0864406158858196, 0.0573382179080996, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756033, 0.0427373843170689, 0.0370116605098802, 0.0427373843170689, 0.0370116605098803, 0.0906596827823249, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170688, 0.0370116605098803, 0.0641060764756032, 0.0427373843170688, 0.0370116605098803, 0.0427373843170689, 0.0370116605098802, 0.2510252948014144, 0.1775016882034323, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756033, 0.0427373843170690, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170690, 0.0370116605098802, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098802, 0.0427373843170690, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170690, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.1775016882034323, 0.1253939592915131, 0.0864406158858195, 0.0573382179080996, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0906596827823249, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170690, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.1253939592915132, 0.0864406158858195, 0.0573382179080996, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756032, 0.0427373843170688, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756033, 0.0427373843170690, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.0641060764756032, 0.0427373843170687, 0.0370116605098802, 0.0427373843170688, 0.0370116605098804, 0.3550033764068646, 0.2510252948014144, 0.1775016882034323, 0.1253939592915132, 0.0864406158858196, 0.0573382179080996, 0.0370116605098804, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170693, 0.0370116605098802, 0.1253939592915131, 0.0864406158858195, 0.0573382179080995, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1775016882034323, 0.1253939592915131, 0.0864406158858196, 0.0573382179080996, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1253939592915133, 0.0864406158858197, 0.0573382179080998, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170693, 0.0370116605098802, 0.2510252948014144, 0.1775016882034322, 0.1253939592915131, 0.0864406158858195, 0.0573382179080995, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170693, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1253939592915131, 0.0864406158858196, 0.0573382179080996, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0906596827823249, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.1775016882034324, 0.1253939592915133, 0.0864406158858197, 0.0573382179080998, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806, 0.0906596827823249, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170687, 0.0370116605098802, 0.0427373843170693, 0.0370116605098802, 0.1253939592915133, 0.0864406158858195, 0.0573382179080995, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756033, 0.0427373843170689, 0.0370116605098806, 0.0427373843170687, 0.0370116605098802, 0.0906596827823250, 0.0641060764756031, 0.0427373843170687, 0.0370116605098802, 0.0427373843170687, 0.0370116605098802, 0.0641060764756035, 0.0427373843170693, 0.0370116605098802, 0.0427373843170689, 0.0370116605098806 ], + [ 0.0000000000000000, 0.5027322404371586, 0.5054945054945055, 0.5111111111111111, 0.5227272727272727, 0.5238095238095238, 0.6000000000000000, 0.7500000000000001, 1.0000000000000000, 0.6666666666666666, 0.5000000000000001, 0.4999999999999999, 0.6666666666666669, 0.5000000000000003, 0.6666666666666666, 0.5000000000000000, 0.5454545454545455, 0.6000000000000001, 0.4999999999999994, 0.6666666666666664, 0.4999999999999994, 0.5000000000000000, 0.6666666666666664, 0.4999999999999994, 0.6666666666666664, 0.5000000000000007, 0.5217391304347826, 0.5454545454545455, 0.5999999999999996, 0.5000000000000000, 0.6666666666666677, 0.5000000000000000, 0.4999999999999996, 0.6666666666666666, 0.5000000000000000, 0.6666666666666677, 0.5000000000000000, 0.5000000000000000, 0.5000000000000004, 0.6666666666666661, 0.4999999999999987, 0.6666666666666666, 0.5000000000000000, 0.5000000000000004, 0.6666666666666661, 0.5000000000000012, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.5217391304347827, 0.5454545454545453, 0.5999999999999996, 0.5000000000000026, 0.6666666666666677, 0.5000000000000026, 0.5000000000000000, 0.6666666666666677, 0.4999999999999974, 0.6666666666666677, 0.4999999999999974, 0.4999999999999996, 0.4999999999999992, 0.6666666666666655, 0.5000000000000026, 0.6666666666666677, 0.5000000000000026, 0.5000000000000000, 0.6666666666666677, 0.4999999999999974, 0.6666666666666677, 0.4999999999999974, 0.5217391304347823, 0.5454545454545457, 0.5999999999999996, 0.4999999999999974, 0.6666666666666677, 0.4999999999999974, 0.5000000000000009, 0.6666666666666644, 0.5000000000000000, 0.6666666666666655, 0.5000000000000026, 0.5000000000000000, 0.5000000000000000, 0.6666666666666677, 0.5000000000000026, 0.6666666666666677, 0.4999999999999974, 0.5000000000000000, 0.6666666666666677, 0.4999999999999974, 0.6666666666666644, 0.5000000000000000, 0.4999999999999999, 0.5000000000000000, 0.5217391304347829, 0.5454545454545453, 0.5999999999999975, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.4999999999999992, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.5217391304347829, 0.5454545454545453, 0.6000000000000016, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.5000000000000051, 0.6666666666666666, 0.5000000000000000, 0.5000000000000009, 0.4999999999999983, 0.6666666666666690, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000002, 0.5217391304347825, 0.5454545454545453, 0.6000000000000016, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666690, 0.4999999999999949, 0.5000000000000000, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.5000000000000051, 0.6666666666666666, 0.5000000000000000, 0.5217391304347829, 0.5454545454545453, 0.5999999999999975, 0.5000000000000051, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.6666666666666690, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.4999999999999992, 0.5000000000000000, 0.6666666666666622, 0.5000000000000000, 0.6666666666666690, 0.5000000000000051, 0.5000000000000017, 0.6666666666666666, 0.5000000000000000, 0.6666666666666690, 0.4999999999999949, 0.5000000000000000, 0.5000000000000001, 0.4999999999999998, 0.5217391304347820, 0.5454545454545461, 0.5999999999999975, 0.4999999999999949, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.5217391304347825, 0.5454545454545471, 0.6000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000004, 0.5217391304347825, 0.5454545454545434, 0.6000000000000032, 0.5000000000000000, 0.6666666666666712, 0.4999999999999899, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5217391304347816, 0.5454545454545451, 0.5999999999999951, 0.4999999999999899, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.5000000000000004, 0.5000000000000000, 0.5217391304347825, 0.5454545454545471, 0.6000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666576, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5217391304347825, 0.5454545454545434, 0.6000000000000032, 0.5000000000000000, 0.6666666666666712, 0.4999999999999899, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999983, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.5217391304347816, 0.5454545454545451, 0.5999999999999951, 0.4999999999999899, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101, 0.5000000000000017, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.6666666666666666, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.5217391304347834, 0.5454545454545471, 0.6000000000000000, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.4999999999999966, 0.6666666666666712, 0.5000000000000101, 0.6666666666666666, 0.5000000000000000, 0.5000000000000033, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.6666666666666666, 0.5000000000000000, 0.5000000000000000, 0.6666666666666576, 0.5000000000000000, 0.6666666666666712, 0.5000000000000101 ], + [ 0.0000000000000000, 0.4972677595628415, 0.4945054945054945, 0.4888888888888889, 0.4772727272727272, 0.4761904761904762, 0.4000000000000000, 0.2500000000000000, 0.0000000000000000, 0.3333333333333333, 0.4999999999999998, 0.5000000000000001, 0.3333333333333332, 0.4999999999999997, 0.3333333333333333, 0.5000000000000000, 0.4545454545454545, 0.3999999999999999, 0.5000000000000007, 0.3333333333333336, 0.5000000000000007, 0.5000000000000000, 0.3333333333333336, 0.5000000000000007, 0.3333333333333336, 0.4999999999999994, 0.4782608695652174, 0.4545454545454545, 0.4000000000000004, 0.5000000000000000, 0.3333333333333322, 0.5000000000000000, 0.5000000000000004, 0.3333333333333333, 0.5000000000000000, 0.3333333333333322, 0.5000000000000000, 0.5000000000000000, 0.4999999999999996, 0.3333333333333339, 0.5000000000000012, 0.3333333333333333, 0.5000000000000000, 0.4999999999999996, 0.3333333333333339, 0.4999999999999987, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.4782608695652172, 0.4545454545454547, 0.4000000000000004, 0.4999999999999974, 0.3333333333333322, 0.4999999999999974, 0.5000000000000000, 0.3333333333333322, 0.5000000000000026, 0.3333333333333322, 0.5000000000000026, 0.5000000000000004, 0.5000000000000009, 0.3333333333333345, 0.4999999999999974, 0.3333333333333322, 0.4999999999999974, 0.5000000000000000, 0.3333333333333322, 0.5000000000000026, 0.3333333333333322, 0.5000000000000026, 0.4782608695652177, 0.4545454545454543, 0.4000000000000004, 0.5000000000000026, 0.3333333333333322, 0.5000000000000026, 0.4999999999999992, 0.3333333333333356, 0.5000000000000000, 0.3333333333333345, 0.4999999999999974, 0.5000000000000000, 0.5000000000000000, 0.3333333333333322, 0.4999999999999974, 0.3333333333333322, 0.5000000000000026, 0.5000000000000000, 0.3333333333333322, 0.5000000000000026, 0.3333333333333356, 0.5000000000000000, 0.5000000000000001, 0.5000000000000000, 0.4782608695652171, 0.4545454545454547, 0.4000000000000024, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.5000000000000009, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.4782608695652171, 0.4545454545454547, 0.3999999999999984, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.4999999999999949, 0.3333333333333333, 0.5000000000000000, 0.4999999999999992, 0.5000000000000017, 0.3333333333333311, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999998, 0.4782608695652175, 0.4545454545454547, 0.3999999999999984, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333311, 0.5000000000000051, 0.5000000000000000, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.4999999999999949, 0.3333333333333333, 0.5000000000000000, 0.4782608695652171, 0.4545454545454547, 0.4000000000000024, 0.4999999999999949, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.3333333333333311, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.5000000000000009, 0.5000000000000000, 0.3333333333333378, 0.5000000000000000, 0.3333333333333311, 0.4999999999999949, 0.4999999999999983, 0.3333333333333333, 0.5000000000000000, 0.3333333333333311, 0.5000000000000051, 0.4999999999999999, 0.4999999999999999, 0.5000000000000002, 0.4782608695652179, 0.4545454545454539, 0.4000000000000024, 0.5000000000000051, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.4782608695652175, 0.4545454545454529, 0.4000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999996, 0.4782608695652175, 0.4545454545454565, 0.3999999999999967, 0.5000000000000000, 0.3333333333333288, 0.5000000000000101, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4782608695652184, 0.4545454545454549, 0.4000000000000049, 0.5000000000000101, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.4999999999999996, 0.5000000000000000, 0.4782608695652175, 0.4545454545454529, 0.4000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333424, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4782608695652175, 0.4545454545454565, 0.3999999999999967, 0.5000000000000000, 0.3333333333333288, 0.5000000000000101, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000017, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.4782608695652184, 0.4545454545454549, 0.4000000000000049, 0.5000000000000101, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899, 0.4999999999999983, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.3333333333333333, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.4782608695652166, 0.4545454545454529, 0.4000000000000000, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000033, 0.3333333333333288, 0.4999999999999899, 0.3333333333333333, 0.5000000000000000, 0.4999999999999966, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.3333333333333333, 0.5000000000000000, 0.5000000000000000, 0.3333333333333424, 0.5000000000000000, 0.3333333333333288, 0.4999999999999899 ] + ] +} diff --git a/benchmarks/GenericPricing/datasets/large/output.data b/benchmarks/GenericPricing/datasets/large/output.data deleted file mode 100644 index 3ee5621..0000000 --- a/benchmarks/GenericPricing/datasets/large/output.data +++ /dev/null @@ -1 +0,0 @@ -[ 1046.2474858484 ] // Price for the large contract diff --git a/benchmarks/GenericPricing/datasets/large/output.json b/benchmarks/GenericPricing/datasets/large/output.json new file mode 100644 index 0000000..5be6d0f --- /dev/null +++ b/benchmarks/GenericPricing/datasets/large/output.json @@ -0,0 +1 @@ +[ 1046.2474858484 ] diff --git a/benchmarks/GenericPricing/datasets/medium/input.data b/benchmarks/GenericPricing/datasets/medium/input.data deleted file mode 100644 index a21a39b..0000000 --- a/benchmarks/GenericPricing/datasets/medium/input.data +++ /dev/null @@ -1,108 +0,0 @@ -2 // contract number -1048576 // number of Monte-Carlo Iterations -5 // number of path dates -3 // number of underlyings -1 // number of models -30 // integer bit-length representation for Sobol - -// Begin Direction vectors [3*5][30] -[ - [ - 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 - ], - [ - 536870912, 805306368, 671088640, 1006632960, 570425344, 855638016, 713031680, 1069547520, 538968064, 808452096, 673710080, 1010565120, 572653568, 858980352, 715816960, 1073725440, 536879104, 805318656, 671098880, 1006648320, 570434048, 855651072, 713042560, 1069563840, 538976288, 808464432, 673720360, 1010580540, 572662306, 858993459 - ], - [ - 536870912, 805306368, 402653184, 603979776, 973078528, 385875968, 595591168, 826277888, 438304768, 657457152, 999817216, 358875136, 538574848, 807862272, 406552576, 605372416, 975183872, 389033984, 597170176, 828646400, 437926400, 656873216, 1002152832, 357921088, 536885792, 805312304, 402662296, 603992420, 973085210, 385885991 - ], - [ - 536870912, 805306368, 939524096, 335544320, 234881024, 721420288, 411041792, 616562688, 920649728, 1062207488, 381157376, 258736128, 771883008, 453181440, 545488896, 817971200, 954261504, 340963328, 238651392, 732843008, 417426944, 609285376, 909831040, 1068349120, 383778848, 256901168, 783810616, 460062740, 537001998, 805503019 - ], - [ - 536870912, 805306368, 402653184, 1006632960, 167772160, 285212672, 713031680, 566231040, 853540864, 489684992, 952631296, 208928768, 316801024, 758317056, 550076416, 813154304, 417505280, 1009913856, 172697600, 297131008, 704744960, 553894656, 847291520, 499194688, 954376224, 204607536, 306915352, 766893116, 536972810, 805552913 - ], - [ - 536870912, 805306368, 402653184, 469762048, 301989888, 721420288, 92274688, 264241152, 941621248, 741343232, 169345024, 924581888, 395444224, 619380736, 1034256384, 603963392, 838868992, 452997120, 494934016, 331357184, 706744832, 120597248, 261621120, 953946048, 800208928, 148581424, 935168536, 350484252, 630339474, 1072370923 - ], - [ - 536870912, 805306368, 134217728, 1006632960, 503316480, 754974720, 629145600, 440401920, 94371840, 711983104, 229113856, 374079488, 330694656, 996212736, 907247616, 557531136, 867573760, 190918656, 1041467392, 490437632, 766918144, 643898624, 462663040, 125527616, 672545696, 202454896, 373006376, 288845836, 1000351766, 930090001 - ], - [ - 536870912, 268435456, 402653184, 872415232, 838860800, 956301312, 612368384, 717225984, 211812352, 386924544, 302514176, 688128000, 1015414784, 516751360, 1051492352, 773734400, 914432000, 63877120, 807741440, 165200896, 748683776, 118489344, 168296832, 486802240, 243663648, 667747216, 439124552, 81674924, 975249610, 350138737 - ], - [ - 536870912, 268435456, 671088640, 469762048, 973078528, 1023410176, 713031680, 339738624, 912261120, 797966336, 176685056, 71565312, 510263296, 865533952, 814120960, 961232896, 887136256, 668078080, 116070400, 382772224, 1047134720, 597098752, 411468416, 625689024, 249602976, 449975248, 745216680, 43033924, 134873446, 201786361 - ], - [ - 536870912, 268435456, 402653184, 67108864, 704643072, 385875968, 696254464, 205520896, 920649728, 946864128, 359137280, 859045888, 302907392, 50659328, 462192640, 524599296, 895541248, 590794752, 168810496, 118033408, 831447552, 138662144, 485185920, 796511296, 1021313184, 1064304752, 619184920, 997458052, 250479054, 745865975 - ], - [ - 536870912, 268435456, 939524096, 1006632960, 838860800, 889192448, 645922816, 46137344, 476053504, 584056832, 210239488, 465829888, 820903936, 689897472, 73695232, 249118720, 110075904, 315338752, 610637824, 517665792, 1049494016, 785318144, 376210304, 735921088, 402760480, 738505552, 168368744, 151499820, 344957894, 936096557 - ], - [ - 536870912, 805306368, 939524096, 1006632960, 503316480, 922746880, 41943040, 423624704, 228589568, 651165696, 195559424, 500957184, 791019520, 261292032, 1040285696, 118407168, 982065152, 625250304, 329533440, 298984448, 153690624, 76845824, 579619712, 692987840, 900670432, 450334832, 363187112, 719119956, 765461306, 382730781 - ], - [ - 536870912, 805306368, 402653184, 603979776, 838860800, 117440512, 478150656, 658505728, 752877568, 1060110336, 141033472, 209453056, 244187136, 272957440, 678068224, 1014546432, 377724928, 876875776, 443160576, 998185984, 168665600, 318837504, 914397568, 71818816, 40763680, 527762288, 939688008, 335855668, 705536494, 587273091 - ], - [ - 536870912, 268435456, 671088640, 738197504, 637534208, 150994944, 813694976, 943718400, 77594624, 179306496, 798490624, 967049216, 134348800, 1006698496, 235044864, 620937216, 377643008, 826314752, 874711040, 854819840, 725109248, 856992512, 664336768, 94804544, 100663328, 419430416, 411041832, 339738668, 580911142, 61865993 - ], - [ - 536870912, 805306368, 939524096, 603979776, 100663296, 452984832, 998244352, 188743680, 866123776, 389021696, 287834112, 172228608, 824836096, 977731584, 153714688, 507854848, 254402560, 88403968, 883578880, 235160576, 118055424, 422917888, 371224704, 326210368, 654926368, 691353392, 773877944, 930190180, 554263078, 842348331 - ] -] // End Direction Vectors - - - - -// The Market / Model Data -// md_c md_vols md_drifts md_starts md_detval md_disc - -[[ // md_c[1][3][3] (begin) - [ 1.0000000 , 0.6000000 , 0.8000000 ], - [ 0.6000000 , 0.8000000 , 0.1500000 ], - [ 0.8000000 , 0.1500000 , 0.5809475 ] -]] // md_c (end) - -[[ // md_vols[1][5][3] volatility (begin) - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ], - [ 0.1900000 , 0.1900000 , 0.1500000 ] -]] // md_vols volatility (end) - -[[ // md_drifts[1][5][3] (begin) - [ -0.0283491736871803 , 0.0178771081725381 , 0.0043096808044729 ], - [ -0.0183841413744211 , -0.0044530897672834 , 0.0024263805987983 ], - [ -0.0172686581005089 , 0.0125638544546015 , 0.0094452810918001 ], - [ -0.0144179417871814 , 0.0157411263968213 , 0.0125315353728014 ], - [ -0.0121497422218761 , 0.0182904634062437 , 0.0151125070556484 ] -]] // md_drifts (end) - -// md_starts[1][3] -[[ 3758.0500000000001819, 11840.0000000000000000, 1200.0000000000000000 ]] - -// model deterministic values [0] -[[ ]] - -// model discounts [5] -[[ 0.9797862861805930 , 0.9505748482484491 , 0.9214621679912968 , 0.8906693055891434 , 0.8588567633110704 ]] - -// Brownian Bridge (BB) Metadata - -//BB indirect accessing: -[ [ 5, 2, 1, 3, 4 ], //bb_bi[5] - [ 0, 0, 0, 2, 3 ], //bb_li[5] - [ 0, 5, 2, 5, 5 ] //bb_ri[5] -] - -//BB (real) data: -[ [ 2.2372928847280580, 1.0960951589853829, 0.7075902730592357, 0.8166828043492210, 0.7075902730592357 ], //bb_sd[5] (standard deviation) - [ 0.0000000000000000, 0.5998905309250137, 0.4993160054719562, 0.6669708029197080, 0.5006839945280438 ], //bb_lw[5] - [ 0.0000000000000000, 0.4001094690749863, 0.5006839945280438, 0.3330291970802919, 0.4993160054719562 ] //bb_rw[5] -] - -// [(EXsimple_price(EUR, 937.3914952240884, "MC BS (C) 3dim, Sobol, 1048576 paths, 1800 ms"))] diff --git a/benchmarks/GenericPricing/datasets/medium/input.json b/benchmarks/GenericPricing/datasets/medium/input.json new file mode 100644 index 0000000..17206ae --- /dev/null +++ b/benchmarks/GenericPricing/datasets/medium/input.json @@ -0,0 +1,106 @@ +{ + "contract_number" : 2, + "monte_carlo_iterations" : 1048576, + "num_path_dates" : 5, + "num_underlyings" : 3, + "num_models" : 1, + "num_bits" : 30, + "dir_vs" : + [ + [ + 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 + ], + [ + 536870912, 805306368, 671088640, 1006632960, 570425344, 855638016, 713031680, 1069547520, 538968064, 808452096, 673710080, 1010565120, 572653568, 858980352, 715816960, 1073725440, 536879104, 805318656, 671098880, 1006648320, 570434048, 855651072, 713042560, 1069563840, 538976288, 808464432, 673720360, 1010580540, 572662306, 858993459 + ], + [ + 536870912, 805306368, 402653184, 603979776, 973078528, 385875968, 595591168, 826277888, 438304768, 657457152, 999817216, 358875136, 538574848, 807862272, 406552576, 605372416, 975183872, 389033984, 597170176, 828646400, 437926400, 656873216, 1002152832, 357921088, 536885792, 805312304, 402662296, 603992420, 973085210, 385885991 + ], + [ + 536870912, 805306368, 939524096, 335544320, 234881024, 721420288, 411041792, 616562688, 920649728, 1062207488, 381157376, 258736128, 771883008, 453181440, 545488896, 817971200, 954261504, 340963328, 238651392, 732843008, 417426944, 609285376, 909831040, 1068349120, 383778848, 256901168, 783810616, 460062740, 537001998, 805503019 + ], + [ + 536870912, 805306368, 402653184, 1006632960, 167772160, 285212672, 713031680, 566231040, 853540864, 489684992, 952631296, 208928768, 316801024, 758317056, 550076416, 813154304, 417505280, 1009913856, 172697600, 297131008, 704744960, 553894656, 847291520, 499194688, 954376224, 204607536, 306915352, 766893116, 536972810, 805552913 + ], + [ + 536870912, 805306368, 402653184, 469762048, 301989888, 721420288, 92274688, 264241152, 941621248, 741343232, 169345024, 924581888, 395444224, 619380736, 1034256384, 603963392, 838868992, 452997120, 494934016, 331357184, 706744832, 120597248, 261621120, 953946048, 800208928, 148581424, 935168536, 350484252, 630339474, 1072370923 + ], + [ + 536870912, 805306368, 134217728, 1006632960, 503316480, 754974720, 629145600, 440401920, 94371840, 711983104, 229113856, 374079488, 330694656, 996212736, 907247616, 557531136, 867573760, 190918656, 1041467392, 490437632, 766918144, 643898624, 462663040, 125527616, 672545696, 202454896, 373006376, 288845836, 1000351766, 930090001 + ], + [ + 536870912, 268435456, 402653184, 872415232, 838860800, 956301312, 612368384, 717225984, 211812352, 386924544, 302514176, 688128000, 1015414784, 516751360, 1051492352, 773734400, 914432000, 63877120, 807741440, 165200896, 748683776, 118489344, 168296832, 486802240, 243663648, 667747216, 439124552, 81674924, 975249610, 350138737 + ], + [ + 536870912, 268435456, 671088640, 469762048, 973078528, 1023410176, 713031680, 339738624, 912261120, 797966336, 176685056, 71565312, 510263296, 865533952, 814120960, 961232896, 887136256, 668078080, 116070400, 382772224, 1047134720, 597098752, 411468416, 625689024, 249602976, 449975248, 745216680, 43033924, 134873446, 201786361 + ], + [ + 536870912, 268435456, 402653184, 67108864, 704643072, 385875968, 696254464, 205520896, 920649728, 946864128, 359137280, 859045888, 302907392, 50659328, 462192640, 524599296, 895541248, 590794752, 168810496, 118033408, 831447552, 138662144, 485185920, 796511296, 1021313184, 1064304752, 619184920, 997458052, 250479054, 745865975 + ], + [ + 536870912, 268435456, 939524096, 1006632960, 838860800, 889192448, 645922816, 46137344, 476053504, 584056832, 210239488, 465829888, 820903936, 689897472, 73695232, 249118720, 110075904, 315338752, 610637824, 517665792, 1049494016, 785318144, 376210304, 735921088, 402760480, 738505552, 168368744, 151499820, 344957894, 936096557 + ], + [ + 536870912, 805306368, 939524096, 1006632960, 503316480, 922746880, 41943040, 423624704, 228589568, 651165696, 195559424, 500957184, 791019520, 261292032, 1040285696, 118407168, 982065152, 625250304, 329533440, 298984448, 153690624, 76845824, 579619712, 692987840, 900670432, 450334832, 363187112, 719119956, 765461306, 382730781 + ], + [ + 536870912, 805306368, 402653184, 603979776, 838860800, 117440512, 478150656, 658505728, 752877568, 1060110336, 141033472, 209453056, 244187136, 272957440, 678068224, 1014546432, 377724928, 876875776, 443160576, 998185984, 168665600, 318837504, 914397568, 71818816, 40763680, 527762288, 939688008, 335855668, 705536494, 587273091 + ], + [ + 536870912, 268435456, 671088640, 738197504, 637534208, 150994944, 813694976, 943718400, 77594624, 179306496, 798490624, 967049216, 134348800, 1006698496, 235044864, 620937216, 377643008, 826314752, 874711040, 854819840, 725109248, 856992512, 664336768, 94804544, 100663328, 419430416, 411041832, 339738668, 580911142, 61865993 + ], + [ + 536870912, 805306368, 939524096, 603979776, 100663296, 452984832, 998244352, 188743680, 866123776, 389021696, 287834112, 172228608, 824836096, 977731584, 153714688, 507854848, 254402560, 88403968, 883578880, 235160576, 118055424, 422917888, 371224704, 326210368, 654926368, 691353392, 773877944, 930190180, 554263078, 842348331 + ] + ], + + "md_c" : [ + [[ 1.0000000 , 0.6000000 , 0.8000000 ], + [ 0.6000000 , 0.8000000 , 0.1500000 ], + [ 0.8000000 , 0.1500000 , 0.5809475 ] + ] + ], + + "md_vols" : [ + [[ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ], + [ 0.1900000 , 0.1900000 , 0.1500000 ] + ] + ], + + "md_drifts" : [ + [[ -0.0283491736871803 , 0.0178771081725381 , 0.0043096808044729 ], + [ -0.0183841413744211 , -0.0044530897672834 , 0.0024263805987983 ], + [ -0.0172686581005089 , 0.0125638544546015 , 0.0094452810918001 ], + [ -0.0144179417871814 , 0.0157411263968213 , 0.0125315353728014 ], + [ -0.0121497422218761 , 0.0182904634062437 , 0.0151125070556484 ] + ] + ], + + "md_starts" : [ + [ 3758.0500000000001819, 11840.0000000000000000, 1200.0000000000000000 ] + ], + + "md_deterministic_values" : [ + [ ] + ], + + "md_discounts" : [ + [ 0.9797862861805930, + 0.9505748482484491, + 0.9214621679912968, + 0.8906693055891434, + 0.8588567633110704] + ], + + "bb_inds" : [[ 5, 2, 1, 3, 4 ], + [ 0, 0, 0, 2, 3 ], + [ 0, 5, 2, 5, 5 ] + ], + + "bb_data" : [[ 2.2372928847280580, 1.0960951589853829, 0.7075902730592357, 0.8166828043492210, 0.7075902730592357 ], + [ 0.0000000000000000, 0.5998905309250137, 0.4993160054719562, 0.6669708029197080, 0.5006839945280438 ], + [ 0.0000000000000000, 0.4001094690749863, 0.5006839945280438, 0.3330291970802919, 0.4993160054719562 ]] +} diff --git a/benchmarks/GenericPricing/datasets/medium/output.data b/benchmarks/GenericPricing/datasets/medium/output.data deleted file mode 100644 index 6111972..0000000 --- a/benchmarks/GenericPricing/datasets/medium/output.data +++ /dev/null @@ -1 +0,0 @@ -[ 937.3915829436 ] // Price for medium contract diff --git a/benchmarks/GenericPricing/datasets/medium/output.json b/benchmarks/GenericPricing/datasets/medium/output.json new file mode 100644 index 0000000..b82a9e1 --- /dev/null +++ b/benchmarks/GenericPricing/datasets/medium/output.json @@ -0,0 +1 @@ +[ 937.3915829436 ] diff --git a/benchmarks/GenericPricing/datasets/small/input.data b/benchmarks/GenericPricing/datasets/small/input.data deleted file mode 100644 index 1f27037..0000000 --- a/benchmarks/GenericPricing/datasets/small/input.data +++ /dev/null @@ -1,56 +0,0 @@ -1 // contract number -8388608 // number of Monte-Carlo Iterations -1 // number of path dates -1 // number of underlyings -1 // number of models -30 // integer bit-length representation for Sobol - -// Begin Direction vectors [1*1][30] -[ - [ - 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 - ] -] // End Direction Vectors - - - - -// The Market / Model Data -// md_c md_vols md_drifts md_starts md_detval md_disc - -[ [ // md_c[1][1] (begin) - [ 1.0000000 ] -] ] // md_c (end) - -[ [ // md_vols[1][1] volatility (begin) - [ 0.1900000 ] -] ] // md_vols volatility (end) - -[ [ // md_drifts[1][1] (begin) - [ -0.0276481070940405 ] -] ] // md_drifts (end) - -// md_starts[1] -[ [ 3758.0500000000001819 ] ] - -// model deterministic values [1] -[ [ 0.9997817434496459 ] ] - -// model discounts [1] -[ [ 0.9805494836196852 ] ] - -// Brownian Bridge (BB) Metadata - -//BB indirect accessing: -[ [ 1 ], //bb_bi[1] - [ 0 ], //bb_li[1] - [ 0 ] //bb_ri[1] -] - -//BB (real) data: -[ [ 0.9889803798765787 ], //bb_sd[1] (standard deviation) - [ 0.0000000000000000 ], //bb_lw[1] - [ 0.0000000000000000 ] //bb_rw[1] -] - -// [(EXsimple_price(EUR, 98.05493927001953, "MC BS (C) 1dim, Sobol, 8388608 paths, 1060 ms"))] diff --git a/benchmarks/GenericPricing/datasets/small/input.json b/benchmarks/GenericPricing/datasets/small/input.json new file mode 100644 index 0000000..5579e24 --- /dev/null +++ b/benchmarks/GenericPricing/datasets/small/input.json @@ -0,0 +1,39 @@ +{ + "contract_number": 1, + "monte_carlo_iterations" : 8388608, + "num_path_dates": 1, + "num_underlyings" : 1, + "num_models" : 1, + "num_bits" : 30, + "dir_vs" : + [ + [ + 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 + ] + ], + "md_c" : [ + [[1.0000000]] + ], + "md_vols" : [ + [[0.1900000]] + ], + "md_drifts" : [ + [[ -0.0276481070940405]] + ], + "md_starts" : [ + [3758.0500000000001819] + ], + "md_deterministic_values" : [ + [0.9997817434496459] + ], + "md_discounts" : [ + [0.9805494836196852] + ], + + "bb_inds" : [[1], + [0], + [0]], + "bb_data" : [[0.9889803798765787], + [0.0000000000000000], + [0.0000000000000000]] +} diff --git a/benchmarks/GenericPricing/datasets/small/output.data b/benchmarks/GenericPricing/datasets/small/output.data deleted file mode 100644 index 128994a..0000000 --- a/benchmarks/GenericPricing/datasets/small/output.data +++ /dev/null @@ -1 +0,0 @@ -[ 167.05571416613 ] // Price for the small contract diff --git a/benchmarks/GenericPricing/datasets/small/output.json b/benchmarks/GenericPricing/datasets/small/output.json new file mode 100644 index 0000000..b96dce3 --- /dev/null +++ b/benchmarks/GenericPricing/datasets/small/output.json @@ -0,0 +1 @@ +[ 167.05571416613 ] diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp b/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp index db0ee96..d6a6afe 100644 --- a/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp +++ b/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp @@ -3,9 +3,6 @@ //#include "Contracts.h" //#include -#include -#include - /*****************************************************/ /*****************************************************/ /*****************************************************/ @@ -17,7 +14,7 @@ run_GPUkernel ( ModelArrays & md_arrs, BrowBridgeArrays& bb_arrs, int & num_cores, - size_t & elapsed + size_t & elapsed_usec ) { @@ -122,7 +119,7 @@ run_GPUkernel ( gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; { // free allocated space shrLog(stderr, "Release CPU buffers and OpenCL objects...\n"); @@ -163,7 +160,7 @@ int main() { double* prices; unsigned long int elapsed_usec; { // run kernel - prices = run_GPUkernel( scals, sob_arrs, md_arrs, bb_arrs, num_cores, elapsed ); + prices = run_GPUkernel( scals, sob_arrs, md_arrs, bb_arrs, num_cores, elapsed_usec ); sob_arrs.cleanup(); md_arrs.cleanup(); @@ -171,13 +168,14 @@ int main() { } { - std::ofstream runtime("runtime.txt"); - runtime << elapsed_usec / 1000; - std::ofstream result("result.data"); - result << *prices; - - free(prices); + FILE* runtime = fopen("runtime.txt", "w"); + FILE* result = fopen("result.json", "w"); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + write_1Darr(result, prices, scals.num_models); + fclose(result); } + return 0; } diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate b/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate index f1ba6ec..8c71c6b 100755 --- a/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate +++ b/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate @@ -3,14 +3,24 @@ set -e cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/platform.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_LIB_DIR/include/SDK_stub.h . cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . -cp -r $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run $FINPAR_IMPLEMENTATION/ContractDefs . -cp $FINPAR_INPUT input.data +cp -r $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/ContractDefs . + +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run < signed (many1 digit) readDouble :: Parser Double readDouble = lexeme $ read <$> signed (s2 <|> s1) where s1 = do bef <- many1 digit - aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) - return $ bef ++ aft + aft <- fromMaybe "" <$> + optional ((:) <$> char '.' <*> many1 digit) + exp <- fromMaybe "" <$> + optional ((:) <$> char 'e' <*> signed (many1 digit)) + return $ bef ++ aft ++ exp s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit readArray :: Parser a -> Parser [a] @@ -474,9 +478,10 @@ main = do s <- getContents Left e -> error $ show e Right m -> do (v,runtime) <- m - writeFile "result.data" $ show v + writeFile "result.json" $ show v writeFile "runtime.txt" $ show runtime where run = do + whitespace contract <- readInt num_mc_it <- readInt num_dates <- readInt @@ -503,7 +508,7 @@ main = do s <- getContents contract num_mc_it num_dates num_under num_models num_bits sob_dirvs md_cs md_vols md_drifts md_starts md_detvals md_discts bb_inds bb_data - end <- v `seq` getCPUTime + end <- v `deepseq` getCPUTime return (v, (end - start) `div` 1000000000) readInt2d = readArray $ readArray readInt diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/instantiate b/benchmarks/GenericPricing/implementations/HaskellLH/instantiate index 267d65b..e17fc9a 100755 --- a/benchmarks/GenericPricing/implementations/HaskellLH/instantiate +++ b/benchmarks/GenericPricing/implementations/HaskellLH/instantiate @@ -7,5 +7,7 @@ input=$FINPAR_INPUT cp $impl_dir/*hs . cp $impl_dir/run . -cp $input input.data + +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data + ghc -Wall -O2 -msse2 -rtsopts GenPricing.hs -o GenPricing diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp b/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp index 54ceb50..6300931 100644 --- a/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp +++ b/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp @@ -168,10 +168,14 @@ int main() { gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; - std::ofstream runtime("runtime.txt"); - runtime << elapsed_usec / 1000; - std::ofstream result("result.data"); - result << *prices; + { + FILE* runtime = fopen("runtime.txt", "w"); + FILE* result = fopen("result.json", "w"); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + write_1Darr(result, prices, scals.num_models); + fclose(result); + } md_arrs .cleanup(); bb_arrs .cleanup(); diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate b/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate index 84ff1e1..b6df103 100755 --- a/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate +++ b/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate @@ -3,13 +3,23 @@ set -e cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/platform.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . -cp $FINPAR_INPUT input.data +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile . + +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run < Date: Sat, 21 Feb 2015 14:51:55 +0100 Subject: [PATCH 013/122] This kind of thing is not necessary anymore. --- platform.mk | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 platform.mk diff --git a/platform.mk b/platform.mk deleted file mode 100644 index c9889b1..0000000 --- a/platform.mk +++ /dev/null @@ -1,28 +0,0 @@ -# platform specification for benchmarks. Edit as appropriate for your -# platform before running - -# 1 = platform has a GPU -HAVE_GPU = 1 -GPU_DEVICE_ID = 0 - -# GPU warp size. Keep consistent if you use the non-log variant -#GPU_WARP = 32 -GPU_LG_WARP = 5 - -# GPU memory sizes in kilobyte -GPU_LOCAL_MEM = 48 -GPU_CONST_MEM = 64 -GPU_REG_MEM = 64 -# device memory in gigabyte -GPU_DEVICE_MEM= 2 -# ``Optimal'' Amount of Local/Fast Memory Per Thread -GPU_LOCAL_MEM_PER_TH=8 -# Number of GPU cores -GPU_NUM_CORES = 192 - -# CPU and memory spec. -NCORES = 4 -# in gigabyte -MEMORY = 4 - -export From 69f1af97b4c01242c18215a93f861c17c28ad280 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sun, 22 Feb 2015 11:32:18 +0100 Subject: [PATCH 014/122] More consistent naming. --- .../CrankNicolson.cl | 0 .../{All_COpenCLMP => cpp_openclmp_all}/Makefile | 0 .../PrepareKernels.h | 0 .../{All_COpenCLMP => cpp_openclmp_all}/Vect_CPU.h | 0 .../{All_COpenCLMP => cpp_openclmp_all}/Vect_GPU.h | 0 .../VolCalibAll.cpp | 0 .../VolCalibInit.h | 0 .../{All_COpenCLMP => cpp_openclmp_all}/instantiate | 0 .../CrankNicolson.cl | 0 .../Makefile | 0 .../PrepareKernels.h | 0 .../Vect_CPU.h | 0 .../Vect_GPU.h | 0 .../VolCalibInit.h | 0 .../VolCalibOuter.cpp | 0 .../instantiate | 0 .../{Orig_COpenMP => cpp_openmp_naive}/Makefile | 0 .../VolCalibOrig.cpp | 0 .../{Orig_COpenMP => cpp_openmp_naive}/instantiate | 0 .../{Original => cpp_sequential}/Makefile | 0 .../{Original => cpp_sequential}/VolCalib | Bin .../{Original => cpp_sequential}/VolCalibOrig.cpp | 0 .../{Original => cpp_sequential}/instantiate | 0 .../{Original => cpp_sequential}/run | 0 .../{HaskellLH => haskell_lh}/VolCalib.hs | 0 .../{HaskellLH => haskell_lh}/instantiate | 0 .../implementations/{HaskellLH => haskell_lh}/run | 0 .../{Orig_COpenMp => c_openmp}/Contracts.h | 0 .../{Orig_COpenMp => c_openmp}/GenPricing.cpp | 0 .../{Orig_COpenMp => c_openmp}/Makefile | 0 .../{Orig_COpenMp => c_openmp}/SobolGaussBB.h | 0 .../{Orig_COpenMp => c_openmp}/instantiate | 0 .../ContractDefs/LargeContract.cl | 0 .../ContractDefs/MediumContract.cl | 0 .../ContractDefs/SmallContract.cl | 0 .../{CppOpenCL => cpp_opencl}/GenPricing.cpp | 0 .../GenericPricingPrivOpt.cl | 0 .../GenericPricingVectOpt.cl | 0 .../GenericPricingVectUncoalesced.cl | 0 .../{CppOpenCL => cpp_opencl}/Makefile | 0 .../{CppOpenCL => cpp_opencl}/StructGPU.h | 0 .../{CppOpenCL => cpp_opencl}/instantiate | 0 .../{HaskellLH => haskell_lh}/GenPricing.hs | 0 .../{HaskellLH => haskell_lh}/Payoff3Cond.hs | 0 .../{HaskellLH => haskell_lh}/instantiate | 0 .../implementations/{HaskellLH => haskell_lh}/run | 0 46 files changed, 0 insertions(+), 0 deletions(-) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/CrankNicolson.cl (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/Makefile (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/PrepareKernels.h (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/Vect_CPU.h (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/Vect_GPU.h (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/VolCalibAll.cpp (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/VolCalibInit.h (100%) rename benchmarks/CalibVolDiff/implementations/{All_COpenCLMP => cpp_openclmp_all}/instantiate (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/CrankNicolson.cl (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/Makefile (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/PrepareKernels.h (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/Vect_CPU.h (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/Vect_GPU.h (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/VolCalibInit.h (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/VolCalibOuter.cpp (100%) rename benchmarks/CalibVolDiff/implementations/{Outer_COpenCLMP => cpp_openclmp_outer}/instantiate (100%) rename benchmarks/CalibVolDiff/implementations/{Orig_COpenMP => cpp_openmp_naive}/Makefile (100%) rename benchmarks/CalibVolDiff/implementations/{Orig_COpenMP => cpp_openmp_naive}/VolCalibOrig.cpp (100%) rename benchmarks/CalibVolDiff/implementations/{Orig_COpenMP => cpp_openmp_naive}/instantiate (100%) rename benchmarks/CalibVolDiff/implementations/{Original => cpp_sequential}/Makefile (100%) rename benchmarks/CalibVolDiff/implementations/{Original => cpp_sequential}/VolCalib (100%) rename benchmarks/CalibVolDiff/implementations/{Original => cpp_sequential}/VolCalibOrig.cpp (100%) rename benchmarks/CalibVolDiff/implementations/{Original => cpp_sequential}/instantiate (100%) rename benchmarks/CalibVolDiff/implementations/{Original => cpp_sequential}/run (100%) rename benchmarks/CalibVolDiff/implementations/{HaskellLH => haskell_lh}/VolCalib.hs (100%) rename benchmarks/CalibVolDiff/implementations/{HaskellLH => haskell_lh}/instantiate (100%) rename benchmarks/CalibVolDiff/implementations/{HaskellLH => haskell_lh}/run (100%) rename benchmarks/GenericPricing/implementations/{Orig_COpenMp => c_openmp}/Contracts.h (100%) rename benchmarks/GenericPricing/implementations/{Orig_COpenMp => c_openmp}/GenPricing.cpp (100%) rename benchmarks/GenericPricing/implementations/{Orig_COpenMp => c_openmp}/Makefile (100%) rename benchmarks/GenericPricing/implementations/{Orig_COpenMp => c_openmp}/SobolGaussBB.h (100%) rename benchmarks/GenericPricing/implementations/{Orig_COpenMp => c_openmp}/instantiate (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/ContractDefs/LargeContract.cl (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/ContractDefs/MediumContract.cl (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/ContractDefs/SmallContract.cl (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/GenPricing.cpp (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/GenericPricingPrivOpt.cl (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/GenericPricingVectOpt.cl (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/GenericPricingVectUncoalesced.cl (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/Makefile (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/StructGPU.h (100%) rename benchmarks/GenericPricing/implementations/{CppOpenCL => cpp_opencl}/instantiate (100%) rename benchmarks/GenericPricing/implementations/{HaskellLH => haskell_lh}/GenPricing.hs (100%) rename benchmarks/GenericPricing/implementations/{HaskellLH => haskell_lh}/Payoff3Cond.hs (100%) rename benchmarks/GenericPricing/implementations/{HaskellLH => haskell_lh}/instantiate (100%) rename benchmarks/GenericPricing/implementations/{HaskellLH => haskell_lh}/run (100%) diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/CrankNicolson.cl rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Makefile rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/PrepareKernels.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/PrepareKernels.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_CPU.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_CPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_CPU.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_CPU.h diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_GPU.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_GPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/Vect_GPU.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_GPU.h diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibAll.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibAll.cpp rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibInit.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibInit.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/VolCalibInit.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibInit.h diff --git a/benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/instantiate similarity index 100% rename from benchmarks/CalibVolDiff/implementations/All_COpenCLMP/instantiate rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/instantiate diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/CrankNicolson.cl rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Makefile rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/PrepareKernels.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/PrepareKernels.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_CPU.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_CPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_CPU.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_CPU.h diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_GPU.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_GPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/Vect_GPU.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_GPU.h diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibInit.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibInit.h rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibOuter.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/VolCalibOuter.cpp rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp diff --git a/benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/instantiate similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Outer_COpenCLMP/instantiate rename to benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/instantiate diff --git a/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Orig_COpenMP/Makefile rename to benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Orig_COpenMP/VolCalibOrig.cpp rename to benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp diff --git a/benchmarks/CalibVolDiff/implementations/Orig_COpenMP/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Orig_COpenMP/instantiate rename to benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate diff --git a/benchmarks/CalibVolDiff/implementations/Original/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Original/Makefile rename to benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/Original/VolCalib b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalib similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Original/VolCalib rename to benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalib diff --git a/benchmarks/CalibVolDiff/implementations/Original/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Original/VolCalibOrig.cpp rename to benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp diff --git a/benchmarks/CalibVolDiff/implementations/Original/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Original/instantiate rename to benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate diff --git a/benchmarks/CalibVolDiff/implementations/Original/run b/benchmarks/CalibVolDiff/implementations/cpp_sequential/run similarity index 100% rename from benchmarks/CalibVolDiff/implementations/Original/run rename to benchmarks/CalibVolDiff/implementations/cpp_sequential/run diff --git a/benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs b/benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs similarity index 100% rename from benchmarks/CalibVolDiff/implementations/HaskellLH/VolCalib.hs rename to benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs diff --git a/benchmarks/CalibVolDiff/implementations/HaskellLH/instantiate b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate similarity index 100% rename from benchmarks/CalibVolDiff/implementations/HaskellLH/instantiate rename to benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate diff --git a/benchmarks/CalibVolDiff/implementations/HaskellLH/run b/benchmarks/CalibVolDiff/implementations/haskell_lh/run similarity index 100% rename from benchmarks/CalibVolDiff/implementations/HaskellLH/run rename to benchmarks/CalibVolDiff/implementations/haskell_lh/run diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/Contracts.h b/benchmarks/GenericPricing/implementations/c_openmp/Contracts.h similarity index 100% rename from benchmarks/GenericPricing/implementations/Orig_COpenMp/Contracts.h rename to benchmarks/GenericPricing/implementations/c_openmp/Contracts.h diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp b/benchmarks/GenericPricing/implementations/c_openmp/GenPricing.cpp similarity index 100% rename from benchmarks/GenericPricing/implementations/Orig_COpenMp/GenPricing.cpp rename to benchmarks/GenericPricing/implementations/c_openmp/GenPricing.cpp diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/Makefile b/benchmarks/GenericPricing/implementations/c_openmp/Makefile similarity index 100% rename from benchmarks/GenericPricing/implementations/Orig_COpenMp/Makefile rename to benchmarks/GenericPricing/implementations/c_openmp/Makefile diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/SobolGaussBB.h b/benchmarks/GenericPricing/implementations/c_openmp/SobolGaussBB.h similarity index 100% rename from benchmarks/GenericPricing/implementations/Orig_COpenMp/SobolGaussBB.h rename to benchmarks/GenericPricing/implementations/c_openmp/SobolGaussBB.h diff --git a/benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate b/benchmarks/GenericPricing/implementations/c_openmp/instantiate similarity index 100% rename from benchmarks/GenericPricing/implementations/Orig_COpenMp/instantiate rename to benchmarks/GenericPricing/implementations/c_openmp/instantiate diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/LargeContract.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/LargeContract.cl rename to benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/MediumContract.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/MediumContract.cl rename to benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/SmallContract.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/ContractDefs/SmallContract.cl rename to benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp b/benchmarks/GenericPricing/implementations/cpp_opencl/GenPricing.cpp similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/GenPricing.cpp rename to benchmarks/GenericPricing/implementations/cpp_opencl/GenPricing.cpp diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingPrivOpt.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingPrivOpt.cl rename to benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectOpt.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectOpt.cl rename to benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectUncoalesced.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/GenericPricingVectUncoalesced.cl rename to benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/Makefile b/benchmarks/GenericPricing/implementations/cpp_opencl/Makefile similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/Makefile rename to benchmarks/GenericPricing/implementations/cpp_opencl/Makefile diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/StructGPU.h b/benchmarks/GenericPricing/implementations/cpp_opencl/StructGPU.h similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/StructGPU.h rename to benchmarks/GenericPricing/implementations/cpp_opencl/StructGPU.h diff --git a/benchmarks/GenericPricing/implementations/CppOpenCL/instantiate b/benchmarks/GenericPricing/implementations/cpp_opencl/instantiate similarity index 100% rename from benchmarks/GenericPricing/implementations/CppOpenCL/instantiate rename to benchmarks/GenericPricing/implementations/cpp_opencl/instantiate diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/GenPricing.hs b/benchmarks/GenericPricing/implementations/haskell_lh/GenPricing.hs similarity index 100% rename from benchmarks/GenericPricing/implementations/HaskellLH/GenPricing.hs rename to benchmarks/GenericPricing/implementations/haskell_lh/GenPricing.hs diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/Payoff3Cond.hs b/benchmarks/GenericPricing/implementations/haskell_lh/Payoff3Cond.hs similarity index 100% rename from benchmarks/GenericPricing/implementations/HaskellLH/Payoff3Cond.hs rename to benchmarks/GenericPricing/implementations/haskell_lh/Payoff3Cond.hs diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/instantiate b/benchmarks/GenericPricing/implementations/haskell_lh/instantiate similarity index 100% rename from benchmarks/GenericPricing/implementations/HaskellLH/instantiate rename to benchmarks/GenericPricing/implementations/haskell_lh/instantiate diff --git a/benchmarks/GenericPricing/implementations/HaskellLH/run b/benchmarks/GenericPricing/implementations/haskell_lh/run similarity index 100% rename from benchmarks/GenericPricing/implementations/HaskellLH/run rename to benchmarks/GenericPricing/implementations/haskell_lh/run From cf2c10d534d9f73036a7dd7f2b877f2c0ed3a9bc Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sun, 22 Feb 2015 12:16:58 +0100 Subject: [PATCH 015/122] Fix OpenCL implementations. --- .../cpp_openclmp_all/CrankNicolson.cl | 2 +- .../cpp_openclmp_all/instantiate | 4 +- .../cpp_openclmp_outer/CrankNicolson.cl | 2 +- .../cpp_openclmp_outer/instantiate | 4 +- .../cpp_openmp_naive/instantiate | 1 - .../cpp_sequential/instantiate | 3 +- .../cpp_opencl/ContractDefs/LargeContract.cl | 2 +- .../cpp_opencl/ContractDefs/MediumContract.cl | 2 +- .../cpp_opencl/ContractDefs/SmallContract.cl | 2 +- .../cpp_opencl/GenericPricingPrivOpt.cl | 2 +- .../cpp_opencl/GenericPricingVectOpt.cl | 2 +- .../implementations/cpp_opencl/instantiate | 3 +- .../{c_openmp => cpp_openmp}/Contracts.h | 0 .../{c_openmp => cpp_openmp}/GenPricing.cpp | 0 .../{c_openmp => cpp_openmp}/Makefile | 0 .../{c_openmp => cpp_openmp}/SobolGaussBB.h | 0 .../{c_openmp => cpp_openmp}/instantiate | 0 lib/include/SDK_stub.h | 78 ++++++++++++++++++- 18 files changed, 92 insertions(+), 15 deletions(-) rename benchmarks/GenericPricing/implementations/{c_openmp => cpp_openmp}/Contracts.h (100%) rename benchmarks/GenericPricing/implementations/{c_openmp => cpp_openmp}/GenPricing.cpp (100%) rename benchmarks/GenericPricing/implementations/{c_openmp => cpp_openmp}/Makefile (100%) rename benchmarks/GenericPricing/implementations/{c_openmp => cpp_openmp}/SobolGaussBB.h (100%) rename benchmarks/GenericPricing/implementations/{c_openmp => cpp_openmp}/instantiate (100%) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl index b3dc3fa..a06a183 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl @@ -1,4 +1,4 @@ -#include "../includeC/Constants.h" +#include "Constants.h" #if (WITH_FLOATS) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/instantiate index c302f3b..397ef61 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/instantiate @@ -3,15 +3,15 @@ set -e cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/platform.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_LIB_DIR/include/SDK_stub.h . +cp $FINPAR_LIB_DIR/include/Utilities.cl . cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/DataStructConst.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParPrefixUtil.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/*cl $FINPAR_IMPLEMENTATION/Makefile . $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data $FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl index edd4b20..15a993a 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl @@ -1,4 +1,4 @@ -#include "../includeC/Constants.h" +#include "Constants.h" #if (WITH_FLOATS) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/instantiate index f48ae72..0ae41f3 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/instantiate @@ -3,15 +3,15 @@ set -e cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/platform.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_LIB_DIR/include/SDK_stub.h . +cp $FINPAR_LIB_DIR/include/Utilities.cl . cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/DataStructConst.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParPrefixUtil.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/*cl $FINPAR_IMPLEMENTATION/Makefile . $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate index 200d861..5b32e00 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate @@ -3,7 +3,6 @@ set -e cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/platform.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate index f20c373..a5a5113 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate @@ -3,12 +3,13 @@ set -e cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/platform.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/run . + $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk make diff --git a/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl index 7a1c51f..7651cb2 100644 --- a/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl +++ b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl @@ -1,4 +1,4 @@ -#include "../includeC/Constants.h" +#include "Constants.h" #ifdef VECT_KERNEL #define underlyings(i,j) \ diff --git a/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl index f694a08..450343b 100644 --- a/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl +++ b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl @@ -1,4 +1,4 @@ -#include "../includeC/Constants.h" +#include "Constants.h" #ifdef VECT_KERNEL #define underlyings(i,j) \ diff --git a/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl index fe85c5d..ec83f9a 100644 --- a/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl +++ b/benchmarks/GenericPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl @@ -1,4 +1,4 @@ -#include "../includeC/Constants.h" +#include "Constants.h" #ifdef VECT_KERNEL #define underlyings(i,j) \ diff --git a/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl index 5facff6..354a8ad 100644 --- a/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl +++ b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl @@ -6,7 +6,7 @@ #define TYPE REAL #define FLAG uchar -#include "../../include/Utilities.cl" +#include "Utilities.cl" /********************************************/ /********** SOBOL NUMER GENERATOR ***********/ diff --git a/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl index fd82232..9049b87 100644 --- a/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl +++ b/benchmarks/GenericPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl @@ -4,7 +4,7 @@ #define TYPE REAL #define FLAG uchar -#include "../../include/Utilities.cl" +#include "Utilities.cl" #define DUMMY 1 diff --git a/benchmarks/GenericPricing/implementations/cpp_opencl/instantiate b/benchmarks/GenericPricing/implementations/cpp_opencl/instantiate index 8c71c6b..914300f 100755 --- a/benchmarks/GenericPricing/implementations/cpp_opencl/instantiate +++ b/benchmarks/GenericPricing/implementations/cpp_opencl/instantiate @@ -6,10 +6,11 @@ cp $FINPAR_LIB_DIR/setup.mk . cp $FINPAR_LIB_DIR/include/ParserC.h . cp $FINPAR_LIB_DIR/include/Util.h . cp $FINPAR_LIB_DIR/include/SDK_stub.h . +cp $FINPAR_LIB_DIR/include/Utilities.cl . cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . -cp -r $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/ContractDefs . +cp -r $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/*cl $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/ContractDefs . $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data $FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk diff --git a/benchmarks/GenericPricing/implementations/c_openmp/Contracts.h b/benchmarks/GenericPricing/implementations/cpp_openmp/Contracts.h similarity index 100% rename from benchmarks/GenericPricing/implementations/c_openmp/Contracts.h rename to benchmarks/GenericPricing/implementations/cpp_openmp/Contracts.h diff --git a/benchmarks/GenericPricing/implementations/c_openmp/GenPricing.cpp b/benchmarks/GenericPricing/implementations/cpp_openmp/GenPricing.cpp similarity index 100% rename from benchmarks/GenericPricing/implementations/c_openmp/GenPricing.cpp rename to benchmarks/GenericPricing/implementations/cpp_openmp/GenPricing.cpp diff --git a/benchmarks/GenericPricing/implementations/c_openmp/Makefile b/benchmarks/GenericPricing/implementations/cpp_openmp/Makefile similarity index 100% rename from benchmarks/GenericPricing/implementations/c_openmp/Makefile rename to benchmarks/GenericPricing/implementations/cpp_openmp/Makefile diff --git a/benchmarks/GenericPricing/implementations/c_openmp/SobolGaussBB.h b/benchmarks/GenericPricing/implementations/cpp_openmp/SobolGaussBB.h similarity index 100% rename from benchmarks/GenericPricing/implementations/c_openmp/SobolGaussBB.h rename to benchmarks/GenericPricing/implementations/cpp_openmp/SobolGaussBB.h diff --git a/benchmarks/GenericPricing/implementations/c_openmp/instantiate b/benchmarks/GenericPricing/implementations/cpp_openmp/instantiate similarity index 100% rename from benchmarks/GenericPricing/implementations/c_openmp/instantiate rename to benchmarks/GenericPricing/implementations/cpp_openmp/instantiate diff --git a/lib/include/SDK_stub.h b/lib/include/SDK_stub.h index c5a1e22..6a928d1 100644 --- a/lib/include/SDK_stub.h +++ b/lib/include/SDK_stub.h @@ -74,6 +74,82 @@ #define oclCheckErrorEX(a, b, c) __oclCheckErrorEX(a, b, c, __FILE__ , __LINE__) #define oclCheckError(a, b) oclCheckErrorEX(a, b, 0) +// Helper function to get OpenCL error string from constant +// ********************************************************************* +const char* oclErrorString(cl_int error) +{ + static const char* errorString[] = { + "CL_SUCCESS", + "CL_DEVICE_NOT_FOUND", + "CL_DEVICE_NOT_AVAILABLE", + "CL_COMPILER_NOT_AVAILABLE", + "CL_MEM_OBJECT_ALLOCATION_FAILURE", + "CL_OUT_OF_RESOURCES", + "CL_OUT_OF_HOST_MEMORY", + "CL_PROFILING_INFO_NOT_AVAILABLE", + "CL_MEM_COPY_OVERLAP", + "CL_IMAGE_FORMAT_MISMATCH", + "CL_IMAGE_FORMAT_NOT_SUPPORTED", + "CL_BUILD_PROGRAM_FAILURE", + "CL_MAP_FAILURE", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "CL_INVALID_VALUE", + "CL_INVALID_DEVICE_TYPE", + "CL_INVALID_PLATFORM", + "CL_INVALID_DEVICE", + "CL_INVALID_CONTEXT", + "CL_INVALID_QUEUE_PROPERTIES", + "CL_INVALID_COMMAND_QUEUE", + "CL_INVALID_HOST_PTR", + "CL_INVALID_MEM_OBJECT", + "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR", + "CL_INVALID_IMAGE_SIZE", + "CL_INVALID_SAMPLER", + "CL_INVALID_BINARY", + "CL_INVALID_BUILD_OPTIONS", + "CL_INVALID_PROGRAM", + "CL_INVALID_PROGRAM_EXECUTABLE", + "CL_INVALID_KERNEL_NAME", + "CL_INVALID_KERNEL_DEFINITION", + "CL_INVALID_KERNEL", + "CL_INVALID_ARG_INDEX", + "CL_INVALID_ARG_VALUE", + "CL_INVALID_ARG_SIZE", + "CL_INVALID_KERNEL_ARGS", + "CL_INVALID_WORK_DIMENSION", + "CL_INVALID_WORK_GROUP_SIZE", + "CL_INVALID_WORK_ITEM_SIZE", + "CL_INVALID_GLOBAL_OFFSET", + "CL_INVALID_EVENT_WAIT_LIST", + "CL_INVALID_EVENT", + "CL_INVALID_OPERATION", + "CL_INVALID_GL_OBJECT", + "CL_INVALID_BUFFER_SIZE", + "CL_INVALID_MIP_LEVEL", + "CL_INVALID_GLOBAL_WORK_SIZE", + }; + const int errorCount = sizeof(errorString) / sizeof(errorString[0]); + const int index = -error; + return (index >= 0 && index < errorCount) ? errorString[index] : "Unspecified Error"; +} + + inline void __oclCheckErrorEX(cl_int iSample, cl_int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) { // An error condition is defined by the sample/test value not equal to the reference @@ -83,7 +159,7 @@ iSample = (iSample == 0) ? -9999 : iSample; // Log the error info - //shrLog(stdlog, "\n !!! Error # %i (%s) at line %i , in file %s !!!\n\n", iSample, oclErrorString(iSample), iLine, cFile); + shrLog(stdlog, "\n !!! Error # %i (%s) at line %i , in file %s !!!\n\n", iSample, oclErrorString(iSample), iLine, cFile); // Cleanup and exit, or just exit if no cleanup function pointer provided. Use iSample (error code in this case) as process exit code. if (pCleanup != NULL) From d6bc7a9b0366a7be97f633b6d11e6bed8374e4d8 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sun, 22 Feb 2015 19:02:10 +0100 Subject: [PATCH 016/122] Properly handle unrunnable instantiations. --- finpar | 1 + 1 file changed, 1 insertion(+) diff --git a/finpar b/finpar index 42e7c40..021c58f 100755 --- a/finpar +++ b/finpar @@ -173,6 +173,7 @@ def run_some_benchmark_implementations(finpar_dir, inst['implementation'], inst['dataset'], "could not run") + continue if proc.returncode != 0: note_result(results, From 4f4bc5634eba7e0e7d6bab427c912abfee1a0533 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sun, 22 Feb 2015 19:02:22 +0100 Subject: [PATCH 017/122] Add Futhark implementation of CalibVolDiff. --- .../implementations/futhark/CalibVolDiff.fut | 172 ++++++++++++++++++ .../implementations/futhark/instantiate | 10 + .../CalibVolDiff/implementations/futhark/run | 5 + 3 files changed, 187 insertions(+) create mode 100644 benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut create mode 100755 benchmarks/CalibVolDiff/implementations/futhark/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/futhark/run diff --git a/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut b/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut new file mode 100644 index 0000000..2c630e7 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut @@ -0,0 +1,172 @@ +fun {int,int,[real],[real],[real],[[real]],[[real]],[[real]],[[real]]} initGrid + (real s0, real alpha, real nu, real t, int numX, int numY, int numT) = + let logAlpha = log(alpha) in + let myTimeline = map(fn real (int i) => t * toReal(i) / (toReal(numT) - 1.0), iota(numT)) in + let {stdX, stdY} = {20.0 * alpha * s0 * sqrt(t), + 10.0 * nu * sqrt(t)} in + let {dx, dy} = {stdX / toReal(numX), stdY / toReal(numY)} in + let {myXindex, myYindex} = {trunc(s0 / dx), numY / 2} in + let myX = map(fn real (int i) => toReal(i) * dx - toReal(myXindex) * dx + s0, iota(numX)) in + let myY = map(fn real (int i) => toReal(i) * dy - toReal(myYindex) * dy + logAlpha, iota(numY)) in + let xXy = replicate(numX,replicate(numY, 0.0)) in + let {myMuX, myVarX, myMuY, myVarY} = {xXy, xXy, xXy, xXy} in + {myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY} + +fun {[[real]],[[real]]} initOperator([real] x) = + let n = size(0, x) in + let dxu = x[1] - x[0] in + let dxl = 0.0 in + let Dxlow = [[0.0, -1.0 / dxu, 1.0 / dxu]] in + let Dxxlow = [[0.0, 0.0, 0.0]] in + let Dxmid = map(fn [real] (int i) => let dxl = x[i] - x[i-1] in + let dxu = x[i+1] - x[i] in + [-dxu/dxl/(dxl+dxu), + (dxu/dxl - dxl/dxu)/(dxl+dxu), + dxl/dxu/(dxl+dxu)], + map (op + (1), iota(n-2))) in + let Dxxmid = map(fn [real] (int i) => let dxl = x[i] - x[i-1] in + let dxu = x[i+1] - x[i] in + [2.0/dxl/(dxl+dxu), + -2.0*(1.0/dxl + 1.0/dxu)/(dxl+dxu), + 2.0/dxu/(dxl+dxu)], + map (op + (1), iota(n-2))) in + let dxl = x[n-1] - x[n-2] in + let dxu = 0.0 in + let Dxhigh = [[-1.0 / dxl, 1.0 / dxl, 0.0 ]] in + let Dxxhigh = [[0.0, 0.0, 0.0 ]] in + let Dx = concat(concat(Dxlow, Dxmid), Dxhigh) in + let Dxx = concat(concat(Dxxlow, Dxxmid), Dxxhigh) in + {Dx, Dxx} + +fun real max(real x, real y) = if y < x then x else y +fun int maxInt(int x, int y) = if y < x then x else y + +fun *[[real]] setPayoff(real strike, [real] myX, [real] myY) = + let n = size(0, myY) in + copy(map(fn [real] (real xi) => replicate(n, max(xi-strike,0.0)), myX)) + +// Returns new myMuX, myVarX, myMuY, myVarY. +fun {[[real]] , [[real]] , [[real]] , [[real]]} updateParams + ([real] myX, [real] myY, [real] myTimeline, int g, real alpha, real beta, real nu) = + unzip (map(fn {[real],[real],[real],[real]} (real xi) => + unzip (map (fn {real,real,real,real} (real yj) => + {0.0, + exp(2.0*(beta*log(xi) + yj - 0.5*nu*nu*myTimeline[g])), + 0.0, + nu * nu}, myY)), myX)) + +fun {[real],[real]} tridag + ([real] a, [real] b, [real] c, [real] r, int n) = + let bet = 1.0/b[0] in + let {u, uu} = {copy(replicate(n,0.0)), + copy(replicate(n,0.0))} in + let u[0] = r[0] * bet in + loop ({u, uu, bet}) = + for j < n-1 do + let j = j + 1 in + let uu[j] = c[j-1]*bet in + let bet = 1.0/(b[j] - a[j] * uu[j]) in + let u[j] = (r[j] - a[j]*u[j-1]) * bet in + {u, uu, bet} in + loop (u) = for j < n - 1 do + let j = n - 2 - j in + let u[j] = u[j] - uu[j+1]*u[j+1] in + u + in {u, uu} + +fun *[[real]] explicitX + (int numX, int numY, real dtInv, + [[real]] myResult, [[real]] myMuX, [[real]] myDx, [[real]] myDxx, [[real]] myVarX) = + copy(map(fn [real] (int j) => + map(fn real (int i) => + let kl = if i == 0 then 1 else 0 in + let ku = 2 - if i==numX-1 then 1 else 0 in + reduce(op +, dtInv*myResult[i,j], + map(fn real (int k) => + let k = k + kl in + 0.5 * (myMuX[i,j]*myDx[i,k]+0.5*myVarX[i,j]*myDxx[i,k]) + * myResult[i+k-1,j], + iota(ku-kl+1))), + iota(numX)), + iota(numY))) + +fun *[[real]] explicitY + (int numX, int numY, real dtInv, + [[real]] myResult, [[real]] myMuY, [[real]] myDy, [[real]] myDyy, [[real]] myVarY) = + copy(map(fn [real] (int i) => + map(fn real (int j) => + let ll = 1 * (if j == 0 then 1 else 0) in + let lu = 2 - 1*(if j==numY-1 then 1 else 0) in + reduce(op +, 0.0, + map(fn real (int l) => + let l = l + ll in + (myMuY[i,j]*myDy[j,l]+0.5*myVarY[i,j]*myDyy[j,l]) + * myResult[i,j+l-1], + iota(lu-ll+1))), + iota(numY)), + iota(numX))) + +fun *[[real]] rollback + ([real] myX, [real] myY, [real] myTimeline, *[[real]] myResult, + [[real]] myMuX, [[real]] myDx, [[real]] myDxx, [[real]] myVarX, + [[real]] myMuY, [[real]] myDy, [[real]] myDyy, [[real]] myVarY, int g) = + let {numX, numY} = {size(0, myX), size(0, myY)} in + let numZ = maxInt(numX, numY) in + let dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]) in + let u = explicitX(numX, numY, dtInv, myResult, myMuX, myDx, myDxx, myVarX) in + let v = explicitY(numX, numY, 0.0, myResult, myMuY, myDy, myDyy, myVarY) in + let u = map(fn [real] ([real] us, [real] vs) => map(op +, zip(us, vs)), + zip(u, transpose(v))) in + let u = map(fn [real] ({[real], int} t) => + let {uj, j} = t in + let {a,b,c} = unzip(map(fn {real,real,real} (int i) => + {-0.5*(myMuX[i,j]*myDx[i,0] + 0.5*myVarX[i,j]*myDxx[i,0]), + dtInv - 0.5*(myMuX[i,j]*myDx[i,1] + 0.5*myVarX[i,j]*myDxx[i,1]), + -0.5*(myMuX[i,j]*myDx[i,2]+0.5*myVarX[i,j]*myDxx[i,2])}, + iota(numX))) in + let {uj, yy} = tridag(a,b,c,uj,numX) in uj, + zip(u, iota(numY))) in + loop (myResult) = + for i < numX do + let {a,b,c} = unzip(map(fn {real,real,real} (int j) => + {-0.5*(myMuY[i,j]*myDy[j,0]+0.5*myVarY[i,j]*myDyy[j,0]), + dtInv - 0.5*(myMuY[i,j]*myDy[j,1]+0.5*myVarY[i,j]*myDyy[j,1]), + -0.5*(myMuY[i,j]*myDy[j,2]+0.5*myVarY[i,j]*myDyy[j,2])}, + iota(numY))) in + let y = copy(replicate(numY, 0.0)) in + loop (y) = for j < numY do + let y[j] = dtInv * u[j,i] - 0.5*v[i,j] in + y in + let {ri, yy} = tridag(a,b,c,y,numY) in + let myResult[i] = ri in myResult + in myResult + +fun real value(int numX, int numY, int numT, real s0, real strike, real t, real alpha, real nu, real beta) = + let {myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY} = + initGrid(s0, alpha, nu, t, numX, numY, numT) in + let {myDx, myDxx} = initOperator(myX) in + let {myDy, myDyy} = initOperator(myY) in + let myResult = setPayoff(strike, myX, myY) in + //loop ((myResult, myMuX, myVarX, myMuY, myVarY)) = + loop (myResult) = + for i < numT - 1 do + let i = numT-2-i in + let {myMuX, myVarX, myMuY, myVarY} = + updateParams(myX, myY, myTimeline, i, alpha, beta, nu) in + let myResult = rollback(myX, myY, myTimeline, myResult, + myMuX, myDx, myDxx, myVarX, + myMuY, myDy, myDyy, myVarY, i) in + //(myResult, myMuX, myVarX, myMuY, myVarY) in + myResult in + myResult[myXindex,myYindex] + +fun [real] main (int outer_loop_count, int numX, int numY, int numT) = + let s0 = 0.03 in + let strike = 0.03 in + let t = 5.0 in + let alpha = 0.2 in + let nu = 0.6 in + let beta = 0.5 in + let strikes = map(fn real (int i) => 0.001*toReal(i), iota(outer_loop_count)) in + let res = map(fn real (real x) => value(numX, numY, numT, s0, x, t, alpha, nu, beta), strikes) in + res diff --git a/benchmarks/CalibVolDiff/implementations/futhark/instantiate b/benchmarks/CalibVolDiff/implementations/futhark/instantiate new file mode 100755 index 0000000..3375ece --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/futhark/instantiate @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data + +cp $FINPAR_IMPLEMENTATION/run . + +futhark -s -fe --in-place-lowering -ae --compile-sequential $FINPAR_IMPLEMENTATION/CalibVolDiff.fut > CalibVolDiff.c +gcc CalibVolDiff.c -O3 -o CalibVolDiff -lm diff --git a/benchmarks/CalibVolDiff/implementations/futhark/run b/benchmarks/CalibVolDiff/implementations/futhark/run new file mode 100755 index 0000000..66c288c --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/futhark/run @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +./CalibVolDiff -t runtime.txt < input.data > result.json From 68ecaef6a2d8819aba287f6c55f4a2be438f7eab Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 23 Feb 2015 08:47:30 +0100 Subject: [PATCH 018/122] Add Futhark implementation of GenericPricing. --- .../futhark/GenericPricing.fut | 331 ++++++++++++++++++ .../implementations/futhark/instantiate | 11 + .../implementations/futhark/run | 5 + 3 files changed, 347 insertions(+) create mode 100644 benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut create mode 100755 benchmarks/GenericPricing/implementations/futhark/instantiate create mode 100755 benchmarks/GenericPricing/implementations/futhark/run diff --git a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut new file mode 100644 index 0000000..0880364 --- /dev/null +++ b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut @@ -0,0 +1,331 @@ +fun int grayCode(int x) = (x >> 1) ^ x + +//////////////////////////////////////// +/// Sobol Generator +//////////////////////////////////////// +fun int index([int] arr, int i) = arr[i] + +fun bool testBit(int n, int ind) = + let t = (1 << ind) in (n & t) == t + +///////////////////////////////////////////////////////////////// +//// DIFFICULT VERSION: filter is hoisted outside map: +//// less computation but variable array size! +///////////////////////////////////////////////////////////////// +//fun int xorInds([int] indices, [int] dir_vs ) = +// reduce( op ^, 0, map( index(dir_vs), indices ) ) +// +//fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = +// let bits = iota ( bits_num ) in +// let indices = filter ( testBit(grayCode(n)), bits ) +// in map( xorInds(indices), dir_vs ) + + +///////////////////////////////////////////////////////////////// +//// EASY VERSION: filter is redundantly computed inside map: +//// more computation but a redofilt pattern, i.e., array +//// not instantiated! +///////////////////////////////////////////////////////////////// +fun int xorInds(int bits_num, int n, [int] dir_vs ) = + let bits = iota ( bits_num ) in + let indices = filter ( testBit(grayCode(n)), bits ) in + reduce( op ^, 0, map( index(dir_vs), indices ) ) + +fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = + map( xorInds(bits_num, n), dir_vs ) +//////////////////////////////////////////////////////////////// + +fun [real] sobolIndR( int bits_num, [[int]] dir_vs, int n ) = + let divisor = 2.0 pow toReal (bits_num) in + let arri = sobolIndI( bits_num, dir_vs, n ) in + map( fn real (int x) => toReal(x) / divisor, arri ) + +//////////////////////////////////////// +/// Inverse Gaussian +//////////////////////////////////////// + +//tmp_rat_evalL :: SpecReal -> [SpecReal] -> SpecReal +fun real polyAppr( real x, + real a0, real a1, real a2, real a3, + real a4, real a5, real a6, real a7, + real b0, real b1, real b2, real b3, + real b4, real b5, real b6, real b7 + ) = + (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0) / + (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) + +fun real smallcase(real q) = + q * polyAppr( 0.180625 - q * q, + + 3.387132872796366608, + 133.14166789178437745, + 1971.5909503065514427, + 13731.693765509461125, + 45921.953931549871457, + 67265.770927008700853, + 33430.575583588128105, + 2509.0809287301226727, + + 1.0, + 42.313330701600911252, + 687.1870074920579083, + 5394.1960214247511077, + 21213.794301586595867, + 39307.89580009271061, + 28729.085735721942674, + 5226.495278852854561 + ) + +fun real intermediate(real r) = + polyAppr( r - 1.6, + + 1.42343711074968357734, + 4.6303378461565452959, + 5.7694972214606914055, + 3.64784832476320460504, + 1.27045825245236838258, + 0.24178072517745061177, + 0.0227238449892691845833, + 7.7454501427834140764e-4, + + 1.0, + 2.05319162663775882187, + 1.6763848301838038494, + 0.68976733498510000455, + 0.14810397642748007459, + 0.0151986665636164571966, + 5.475938084995344946e-4, + 1.05075007164441684324e-9 + ) + +fun real tail(real r) = + polyAppr( r - 5.0, + + 6.6579046435011037772, + 5.4637849111641143699, + 1.7848265399172913358, + 0.29656057182850489123, + 0.026532189526576123093, + 0.0012426609473880784386, + 2.71155556874348757815e-5, + 2.01033439929228813265e-7, + + 1.0, + 0.59983220655588793769, + 0.13692988092273580531, + 0.0148753612908506148525, + 7.868691311456132591e-4, + 1.8463183175100546818e-5, + 1.4215117583164458887e-7, + 2.04426310338993978564e-5 + ) + +fun real ugaussianEl( real p ) = + let dp = p - 0.5 + in //if ( fabs(dp) <= 0.425 ) + if ( ( (dp < 0.0) && (0.0 - dp <= 0.425) ) || ( (0.0 <= dp) && (dp <= 0.425) ) ) + then smallcase(dp) + else let pp = if(dp < 0.0) then dp + 0.5 else 0.5 - dp in + let r = sqrt( - log(pp) ) in + let x = if(r <= 5.0) then intermediate(r) else tail(r) in + if(dp < 0.0) then 0.0 - x else x + +// Transforms a uniform distribution [0,1) into a gaussian distribution (-inf, +inf) +fun [real] ugaussian([real] ps) = map(ugaussianEl, ps) + + +///////////////////////////////// +/// Brownian Bridge +///////////////////////////////// + +fun [real] brownianBridgeDates ( + int num_dates, + [[int ]] bb_inds, // [3, num_dates] + [[real]] bb_data, // [3, num_dates] + [real] gauss // [num_dates] + ) = + let bi = bb_inds[0] in + let li = bb_inds[1] in + let ri = bb_inds[2] in + let sd = bb_data[0] in + let lw = bb_data[1] in + let rw = bb_data[2] in + +// let gauss[ bi[0]-1 ] = sd[0] * gauss[0] in + let bbrow = copy(replicate(num_dates, 0.0)) in + let bbrow[ bi[0]-1 ] = sd[0] * gauss[0] in + + loop (bbrow) = + for i < num_dates-1 do // use i+1 since i in 1 .. num_dates-1 + let j = li[i+1] - 1 in + let k = ri[i+1] - 1 in + let l = bi[i+1] - 1 in + + let wk = bbrow [k ] in + let zi = gauss [i+1] in + let tmp= rw[i+1] * wk + sd[i+1] * zi in + + let bbrow[ l ] = if( (j + 1) == 0) // if(j=-1) + then tmp + else tmp + lw[i+1] * bbrow[j] + in bbrow + + // This can be written as map-reduce, but it + // needs delayed arrays to be mapped nicely! + in loop (bbrow) = + for ii < num_dates-1 do + let i = num_dates - (ii+1) in + let bbrow[i] = bbrow[i] - bbrow[i-1] + in bbrow + in bbrow + +// [num_dates,num_paths] +fun [[real]] brownianBridge ( + int num_paths, + int num_dates, + [[int ]] bb_inds, // [3, num_dates] + [[real]] bb_data, // [3, num_dates] + [real] gaussian_arr // [num_paths * num_dates] + ) = + let gauss2d = reshape((num_dates,num_paths), gaussian_arr) in + let gauss2dT = transpose(gauss2d) in + transpose( map( brownianBridgeDates(num_dates, bb_inds, bb_data), gauss2dT ) ) + + +///////////////////////////////// +/// Black-Scholes +///////////////////////////////// + +fun real zwop(real a, real b, int j) = a * b + +fun [real] take(int n, [real] a) = let {first, rest} = split(n, a) in first + +fun [real] fftmp(int num_paths, [[real]] md_c, [real] zi) = + map( fn real (int j) => + let x = map(zwop, zip(take(j+1,zi), take(j+1,md_c[j]), iota(j+1))) + in reduce(op +, 0.0, x), + iota(num_paths) + ) + +fun [[real]] correlateDeltas(int num_paths, [[real]] md_c, [[real]] zds) = + map( fftmp(num_paths, md_c), zds ) + +fun [real] combineVs([real] n_row, [real] vol_row, [real] dr_row) = + map( op +, zip(dr_row, map( op *, zip(n_row, vol_row ) ))) + +fun [[real]] mkPrices ([real] md_starts, [[real]] md_vols, [[real]] md_drifts, [[real]] noises) = + let e_rows = map( fn [real] ([real] x) => map(exp, x), + map(combineVs, zip(noises, md_vols, md_drifts)) + ) + in scan( fn [real] ([real] x, [real] y) => map(op *, zip(x, y)), md_starts, e_rows ) + +//[num_dates, num_paths] +fun [[real]] blackScholes( + int num_paths, + [[real]] md_c, //[num_paths, num_paths] + [[real]] md_vols, //[num_paths, num_dates] + [[real]] md_drifts, //[num_paths, num_dates] + [real] md_starts, //[num_paths] + [[real]] bb_arr //[num_dates,num_paths] + ) = + let noises = correlateDeltas(num_paths, md_c, bb_arr) + in mkPrices(md_starts, md_vols, md_drifts, noises) + +//////////////////////////////////////// +// MAIN +//////////////////////////////////////// + +fun [real] main(int contract_number, + int num_mc_it, + int num_dates, + int num_und, + int num_models, // Unused? + int num_bits, + [[int]] dir_vs, + [[[real]]] all_md_c, + [[[real]]] all_md_vols, + [[[real]]] all_md_drifts, + [[real]] all_md_st, + [[real]] all_md_detvals, + [[real]] all_md_disc, + [[int]] bb_inds, + [[real]] bb_data) = + let md_c = all_md_c[0] in + let md_vols = all_md_vols[0] in + let md_drifts = all_md_drifts[0] in + let md_st = all_md_st[0] in + let md_detvals = all_md_detvals[0] in + let md_disc = all_md_disc[0] in + let sobol_mat = map ( sobolIndR(num_bits, dir_vs), map(fn int (int x) => x + 1, iota(num_mc_it)) ) in + let gauss_mat = map ( ugaussian, sobol_mat ) in + let bb_mat = map ( brownianBridge( num_und, num_dates, bb_inds, bb_data ), gauss_mat ) in + let bs_mat = map ( blackScholes( num_und, md_c, md_vols, md_drifts, md_st ), bb_mat ) in + + let payoff = + if contract_number == 1 then + let payoffs = map ( payoff1(md_disc, md_detvals), bs_mat ) in + reduce ( op +, 0.0, payoffs ) + else if contract_number == 2 then + let payoffs = map ( payoff2(md_disc), bs_mat ) in + reduce ( op +, 0.0, payoffs ) + else if contract_number == 3 then + let payoffs = map ( payoff3(md_disc), bs_mat ) in + reduce ( op +, 0.0, payoffs ) + else 0.0 in + [ payoff / toReal(num_mc_it) ] + +//////////////////////////////////////// +// PAYOFF FUNCTION +//////////////////////////////////////// + +// This function is super weird, but a faithful translation of the +// Haskell version... +fun real payoff1 ([real] md_disc, [real] md_detvals, [[real]] xss) = + let detval = md_detvals[0] in + let amount = (xss[0,0] - 4000.0) * detval in + let amount2 = if amount < 0.0 then 0.0 else amount in + trajInner(amount2, 0, md_disc) + +fun real payoff2 ([real] md_disc, [[real]] xss) = +// invariant: length(xss) == 5, i.e., 5x3 matrix + let divs = [ 1.0/3758.05, 1.0/11840.0, 1.0/1200.0 ] in + let xss_div = map( fn [real] ([real] xs) => map(op *, zip(xs, divs)), xss ) in + let mins = map( MIN, xss_div ) + in if( 1.0 <= mins[0] ) then trajInner(1150.0, 0, md_disc) + else if( 1.0 <= mins[1] ) then trajInner(1300.0, 1, md_disc) + else if( 1.0 <= mins[2] ) then trajInner(1450.0, 2, md_disc) + else if( 1.0 <= mins[3] ) then trajInner(1600.0, 3, md_disc) + else if( 1.0 <= mins[4] ) then trajInner(1750.0, 4, md_disc) + else if( 0.75 < mins[4] ) then trajInner(1000.0, 4, md_disc) + else trajInner(1000.0 * mins[4], 4, md_disc) + +fun real payoff3 ([real] md_disc, [[real]] xss) = + // invariant: size(1,xss) == 3. + let x3309 = reduce(op ||, False, + map (fn bool ([real] xs) => + xs[0] <= 2630.6349999999998 || + xs[1] <= 8288.0 || + xs[2] <= 840.0, + xss)) in + let goto_40 = (x3309 && + (xss[366,0] < 3758.05 || + xss[366,2] < 1200.0 || + xss[366,1] < 11840.0)) in + let price1 = trajInner(100.0, 0, md_disc) in + let price2 = + if goto_40 then let m1 = min((xss[366,2] / 1200.00) - 1.0, + (xss[366,0] / 3758.05) - 1.0) in + let m2 = min((xss[366,1] / 11840.00) - 1.0, + m1) in + let amount = 1000.0 * (1.0 + m2) in + trajInner(amount, 1, md_disc) + else trajInner(1000.0, 1, md_disc) in + price1 + price2 + +fun real min(real x, real y) = + if x < y then x else y + +fun real MIN([real] arr) = + reduce( fn real (real x, real y) => if(x input.data + +cp $FINPAR_IMPLEMENTATION/run . + +futhark -s -fe -ae $FINPAR_IMPLEMENTATION/GenericPricing.fut > optimised.fut +futhark -s -fe -ae --compile-sequential $FINPAR_IMPLEMENTATION/GenericPricing.fut > GenericPricing.c +gcc GenericPricing.c -O3 -o GenericPricing -lm diff --git a/benchmarks/GenericPricing/implementations/futhark/run b/benchmarks/GenericPricing/implementations/futhark/run new file mode 100755 index 0000000..9aef238 --- /dev/null +++ b/benchmarks/GenericPricing/implementations/futhark/run @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +./GenericPricing -t runtime.txt < input.data > result.json From bd9518cfd443c40e41453092e04d7bfa51f7ab70 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 23 Feb 2015 11:39:46 +0100 Subject: [PATCH 019/122] Do not generate an optimised.fut file. --- benchmarks/GenericPricing/implementations/futhark/instantiate | 1 - 1 file changed, 1 deletion(-) diff --git a/benchmarks/GenericPricing/implementations/futhark/instantiate b/benchmarks/GenericPricing/implementations/futhark/instantiate index 3614000..a9e0508 100755 --- a/benchmarks/GenericPricing/implementations/futhark/instantiate +++ b/benchmarks/GenericPricing/implementations/futhark/instantiate @@ -6,6 +6,5 @@ $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iter cp $FINPAR_IMPLEMENTATION/run . -futhark -s -fe -ae $FINPAR_IMPLEMENTATION/GenericPricing.fut > optimised.fut futhark -s -fe -ae --compile-sequential $FINPAR_IMPLEMENTATION/GenericPricing.fut > GenericPricing.c gcc GenericPricing.c -O3 -o GenericPricing -lm From 168e2b198958c421dfef5597de2ad1e95d755fa9 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Wed, 25 Feb 2015 22:52:34 +0100 Subject: [PATCH 020/122] Use --in-place-lowering for Futhark implementation of GenericPricing. --- benchmarks/GenericPricing/implementations/futhark/instantiate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/GenericPricing/implementations/futhark/instantiate b/benchmarks/GenericPricing/implementations/futhark/instantiate index a9e0508..8bb7b59 100755 --- a/benchmarks/GenericPricing/implementations/futhark/instantiate +++ b/benchmarks/GenericPricing/implementations/futhark/instantiate @@ -6,5 +6,5 @@ $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iter cp $FINPAR_IMPLEMENTATION/run . -futhark -s -fe -ae --compile-sequential $FINPAR_IMPLEMENTATION/GenericPricing.fut > GenericPricing.c +futhark -s -fe --in-place-lowering -ae --compile-sequential $FINPAR_IMPLEMENTATION/GenericPricing.fut > GenericPricing.c gcc GenericPricing.c -O3 -o GenericPricing -lm From ae1ff95c5c74dc56c8a3264acf9898dd19ef3b92 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 9 Mar 2015 20:04:12 +0100 Subject: [PATCH 021/122] We changed how split works. --- .../GenericPricing/implementations/futhark/GenericPricing.fut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut index 0880364..50e87da 100644 --- a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut +++ b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut @@ -198,7 +198,7 @@ fun [[real]] brownianBridge ( fun real zwop(real a, real b, int j) = a * b -fun [real] take(int n, [real] a) = let {first, rest} = split(n, a) in first +fun [real] take(int n, [real] a) = let {first, rest} = split((n), a) in first fun [real] fftmp(int num_paths, [[real]] md_c, [real] zi) = map( fn real (int j) => From c21f4c38d6c880c9709dffc7cd76a6d21e474350 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 16 Apr 2015 09:02:32 +0200 Subject: [PATCH 022/122] Update Futhark benchmarks to newest compiler version. --- .../implementations/futhark/CalibVolDiff.fut | 10 +++++----- .../implementations/futhark/instantiate | 3 +-- .../futhark/GenericPricing.fut | 20 +++++++++---------- .../implementations/futhark/instantiate | 3 +-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut b/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut index 2c630e7..eda4cf8 100644 --- a/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut +++ b/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut @@ -23,13 +23,13 @@ fun {[[real]],[[real]]} initOperator([real] x) = [-dxu/dxl/(dxl+dxu), (dxu/dxl - dxl/dxu)/(dxl+dxu), dxl/dxu/(dxl+dxu)], - map (op + (1), iota(n-2))) in + map (+1, iota(n-2))) in let Dxxmid = map(fn [real] (int i) => let dxl = x[i] - x[i-1] in let dxu = x[i+1] - x[i] in [2.0/dxl/(dxl+dxu), -2.0*(1.0/dxl + 1.0/dxu)/(dxl+dxu), 2.0/dxu/(dxl+dxu)], - map (op + (1), iota(n-2))) in + map (+1, iota(n-2))) in let dxl = x[n-1] - x[n-2] in let dxu = 0.0 in let Dxhigh = [[-1.0 / dxl, 1.0 / dxl, 0.0 ]] in @@ -81,7 +81,7 @@ fun *[[real]] explicitX map(fn real (int i) => let kl = if i == 0 then 1 else 0 in let ku = 2 - if i==numX-1 then 1 else 0 in - reduce(op +, dtInv*myResult[i,j], + reduce(+, dtInv*myResult[i,j], map(fn real (int k) => let k = k + kl in 0.5 * (myMuX[i,j]*myDx[i,k]+0.5*myVarX[i,j]*myDxx[i,k]) @@ -97,7 +97,7 @@ fun *[[real]] explicitY map(fn real (int j) => let ll = 1 * (if j == 0 then 1 else 0) in let lu = 2 - 1*(if j==numY-1 then 1 else 0) in - reduce(op +, 0.0, + reduce(+, 0.0, map(fn real (int l) => let l = l + ll in (myMuY[i,j]*myDy[j,l]+0.5*myVarY[i,j]*myDyy[j,l]) @@ -115,7 +115,7 @@ fun *[[real]] rollback let dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]) in let u = explicitX(numX, numY, dtInv, myResult, myMuX, myDx, myDxx, myVarX) in let v = explicitY(numX, numY, 0.0, myResult, myMuY, myDy, myDyy, myVarY) in - let u = map(fn [real] ([real] us, [real] vs) => map(op +, zip(us, vs)), + let u = map(fn [real] ([real] us, [real] vs) => map(+, zip(us, vs)), zip(u, transpose(v))) in let u = map(fn [real] ({[real], int} t) => let {uj, j} = t in diff --git a/benchmarks/CalibVolDiff/implementations/futhark/instantiate b/benchmarks/CalibVolDiff/implementations/futhark/instantiate index 3375ece..82ef9eb 100755 --- a/benchmarks/CalibVolDiff/implementations/futhark/instantiate +++ b/benchmarks/CalibVolDiff/implementations/futhark/instantiate @@ -6,5 +6,4 @@ $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input. cp $FINPAR_IMPLEMENTATION/run . -futhark -s -fe --in-place-lowering -ae --compile-sequential $FINPAR_IMPLEMENTATION/CalibVolDiff.fut > CalibVolDiff.c -gcc CalibVolDiff.c -O3 -o CalibVolDiff -lm +futhark-c $FINPAR_IMPLEMENTATION/CalibVolDiff.fut diff --git a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut index 50e87da..2837190 100644 --- a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut +++ b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut @@ -13,7 +13,7 @@ fun bool testBit(int n, int ind) = //// less computation but variable array size! ///////////////////////////////////////////////////////////////// //fun int xorInds([int] indices, [int] dir_vs ) = -// reduce( op ^, 0, map( index(dir_vs), indices ) ) +// reduce( ^, 0, map( index(dir_vs), indices ) ) // //fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = // let bits = iota ( bits_num ) in @@ -29,7 +29,7 @@ fun bool testBit(int n, int ind) = fun int xorInds(int bits_num, int n, [int] dir_vs ) = let bits = iota ( bits_num ) in let indices = filter ( testBit(grayCode(n)), bits ) in - reduce( op ^, 0, map( index(dir_vs), indices ) ) + reduce( ^, 0, map( index(dir_vs), indices ) ) fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = map( xorInds(bits_num, n), dir_vs ) @@ -203,7 +203,7 @@ fun [real] take(int n, [real] a) = let {first, rest} = split((n), a) in first fun [real] fftmp(int num_paths, [[real]] md_c, [real] zi) = map( fn real (int j) => let x = map(zwop, zip(take(j+1,zi), take(j+1,md_c[j]), iota(j+1))) - in reduce(op +, 0.0, x), + in reduce(+, 0.0, x), iota(num_paths) ) @@ -211,13 +211,13 @@ fun [[real]] correlateDeltas(int num_paths, [[real]] md_c, [[real]] zds) = map( fftmp(num_paths, md_c), zds ) fun [real] combineVs([real] n_row, [real] vol_row, [real] dr_row) = - map( op +, zip(dr_row, map( op *, zip(n_row, vol_row ) ))) + map( +, zip(dr_row, map( *, zip(n_row, vol_row ) ))) fun [[real]] mkPrices ([real] md_starts, [[real]] md_vols, [[real]] md_drifts, [[real]] noises) = let e_rows = map( fn [real] ([real] x) => map(exp, x), map(combineVs, zip(noises, md_vols, md_drifts)) ) - in scan( fn [real] ([real] x, [real] y) => map(op *, zip(x, y)), md_starts, e_rows ) + in scan( fn [real] ([real] x, [real] y) => map(*, zip(x, y)), md_starts, e_rows ) //[num_dates, num_paths] fun [[real]] blackScholes( @@ -264,13 +264,13 @@ fun [real] main(int contract_number, let payoff = if contract_number == 1 then let payoffs = map ( payoff1(md_disc, md_detvals), bs_mat ) in - reduce ( op +, 0.0, payoffs ) + reduce ( +, 0.0, payoffs ) else if contract_number == 2 then let payoffs = map ( payoff2(md_disc), bs_mat ) in - reduce ( op +, 0.0, payoffs ) + reduce ( +, 0.0, payoffs ) else if contract_number == 3 then let payoffs = map ( payoff3(md_disc), bs_mat ) in - reduce ( op +, 0.0, payoffs ) + reduce ( +, 0.0, payoffs ) else 0.0 in [ payoff / toReal(num_mc_it) ] @@ -289,7 +289,7 @@ fun real payoff1 ([real] md_disc, [real] md_detvals, [[real]] xss) = fun real payoff2 ([real] md_disc, [[real]] xss) = // invariant: length(xss) == 5, i.e., 5x3 matrix let divs = [ 1.0/3758.05, 1.0/11840.0, 1.0/1200.0 ] in - let xss_div = map( fn [real] ([real] xs) => map(op *, zip(xs, divs)), xss ) in + let xss_div = map( fn [real] ([real] xs) => map(*, zip(xs, divs)), xss ) in let mins = map( MIN, xss_div ) in if( 1.0 <= mins[0] ) then trajInner(1150.0, 0, md_disc) else if( 1.0 <= mins[1] ) then trajInner(1300.0, 1, md_disc) @@ -301,7 +301,7 @@ fun real payoff2 ([real] md_disc, [[real]] xss) = fun real payoff3 ([real] md_disc, [[real]] xss) = // invariant: size(1,xss) == 3. - let x3309 = reduce(op ||, False, + let x3309 = reduce(||, False, map (fn bool ([real] xs) => xs[0] <= 2630.6349999999998 || xs[1] <= 8288.0 || diff --git a/benchmarks/GenericPricing/implementations/futhark/instantiate b/benchmarks/GenericPricing/implementations/futhark/instantiate index 8bb7b59..7c69114 100755 --- a/benchmarks/GenericPricing/implementations/futhark/instantiate +++ b/benchmarks/GenericPricing/implementations/futhark/instantiate @@ -6,5 +6,4 @@ $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iter cp $FINPAR_IMPLEMENTATION/run . -futhark -s -fe --in-place-lowering -ae --compile-sequential $FINPAR_IMPLEMENTATION/GenericPricing.fut > GenericPricing.c -gcc GenericPricing.c -O3 -o GenericPricing -lm +futhark-c $FINPAR_IMPLEMENTATION/GenericPricing.fut From ceff7b4eb76abc45cf6d05354add53dbcd900a83 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 12 May 2015 22:39:59 +0200 Subject: [PATCH 023/122] Update CalibVolDiff to newest version. --- .../implementations/futhark/CalibVolDiff.fut | 352 +++++++++++------- 1 file changed, 220 insertions(+), 132 deletions(-) diff --git a/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut b/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut index eda4cf8..480b004 100644 --- a/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut +++ b/benchmarks/CalibVolDiff/implementations/futhark/CalibVolDiff.fut @@ -1,153 +1,246 @@ -fun {int,int,[real],[real],[real],[[real]],[[real]],[[real]],[[real]]} initGrid - (real s0, real alpha, real nu, real t, int numX, int numY, int numT) = +fun {int,int,[real],[real],[real]} +initGrid(real s0, real alpha, real nu, real t, int numX, int numY, int numT) = let logAlpha = log(alpha) in - let myTimeline = map(fn real (int i) => t * toReal(i) / (toReal(numT) - 1.0), iota(numT)) in + let myTimeline = map(fn real (int i) => t * toFloat(i) / (toFloat(numT) - 1.0), iota(numT)) in let {stdX, stdY} = {20.0 * alpha * s0 * sqrt(t), 10.0 * nu * sqrt(t)} in - let {dx, dy} = {stdX / toReal(numX), stdY / toReal(numY)} in + let {dx, dy} = {stdX / toFloat(numX), stdY / toFloat(numY)} in let {myXindex, myYindex} = {trunc(s0 / dx), numY / 2} in - let myX = map(fn real (int i) => toReal(i) * dx - toReal(myXindex) * dx + s0, iota(numX)) in - let myY = map(fn real (int i) => toReal(i) * dy - toReal(myYindex) * dy + logAlpha, iota(numY)) in - let xXy = replicate(numX,replicate(numY, 0.0)) in - let {myMuX, myVarX, myMuY, myVarY} = {xXy, xXy, xXy, xXy} in - {myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY} + let myX = map(fn real (int i) => toFloat(i) * dx - toFloat(myXindex) * dx + s0, iota(numX)) in + let myY = map(fn real (int i) => toFloat(i) * dy - toFloat(myYindex) * dy + logAlpha, iota(numY)) in + {myXindex, myYindex, myX, myY, myTimeline} +// make the innermost dimension of the result of size 4 instead of 3? fun {[[real]],[[real]]} initOperator([real] x) = - let n = size(0, x) in - let dxu = x[1] - x[0] in - let dxl = 0.0 in - let Dxlow = [[0.0, -1.0 / dxu, 1.0 / dxu]] in - let Dxxlow = [[0.0, 0.0, 0.0]] in - let Dxmid = map(fn [real] (int i) => let dxl = x[i] - x[i-1] in - let dxu = x[i+1] - x[i] in - [-dxu/dxl/(dxl+dxu), - (dxu/dxl - dxl/dxu)/(dxl+dxu), - dxl/dxu/(dxl+dxu)], - map (+1, iota(n-2))) in - let Dxxmid = map(fn [real] (int i) => let dxl = x[i] - x[i-1] in - let dxu = x[i+1] - x[i] in - [2.0/dxl/(dxl+dxu), - -2.0*(1.0/dxl + 1.0/dxu)/(dxl+dxu), - 2.0/dxu/(dxl+dxu)], - map (+1, iota(n-2))) in - let dxl = x[n-1] - x[n-2] in - let dxu = 0.0 in + let n = size(0, x) in + let dxu = x[1] - x[0] in + let dxl = 0.0 in + let Dxlow = [[0.0, -1.0 / dxu, 1.0 / dxu]] in + let Dxxlow = [[0.0, 0.0, 0.0]] in + let Dxmids = map(fn {[real],[real]} (int i) => + let dxl = x[i] - x[i-1] in + let dxu = x[i+1] - x[i] in + { [ -dxu/dxl/(dxl+dxu), (dxu/dxl - dxl/dxu)/(dxl+dxu), dxl/dxu/(dxl+dxu) ], + [ 2.0/dxl/(dxl+dxu), -2.0*(1.0/dxl + 1.0/dxu)/(dxl+dxu), 2.0/dxu/(dxl+dxu) ] } + , map (+ (1), iota(n-2))) in + let {Dxmid, Dxxmid} = unzip(Dxmids) in + let dxl = x[n-1] - x[n-2] in + let dxu = 0.0 in let Dxhigh = [[-1.0 / dxl, 1.0 / dxl, 0.0 ]] in - let Dxxhigh = [[0.0, 0.0, 0.0 ]] in - let Dx = concat(concat(Dxlow, Dxmid), Dxhigh) in - let Dxx = concat(concat(Dxxlow, Dxxmid), Dxxhigh) in - {Dx, Dxx} + let Dxxhigh= [[0.0, 0.0, 0.0 ]] in + let Dx = concat(concat(Dxlow, Dxmid), Dxhigh) in + let Dxx = concat(concat(Dxxlow, Dxxmid), Dxxhigh) + in {Dx, Dxx} fun real max(real x, real y) = if y < x then x else y fun int maxInt(int x, int y) = if y < x then x else y fun *[[real]] setPayoff(real strike, [real] myX, [real] myY) = - let n = size(0, myY) in - copy(map(fn [real] (real xi) => replicate(n, max(xi-strike,0.0)), myX)) + let n = size(0, myY) in + let myres = map(fn [real] (real xi) => replicate(n, max(xi-strike,0.0)), myX) in + copy(transpose(myres)) // Returns new myMuX, myVarX, myMuY, myVarY. -fun {[[real]] , [[real]] , [[real]] , [[real]]} updateParams - ([real] myX, [real] myY, [real] myTimeline, int g, real alpha, real beta, real nu) = - unzip (map(fn {[real],[real],[real],[real]} (real xi) => - unzip (map (fn {real,real,real,real} (real yj) => - {0.0, - exp(2.0*(beta*log(xi) + yj - 0.5*nu*nu*myTimeline[g])), - 0.0, - nu * nu}, myY)), myX)) +fun {[[real]] , [[real]] , [[real]] , [[real]]} +updateParams( [real] myX, [real] myY, [real] myTimeline, + int g, real alpha, real beta, real nu ) = + let { numX, numY } = { size(0,myX), size(0,myY) } in + let myMuY = replicate(numX, replicate(numY, 0.0 )) in + let myVarY = replicate(numX, replicate(numY, nu*nu)) in + let myMuX = replicate(numY, replicate(numX, 0.0 )) in + let myVarX = map( fn [real] (real yj) => + map ( fn real (real xi) => + exp(2.0*(beta*log(xi) + yj - 0.5*nu*nu*myTimeline[g])) + , myX ) + , myY ) + in { myMuX, myVarX, myMuY, myVarY } -fun {[real],[real]} tridag - ([real] a, [real] b, [real] c, [real] r, int n) = - let bet = 1.0/b[0] in - let {u, uu} = {copy(replicate(n,0.0)), - copy(replicate(n,0.0))} in - let u[0] = r[0] * bet in - loop ({u, uu, bet}) = - for j < n-1 do - let j = j + 1 in - let uu[j] = c[j-1]*bet in - let bet = 1.0/(b[j] - a[j] * uu[j]) in - let u[j] = (r[j] - a[j]*u[j-1]) * bet in - {u, uu, bet} in - loop (u) = for j < n - 1 do - let j = n - 2 - j in - let u[j] = u[j] - uu[j+1]*u[j+1] in - u - in {u, uu} +fun *[real] tridagSeq( [real] a, *[real] b, [real] c, *[real] y ) = + let n = size(0, a) in + loop ({y, b}) = + for i < n-1 do + let i = i + 1 in + let beta = a[i] / b[i-1] in + let b[i] = b[i] - beta*c[i-1] in + let y[i] = y[i] - beta*y[i-1] + in {y, b} + in + let y[n-1] = y[n-1]/b[n-1] in + loop (y) = for j < n - 1 do + let i = n - 2 - j in + let y[i] = (y[i] - c[i]*y[i+1]) / b[i] + in y + in y -fun *[[real]] explicitX - (int numX, int numY, real dtInv, - [[real]] myResult, [[real]] myMuX, [[real]] myDx, [[real]] myDxx, [[real]] myVarX) = - copy(map(fn [real] (int j) => - map(fn real (int i) => - let kl = if i == 0 then 1 else 0 in - let ku = 2 - if i==numX-1 then 1 else 0 in - reduce(+, dtInv*myResult[i,j], - map(fn real (int k) => - let k = k + kl in - 0.5 * (myMuX[i,j]*myDx[i,k]+0.5*myVarX[i,j]*myDxx[i,k]) - * myResult[i+k-1,j], - iota(ku-kl+1))), - iota(numX)), - iota(numY))) +fun *[real] tridagPar( [real] a, *[real] b, [real] c, *[real] y ) = + let n = size(0, a) in + //////////////////////////////////////////////////// + // Recurrence 1: b[i] = b[i] - a[i]*c[i-1]/b[i-1] // + // solved by scan with 2x2 matrix mult operator // + //////////////////////////////////////////////////// + let b0 = b[0] in + let mats = map ( fn {real,real,real,real} (int i) => + if 0 < i + then {b[i], 0.0-a[i]*c[i-1], 1.0, 0.0} + else {1.0, 0.0, 0.0, 1.0} + , iota(n) ) in + let scmt = scan( fn {real,real,real,real} ( {real,real,real,real} a, + {real,real,real,real} b ) => + let {a0,a1,a2,a3} = a in + let {b0,b1,b2,b3} = b in + let val = 1.0/(a0*b0) in + { (b0*a0 + b1*a2)*val, + (b0*a1 + b1*a3)*val, + (b2*a0 + b3*a2)*val, + (b2*a1 + b3*a3)*val + } + , {1.0, 0.0, 0.0, 1.0}, mats ) in + let b = map ( fn real ({real,real,real,real} tup) => + let {t0,t1,t2,t3} = tup in + (t0*b0 + t1) / (t2*b0 + t3) + , scmt ) in + ////////////////////////////////////////////////////// + // Recurrence 2: y[i] = y[i] - (a[i]/b[i-1])*y[i-1] // + // solved by scan with linear func comp operator // + ////////////////////////////////////////////////////// + let y0 = y[0] in + let lfuns= map ( fn {real,real} (int i) => + if 0 < i + then {y[i], 0.0-a[i]/b[i-1]} + else {0.0, 1.0 } + , iota(n) ) in + let cfuns= scan( fn {real,real} ({real,real} a, {real,real} b) => + let {a0,a1} = a in + let {b0,b1} = b in + { b0 + b1*a0, a1*b1 } + , {0.0, 1.0}, lfuns ) in + let y = map ( fn real ({real,real} tup) => + let {a,b} = tup in + a + b*y0 + , cfuns ) in + ////////////////////////////////////////////////////// + // Recurrence 3: backward recurrence solved via // + // scan with linear func comp operator // + ////////////////////////////////////////////////////// + let yn = y[n-1]/b[n-1] in + let lfuns= map ( fn {real,real} (int k) => + let i = n-k-1 + in if 0 < k + then {y[i]/b[i], 0.0-c[i]/b[i]} + else {0.0, 1.0 } + , iota(n) ) in + let cfuns= scan( fn {real,real} ({real,real} a, {real,real} b) => + let {a0,a1} = a in + let {b0,b1} = b in + {b0 + b1*a0, a1*b1} + , {0.0, 1.0}, lfuns ) in + let y = map ( fn real ({real,real} tup) => + let {a,b} = tup in + a + b*yn + , cfuns ) in + let y = map (fn real (int i) => y[n-i-1], iota(n)) in + copy(y) -fun *[[real]] explicitY - (int numX, int numY, real dtInv, - [[real]] myResult, [[real]] myMuY, [[real]] myDy, [[real]] myDyy, [[real]] myVarY) = - copy(map(fn [real] (int i) => - map(fn real (int j) => - let ll = 1 * (if j == 0 then 1 else 0) in - let lu = 2 - 1*(if j==numY-1 then 1 else 0) in - reduce(+, 0.0, - map(fn real (int l) => - let l = l + ll in - (myMuY[i,j]*myDy[j,l]+0.5*myVarY[i,j]*myDyy[j,l]) - * myResult[i,j+l-1], - iota(lu-ll+1))), - iota(numY)), - iota(numX))) +/////////////////////////////////////////// +// myD,myDD : [[real,3],m] +// myMu,myVar,result : [[real,m],n] +// RETURN : [[real,m],n] +/////////////////////////////////////////// +fun *[[real]] explicitMethod( [[real]] myD, [[real]] myDD, + [[real]] myMu, [[real]] myVar, [[real]] result ) = + // 0 <= i < m AND 0 <= j < n + let m = size(0,myD) in + copy( map( fn [real] ( {[real],[real],[real]} tup ) => + let {mu_row, var_row, result_row} = tup in + map( fn real ({[real], [real], real, real, int} tup) => + let { dx, dxx, mu, var, j } = tup in + let c1 = if 0 < j + then ( mu*dx[0] + 0.5*var*dxx[0] ) * result_row[j-1] + else 0.0 in + let c3 = if j < (m-1) + then ( mu*dx[2] + 0.5*var*dxx[2] ) * result_row[j+1] + else 0.0 in + let c2 = ( mu*dx[1] + 0.5*var*dxx[1] ) * result_row[j ] + in c1 + c2 + c3 + , zip( myD, myDD, mu_row, var_row, iota(m) ) + ) + , zip( myMu, myVar, result ) + ) + ) + +/////////////////////////////////////////// +// myD,myDD : [[real,3],m] +// myMu,myVar,u : [[real,m],n] +// RETURN : [[real,m],n] +/////////////////////////////////////////// +// for implicitY: should be called with transpose(u) instead of u +fun *[[real]] implicitMethod( [[real]] myD, [[real]] myDD, + [[real]] myMu, [[real]] myVar, + *[[real]] u, real dtInv ) = + map( fn *[real] ( {[real],[real],*[real]} tup ) => + let {mu_row,var_row,u_row} = tup in + let abc = map( fn {real,real,real} ({real,real,[real],[real]} tup) => + let {mu, var, d, dd} = tup in + { 0.0 - 0.5*(mu*d[0] + 0.5*var*dd[0]) + , dtInv - 0.5*(mu*d[1] + 0.5*var*dd[1]) + , 0.0 - 0.5*(mu*d[2] + 0.5*var*dd[2]) + } + , zip(mu_row, var_row, myD, myDD) + ) in + let {a,b,c} = unzip(abc) in + if 1==1 then tridagSeq( a, copy(b), c, u_row ) + else tridagPar( a, copy(b), c, u_row ) + , zip(myMu,myVar,u) + ) fun *[[real]] rollback ([real] myX, [real] myY, [real] myTimeline, *[[real]] myResult, [[real]] myMuX, [[real]] myDx, [[real]] myDxx, [[real]] myVarX, [[real]] myMuY, [[real]] myDy, [[real]] myDyy, [[real]] myVarY, int g) = + let {numX, numY} = {size(0, myX), size(0, myY)} in - let numZ = maxInt(numX, numY) in let dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]) in - let u = explicitX(numX, numY, dtInv, myResult, myMuX, myDx, myDxx, myVarX) in - let v = explicitY(numX, numY, 0.0, myResult, myMuY, myDy, myDyy, myVarY) in - let u = map(fn [real] ([real] us, [real] vs) => map(+, zip(us, vs)), - zip(u, transpose(v))) in - let u = map(fn [real] ({[real], int} t) => - let {uj, j} = t in - let {a,b,c} = unzip(map(fn {real,real,real} (int i) => - {-0.5*(myMuX[i,j]*myDx[i,0] + 0.5*myVarX[i,j]*myDxx[i,0]), - dtInv - 0.5*(myMuX[i,j]*myDx[i,1] + 0.5*myVarX[i,j]*myDxx[i,1]), - -0.5*(myMuX[i,j]*myDx[i,2]+0.5*myVarX[i,j]*myDxx[i,2])}, - iota(numX))) in - let {uj, yy} = tridag(a,b,c,uj,numX) in uj, - zip(u, iota(numY))) in - loop (myResult) = - for i < numX do - let {a,b,c} = unzip(map(fn {real,real,real} (int j) => - {-0.5*(myMuY[i,j]*myDy[j,0]+0.5*myVarY[i,j]*myDyy[j,0]), - dtInv - 0.5*(myMuY[i,j]*myDy[j,1]+0.5*myVarY[i,j]*myDyy[j,1]), - -0.5*(myMuY[i,j]*myDy[j,2]+0.5*myVarY[i,j]*myDyy[j,2])}, - iota(numY))) in - let y = copy(replicate(numY, 0.0)) in - loop (y) = for j < numY do - let y[j] = dtInv * u[j,i] - 0.5*v[i,j] in - y in - let {ri, yy} = tridag(a,b,c,y,numY) in - let myResult[i] = ri in myResult - in myResult + + // explicitX + let u = explicitMethod( myDx, myDxx, myMuX, myVarX, myResult ) in + let u = map( fn [real] ({[real],[real]} tup) => + let {u_row, res_row} = tup in + map (fn real ({real,real} tup) => + let {u_el,res_el} = tup + in dtInv*res_el + 0.5*u_el + , zip(u_row,res_row) ) + , zip(u,myResult) ) + in + // explicitY + let myResultTR = transpose(myResult) in + let v = explicitMethod( myDy, myDyy, myMuY, myVarY, myResultTR ) in + let u = map( fn *[real] ([real] us, [real] vs) => + copy(map(+, zip(us, vs))) + , zip(u, transpose(v)) + ) in + // implicitX + let u = implicitMethod( myDx, myDxx, myMuX, myVarX, u, dtInv ) in + // implicitY + let y = copy( map( fn [real] ({[real],[real]} uv_row) => + let {u_row, v_row} = uv_row in + map( fn real ({real,real} uv) => + let {u_el,v_el} = uv + in dtInv*u_el - 0.5*v_el + , zip(u_row,v_row) + ) + , zip(transpose(u),v) + ) ) + in + let myResultTR = implicitMethod( myDy, myDyy, myMuY, myVarY, y, dtInv ) + in transpose(myResultTR) fun real value(int numX, int numY, int numT, real s0, real strike, real t, real alpha, real nu, real beta) = - let {myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY} = + let {myXindex, myYindex, myX, myY, myTimeline} = initGrid(s0, alpha, nu, t, numX, numY, numT) in - let {myDx, myDxx} = initOperator(myX) in - let {myDy, myDyy} = initOperator(myY) in + let {myDx, myDxx} = initOperator(myX) in + let {myDy, myDyy} = initOperator(myY) in let myResult = setPayoff(strike, myX, myY) in - //loop ((myResult, myMuX, myVarX, myMuY, myVarY)) = + loop (myResult) = for i < numT - 1 do let i = numT-2-i in @@ -156,17 +249,12 @@ fun real value(int numX, int numY, int numT, real s0, real strike, real t, real let myResult = rollback(myX, myY, myTimeline, myResult, myMuX, myDx, myDxx, myVarX, myMuY, myDy, myDyy, myVarY, i) in - //(myResult, myMuX, myVarX, myMuY, myVarY) in + myResult in - myResult[myXindex,myYindex] + myResult[myYindex,myXindex] -fun [real] main (int outer_loop_count, int numX, int numY, int numT) = - let s0 = 0.03 in - let strike = 0.03 in - let t = 5.0 in - let alpha = 0.2 in - let nu = 0.6 in - let beta = 0.5 in - let strikes = map(fn real (int i) => 0.001*toReal(i), iota(outer_loop_count)) in +fun [real] main (int outer_loop_count, int numX, int numY, int numT, + real s0, real strike, real t, real alpha, real nu, real beta) = + let strikes = map(fn real (int i) => 0.001*toFloat(i), iota(outer_loop_count)) in let res = map(fn real (real x) => value(numX, numY, numT, s0, x, t, alpha, nu, beta), strikes) in res From 74a80d2d4f17463e3029fc8c3ee646477b257771 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 19 Jun 2015 13:31:33 +0200 Subject: [PATCH 024/122] Fix 2D array printing. --- lib/include/ParserC.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/ParserC.h b/lib/include/ParserC.h index a6019ae..a870d14 100644 --- a/lib/include/ParserC.h +++ b/lib/include/ParserC.h @@ -240,7 +240,7 @@ template void write_2Darr( FILE* out, const T* ptr, const int& Nouter, const int& Ninner ) { fprintf(out, "\n[ "); for( int i = 0; i < Nouter-1; i ++ ) { - write_1Darr( stdout, ptr + i*Ninner, Ninner ); + write_1Darr( out, ptr + i*Ninner, Ninner ); fprintf(out, ","); } write_1Darr( out, ptr + (Nouter-1)*Ninner, Ninner ); From e23456f6dbf6da589850417fa57ecf0ac834bde7 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 19 Jun 2015 13:31:54 +0200 Subject: [PATCH 025/122] Fix Futhark generic pricing. --- .../implementations/futhark/GenericPricing.fut | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut index 2837190..b86f7f7 100644 --- a/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut +++ b/benchmarks/GenericPricing/implementations/futhark/GenericPricing.fut @@ -36,9 +36,9 @@ fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = //////////////////////////////////////////////////////////////// fun [real] sobolIndR( int bits_num, [[int]] dir_vs, int n ) = - let divisor = 2.0 pow toReal (bits_num) in + let divisor = 2.0 pow toFloat (bits_num) in let arri = sobolIndI( bits_num, dir_vs, n ) in - map( fn real (int x) => toReal(x) / divisor, arri ) + map( fn real (int x) => toFloat(x) / divisor, arri ) //////////////////////////////////////// /// Inverse Gaussian @@ -272,7 +272,7 @@ fun [real] main(int contract_number, let payoffs = map ( payoff3(md_disc), bs_mat ) in reduce ( +, 0.0, payoffs ) else 0.0 in - [ payoff / toReal(num_mc_it) ] + [ payoff / toFloat(num_mc_it) ] //////////////////////////////////////// // PAYOFF FUNCTION From 94bcf7965f666a17d850b68be538a0b87600acc2 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 19 Jun 2015 13:33:44 +0200 Subject: [PATCH 026/122] First draft of fixing CalibGA. --- .../datasets/large/{input.data => input.json} | 68 +++--- benchmarks/CalibGA/datasets/large/output.data | 206 ----------------- benchmarks/CalibGA/datasets/large/output.json | 207 +++++++++++++++++ .../medium/{input.data => input.json} | 66 +++--- .../CalibGA/datasets/medium/output.data | 206 ----------------- .../CalibGA/datasets/medium/output.json | 208 ++++++++++++++++++ .../datasets/small/{input.data => input.json} | 66 +++--- benchmarks/CalibGA/datasets/small/output.data | 202 ----------------- benchmarks/CalibGA/datasets/small/output.json | 203 +++++++++++++++++ .../FindBestKer.h | 0 .../GenAlgFlat.h | 0 .../GenAlgKers.h | 0 .../MainKer.h | 0 .../Makefile | 0 .../SrcCL/BestIndValRedKer.cl | 0 .../SrcCL/CalibKers.cl | 0 .../SrcCL/Date.cl | 0 .../SrcCL/ExactYhat.cl | 0 .../SrcCL/G2ppUtil.cl | 0 .../SrcCL/GenAlg.cl | 0 .../SrcCL/Reductions.cl | 0 .../SwapCalib.cpp | 0 .../UtilGPGPU.h | 0 .../cpp_opencl_all/instantiate | 24 ++ .../GenAlgFlat.h | 0 .../Makefile | 6 +- .../SwapCalib | Bin .../SwapCalib.cpp | 35 +-- .../UtilCPU.h | 0 .../cpp_openmp_outer/instantiate | 35 +++ benchmarks/CalibGA/includeC/ParseInput.h | 199 ----------------- .../{includeC => lib/include}/Candidate.h | 0 .../{includeC => lib/include}/Constants.h | 0 .../CalibGA/{includeC => lib/include}/Date.h | 0 .../{includeC => lib/include}/EvalGenomeInl.h | 0 .../CalibGA/{includeC => lib/include}/G2PP.h | 0 .../{includeC => lib/include}/G2ppUtil.h | 0 .../{includeC => lib/include}/GenAlgUtil.h | 0 .../{includeC => lib/include}/IrregShape.h | 0 .../{includeC => lib/include}/KerConsts.h | 0 .../{includeC => lib/include}/MathModule.h | 0 benchmarks/CalibGA/lib/include/ParseInput.h | 102 +++++++++ .../{includeC => lib/include}/tmp/Constants.h | 0 .../include}/tmp/DataStructConst.h | 0 .../{includeC => lib/include}/tmp/G2PP.h | 0 45 files changed, 901 insertions(+), 932 deletions(-) rename benchmarks/CalibGA/datasets/large/{input.data => input.json} (83%) delete mode 100644 benchmarks/CalibGA/datasets/large/output.data create mode 100644 benchmarks/CalibGA/datasets/large/output.json rename benchmarks/CalibGA/datasets/medium/{input.data => input.json} (83%) delete mode 100644 benchmarks/CalibGA/datasets/medium/output.data create mode 100644 benchmarks/CalibGA/datasets/medium/output.json rename benchmarks/CalibGA/datasets/small/{input.data => input.json} (83%) delete mode 100644 benchmarks/CalibGA/datasets/small/output.data create mode 100644 benchmarks/CalibGA/datasets/small/output.json rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/FindBestKer.h (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/GenAlgFlat.h (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/GenAlgKers.h (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/MainKer.h (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/Makefile (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/BestIndValRedKer.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/CalibKers.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/Date.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/ExactYhat.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/G2ppUtil.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/GenAlg.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SrcCL/Reductions.cl (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/SwapCalib.cpp (100%) rename benchmarks/CalibGA/implementations/{All_CppOpenCL => cpp_opencl_all}/UtilGPGPU.h (100%) create mode 100755 benchmarks/CalibGA/implementations/cpp_opencl_all/instantiate rename benchmarks/CalibGA/implementations/{Outer_CppOpenMP => cpp_openmp_outer}/GenAlgFlat.h (100%) rename benchmarks/CalibGA/implementations/{Outer_CppOpenMP => cpp_openmp_outer}/Makefile (89%) rename benchmarks/CalibGA/implementations/{Outer_CppOpenMP => cpp_openmp_outer}/SwapCalib (100%) rename benchmarks/CalibGA/implementations/{Outer_CppOpenMP => cpp_openmp_outer}/SwapCalib.cpp (61%) rename benchmarks/CalibGA/implementations/{Outer_CppOpenMP => cpp_openmp_outer}/UtilCPU.h (100%) create mode 100755 benchmarks/CalibGA/implementations/cpp_openmp_outer/instantiate delete mode 100644 benchmarks/CalibGA/includeC/ParseInput.h rename benchmarks/CalibGA/{includeC => lib/include}/Candidate.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/Constants.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/Date.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/EvalGenomeInl.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/G2PP.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/G2ppUtil.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/GenAlgUtil.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/IrregShape.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/KerConsts.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/MathModule.h (100%) create mode 100644 benchmarks/CalibGA/lib/include/ParseInput.h rename benchmarks/CalibGA/{includeC => lib/include}/tmp/Constants.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/tmp/DataStructConst.h (100%) rename benchmarks/CalibGA/{includeC => lib/include}/tmp/G2PP.h (100%) diff --git a/benchmarks/CalibGA/datasets/large/input.data b/benchmarks/CalibGA/datasets/large/input.json similarity index 83% rename from benchmarks/CalibGA/datasets/large/input.data rename to benchmarks/CalibGA/datasets/large/input.json index 43c8491..92db00c 100644 --- a/benchmarks/CalibGA/datasets/large/input.data +++ b/benchmarks/CalibGA/datasets/large/input.json @@ -1,7 +1,9 @@ -256 // population size -128 // number of iterations of the convergence loop -196 // number of swaption quotes (NUM_SWAP_QUOTES) -[ +{ + "population_size": 256, + "convergence_iterations": 128, + "num_swaption_quotes": 196, + "swaption_quotes": + [ [1.0, 6.0, 1.0, 1.052], [2.0, 6.0, 1.0, 0.81485], [3.0, 6.0, 1.0, 0.6165], @@ -211,33 +213,31 @@ [20.0, 6.0, 30.0, 0.1989], [25.0, 6.0, 30.0, 0.18115], [30.0, 6.0, 30.0, 0.16355] -] // SwaptionQuotes :: REAL[NUM_SWAP_QUOTES,4] - - - -11 // Gauss_DIM: Number of Hermite Coefficients; -[ - 0.0, 0.6568095668820999044613, -0.6568095668820997934390, - -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, - -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, - 3.6684708465595856630159, -3.6684708465595838866591 -] // GaussHermiteCoefs::coefs[Gauss_DIM] - -[ - 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, - 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, - 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, - 1.0065267861723647957461, 1.0065267861723774522886 -] // GaussHermiteCoefs::weights[Gauss_DIM] - - - -30 // SOBOL_BITS_NUM -[ 536870912, 268435456, 134217728, 67108864, 33554432, - 16777216, 8388608, 4194304, 2097152, 1048576, - 524288, 262144, 131072, 65536, 32768, - 16384, 8192, 4096, 2048, 1024, - 512, 256, 128, 64, 32, - 16, 8, 4, 2, 1 -] // SOBOL_DIR_VCT == Sobol Direction Vectors REAL[SOBOL_BITS_NUM] - + ], + + "num_hermite_coefficients": 11, + "hermite_coefficients": + [ 0.0, 0.6568095668820999044613, -0.6568095668820997934390, + -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, + -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, + 3.6684708465595856630159, -3.6684708465595838866591 + ], + + "hermite_coefficient_weights": + [ + 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, + 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, + 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, + 1.0065267861723647957461, 1.0065267861723774522886 + ], + + "sobol_num_bits": 30, + "sobol_dir_vs": + [ 536870912, 268435456, 134217728, 67108864, 33554432, + 16777216, 8388608, 4194304, 2097152, 1048576, + 524288, 262144, 131072, 65536, 32768, + 16384, 8192, 4096, 2048, 1024, + 512, 256, 128, 64, 32, + 16, 8, 4, 2, 1 + ] +} diff --git a/benchmarks/CalibGA/datasets/large/output.data b/benchmarks/CalibGA/datasets/large/output.data deleted file mode 100644 index 244da62..0000000 --- a/benchmarks/CalibGA/datasets/large/output.data +++ /dev/null @@ -1,206 +0,0 @@ -0.325608 // a-field of the winning genome -0.001000 // b-field of the winning genome -0.009058 // sigma-field of the winning genome -0.018683 // nu-field of the winning genome --0.083963 // rho-field of the winning genome -624.116935 // LgLikelihood of the winning genome - -[ - [ 74.172585 , 115.320470 , 35.681337 ], - [ 100.626570 , 162.945479 , 38.245252 ], - [ 118.719023 , 174.297729 , 31.887223 ], - [ 132.735321 , 171.631308 , 22.662524 ], - [ 143.164628 , 168.408756 , 14.989796 ], - [ 151.813418 , 168.310831 , 9.801754 ], - [ 158.832697 , 169.877089 , 6.501402 ], - [ 164.984854 , 172.511293 , 4.362868 ], - [ 169.170571 , 172.824865 , 2.114449 ], - [ 172.872471 , 172.561368 , 0.180286 ], - [ 181.530751 , 177.275607 , 2.400298 ], - [ 180.340962 , 161.933876 , 11.367038 ], - [ 172.565436 , 139.430038 , 23.764892 ], - [ 162.247156 , 120.029132 , 35.173148 ], - [ 74.172585 , 69.393222 , 6.887362 ], - [ 100.626570 , 116.015964 , 13.264894 ], - [ 118.719023 , 139.816103 , 15.089163 ], - [ 132.735321 , 149.054929 , 10.948721 ], - [ 143.164628 , 155.120122 , 7.707249 ], - [ 151.813418 , 159.302301 , 4.701052 ], - [ 158.832697 , 163.950093 , 3.121313 ], - [ 164.984854 , 167.731363 , 1.637445 ], - [ 169.170571 , 170.144777 , 0.572575 ], - [ 172.872471 , 170.402787 , 1.449321 ], - [ 181.530751 , 179.579039 , 1.086827 ], - [ 180.340962 , 161.791994 , 11.464700 ], - [ 172.565436 , 139.415641 , 23.777673 ], - [ 162.247156 , 119.885477 , 35.335121 ], - [ 74.172585 , 65.999080 , 12.384271 ], - [ 100.626570 , 105.242095 , 4.385626 ], - [ 118.719023 , 129.573722 , 8.377237 ], - [ 132.735321 , 142.022857 , 6.539466 ], - [ 143.164628 , 149.987013 , 4.548651 ], - [ 151.813418 , 156.932387 , 3.261895 ], - [ 158.832697 , 161.950891 , 1.925395 ], - [ 164.984854 , 166.244493 , 0.757703 ], - [ 169.170571 , 168.937454 , 0.137990 ], - [ 172.872471 , 170.174723 , 1.585282 ], - [ 181.530751 , 180.595670 , 0.517776 ], - [ 180.340962 , 161.777322 , 11.474810 ], - [ 172.565436 , 139.416628 , 23.776797 ], - [ 162.247156 , 119.914803 , 35.302024 ], - [ 74.172585 , 61.368583 , 20.864099 ], - [ 100.626570 , 99.252149 , 1.384777 ], - [ 118.719023 , 122.849829 , 3.362484 ], - [ 132.735321 , 137.637329 , 3.561540 ], - [ 143.164628 , 147.875713 , 3.185841 ], - [ 151.813418 , 154.781404 , 1.917534 ], - [ 158.832697 , 160.084818 , 0.782161 ], - [ 164.984854 , 165.269065 , 0.171969 ], - [ 169.170571 , 168.580130 , 0.350243 ], - [ 172.872471 , 170.856618 , 1.179851 ], - [ 181.530751 , 181.485729 , 0.024807 ], - [ 180.340962 , 161.795624 , 11.462200 ], - [ 172.565436 , 139.412376 , 23.780571 ], - [ 162.247156 , 119.914803 , 35.302024 ], - [ 74.172585 , 58.655078 , 26.455521 ], - [ 100.626570 , 95.973733 , 4.848031 ], - [ 118.719023 , 119.408556 , 0.577457 ], - [ 132.735321 , 134.902103 , 1.606189 ], - [ 143.164628 , 145.442875 , 1.566421 ], - [ 151.813418 , 153.303090 , 0.971717 ], - [ 158.832697 , 158.972444 , 0.087907 ], - [ 164.984854 , 165.290371 , 0.184837 ], - [ 169.170571 , 168.326957 , 0.501176 ], - [ 172.872471 , 172.681440 , 0.110626 ], - [ 181.530751 , 182.061213 , 0.291365 ], - [ 180.340962 , 161.805228 , 11.455584 ], - [ 172.565436 , 139.451166 , 23.746141 ], - [ 162.247156 , 119.902772 , 35.315600 ], - [ 74.172585 , 54.317928 , 36.552677 ], - [ 100.626570 , 90.924762 , 10.670150 ], - [ 118.719023 , 115.804615 , 2.516660 ], - [ 132.735321 , 131.667834 , 0.810742 ], - [ 143.164628 , 143.353504 , 0.131756 ], - [ 151.813418 , 151.871055 , 0.037951 ], - [ 158.832697 , 158.972444 , 0.087907 ], - [ 164.984854 , 165.332970 , 0.210555 ], - [ 169.170571 , 169.958627 , 0.463675 ], - [ 172.872471 , 174.591476 , 0.984587 ], - [ 181.530751 , 182.627862 , 0.600736 ], - [ 180.340962 , 161.791994 , 11.464700 ], - [ 172.565436 , 139.366537 , 23.821284 ], - [ 162.247156 , 119.882956 , 35.337967 ], - [ 74.172585 , 51.415081 , 44.262312 ], - [ 100.626570 , 88.139705 , 14.167127 ], - [ 118.719023 , 113.272969 , 4.807903 ], - [ 132.735321 , 129.285558 , 2.668328 ], - [ 143.164628 , 141.639008 , 1.077118 ], - [ 151.813418 , 151.139856 , 0.445654 ], - [ 158.832697 , 159.077811 , 0.154085 ], - [ 164.984854 , 166.349944 , 0.820614 ], - [ 169.170571 , 171.699296 , 1.472764 ], - [ 172.872471 , 176.724544 , 2.179704 ], - [ 181.530751 , 183.033936 , 0.821260 ], - [ 180.340962 , 161.805228 , 11.455584 ], - [ 172.565436 , 139.341880 , 23.843195 ], - [ 162.247156 , 119.866098 , 35.357001 ], - [ 74.172585 , 49.394757 , 50.162869 ], - [ 100.626570 , 85.483070 , 17.715203 ], - [ 118.719023 , 110.722034 , 7.222582 ], - [ 132.735321 , 128.407529 , 3.370356 ], - [ 143.164628 , 140.690570 , 1.758510 ], - [ 151.813418 , 151.038030 , 0.513372 ], - [ 158.832697 , 159.896627 , 0.665386 ], - [ 164.984854 , 168.125416 , 1.867988 ], - [ 169.170571 , 173.579086 , 2.539774 ], - [ 172.872471 , 178.889185 , 3.363375 ], - [ 181.530751 , 183.044146 , 0.826792 ], - [ 180.340962 , 161.778554 , 11.473961 ], - [ 172.565436 , 139.305384 , 23.875640 ], - [ 162.247156 , 119.868276 , 35.354542 ], - [ 74.172585 , 48.150355 , 54.043693 ], - [ 100.626570 , 83.680300 , 20.251205 ], - [ 118.719023 , 108.828031 , 9.088644 ], - [ 132.735321 , 126.982834 , 4.530130 ], - [ 143.164628 , 140.271822 , 2.062285 ], - [ 151.813418 , 151.871055 , 0.037951 ], - [ 158.832697 , 161.228617 , 1.486039 ], - [ 164.984854 , 169.848150 , 2.863320 ], - [ 169.170571 , 175.507928 , 3.610867 ], - [ 172.872471 , 180.935750 , 4.456432 ], - [ 181.530751 , 183.039043 , 0.824028 ], - [ 180.340962 , 161.705481 , 11.524334 ], - [ 172.565436 , 139.273208 , 23.904259 ], - [ 162.247156 , 119.959075 , 35.252090 ], - [ 74.172585 , 47.566884 , 55.933243 ], - [ 100.626570 , 82.699087 , 21.677969 ], - [ 118.719023 , 107.658511 , 10.273700 ], - [ 132.735321 , 126.233454 , 5.150669 ], - [ 143.164628 , 140.576453 , 1.841116 ], - [ 151.813418 , 152.719787 , 0.593485 ], - [ 158.832697 , 162.995553 , 2.553969 ], - [ 164.984854 , 171.857872 , 3.999246 ], - [ 169.170571 , 177.664858 , 4.781073 ], - [ 172.872471 , 182.786539 , 5.423850 ], - [ 181.530751 , 184.309522 , 1.507666 ], - [ 180.340962 , 161.643543 , 11.567068 ], - [ 172.565436 , 139.231253 , 23.941595 ], - [ 162.247156 , 119.965390 , 35.244969 ], - [ 74.172585 , 43.226030 , 71.592407 ], - [ 100.626570 , 77.234542 , 30.287003 ], - [ 118.719023 , 103.998937 , 14.154074 ], - [ 132.735321 , 124.711169 , 6.434189 ], - [ 143.164628 , 139.489096 , 2.634995 ], - [ 151.813418 , 152.376815 , 0.369740 ], - [ 158.832697 , 162.771016 , 2.419546 ], - [ 164.984854 , 171.399588 , 3.742561 ], - [ 169.170571 , 176.519214 , 4.163084 ], - [ 172.872471 , 180.536313 , 4.245041 ], - [ 181.530751 , 180.178093 , 0.750734 ], - [ 180.340962 , 160.074815 , 12.660422 ], - [ 172.565436 , 138.305476 , 24.771224 ], - [ 162.247156 , 119.353334 , 35.938520 ], - [ 74.172585 , 43.304897 , 71.279901 ], - [ 100.626570 , 78.454597 , 28.260897 ], - [ 118.719023 , 105.606244 , 12.416671 ], - [ 132.735321 , 125.994568 , 5.350034 ], - [ 143.164628 , 141.582230 , 1.117653 ], - [ 151.813418 , 153.343235 , 0.997643 ], - [ 158.832697 , 162.893544 , 2.492946 ], - [ 164.984854 , 170.999163 , 3.517157 ], - [ 169.170571 , 175.833917 , 3.789568 ], - [ 172.872471 , 179.068771 , 3.460291 ], - [ 181.530751 , 176.723990 , 2.719926 ], - [ 180.340962 , 157.752190 , 14.319149 ], - [ 172.565436 , 137.392795 , 25.600062 ], - [ 162.247156 , 118.903128 , 36.453228 ], - [ 74.172585 , 43.462616 , 70.658354 ], - [ 100.626570 , 78.912756 , 27.516228 ], - [ 118.719023 , 106.612590 , 11.355539 ], - [ 132.735321 , 126.403955 , 5.008836 ], - [ 143.164628 , 142.375639 , 0.554160 ], - [ 151.813418 , 153.724089 , 1.242923 ], - [ 158.832697 , 162.443649 , 2.222895 ], - [ 164.984854 , 169.949698 , 2.921361 ], - [ 169.170571 , 173.598830 , 2.550858 ], - [ 172.872471 , 176.799304 , 2.221068 ], - [ 181.530751 , 173.447298 , 4.660467 ], - [ 180.340962 , 156.392633 , 15.312952 ], - [ 172.565436 , 136.374905 , 26.537530 ], - [ 162.247156 , 118.714142 , 36.670453 ], - [ 1403.330455 , 876.885316 , 60.035803 ], - [ 1901.397958 , 1587.638861 , 19.762624 ], - [ 2232.562804 , 2124.580533 , 5.082522 ], - [ 2471.970560 , 2509.129235 , 1.480939 ], - [ 2650.891041 , 2819.187942 , 5.969694 ], - [ 2785.299006 , 3044.948789 , 8.527230 ], - [ 2886.144180 , 3196.018358 , 9.695632 ], - [ 2960.257561 , 3339.851753 , 11.365600 ], - [ 3012.875689 , 3435.052610 , 12.290261 ], - [ 3047.821242 , 3482.652710 , 12.485640 ], - [ 3044.984927 , 3448.098035 , 11.690883 ], - [ 2877.611282 , 3105.329082 , 7.333129 ], - [ 2641.365086 , 2736.951332 , 3.492435 ], - [ 2382.949281 , 2378.093534 , 0.204187 ] -] //Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff] - diff --git a/benchmarks/CalibGA/datasets/large/output.json b/benchmarks/CalibGA/datasets/large/output.json new file mode 100644 index 0000000..6367af8 --- /dev/null +++ b/benchmarks/CalibGA/datasets/large/output.json @@ -0,0 +1,207 @@ +{ + "a_field": 0.325608, + "b_field": 0.001000, + "sigma_field": 0.009058, + "nu_field": 0.018683, + "rho_field": -0.083963, + "lg_likelyhood": 624.116935, + "swaption_calibration_results": + [ + [ 74.172585 , 115.320470 , 35.681337 ], + [ 100.626570 , 162.945479 , 38.245252 ], + [ 118.719023 , 174.297729 , 31.887223 ], + [ 132.735321 , 171.631308 , 22.662524 ], + [ 143.164628 , 168.408756 , 14.989796 ], + [ 151.813418 , 168.310831 , 9.801754 ], + [ 158.832697 , 169.877089 , 6.501402 ], + [ 164.984854 , 172.511293 , 4.362868 ], + [ 169.170571 , 172.824865 , 2.114449 ], + [ 172.872471 , 172.561368 , 0.180286 ], + [ 181.530751 , 177.275607 , 2.400298 ], + [ 180.340962 , 161.933876 , 11.367038 ], + [ 172.565436 , 139.430038 , 23.764892 ], + [ 162.247156 , 120.029132 , 35.173148 ], + [ 74.172585 , 69.393222 , 6.887362 ], + [ 100.626570 , 116.015964 , 13.264894 ], + [ 118.719023 , 139.816103 , 15.089163 ], + [ 132.735321 , 149.054929 , 10.948721 ], + [ 143.164628 , 155.120122 , 7.707249 ], + [ 151.813418 , 159.302301 , 4.701052 ], + [ 158.832697 , 163.950093 , 3.121313 ], + [ 164.984854 , 167.731363 , 1.637445 ], + [ 169.170571 , 170.144777 , 0.572575 ], + [ 172.872471 , 170.402787 , 1.449321 ], + [ 181.530751 , 179.579039 , 1.086827 ], + [ 180.340962 , 161.791994 , 11.464700 ], + [ 172.565436 , 139.415641 , 23.777673 ], + [ 162.247156 , 119.885477 , 35.335121 ], + [ 74.172585 , 65.999080 , 12.384271 ], + [ 100.626570 , 105.242095 , 4.385626 ], + [ 118.719023 , 129.573722 , 8.377237 ], + [ 132.735321 , 142.022857 , 6.539466 ], + [ 143.164628 , 149.987013 , 4.548651 ], + [ 151.813418 , 156.932387 , 3.261895 ], + [ 158.832697 , 161.950891 , 1.925395 ], + [ 164.984854 , 166.244493 , 0.757703 ], + [ 169.170571 , 168.937454 , 0.137990 ], + [ 172.872471 , 170.174723 , 1.585282 ], + [ 181.530751 , 180.595670 , 0.517776 ], + [ 180.340962 , 161.777322 , 11.474810 ], + [ 172.565436 , 139.416628 , 23.776797 ], + [ 162.247156 , 119.914803 , 35.302024 ], + [ 74.172585 , 61.368583 , 20.864099 ], + [ 100.626570 , 99.252149 , 1.384777 ], + [ 118.719023 , 122.849829 , 3.362484 ], + [ 132.735321 , 137.637329 , 3.561540 ], + [ 143.164628 , 147.875713 , 3.185841 ], + [ 151.813418 , 154.781404 , 1.917534 ], + [ 158.832697 , 160.084818 , 0.782161 ], + [ 164.984854 , 165.269065 , 0.171969 ], + [ 169.170571 , 168.580130 , 0.350243 ], + [ 172.872471 , 170.856618 , 1.179851 ], + [ 181.530751 , 181.485729 , 0.024807 ], + [ 180.340962 , 161.795624 , 11.462200 ], + [ 172.565436 , 139.412376 , 23.780571 ], + [ 162.247156 , 119.914803 , 35.302024 ], + [ 74.172585 , 58.655078 , 26.455521 ], + [ 100.626570 , 95.973733 , 4.848031 ], + [ 118.719023 , 119.408556 , 0.577457 ], + [ 132.735321 , 134.902103 , 1.606189 ], + [ 143.164628 , 145.442875 , 1.566421 ], + [ 151.813418 , 153.303090 , 0.971717 ], + [ 158.832697 , 158.972444 , 0.087907 ], + [ 164.984854 , 165.290371 , 0.184837 ], + [ 169.170571 , 168.326957 , 0.501176 ], + [ 172.872471 , 172.681440 , 0.110626 ], + [ 181.530751 , 182.061213 , 0.291365 ], + [ 180.340962 , 161.805228 , 11.455584 ], + [ 172.565436 , 139.451166 , 23.746141 ], + [ 162.247156 , 119.902772 , 35.315600 ], + [ 74.172585 , 54.317928 , 36.552677 ], + [ 100.626570 , 90.924762 , 10.670150 ], + [ 118.719023 , 115.804615 , 2.516660 ], + [ 132.735321 , 131.667834 , 0.810742 ], + [ 143.164628 , 143.353504 , 0.131756 ], + [ 151.813418 , 151.871055 , 0.037951 ], + [ 158.832697 , 158.972444 , 0.087907 ], + [ 164.984854 , 165.332970 , 0.210555 ], + [ 169.170571 , 169.958627 , 0.463675 ], + [ 172.872471 , 174.591476 , 0.984587 ], + [ 181.530751 , 182.627862 , 0.600736 ], + [ 180.340962 , 161.791994 , 11.464700 ], + [ 172.565436 , 139.366537 , 23.821284 ], + [ 162.247156 , 119.882956 , 35.337967 ], + [ 74.172585 , 51.415081 , 44.262312 ], + [ 100.626570 , 88.139705 , 14.167127 ], + [ 118.719023 , 113.272969 , 4.807903 ], + [ 132.735321 , 129.285558 , 2.668328 ], + [ 143.164628 , 141.639008 , 1.077118 ], + [ 151.813418 , 151.139856 , 0.445654 ], + [ 158.832697 , 159.077811 , 0.154085 ], + [ 164.984854 , 166.349944 , 0.820614 ], + [ 169.170571 , 171.699296 , 1.472764 ], + [ 172.872471 , 176.724544 , 2.179704 ], + [ 181.530751 , 183.033936 , 0.821260 ], + [ 180.340962 , 161.805228 , 11.455584 ], + [ 172.565436 , 139.341880 , 23.843195 ], + [ 162.247156 , 119.866098 , 35.357001 ], + [ 74.172585 , 49.394757 , 50.162869 ], + [ 100.626570 , 85.483070 , 17.715203 ], + [ 118.719023 , 110.722034 , 7.222582 ], + [ 132.735321 , 128.407529 , 3.370356 ], + [ 143.164628 , 140.690570 , 1.758510 ], + [ 151.813418 , 151.038030 , 0.513372 ], + [ 158.832697 , 159.896627 , 0.665386 ], + [ 164.984854 , 168.125416 , 1.867988 ], + [ 169.170571 , 173.579086 , 2.539774 ], + [ 172.872471 , 178.889185 , 3.363375 ], + [ 181.530751 , 183.044146 , 0.826792 ], + [ 180.340962 , 161.778554 , 11.473961 ], + [ 172.565436 , 139.305384 , 23.875640 ], + [ 162.247156 , 119.868276 , 35.354542 ], + [ 74.172585 , 48.150355 , 54.043693 ], + [ 100.626570 , 83.680300 , 20.251205 ], + [ 118.719023 , 108.828031 , 9.088644 ], + [ 132.735321 , 126.982834 , 4.530130 ], + [ 143.164628 , 140.271822 , 2.062285 ], + [ 151.813418 , 151.871055 , 0.037951 ], + [ 158.832697 , 161.228617 , 1.486039 ], + [ 164.984854 , 169.848150 , 2.863320 ], + [ 169.170571 , 175.507928 , 3.610867 ], + [ 172.872471 , 180.935750 , 4.456432 ], + [ 181.530751 , 183.039043 , 0.824028 ], + [ 180.340962 , 161.705481 , 11.524334 ], + [ 172.565436 , 139.273208 , 23.904259 ], + [ 162.247156 , 119.959075 , 35.252090 ], + [ 74.172585 , 47.566884 , 55.933243 ], + [ 100.626570 , 82.699087 , 21.677969 ], + [ 118.719023 , 107.658511 , 10.273700 ], + [ 132.735321 , 126.233454 , 5.150669 ], + [ 143.164628 , 140.576453 , 1.841116 ], + [ 151.813418 , 152.719787 , 0.593485 ], + [ 158.832697 , 162.995553 , 2.553969 ], + [ 164.984854 , 171.857872 , 3.999246 ], + [ 169.170571 , 177.664858 , 4.781073 ], + [ 172.872471 , 182.786539 , 5.423850 ], + [ 181.530751 , 184.309522 , 1.507666 ], + [ 180.340962 , 161.643543 , 11.567068 ], + [ 172.565436 , 139.231253 , 23.941595 ], + [ 162.247156 , 119.965390 , 35.244969 ], + [ 74.172585 , 43.226030 , 71.592407 ], + [ 100.626570 , 77.234542 , 30.287003 ], + [ 118.719023 , 103.998937 , 14.154074 ], + [ 132.735321 , 124.711169 , 6.434189 ], + [ 143.164628 , 139.489096 , 2.634995 ], + [ 151.813418 , 152.376815 , 0.369740 ], + [ 158.832697 , 162.771016 , 2.419546 ], + [ 164.984854 , 171.399588 , 3.742561 ], + [ 169.170571 , 176.519214 , 4.163084 ], + [ 172.872471 , 180.536313 , 4.245041 ], + [ 181.530751 , 180.178093 , 0.750734 ], + [ 180.340962 , 160.074815 , 12.660422 ], + [ 172.565436 , 138.305476 , 24.771224 ], + [ 162.247156 , 119.353334 , 35.938520 ], + [ 74.172585 , 43.304897 , 71.279901 ], + [ 100.626570 , 78.454597 , 28.260897 ], + [ 118.719023 , 105.606244 , 12.416671 ], + [ 132.735321 , 125.994568 , 5.350034 ], + [ 143.164628 , 141.582230 , 1.117653 ], + [ 151.813418 , 153.343235 , 0.997643 ], + [ 158.832697 , 162.893544 , 2.492946 ], + [ 164.984854 , 170.999163 , 3.517157 ], + [ 169.170571 , 175.833917 , 3.789568 ], + [ 172.872471 , 179.068771 , 3.460291 ], + [ 181.530751 , 176.723990 , 2.719926 ], + [ 180.340962 , 157.752190 , 14.319149 ], + [ 172.565436 , 137.392795 , 25.600062 ], + [ 162.247156 , 118.903128 , 36.453228 ], + [ 74.172585 , 43.462616 , 70.658354 ], + [ 100.626570 , 78.912756 , 27.516228 ], + [ 118.719023 , 106.612590 , 11.355539 ], + [ 132.735321 , 126.403955 , 5.008836 ], + [ 143.164628 , 142.375639 , 0.554160 ], + [ 151.813418 , 153.724089 , 1.242923 ], + [ 158.832697 , 162.443649 , 2.222895 ], + [ 164.984854 , 169.949698 , 2.921361 ], + [ 169.170571 , 173.598830 , 2.550858 ], + [ 172.872471 , 176.799304 , 2.221068 ], + [ 181.530751 , 173.447298 , 4.660467 ], + [ 180.340962 , 156.392633 , 15.312952 ], + [ 172.565436 , 136.374905 , 26.537530 ], + [ 162.247156 , 118.714142 , 36.670453 ], + [ 1403.330455 , 876.885316 , 60.035803 ], + [ 1901.397958 , 1587.638861 , 19.762624 ], + [ 2232.562804 , 2124.580533 , 5.082522 ], + [ 2471.970560 , 2509.129235 , 1.480939 ], + [ 2650.891041 , 2819.187942 , 5.969694 ], + [ 2785.299006 , 3044.948789 , 8.527230 ], + [ 2886.144180 , 3196.018358 , 9.695632 ], + [ 2960.257561 , 3339.851753 , 11.365600 ], + [ 3012.875689 , 3435.052610 , 12.290261 ], + [ 3047.821242 , 3482.652710 , 12.485640 ], + [ 3044.984927 , 3448.098035 , 11.690883 ], + [ 2877.611282 , 3105.329082 , 7.333129 ], + [ 2641.365086 , 2736.951332 , 3.492435 ], + [ 2382.949281 , 2378.093534 , 0.204187 ] + ] +} diff --git a/benchmarks/CalibGA/datasets/medium/input.data b/benchmarks/CalibGA/datasets/medium/input.json similarity index 83% rename from benchmarks/CalibGA/datasets/medium/input.data rename to benchmarks/CalibGA/datasets/medium/input.json index 58d5534..d5814b7 100644 --- a/benchmarks/CalibGA/datasets/medium/input.data +++ b/benchmarks/CalibGA/datasets/medium/input.json @@ -1,7 +1,9 @@ -128 // population size -424 // number of iterations of the convergence loop -196 // number of swaption quotes (NUM_SWAP_QUOTES) -[ +{ + "population_size": 128, + "convergence_iterations": 424, + "num_swaption_quotes": 196, + "swaption_quotes": + [ [1.0, 6.0, 1.0, 1.052], [2.0, 6.0, 1.0, 0.81485], [3.0, 6.0, 1.0, 0.6165], @@ -211,33 +213,29 @@ [20.0, 6.0, 30.0, 0.1989], [25.0, 6.0, 30.0, 0.18115], [30.0, 6.0, 30.0, 0.16355] -] // SwaptionQuotes :: REAL[NUM_SWAP_QUOTES,4] - - - -11 // Gauss_DIM: Number of Hermite Coefficients; -[ - 0.0, 0.6568095668820999044613, -0.6568095668820997934390, - -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, - -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, - 3.6684708465595856630159, -3.6684708465595838866591 -] // GaussHermiteCoefs::coefs[Gauss_DIM] - -[ - 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, - 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, - 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, - 1.0065267861723647957461, 1.0065267861723774522886 -] // GaussHermiteCoefs::weights[Gauss_DIM] - - - -30 // SOBOL_BITS_NUM -[ 536870912, 268435456, 134217728, 67108864, 33554432, - 16777216, 8388608, 4194304, 2097152, 1048576, - 524288, 262144, 131072, 65536, 32768, - 16384, 8192, 4096, 2048, 1024, - 512, 256, 128, 64, 32, - 16, 8, 4, 2, 1 -] // SOBOL_DIR_VCT == Sobol Direction Vectors REAL[SOBOL_BITS_NUM] - + ], + + "num_hermite_coefficients": 11, + "hermite_coefficients": + [ 0.0, 0.6568095668820999044613, -0.6568095668820997934390, + -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, + -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, + 3.6684708465595856630159, -3.6684708465595838866591 + ] + "hermite_coefficient_weights": + [ + 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, + 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, + 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, + 1.0065267861723647957461, 1.0065267861723774522886 + ], + "sobol_num_bits": 30, + "sobol_dir_vs": + [ 536870912, 268435456, 134217728, 67108864, 33554432, + 16777216, 8388608, 4194304, 2097152, 1048576, + 524288, 262144, 131072, 65536, 32768, + 16384, 8192, 4096, 2048, 1024, + 512, 256, 128, 64, 32, + 16, 8, 4, 2, 1 + ] +} diff --git a/benchmarks/CalibGA/datasets/medium/output.data b/benchmarks/CalibGA/datasets/medium/output.data deleted file mode 100644 index ee3d804..0000000 --- a/benchmarks/CalibGA/datasets/medium/output.data +++ /dev/null @@ -1,206 +0,0 @@ -0.023511 // a-field of the winning genome -0.964110 // b-field of the winning genome -0.025390 // sigma-field of the winning genome -0.142763 // nu-field of the winning genome --0.912444 // rho-field of the winning genome -504.367344 // LgLikelihood of the winning genome - -[ - [ 157.397565 , 115.320470 , 36.487100 ], - [ 158.760952 , 162.945479 , 2.568054 ], - [ 165.097976 , 174.297729 , 5.278183 ], - [ 175.510974 , 171.631308 , 2.260465 ], - [ 185.096581 , 168.408756 , 9.909120 ], - [ 193.322704 , 168.310831 , 14.860525 ], - [ 199.745999 , 169.877089 , 17.582659 ], - [ 204.980646 , 172.511293 , 18.821581 ], - [ 207.965455 , 172.824865 , 20.333063 ], - [ 210.211604 , 172.561368 , 21.818462 ], - [ 209.496752 , 177.275607 , 18.175735 ], - [ 198.058665 , 161.933876 , 22.308358 ], - [ 180.931070 , 139.430038 , 29.764772 ], - [ 162.740296 , 120.029132 , 35.583998 ], - [ 180.828953 , 136.735565 , 32.247198 ], - [ 197.570095 , 228.603138 , 13.575073 ], - [ 231.652896 , 275.866189 , 16.027079 ], - [ 267.035700 , 293.303444 , 8.955825 ], - [ 296.574053 , 305.655752 , 2.971218 ], - [ 320.041550 , 313.896508 , 1.957665 ], - [ 338.547315 , 323.484107 , 4.656553 ], - [ 352.372052 , 330.054072 , 6.761916 ], - [ 362.299599 , 335.261016 , 8.064935 ], - [ 369.752884 , 335.769411 , 10.121075 ], - [ 379.269057 , 354.321026 , 7.041081 ], - [ 362.343709 , 318.366856 , 13.813264 ], - [ 333.799298 , 274.710927 , 21.509290 ], - [ 301.589807 , 236.227803 , 27.669057 ], - [ 172.210684 , 192.203184 , 10.401753 ], - [ 227.955695 , 306.754568 , 25.687922 ], - [ 299.934061 , 377.675217 , 20.584129 ], - [ 362.136697 , 412.847194 , 12.283115 ], - [ 410.791383 , 436.793689 , 5.952995 ], - [ 448.676865 , 457.418930 , 1.911173 ], - [ 477.384722 , 472.046625 , 1.130841 ], - [ 499.183038 , 483.257228 , 3.295514 ], - [ 515.122617 , 491.981354 , 4.703687 ], - [ 527.462746 , 496.017051 , 6.339640 ], - [ 543.860701 , 526.391523 , 3.318666 ], - [ 520.875868 , 470.271579 , 10.760652 ], - [ 480.620983 , 406.010507 , 18.376489 ], - [ 434.912156 , 349.521869 , 24.430599 ], - [ 175.817605 , 234.956228 , 25.170060 ], - [ 281.983907 , 379.997542 , 25.793229 ], - [ 386.986699 , 470.343801 , 17.722590 ], - [ 470.710384 , 525.541048 , 10.433184 ], - [ 534.924952 , 566.158092 , 5.516682 ], - [ 583.629049 , 592.597274 , 1.513376 ], - [ 620.647894 , 612.901965 , 1.263812 ], - [ 648.638703 , 631.047390 , 2.787637 ], - [ 669.568744 , 645.427184 , 3.740400 ], - [ 684.736202 , 654.142965 , 4.676843 ], - [ 704.954513 , 694.837660 , 1.456002 ], - [ 674.726162 , 617.784741 , 9.217033 ], - [ 622.980296 , 533.755298 , 16.716461 ], - [ 563.277986 , 459.106740 , 22.689984 ], - [ 203.693343 , 276.585395 , 26.354266 ], - [ 354.131456 , 452.559843 , 21.749253 ], - [ 484.673742 , 563.065703 , 13.922347 ], - [ 585.697217 , 634.734726 , 7.725670 ], - [ 661.769994 , 685.829366 , 3.508070 ], - [ 719.413650 , 722.893858 , 0.481427 ], - [ 763.082942 , 749.627445 , 1.794958 ], - [ 796.409044 , 777.716103 , 2.403569 ], - [ 820.552620 , 793.738233 , 3.378241 ], - [ 838.266809 , 814.271603 , 2.946831 ], - [ 860.928096 , 858.501503 , 0.282654 ], - [ 824.031243 , 761.317980 , 8.237460 ], - [ 760.549282 , 657.575731 , 15.659573 ], - [ 687.849618 , 565.396155 , 21.657994 ], - [ 248.505950 , 302.881789 , 17.952826 ], - [ 434.064679 , 507.004879 , 14.386489 ], - [ 585.500618 , 646.006214 , 9.366101 ], - [ 700.296189 , 732.520960 , 4.399160 ], - [ 786.607031 , 799.352396 , 1.594461 ], - [ 851.884344 , 846.847045 , 0.594830 ], - [ 901.714482 , 886.814283 , 1.680194 ], - [ 939.036181 , 919.813612 , 2.089833 ], - [ 966.478792 , 947.705019 , 1.980972 ], - [ 986.566873 , 973.538216 , 1.338279 ], - [ 1012.284446 , 1018.774022 , 0.636999 ], - [ 968.529570 , 900.113746 , 7.600798 ], - [ 894.291386 , 777.120699 , 15.077540 ], - [ 809.047014 , 668.478449 , 21.028137 ], - [ 301.083452 , 329.637202 , 8.662175 ], - [ 515.826990 , 565.288233 , 8.749739 ], - [ 684.590231 , 726.481623 , 5.766339 ], - [ 811.675874 , 826.947428 , 1.846738 ], - [ 907.198294 , 908.089329 , 0.098122 ], - [ 979.880266 , 969.342726 , 1.087081 ], - [ 1034.847365 , 1020.253181 , 1.430447 ], - [ 1076.438202 , 1064.021851 , 1.166926 ], - [ 1107.169795 , 1100.814671 , 0.577311 ], - [ 1130.070001 , 1133.431347 , 0.296564 ], - [ 1158.486301 , 1173.896940 , 1.312776 ], - [ 1108.583472 , 1034.952546 , 7.114425 ], - [ 1023.739103 , 893.361764 , 14.594014 ], - [ 926.405670 , 768.766979 , 20.505393 ], - [ 356.263480 , 356.827677 , 0.158115 ], - [ 595.869060 , 617.529617 , 3.507614 ], - [ 780.304180 , 799.855865 , 2.444401 ], - [ 918.734772 , 925.119226 , 0.690122 ], - [ 1023.322212 , 1016.348538 , 0.686150 ], - [ 1102.541547 , 1091.098583 , 1.048756 ], - [ 1162.947248 , 1155.093079 , 0.679960 ], - [ 1208.815882 , 1211.268964 , 0.202522 ], - [ 1243.236271 , 1253.935152 , 0.853224 ], - [ 1268.212772 , 1292.295297 , 1.863547 ], - [ 1299.649410 , 1322.310735 , 1.713767 ], - [ 1243.247078 , 1165.542638 , 6.666804 ], - [ 1147.864983 , 1006.341959 , 14.063115 ], - [ 1037.737231 , 865.928307 , 19.841010 ], - [ 411.077411 , 385.708301 , 6.577279 ], - [ 673.052319 , 670.320845 , 0.407487 ], - [ 872.045789 , 871.766681 , 0.032016 ], - [ 1021.605672 , 1014.726741 , 0.677910 ], - [ 1134.443556 , 1123.647094 , 0.960841 ], - [ 1220.439476 , 1216.562717 , 0.318665 ], - [ 1286.238835 , 1291.521445 , 0.409022 ], - [ 1336.683060 , 1357.265823 , 1.516487 ], - [ 1373.994926 , 1405.905836 , 2.269776 ], - [ 1401.325508 , 1449.385390 , 3.315880 ], - [ 1434.917178 , 1466.233816 , 2.135856 ], - [ 1371.509883 , 1292.197312 , 6.137807 ], - [ 1264.493843 , 1115.647694 , 13.341680 ], - [ 1141.954794 , 960.931878 , 18.838267 ], - [ 464.369070 , 417.340024 , 11.268760 ], - [ 746.924235 , 725.581250 , 2.941502 ], - [ 960.029056 , 944.790788 , 1.612872 ], - [ 1119.892820 , 1104.819384 , 1.364335 ], - [ 1241.112296 , 1233.382877 , 0.626684 ], - [ 1333.761841 , 1339.925477 , 0.459998 ], - [ 1405.131840 , 1430.418237 , 1.767762 ], - [ 1459.286022 , 1504.133035 , 2.981586 ], - [ 1499.614145 , 1558.787332 , 3.796104 ], - [ 1529.026303 , 1603.723695 , 4.657747 ], - [ 1563.609130 , 1617.465612 , 3.329683 ], - [ 1491.509266 , 1414.735272 , 5.426739 ], - [ 1372.969721 , 1221.580427 , 12.392904 ], - [ 1238.265153 , 1052.546538 , 17.644694 ], - [ 697.607256 , 530.230908 , 31.566690 ], - [ 1069.199975 , 947.532306 , 12.840477 ], - [ 1345.044085 , 1275.884477 , 5.420523 ], - [ 1552.898160 , 1525.869310 , 1.771374 ], - [ 1711.010275 , 1711.039174 , 0.001689 ], - [ 1831.352455 , 1869.396149 , 2.035079 ], - [ 1922.088013 , 1996.914758 , 3.747118 ], - [ 1989.466621 , 2097.112670 , 5.133060 ], - [ 2037.854512 , 2165.268099 , 5.884425 ], - [ 2071.221986 , 2214.863774 , 6.485355 ], - [ 2085.093776 , 2210.469050 , 5.671886 ], - [ 1964.177356 , 1958.551506 , 0.287245 ], - [ 1790.799073 , 1696.520335 , 5.557183 ], - [ 1603.204230 , 1464.255987 , 9.489341 ], - [ 880.212905 , 661.437438 , 33.075761 ], - [ 1324.703181 , 1198.312686 , 10.547372 ], - [ 1650.853118 , 1613.025965 , 2.345105 ], - [ 1893.136248 , 1919.256956 , 1.360980 ], - [ 2073.770699 , 2162.521880 , 4.104059 ], - [ 2206.964010 , 2342.159055 , 5.772240 ], - [ 2304.126621 , 2488.030128 , 7.391531 ], - [ 2373.154766 , 2604.805409 , 8.893203 ], - [ 2420.005673 , 2685.680924 , 9.892286 ], - [ 2448.863167 , 2735.089966 , 10.464987 ], - [ 2422.889960 , 2699.275863 , 10.239261 ], - [ 2253.562833 , 2403.016190 , 6.219407 ], - [ 2034.519052 , 2098.532599 , 3.050396 ], - [ 1806.243306 , 1816.122090 , 0.543949 ], - [ 1023.193649 , 776.276975 , 31.807806 ], - [ 1525.146555 , 1409.444747 , 8.209035 ], - [ 1886.122306 , 1904.185866 , 0.948624 ], - [ 2148.130146 , 2251.764495 , 4.602362 ], - [ 2338.190044 , 2542.942445 , 8.051791 ], - [ 2474.348845 , 2745.634809 , 9.880628 ], - [ 2570.187192 , 2901.373100 , 11.414799 ], - [ 2635.146070 , 3027.489893 , 12.959377 ], - [ 2675.747420 , 3100.613536 , 13.702647 ], - [ 2697.190433 , 3157.776542 , 14.585773 ], - [ 2625.390139 , 3097.907042 , 15.252779 ], - [ 2405.414280 , 2785.983861 , 13.660150 ], - [ 2140.334096 , 2435.764543 , 12.128859 ], - [ 1918.911826 , 2120.329248 , 9.499346 ], - [ 1134.844622 , 876.885316 , 29.417679 ], - [ 1679.290415 , 1587.638861 , 5.772821 ], - [ 2062.069732 , 2124.580533 , 2.942266 ], - [ 2333.411719 , 2509.129235 , 7.003127 ], - [ 2525.701359 , 2819.187942 , 10.410323 ], - [ 2659.649760 , 3044.948789 , 12.653711 ], - [ 2750.616462 , 3196.018358 , 13.936150 ], - [ 2808.740074 , 3339.851753 , 15.902253 ], - [ 2841.435455 , 3435.052610 , 17.281166 ], - [ 2854.008165 , 3482.652710 , 18.050739 ], - [ 2726.384653 , 3448.098035 , 20.930767 ], - [ 2458.831616 , 3105.329082 , 20.818968 ], - [ 2239.608440 , 2736.951332 , 18.171419 ], - [ 1972.754114 , 2378.093534 , 17.044722 ] -] //Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff] - diff --git a/benchmarks/CalibGA/datasets/medium/output.json b/benchmarks/CalibGA/datasets/medium/output.json new file mode 100644 index 0000000..54af5f1 --- /dev/null +++ b/benchmarks/CalibGA/datasets/medium/output.json @@ -0,0 +1,208 @@ +{ + "a_field": 0.023511, + "b_field": 0.964110, + "sigma_field": 0.025390, + "nu_field": 0.142763, + "rho_field": -0.912444, + "lg_likelyhood": 504.367344, + + "swaption_calibration_result": + [ + [ 157.397565 , 115.320470 , 36.487100 ], + [ 158.760952 , 162.945479 , 2.568054 ], + [ 165.097976 , 174.297729 , 5.278183 ], + [ 175.510974 , 171.631308 , 2.260465 ], + [ 185.096581 , 168.408756 , 9.909120 ], + [ 193.322704 , 168.310831 , 14.860525 ], + [ 199.745999 , 169.877089 , 17.582659 ], + [ 204.980646 , 172.511293 , 18.821581 ], + [ 207.965455 , 172.824865 , 20.333063 ], + [ 210.211604 , 172.561368 , 21.818462 ], + [ 209.496752 , 177.275607 , 18.175735 ], + [ 198.058665 , 161.933876 , 22.308358 ], + [ 180.931070 , 139.430038 , 29.764772 ], + [ 162.740296 , 120.029132 , 35.583998 ], + [ 180.828953 , 136.735565 , 32.247198 ], + [ 197.570095 , 228.603138 , 13.575073 ], + [ 231.652896 , 275.866189 , 16.027079 ], + [ 267.035700 , 293.303444 , 8.955825 ], + [ 296.574053 , 305.655752 , 2.971218 ], + [ 320.041550 , 313.896508 , 1.957665 ], + [ 338.547315 , 323.484107 , 4.656553 ], + [ 352.372052 , 330.054072 , 6.761916 ], + [ 362.299599 , 335.261016 , 8.064935 ], + [ 369.752884 , 335.769411 , 10.121075 ], + [ 379.269057 , 354.321026 , 7.041081 ], + [ 362.343709 , 318.366856 , 13.813264 ], + [ 333.799298 , 274.710927 , 21.509290 ], + [ 301.589807 , 236.227803 , 27.669057 ], + [ 172.210684 , 192.203184 , 10.401753 ], + [ 227.955695 , 306.754568 , 25.687922 ], + [ 299.934061 , 377.675217 , 20.584129 ], + [ 362.136697 , 412.847194 , 12.283115 ], + [ 410.791383 , 436.793689 , 5.952995 ], + [ 448.676865 , 457.418930 , 1.911173 ], + [ 477.384722 , 472.046625 , 1.130841 ], + [ 499.183038 , 483.257228 , 3.295514 ], + [ 515.122617 , 491.981354 , 4.703687 ], + [ 527.462746 , 496.017051 , 6.339640 ], + [ 543.860701 , 526.391523 , 3.318666 ], + [ 520.875868 , 470.271579 , 10.760652 ], + [ 480.620983 , 406.010507 , 18.376489 ], + [ 434.912156 , 349.521869 , 24.430599 ], + [ 175.817605 , 234.956228 , 25.170060 ], + [ 281.983907 , 379.997542 , 25.793229 ], + [ 386.986699 , 470.343801 , 17.722590 ], + [ 470.710384 , 525.541048 , 10.433184 ], + [ 534.924952 , 566.158092 , 5.516682 ], + [ 583.629049 , 592.597274 , 1.513376 ], + [ 620.647894 , 612.901965 , 1.263812 ], + [ 648.638703 , 631.047390 , 2.787637 ], + [ 669.568744 , 645.427184 , 3.740400 ], + [ 684.736202 , 654.142965 , 4.676843 ], + [ 704.954513 , 694.837660 , 1.456002 ], + [ 674.726162 , 617.784741 , 9.217033 ], + [ 622.980296 , 533.755298 , 16.716461 ], + [ 563.277986 , 459.106740 , 22.689984 ], + [ 203.693343 , 276.585395 , 26.354266 ], + [ 354.131456 , 452.559843 , 21.749253 ], + [ 484.673742 , 563.065703 , 13.922347 ], + [ 585.697217 , 634.734726 , 7.725670 ], + [ 661.769994 , 685.829366 , 3.508070 ], + [ 719.413650 , 722.893858 , 0.481427 ], + [ 763.082942 , 749.627445 , 1.794958 ], + [ 796.409044 , 777.716103 , 2.403569 ], + [ 820.552620 , 793.738233 , 3.378241 ], + [ 838.266809 , 814.271603 , 2.946831 ], + [ 860.928096 , 858.501503 , 0.282654 ], + [ 824.031243 , 761.317980 , 8.237460 ], + [ 760.549282 , 657.575731 , 15.659573 ], + [ 687.849618 , 565.396155 , 21.657994 ], + [ 248.505950 , 302.881789 , 17.952826 ], + [ 434.064679 , 507.004879 , 14.386489 ], + [ 585.500618 , 646.006214 , 9.366101 ], + [ 700.296189 , 732.520960 , 4.399160 ], + [ 786.607031 , 799.352396 , 1.594461 ], + [ 851.884344 , 846.847045 , 0.594830 ], + [ 901.714482 , 886.814283 , 1.680194 ], + [ 939.036181 , 919.813612 , 2.089833 ], + [ 966.478792 , 947.705019 , 1.980972 ], + [ 986.566873 , 973.538216 , 1.338279 ], + [ 1012.284446 , 1018.774022 , 0.636999 ], + [ 968.529570 , 900.113746 , 7.600798 ], + [ 894.291386 , 777.120699 , 15.077540 ], + [ 809.047014 , 668.478449 , 21.028137 ], + [ 301.083452 , 329.637202 , 8.662175 ], + [ 515.826990 , 565.288233 , 8.749739 ], + [ 684.590231 , 726.481623 , 5.766339 ], + [ 811.675874 , 826.947428 , 1.846738 ], + [ 907.198294 , 908.089329 , 0.098122 ], + [ 979.880266 , 969.342726 , 1.087081 ], + [ 1034.847365 , 1020.253181 , 1.430447 ], + [ 1076.438202 , 1064.021851 , 1.166926 ], + [ 1107.169795 , 1100.814671 , 0.577311 ], + [ 1130.070001 , 1133.431347 , 0.296564 ], + [ 1158.486301 , 1173.896940 , 1.312776 ], + [ 1108.583472 , 1034.952546 , 7.114425 ], + [ 1023.739103 , 893.361764 , 14.594014 ], + [ 926.405670 , 768.766979 , 20.505393 ], + [ 356.263480 , 356.827677 , 0.158115 ], + [ 595.869060 , 617.529617 , 3.507614 ], + [ 780.304180 , 799.855865 , 2.444401 ], + [ 918.734772 , 925.119226 , 0.690122 ], + [ 1023.322212 , 1016.348538 , 0.686150 ], + [ 1102.541547 , 1091.098583 , 1.048756 ], + [ 1162.947248 , 1155.093079 , 0.679960 ], + [ 1208.815882 , 1211.268964 , 0.202522 ], + [ 1243.236271 , 1253.935152 , 0.853224 ], + [ 1268.212772 , 1292.295297 , 1.863547 ], + [ 1299.649410 , 1322.310735 , 1.713767 ], + [ 1243.247078 , 1165.542638 , 6.666804 ], + [ 1147.864983 , 1006.341959 , 14.063115 ], + [ 1037.737231 , 865.928307 , 19.841010 ], + [ 411.077411 , 385.708301 , 6.577279 ], + [ 673.052319 , 670.320845 , 0.407487 ], + [ 872.045789 , 871.766681 , 0.032016 ], + [ 1021.605672 , 1014.726741 , 0.677910 ], + [ 1134.443556 , 1123.647094 , 0.960841 ], + [ 1220.439476 , 1216.562717 , 0.318665 ], + [ 1286.238835 , 1291.521445 , 0.409022 ], + [ 1336.683060 , 1357.265823 , 1.516487 ], + [ 1373.994926 , 1405.905836 , 2.269776 ], + [ 1401.325508 , 1449.385390 , 3.315880 ], + [ 1434.917178 , 1466.233816 , 2.135856 ], + [ 1371.509883 , 1292.197312 , 6.137807 ], + [ 1264.493843 , 1115.647694 , 13.341680 ], + [ 1141.954794 , 960.931878 , 18.838267 ], + [ 464.369070 , 417.340024 , 11.268760 ], + [ 746.924235 , 725.581250 , 2.941502 ], + [ 960.029056 , 944.790788 , 1.612872 ], + [ 1119.892820 , 1104.819384 , 1.364335 ], + [ 1241.112296 , 1233.382877 , 0.626684 ], + [ 1333.761841 , 1339.925477 , 0.459998 ], + [ 1405.131840 , 1430.418237 , 1.767762 ], + [ 1459.286022 , 1504.133035 , 2.981586 ], + [ 1499.614145 , 1558.787332 , 3.796104 ], + [ 1529.026303 , 1603.723695 , 4.657747 ], + [ 1563.609130 , 1617.465612 , 3.329683 ], + [ 1491.509266 , 1414.735272 , 5.426739 ], + [ 1372.969721 , 1221.580427 , 12.392904 ], + [ 1238.265153 , 1052.546538 , 17.644694 ], + [ 697.607256 , 530.230908 , 31.566690 ], + [ 1069.199975 , 947.532306 , 12.840477 ], + [ 1345.044085 , 1275.884477 , 5.420523 ], + [ 1552.898160 , 1525.869310 , 1.771374 ], + [ 1711.010275 , 1711.039174 , 0.001689 ], + [ 1831.352455 , 1869.396149 , 2.035079 ], + [ 1922.088013 , 1996.914758 , 3.747118 ], + [ 1989.466621 , 2097.112670 , 5.133060 ], + [ 2037.854512 , 2165.268099 , 5.884425 ], + [ 2071.221986 , 2214.863774 , 6.485355 ], + [ 2085.093776 , 2210.469050 , 5.671886 ], + [ 1964.177356 , 1958.551506 , 0.287245 ], + [ 1790.799073 , 1696.520335 , 5.557183 ], + [ 1603.204230 , 1464.255987 , 9.489341 ], + [ 880.212905 , 661.437438 , 33.075761 ], + [ 1324.703181 , 1198.312686 , 10.547372 ], + [ 1650.853118 , 1613.025965 , 2.345105 ], + [ 1893.136248 , 1919.256956 , 1.360980 ], + [ 2073.770699 , 2162.521880 , 4.104059 ], + [ 2206.964010 , 2342.159055 , 5.772240 ], + [ 2304.126621 , 2488.030128 , 7.391531 ], + [ 2373.154766 , 2604.805409 , 8.893203 ], + [ 2420.005673 , 2685.680924 , 9.892286 ], + [ 2448.863167 , 2735.089966 , 10.464987 ], + [ 2422.889960 , 2699.275863 , 10.239261 ], + [ 2253.562833 , 2403.016190 , 6.219407 ], + [ 2034.519052 , 2098.532599 , 3.050396 ], + [ 1806.243306 , 1816.122090 , 0.543949 ], + [ 1023.193649 , 776.276975 , 31.807806 ], + [ 1525.146555 , 1409.444747 , 8.209035 ], + [ 1886.122306 , 1904.185866 , 0.948624 ], + [ 2148.130146 , 2251.764495 , 4.602362 ], + [ 2338.190044 , 2542.942445 , 8.051791 ], + [ 2474.348845 , 2745.634809 , 9.880628 ], + [ 2570.187192 , 2901.373100 , 11.414799 ], + [ 2635.146070 , 3027.489893 , 12.959377 ], + [ 2675.747420 , 3100.613536 , 13.702647 ], + [ 2697.190433 , 3157.776542 , 14.585773 ], + [ 2625.390139 , 3097.907042 , 15.252779 ], + [ 2405.414280 , 2785.983861 , 13.660150 ], + [ 2140.334096 , 2435.764543 , 12.128859 ], + [ 1918.911826 , 2120.329248 , 9.499346 ], + [ 1134.844622 , 876.885316 , 29.417679 ], + [ 1679.290415 , 1587.638861 , 5.772821 ], + [ 2062.069732 , 2124.580533 , 2.942266 ], + [ 2333.411719 , 2509.129235 , 7.003127 ], + [ 2525.701359 , 2819.187942 , 10.410323 ], + [ 2659.649760 , 3044.948789 , 12.653711 ], + [ 2750.616462 , 3196.018358 , 13.936150 ], + [ 2808.740074 , 3339.851753 , 15.902253 ], + [ 2841.435455 , 3435.052610 , 17.281166 ], + [ 2854.008165 , 3482.652710 , 18.050739 ], + [ 2726.384653 , 3448.098035 , 20.930767 ], + [ 2458.831616 , 3105.329082 , 20.818968 ], + [ 2239.608440 , 2736.951332 , 18.171419 ], + [ 1972.754114 , 2378.093534 , 17.044722 ] + ] +} diff --git a/benchmarks/CalibGA/datasets/small/input.data b/benchmarks/CalibGA/datasets/small/input.json similarity index 83% rename from benchmarks/CalibGA/datasets/small/input.data rename to benchmarks/CalibGA/datasets/small/input.json index 2ccd109..217e36a 100644 --- a/benchmarks/CalibGA/datasets/small/input.data +++ b/benchmarks/CalibGA/datasets/small/input.json @@ -1,7 +1,9 @@ -128 // population size -424 // number of iterations of the convergence loop -192 // number of swaption quotes (NUM_SWAP_QUOTES) -[ +{ + "population_size" : 128, + "convergence_iterations": 424, + "num_swaption_quotes": 192, + "swaption_quotes": + [ [5.0, 6.0, 32.0, 0.38295], [6.0, 6.0, 32.0, 0.3325], [7.0, 6.0, 32.0, 0.3016], @@ -207,33 +209,29 @@ [20.0, 6.0, 32.0, 0.1989], [25.0, 6.0, 32.0, 0.18115], [30.0, 6.0, 32.0, 0.16355] -] // SwaptionQuotes :: REAL[NUM_SWAP_QUOTES,4] - - - -11 // Gauss_DIM: Number of Hermite Coefficients; -[ - 0.0, 0.6568095668820999044613, -0.6568095668820997934390, - -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, - -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, - 3.6684708465595856630159, -3.6684708465595838866591 -] // GaussHermiteCoefs::coefs[Gauss_DIM] - -[ - 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, - 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, - 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, - 1.0065267861723647957461, 1.0065267861723774522886 -] // GaussHermiteCoefs::weights[Gauss_DIM] - - - -30 // SOBOL_BITS_NUM -[ 536870912, 268435456, 134217728, 67108864, 33554432, - 16777216, 8388608, 4194304, 2097152, 1048576, - 524288, 262144, 131072, 65536, 32768, - 16384, 8192, 4096, 2048, 1024, - 512, 256, 128, 64, 32, - 16, 8, 4, 2, 1 -] // SOBOL_DIR_VCT == Sobol Direction Vectors REAL[SOBOL_BITS_NUM] - + ], + + "num_hermite_coefficients": 11, + "hermite_coefficients": + [ 0.0, 0.6568095668820999044613, -0.6568095668820997934390, + -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, + -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, + 3.6684708465595856630159, -3.6684708465595838866591 + ], + "hermite_coefficient_weights": + [ + 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, + 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, + 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, + 1.0065267861723647957461, 1.0065267861723774522886 + ], + "sobol_num_bits": 30, + "sobol_dir_vs": + [ 536870912, 268435456, 134217728, 67108864, 33554432, + 16777216, 8388608, 4194304, 2097152, 1048576, + 524288, 262144, 131072, 65536, 32768, + 16384, 8192, 4096, 2048, 1024, + 512, 256, 128, 64, 32, + 16, 8, 4, 2, 1 + ] +} diff --git a/benchmarks/CalibGA/datasets/small/output.data b/benchmarks/CalibGA/datasets/small/output.data deleted file mode 100644 index 5b50f30..0000000 --- a/benchmarks/CalibGA/datasets/small/output.data +++ /dev/null @@ -1,202 +0,0 @@ -0.354136 // a-field of the winning genome -0.040196 // b-field of the winning genome -0.199936 // sigma-field of the winning genome -0.057156 // nu-field of the winning genome --0.999000 // rho-field of the winning genome -382.042219 // LgLikelihood of the winning genome - -[ - [ 3018.728472 , 3517.865132 , 14.188624 ], - [ 3258.265121 , 3515.819590 , 7.325588 ], - [ 3430.596870 , 3548.536924 , 3.323625 ], - [ 3549.010001 , 3593.863556 , 1.248059 ], - [ 3624.740401 , 3610.112568 , 0.405191 ], - [ 3666.381633 , 3604.608406 , 1.713729 ], - [ 3571.630074 , 3703.083453 , 3.549836 ], - [ 3257.030584 , 3373.508169 , 3.452714 ], - [ 2891.629540 , 2912.533049 , 0.717709 ], - [ 2534.324414 , 2507.270448 , 1.079021 ], - [ 1084.972858 , 1449.544560 , 25.150776 ], - [ 1743.886842 , 2423.439993 , 28.040849 ], - [ 2275.408269 , 2920.597501 , 22.091001 ], - [ 2695.763026 , 3105.205858 , 13.185690 ], - [ 3018.728472 , 3240.280860 , 6.837444 ], - [ 3258.265121 , 3327.641768 , 2.084859 ], - [ 3430.596870 , 3424.728779 , 0.171345 ], - [ 3549.010001 , 3494.285048 , 1.566127 ], - [ 3624.740401 , 3554.128611 , 1.986754 ], - [ 3666.381633 , 3559.518143 , 3.002190 ], - [ 3571.630074 , 3751.199477 , 4.786986 ], - [ 3257.030584 , 3370.552399 , 3.368048 ], - [ 2891.629540 , 2912.232318 , 0.707457 ], - [ 2534.324414 , 2504.269663 , 1.200140 ], - [ 1084.972858 , 1378.644830 , 21.301496 ], - [ 1743.886842 , 2198.386263 , 20.674230 ], - [ 2275.408269 , 2706.645952 , 15.932549 ], - [ 2695.763026 , 2958.709328 , 8.887196 ], - [ 3018.728472 , 3133.056112 , 3.649077 ], - [ 3258.265121 , 3278.136979 , 0.606194 ], - [ 3430.596870 , 3382.967768 , 1.407909 ], - [ 3549.010001 , 3463.309642 , 2.474522 ], - [ 3624.740401 , 3528.909020 , 2.715609 ], - [ 3666.381633 , 3554.754142 , 3.140231 ], - [ 3571.630074 , 3772.435734 , 5.322971 ], - [ 3257.030584 , 3370.246729 , 3.359284 ], - [ 2891.629540 , 2912.252929 , 0.708159 ], - [ 2534.324414 , 2504.882260 , 1.175391 ], - [ 1084.972858 , 1281.919076 , 15.363389 ], - [ 1743.886842 , 2073.263185 , 15.886856 ], - [ 2275.408269 , 2566.191567 , 11.331317 ], - [ 2695.763026 , 2867.347248 , 5.984075 ], - [ 3018.728472 , 3088.953478 , 2.273424 ], - [ 3258.265121 , 3233.205420 , 0.775073 ], - [ 3430.596870 , 3343.987631 , 2.589999 ], - [ 3549.010001 , 3442.988908 , 3.079333 ], - [ 3624.740401 , 3521.444936 , 2.933326 ], - [ 3666.381633 , 3568.998156 , 2.728594 ], - [ 3571.630074 , 3791.028049 , 5.787295 ], - [ 3257.030584 , 3370.628011 , 3.370215 ], - [ 2891.629540 , 2912.164124 , 0.705131 ], - [ 2534.324414 , 2504.882260 , 1.175391 ], - [ 1084.972858 , 1225.237085 , 11.447925 ], - [ 1743.886842 , 2004.780849 , 13.013592 ], - [ 2275.408269 , 2494.307342 , 8.775946 ], - [ 2695.763026 , 2810.365310 , 4.077843 ], - [ 3018.728472 , 3038.134293 , 0.638741 ], - [ 3258.265121 , 3202.325140 , 1.746855 ], - [ 3430.596870 , 3320.751432 , 3.307849 ], - [ 3549.010001 , 3443.432773 , 3.066046 ], - [ 3624.740401 , 3516.156446 , 3.088143 ], - [ 3666.381633 , 3607.116588 , 1.643003 ], - [ 3571.630074 , 3803.049254 , 6.085096 ], - [ 3257.030584 , 3370.828084 , 3.375951 ], - [ 2891.629540 , 2912.974390 , 0.732751 ], - [ 2534.324414 , 2504.630938 , 1.185543 ], - [ 1084.972858 , 1134.639011 , 4.377265 ], - [ 1743.886842 , 1899.313643 , 8.183314 ], - [ 2275.408269 , 2419.025155 , 5.936974 ], - [ 2695.763026 , 2742.986972 , 1.721625 ], - [ 3018.728472 , 2994.489746 , 0.809444 ], - [ 3258.265121 , 3172.411575 , 2.706255 ], - [ 3430.596870 , 3320.751432 , 3.307849 ], - [ 3549.010001 , 3444.320223 , 3.039490 ], - [ 3624.740401 , 3550.240141 , 2.098457 ], - [ 3666.381633 , 3647.015035 , 0.531026 ], - [ 3571.630074 , 3814.885885 , 6.376490 ], - [ 3257.030584 , 3370.552399 , 3.368048 ], - [ 2891.629540 , 2911.206593 , 0.672472 ], - [ 2534.324414 , 2504.217002 , 1.202268 ], - [ 1084.972858 , 1074.001880 , 1.021505 ], - [ 1743.886842 , 1841.137026 , 5.282072 ], - [ 2275.408269 , 2366.141972 , 3.834669 ], - [ 2695.763026 , 2693.357899 , 0.089298 ], - [ 3018.728472 , 2958.675900 , 2.029711 ], - [ 3258.265121 , 3157.137683 , 3.203137 ], - [ 3430.596870 , 3322.952427 , 3.239422 ], - [ 3549.010001 , 3465.506463 , 2.409562 ], - [ 3624.740401 , 3586.600714 , 1.063394 ], - [ 3666.381633 , 3691.572363 , 0.682385 ], - [ 3571.630074 , 3823.368315 , 6.584201 ], - [ 3257.030584 , 3370.828084 , 3.375951 ], - [ 2891.629540 , 2910.691533 , 0.654896 ], - [ 2534.324414 , 2503.864870 , 1.216501 ], - [ 1084.972858 , 1031.799638 , 5.153444 ], - [ 1743.886842 , 1785.642974 , 2.338437 ], - [ 2275.408269 , 2312.855880 , 1.619107 ], - [ 2695.763026 , 2675.066265 , 0.773692 ], - [ 3018.728472 , 2938.864109 , 2.717525 ], - [ 3258.265121 , 3155.010653 , 3.272714 ], - [ 3430.596870 , 3340.056551 , 2.710742 ], - [ 3549.010001 , 3502.494224 , 1.328076 ], - [ 3624.740401 , 3625.867380 , 0.031082 ], - [ 3666.381633 , 3736.789226 , 1.884174 ], - [ 3571.630074 , 3823.581590 , 6.589411 ], - [ 3257.030584 , 3370.272400 , 3.360020 ], - [ 2891.629540 , 2909.929175 , 0.628869 ], - [ 2534.324414 , 2503.910349 , 1.214663 ], - [ 1084.972858 , 1005.805504 , 7.871040 ], - [ 1743.886842 , 1747.985187 , 0.234461 ], - [ 2275.408269 , 2273.292342 , 0.093078 ], - [ 2695.763026 , 2645.386108 , 1.904331 ], - [ 3018.728472 , 2930.116957 , 3.024163 ], - [ 3258.265121 , 3172.411575 , 2.706255 ], - [ 3430.596870 , 3367.880279 , 1.862198 ], - [ 3549.010001 , 3538.383298 , 0.300327 ], - [ 3624.740401 , 3666.158666 , 1.129746 ], - [ 3666.381633 , 3779.539619 , 2.993962 ], - [ 3571.630074 , 3823.474996 , 6.586807 ], - [ 3257.030584 , 3368.750108 , 3.316349 ], - [ 2891.629540 , 2909.257048 , 0.605911 ], - [ 2534.324414 , 2505.807033 , 1.138052 ], - [ 1084.972858 , 993.617470 , 9.194221 ], - [ 1743.886842 , 1727.488773 , 0.949243 ], - [ 2275.408269 , 2248.862409 , 1.180413 ], - [ 2695.763026 , 2629.774561 , 2.509282 ], - [ 3018.728472 , 2936.480336 , 2.800909 ], - [ 3258.265121 , 3190.140619 , 2.135470 ], - [ 3430.596870 , 3404.789548 , 0.757971 ], - [ 3549.010001 , 3580.251079 , 0.872595 ], - [ 3624.740401 , 3711.214444 , 2.330074 ], - [ 3666.381633 , 3818.200480 , 3.976188 ], - [ 3571.630074 , 3850.013841 , 7.230721 ], - [ 3257.030584 , 3367.459771 , 3.279302 ], - [ 2891.629540 , 2908.380656 , 0.575960 ], - [ 2534.324414 , 2505.938966 , 1.132727 ], - [ 1084.972858 , 902.942022 , 20.159748 ], - [ 1743.886842 , 1613.340705 , 8.091666 ], - [ 2275.408269 , 2172.418130 , 4.740806 ], - [ 2695.763026 , 2598.061356 , 3.760561 ], - [ 3018.728472 , 2913.766713 , 3.602271 ], - [ 3258.265121 , 3182.976328 , 2.365358 ], - [ 3430.596870 , 3400.099228 , 0.896963 ], - [ 3549.010001 , 3570.703828 , 0.607550 ], - [ 3624.740401 , 3687.283264 , 1.696177 ], - [ 3666.381633 , 3771.195830 , 2.779336 ], - [ 3571.630074 , 3763.713038 , 5.103550 ], - [ 3257.030584 , 3334.779031 , 2.331442 ], - [ 2891.629540 , 2889.042259 , 0.089555 ], - [ 2534.324414 , 2493.153817 , 1.651346 ], - [ 1084.972858 , 904.589468 , 19.940912 ], - [ 1743.886842 , 1638.826250 , 6.410722 ], - [ 2275.408269 , 2205.992913 , 3.146672 ], - [ 2695.763026 , 2624.797947 , 2.703640 ], - [ 3018.728472 , 2957.489864 , 2.070628 ], - [ 3258.265121 , 3203.163735 , 1.720218 ], - [ 3430.596870 , 3402.658698 , 0.821069 ], - [ 3549.010001 , 3562.361919 , 0.374805 ], - [ 3624.740401 , 3672.968205 , 1.313047 ], - [ 3666.381633 , 3740.540582 , 1.982573 ], - [ 3571.630074 , 3691.560802 , 3.248781 ], - [ 3257.030584 , 3286.392655 , 0.893444 ], - [ 2891.629540 , 2869.977384 , 0.754436 ], - [ 2534.324414 , 2483.749516 , 2.036232 ], - [ 1084.972858 , 907.884031 , 19.505666 ], - [ 1743.886842 , 1648.396668 , 5.792912 ], - [ 2275.408269 , 2227.014322 , 2.173042 ], - [ 2695.763026 , 2633.326538 , 2.371012 ], - [ 3018.728472 , 2974.063271 , 1.501824 ], - [ 3258.265121 , 3211.119331 , 1.468204 ], - [ 3430.596870 , 3393.260902 , 1.100298 ], - [ 3549.010001 , 3540.498793 , 0.240396 ], - [ 3624.740401 , 3626.279806 , 0.042451 ], - [ 3666.381633 , 3693.134011 , 0.724381 ], - [ 3571.630074 , 3623.114464 , 1.420998 ], - [ 3257.030584 , 3258.069505 , 0.031888 ], - [ 2891.629540 , 2848.714834 , 1.506458 ], - [ 2534.324414 , 2479.801834 , 2.198667 ], - [ 1084.972858 , 911.883978 , 18.981459 ], - [ 1743.886842 , 1651.005456 , 5.625747 ], - [ 2275.408269 , 2209.253519 , 2.994439 ], - [ 2695.763026 , 2609.128016 , 3.320458 ], - [ 3018.728472 , 2931.708709 , 2.968227 ], - [ 3258.265121 , 3166.480230 , 2.898641 ], - [ 3430.596870 , 3323.392404 , 3.225754 ], - [ 3549.010001 , 3472.958132 , 2.189830 ], - [ 3624.740401 , 3572.154059 , 1.472119 ], - [ 3666.381633 , 3621.653997 , 1.235006 ], - [ 3571.630074 , 3585.518458 , 0.387347 ], - [ 3257.030584 , 3229.088800 , 0.865315 ], - [ 2891.629540 , 2846.189831 , 1.596510 ], - [ 2534.324414 , 2473.009131 , 2.479380 ] -] //Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff] - diff --git a/benchmarks/CalibGA/datasets/small/output.json b/benchmarks/CalibGA/datasets/small/output.json new file mode 100644 index 0000000..a1acf89 --- /dev/null +++ b/benchmarks/CalibGA/datasets/small/output.json @@ -0,0 +1,203 @@ +{ + "a_field": 0.354136, + "b_field": 0.040196, + "sigma_field": 0.199936, + "nu_field": 0.057156, + "rho_field": -0.999000, + "lg_likelyhood": 382.042219, + "swaption_calibration_result": + [ + [ 3018.728472 , 3517.865132 , 14.188624 ], + [ 3258.265121 , 3515.819590 , 7.325588 ], + [ 3430.596870 , 3548.536924 , 3.323625 ], + [ 3549.010001 , 3593.863556 , 1.248059 ], + [ 3624.740401 , 3610.112568 , 0.405191 ], + [ 3666.381633 , 3604.608406 , 1.713729 ], + [ 3571.630074 , 3703.083453 , 3.549836 ], + [ 3257.030584 , 3373.508169 , 3.452714 ], + [ 2891.629540 , 2912.533049 , 0.717709 ], + [ 2534.324414 , 2507.270448 , 1.079021 ], + [ 1084.972858 , 1449.544560 , 25.150776 ], + [ 1743.886842 , 2423.439993 , 28.040849 ], + [ 2275.408269 , 2920.597501 , 22.091001 ], + [ 2695.763026 , 3105.205858 , 13.185690 ], + [ 3018.728472 , 3240.280860 , 6.837444 ], + [ 3258.265121 , 3327.641768 , 2.084859 ], + [ 3430.596870 , 3424.728779 , 0.171345 ], + [ 3549.010001 , 3494.285048 , 1.566127 ], + [ 3624.740401 , 3554.128611 , 1.986754 ], + [ 3666.381633 , 3559.518143 , 3.002190 ], + [ 3571.630074 , 3751.199477 , 4.786986 ], + [ 3257.030584 , 3370.552399 , 3.368048 ], + [ 2891.629540 , 2912.232318 , 0.707457 ], + [ 2534.324414 , 2504.269663 , 1.200140 ], + [ 1084.972858 , 1378.644830 , 21.301496 ], + [ 1743.886842 , 2198.386263 , 20.674230 ], + [ 2275.408269 , 2706.645952 , 15.932549 ], + [ 2695.763026 , 2958.709328 , 8.887196 ], + [ 3018.728472 , 3133.056112 , 3.649077 ], + [ 3258.265121 , 3278.136979 , 0.606194 ], + [ 3430.596870 , 3382.967768 , 1.407909 ], + [ 3549.010001 , 3463.309642 , 2.474522 ], + [ 3624.740401 , 3528.909020 , 2.715609 ], + [ 3666.381633 , 3554.754142 , 3.140231 ], + [ 3571.630074 , 3772.435734 , 5.322971 ], + [ 3257.030584 , 3370.246729 , 3.359284 ], + [ 2891.629540 , 2912.252929 , 0.708159 ], + [ 2534.324414 , 2504.882260 , 1.175391 ], + [ 1084.972858 , 1281.919076 , 15.363389 ], + [ 1743.886842 , 2073.263185 , 15.886856 ], + [ 2275.408269 , 2566.191567 , 11.331317 ], + [ 2695.763026 , 2867.347248 , 5.984075 ], + [ 3018.728472 , 3088.953478 , 2.273424 ], + [ 3258.265121 , 3233.205420 , 0.775073 ], + [ 3430.596870 , 3343.987631 , 2.589999 ], + [ 3549.010001 , 3442.988908 , 3.079333 ], + [ 3624.740401 , 3521.444936 , 2.933326 ], + [ 3666.381633 , 3568.998156 , 2.728594 ], + [ 3571.630074 , 3791.028049 , 5.787295 ], + [ 3257.030584 , 3370.628011 , 3.370215 ], + [ 2891.629540 , 2912.164124 , 0.705131 ], + [ 2534.324414 , 2504.882260 , 1.175391 ], + [ 1084.972858 , 1225.237085 , 11.447925 ], + [ 1743.886842 , 2004.780849 , 13.013592 ], + [ 2275.408269 , 2494.307342 , 8.775946 ], + [ 2695.763026 , 2810.365310 , 4.077843 ], + [ 3018.728472 , 3038.134293 , 0.638741 ], + [ 3258.265121 , 3202.325140 , 1.746855 ], + [ 3430.596870 , 3320.751432 , 3.307849 ], + [ 3549.010001 , 3443.432773 , 3.066046 ], + [ 3624.740401 , 3516.156446 , 3.088143 ], + [ 3666.381633 , 3607.116588 , 1.643003 ], + [ 3571.630074 , 3803.049254 , 6.085096 ], + [ 3257.030584 , 3370.828084 , 3.375951 ], + [ 2891.629540 , 2912.974390 , 0.732751 ], + [ 2534.324414 , 2504.630938 , 1.185543 ], + [ 1084.972858 , 1134.639011 , 4.377265 ], + [ 1743.886842 , 1899.313643 , 8.183314 ], + [ 2275.408269 , 2419.025155 , 5.936974 ], + [ 2695.763026 , 2742.986972 , 1.721625 ], + [ 3018.728472 , 2994.489746 , 0.809444 ], + [ 3258.265121 , 3172.411575 , 2.706255 ], + [ 3430.596870 , 3320.751432 , 3.307849 ], + [ 3549.010001 , 3444.320223 , 3.039490 ], + [ 3624.740401 , 3550.240141 , 2.098457 ], + [ 3666.381633 , 3647.015035 , 0.531026 ], + [ 3571.630074 , 3814.885885 , 6.376490 ], + [ 3257.030584 , 3370.552399 , 3.368048 ], + [ 2891.629540 , 2911.206593 , 0.672472 ], + [ 2534.324414 , 2504.217002 , 1.202268 ], + [ 1084.972858 , 1074.001880 , 1.021505 ], + [ 1743.886842 , 1841.137026 , 5.282072 ], + [ 2275.408269 , 2366.141972 , 3.834669 ], + [ 2695.763026 , 2693.357899 , 0.089298 ], + [ 3018.728472 , 2958.675900 , 2.029711 ], + [ 3258.265121 , 3157.137683 , 3.203137 ], + [ 3430.596870 , 3322.952427 , 3.239422 ], + [ 3549.010001 , 3465.506463 , 2.409562 ], + [ 3624.740401 , 3586.600714 , 1.063394 ], + [ 3666.381633 , 3691.572363 , 0.682385 ], + [ 3571.630074 , 3823.368315 , 6.584201 ], + [ 3257.030584 , 3370.828084 , 3.375951 ], + [ 2891.629540 , 2910.691533 , 0.654896 ], + [ 2534.324414 , 2503.864870 , 1.216501 ], + [ 1084.972858 , 1031.799638 , 5.153444 ], + [ 1743.886842 , 1785.642974 , 2.338437 ], + [ 2275.408269 , 2312.855880 , 1.619107 ], + [ 2695.763026 , 2675.066265 , 0.773692 ], + [ 3018.728472 , 2938.864109 , 2.717525 ], + [ 3258.265121 , 3155.010653 , 3.272714 ], + [ 3430.596870 , 3340.056551 , 2.710742 ], + [ 3549.010001 , 3502.494224 , 1.328076 ], + [ 3624.740401 , 3625.867380 , 0.031082 ], + [ 3666.381633 , 3736.789226 , 1.884174 ], + [ 3571.630074 , 3823.581590 , 6.589411 ], + [ 3257.030584 , 3370.272400 , 3.360020 ], + [ 2891.629540 , 2909.929175 , 0.628869 ], + [ 2534.324414 , 2503.910349 , 1.214663 ], + [ 1084.972858 , 1005.805504 , 7.871040 ], + [ 1743.886842 , 1747.985187 , 0.234461 ], + [ 2275.408269 , 2273.292342 , 0.093078 ], + [ 2695.763026 , 2645.386108 , 1.904331 ], + [ 3018.728472 , 2930.116957 , 3.024163 ], + [ 3258.265121 , 3172.411575 , 2.706255 ], + [ 3430.596870 , 3367.880279 , 1.862198 ], + [ 3549.010001 , 3538.383298 , 0.300327 ], + [ 3624.740401 , 3666.158666 , 1.129746 ], + [ 3666.381633 , 3779.539619 , 2.993962 ], + [ 3571.630074 , 3823.474996 , 6.586807 ], + [ 3257.030584 , 3368.750108 , 3.316349 ], + [ 2891.629540 , 2909.257048 , 0.605911 ], + [ 2534.324414 , 2505.807033 , 1.138052 ], + [ 1084.972858 , 993.617470 , 9.194221 ], + [ 1743.886842 , 1727.488773 , 0.949243 ], + [ 2275.408269 , 2248.862409 , 1.180413 ], + [ 2695.763026 , 2629.774561 , 2.509282 ], + [ 3018.728472 , 2936.480336 , 2.800909 ], + [ 3258.265121 , 3190.140619 , 2.135470 ], + [ 3430.596870 , 3404.789548 , 0.757971 ], + [ 3549.010001 , 3580.251079 , 0.872595 ], + [ 3624.740401 , 3711.214444 , 2.330074 ], + [ 3666.381633 , 3818.200480 , 3.976188 ], + [ 3571.630074 , 3850.013841 , 7.230721 ], + [ 3257.030584 , 3367.459771 , 3.279302 ], + [ 2891.629540 , 2908.380656 , 0.575960 ], + [ 2534.324414 , 2505.938966 , 1.132727 ], + [ 1084.972858 , 902.942022 , 20.159748 ], + [ 1743.886842 , 1613.340705 , 8.091666 ], + [ 2275.408269 , 2172.418130 , 4.740806 ], + [ 2695.763026 , 2598.061356 , 3.760561 ], + [ 3018.728472 , 2913.766713 , 3.602271 ], + [ 3258.265121 , 3182.976328 , 2.365358 ], + [ 3430.596870 , 3400.099228 , 0.896963 ], + [ 3549.010001 , 3570.703828 , 0.607550 ], + [ 3624.740401 , 3687.283264 , 1.696177 ], + [ 3666.381633 , 3771.195830 , 2.779336 ], + [ 3571.630074 , 3763.713038 , 5.103550 ], + [ 3257.030584 , 3334.779031 , 2.331442 ], + [ 2891.629540 , 2889.042259 , 0.089555 ], + [ 2534.324414 , 2493.153817 , 1.651346 ], + [ 1084.972858 , 904.589468 , 19.940912 ], + [ 1743.886842 , 1638.826250 , 6.410722 ], + [ 2275.408269 , 2205.992913 , 3.146672 ], + [ 2695.763026 , 2624.797947 , 2.703640 ], + [ 3018.728472 , 2957.489864 , 2.070628 ], + [ 3258.265121 , 3203.163735 , 1.720218 ], + [ 3430.596870 , 3402.658698 , 0.821069 ], + [ 3549.010001 , 3562.361919 , 0.374805 ], + [ 3624.740401 , 3672.968205 , 1.313047 ], + [ 3666.381633 , 3740.540582 , 1.982573 ], + [ 3571.630074 , 3691.560802 , 3.248781 ], + [ 3257.030584 , 3286.392655 , 0.893444 ], + [ 2891.629540 , 2869.977384 , 0.754436 ], + [ 2534.324414 , 2483.749516 , 2.036232 ], + [ 1084.972858 , 907.884031 , 19.505666 ], + [ 1743.886842 , 1648.396668 , 5.792912 ], + [ 2275.408269 , 2227.014322 , 2.173042 ], + [ 2695.763026 , 2633.326538 , 2.371012 ], + [ 3018.728472 , 2974.063271 , 1.501824 ], + [ 3258.265121 , 3211.119331 , 1.468204 ], + [ 3430.596870 , 3393.260902 , 1.100298 ], + [ 3549.010001 , 3540.498793 , 0.240396 ], + [ 3624.740401 , 3626.279806 , 0.042451 ], + [ 3666.381633 , 3693.134011 , 0.724381 ], + [ 3571.630074 , 3623.114464 , 1.420998 ], + [ 3257.030584 , 3258.069505 , 0.031888 ], + [ 2891.629540 , 2848.714834 , 1.506458 ], + [ 2534.324414 , 2479.801834 , 2.198667 ], + [ 1084.972858 , 911.883978 , 18.981459 ], + [ 1743.886842 , 1651.005456 , 5.625747 ], + [ 2275.408269 , 2209.253519 , 2.994439 ], + [ 2695.763026 , 2609.128016 , 3.320458 ], + [ 3018.728472 , 2931.708709 , 2.968227 ], + [ 3258.265121 , 3166.480230 , 2.898641 ], + [ 3430.596870 , 3323.392404 , 3.225754 ], + [ 3549.010001 , 3472.958132 , 2.189830 ], + [ 3624.740401 , 3572.154059 , 1.472119 ], + [ 3666.381633 , 3621.653997 , 1.235006 ], + [ 3571.630074 , 3585.518458 , 0.387347 ], + [ 3257.030584 , 3229.088800 , 0.865315 ], + [ 2891.629540 , 2846.189831 , 1.596510 ], + [ 2534.324414 , 2473.009131 , 2.479380 ] + ] +} diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/FindBestKer.h b/benchmarks/CalibGA/implementations/cpp_opencl_all/FindBestKer.h similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/FindBestKer.h rename to benchmarks/CalibGA/implementations/cpp_opencl_all/FindBestKer.h diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgFlat.h b/benchmarks/CalibGA/implementations/cpp_opencl_all/GenAlgFlat.h similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgFlat.h rename to benchmarks/CalibGA/implementations/cpp_opencl_all/GenAlgFlat.h diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgKers.h b/benchmarks/CalibGA/implementations/cpp_opencl_all/GenAlgKers.h similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/GenAlgKers.h rename to benchmarks/CalibGA/implementations/cpp_opencl_all/GenAlgKers.h diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/MainKer.h b/benchmarks/CalibGA/implementations/cpp_opencl_all/MainKer.h similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/MainKer.h rename to benchmarks/CalibGA/implementations/cpp_opencl_all/MainKer.h diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/Makefile b/benchmarks/CalibGA/implementations/cpp_opencl_all/Makefile similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/Makefile rename to benchmarks/CalibGA/implementations/cpp_opencl_all/Makefile diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/BestIndValRedKer.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/BestIndValRedKer.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/BestIndValRedKer.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/BestIndValRedKer.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/CalibKers.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/CalibKers.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/CalibKers.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/CalibKers.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Date.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/Date.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Date.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/Date.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/ExactYhat.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/ExactYhat.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/ExactYhat.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/ExactYhat.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/G2ppUtil.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/G2ppUtil.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/G2ppUtil.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/G2ppUtil.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/GenAlg.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/GenAlg.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/GenAlg.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/GenAlg.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Reductions.cl b/benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/Reductions.cl similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SrcCL/Reductions.cl rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SrcCL/Reductions.cl diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/SwapCalib.cpp b/benchmarks/CalibGA/implementations/cpp_opencl_all/SwapCalib.cpp similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/SwapCalib.cpp rename to benchmarks/CalibGA/implementations/cpp_opencl_all/SwapCalib.cpp diff --git a/benchmarks/CalibGA/implementations/All_CppOpenCL/UtilGPGPU.h b/benchmarks/CalibGA/implementations/cpp_opencl_all/UtilGPGPU.h similarity index 100% rename from benchmarks/CalibGA/implementations/All_CppOpenCL/UtilGPGPU.h rename to benchmarks/CalibGA/implementations/cpp_opencl_all/UtilGPGPU.h diff --git a/benchmarks/CalibGA/implementations/cpp_opencl_all/instantiate b/benchmarks/CalibGA/implementations/cpp_opencl_all/instantiate new file mode 100755 index 0000000..5b32e00 --- /dev/null +++ b/benchmarks/CalibGA/implementations/cpp_opencl_all/instantiate @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile . + +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run <(NUM_SWAP_QUOTES), 3); + + fclose(result); } - return 1; + return 0; } @@ -59,4 +69,3 @@ void test_all() { test_pricer_of_swaption(); } #endif - diff --git a/benchmarks/CalibGA/implementations/Outer_CppOpenMP/UtilCPU.h b/benchmarks/CalibGA/implementations/cpp_openmp_outer/UtilCPU.h similarity index 100% rename from benchmarks/CalibGA/implementations/Outer_CppOpenMP/UtilCPU.h rename to benchmarks/CalibGA/implementations/cpp_openmp_outer/UtilCPU.h diff --git a/benchmarks/CalibGA/implementations/cpp_openmp_outer/instantiate b/benchmarks/CalibGA/implementations/cpp_openmp_outer/instantiate new file mode 100755 index 0000000..67b239b --- /dev/null +++ b/benchmarks/CalibGA/implementations/cpp_openmp_outer/instantiate @@ -0,0 +1,35 @@ +#!/bin/sh + +set -e + +cp $FINPAR_LIB_DIR/setup.mk . +cp $FINPAR_LIB_DIR/include/ParserC.h . +cp $FINPAR_LIB_DIR/include/Util.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/KerConsts.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Date.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/GenAlgUtil.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/Candidate.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/IrregShape.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/EvalGenomeInl.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/G2PP.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/G2ppUtil.h . +cp $FINPAR_BENCHMARK_LIB_DIR/include/MathModule.h . +cp $FINPAR_IMPLEMENTATION/GenAlgFlat.h . +cp $FINPAR_IMPLEMENTATION/UtilCPU.h . +cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile . + +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > input.data +$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk +NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) + +cat > run < -#include -#include -#include "GenAlgUtil.h" - -//using namespace std; - -#if WITH_FLOAT - #define read_real read_float -#else - #define read_real read_double -#endif - -/***********************************/ -/********** READ DATA SET **********/ -/***********************************/ - -void readDataSet( UINT& pop_size, - UINT& num_conv_iters, - UINT& num_swap_quotes, - REAL*& swaption_quotes, // [num_swap_quotes,4] - - UINT& num_hermitians, - REAL*& hermite_coefs, // [num_hermite] - REAL*& hermite_weights, // [num_hermite] - - UINT& num_sobol_bits, - int*& sobol_dirs_vct // [num_sobol_bits] -) { - int64_t shape[3]; - bool atr_ok = true; - - if ( read_int( static_cast( &pop_size ) ) || - read_int( static_cast( &num_conv_iters ) ) ) { - fprintf(stderr, "Syntax error when reading population size or convergence-loop count!\n"); - exit(1); - } - atr_ok = (pop_size >= 64) && (num_conv_iters >= 100); - assert(atr_ok && "Population size < 64 OR convergence-loop count < 100!\n"); - - { // swaption quotes - if ( read_int( static_cast( &num_swap_quotes ) ) ) { - fprintf(stderr, "Syntax error when reading NUM_SWAP_QUOTES.\n"); - exit(1); - } - atr_ok = num_swap_quotes > 0; - assert(atr_ok && "Number of swaptions LESS or equal to ZERO!\n"); - - if ( read_array(sizeof(REAL), read_real, (void**)&swaption_quotes, shape, 2) ) { - fprintf(stderr, "Syntax error when reading the swaption quotes.\n"); - exit(1); - } - atr_ok = ( shape[1] == 4 && shape[0] == num_swap_quotes ); - assert(atr_ok && "Incorrect shape of the swaption quotes!"); - } - - { // hermitean coefficients - if ( read_int( static_cast( &num_hermitians ) ) ) { - fprintf(stderr, "Syntax error when reading number of hermitians.\n"); - exit(1); - } - atr_ok = num_hermitians > 0; - assert(atr_ok && "Number of hermitians LESS or equal to ZERO!\n"); - - if ( read_array(sizeof(REAL), read_real, (void**)&hermite_coefs, shape, 1) ) { - fprintf(stderr, "Syntax error when reading the hermitian coeficients.\n"); - exit(1); - } - atr_ok = ( shape[0] == num_hermitians ); - assert(atr_ok && "Incorrect shape of the hermitian coefficients!"); - - if ( read_array(sizeof(REAL), read_real, (void**)&hermite_weights, shape, 1) ) { - fprintf(stderr, "Syntax error when reading the hermitian weights.\n"); - exit(1); - } - atr_ok = ( shape[0] == num_hermitians ); - assert(atr_ok && "Incorrect shape of the hermitian weights!"); - } - - { // sobol direction vectors! - if ( read_int( static_cast( &num_sobol_bits ) ) ) { - fprintf(stderr, "Syntax error when reading NUM_SOBOL_BITS.\n"); - exit(1); - } - atr_ok = num_sobol_bits > 0; - assert(atr_ok && "Number of sobol bits LESS or equal to ZERO!\n"); - - if ( read_array(sizeof(int), read_int, (void**)&sobol_dirs_vct, shape, 1) ) { - fprintf(stderr, "Syntax error when reading sobol direction vectors.\n"); - exit(1); - } - atr_ok = ( shape[0] == num_sobol_bits ); - assert( atr_ok && "Incorrect shape of sobol direction vectors!" ); - } -} - -REAL* readOutput( const int& N, REAL& ref_logLik ) { - REAL* result; - int64_t shape[3]; - - REAL ref_a, ref_b, ref_sigma, ref_nu, ref_rho; - - // reading the reference genome! - if( read_real( &ref_a ) || read_real( &ref_b ) || - read_real( &ref_sigma ) || read_real( &ref_nu ) || - read_real( &ref_rho ) || read_real( &ref_logLik ) ) { - fprintf(stderr, "Syntax error when reading the reference genome or its likelihood.\n"); - exit(1); - } - - // reading the standard output - if ( read_array(sizeof(REAL), read_real, (void**)&result, shape, 2) ) { - fprintf(stderr, "Syntax error when reading the output.\n"); - exit(1); - } - bool ok = ( shape[0] == N ) && ( shape[1] == 3 ); - assert(ok && "Incorrect shape of the reference array result!"); - - return result; -} - -bool validate( const REAL& logLik, const REAL* res, const int& N ) { - bool is_valid = true; - - REAL ref_logLik; - REAL* ref_res = readOutput( N, ref_logLik ); - - if( fabs(ref_logLik - logLik) > 1.0 ) { - is_valid = false; - fprintf(stderr, "Difference in logLikelihood > 1.0: result logLik %f, reference logLik = %f!\n", - logLik, ref_logLik ); - return is_valid; - } else if ( logLik < ref_logLik && fabs(ref_logLik - logLik) > 0.5 ) { - is_valid = false; - fprintf(stderr, "Result likelihood is worse than reference with more than 0.5: result logLik %f, reference logLik = %f!\n", - logLik, ref_logLik ); - return is_valid; - } - - for ( int i = 0; i < N; i ++ ) { - REAL lgLik_cur = logLikelihood( res[3*i+1], res[3*i]); - REAL lgLik_ref = logLikelihood(ref_res[3*i+1],ref_res[3*i]); - REAL diff_curr_lgLik = (lgLik_cur > lgLik_ref) ? - 0.0 : lgLik_ref - lgLik_cur ; - - if (diff_curr_lgLik > 0.7) { - is_valid = false; - fprintf(stderr, "Error[%d] = %f, Acceptable = 1.1!\n", - i, diff_curr_lgLik ); - break; - } - } - - return is_valid; -} - -void writeStatsAndResult( const bool& valid, - const REAL& wg_a, - const REAL& wg_b, - const REAL& wg_sigma, - const REAL& wg_nu, - const REAL& wg_rho, - const REAL& wg_logLik, - const REAL* calib_arr, - const int & NUM_SWAP_QUOTES, - const bool& is_gpu, - const int & P, - const unsigned long int& elapsed -) { - // print stats to stdout - fprintf(stdout, "// Dataset with Number of Swaption Quotes = %d.\n", - NUM_SWAP_QUOTES ); - - if(valid) { fprintf(stdout, "1\t\t// VALID Result,\n"); } - else { fprintf(stdout, "0\t\t// INVALID Result,\n"); } - - fprintf(stdout, "%ld\t\t// Runtime in microseconds,\n", elapsed); - if(is_gpu) fprintf(stdout, "%d\t\t// GPU Threads,\n\n", P); - else fprintf(stdout, "%d\t\t// CPU Threads,\n\n", P); - - // write the genome - write_scal(&wg_a, "a-field of the winning genome"); - write_scal(&wg_b, "b-field of the winning genome"); - write_scal(&wg_sigma, "sigma-field of the winning genome"); - write_scal(&wg_nu, "nu-field of the winning genome"); - write_scal(&wg_rho, "rho-field of the winning genome"); - write_scal(&wg_logLik,"LgLikelihood of the winning genome"); - - // write the result - write_2Darr( calib_arr, static_cast(NUM_SWAP_QUOTES), 3, - "Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff]" ); -} - -#endif // PARSE_INPUT - diff --git a/benchmarks/CalibGA/includeC/Candidate.h b/benchmarks/CalibGA/lib/include/Candidate.h similarity index 100% rename from benchmarks/CalibGA/includeC/Candidate.h rename to benchmarks/CalibGA/lib/include/Candidate.h diff --git a/benchmarks/CalibGA/includeC/Constants.h b/benchmarks/CalibGA/lib/include/Constants.h similarity index 100% rename from benchmarks/CalibGA/includeC/Constants.h rename to benchmarks/CalibGA/lib/include/Constants.h diff --git a/benchmarks/CalibGA/includeC/Date.h b/benchmarks/CalibGA/lib/include/Date.h similarity index 100% rename from benchmarks/CalibGA/includeC/Date.h rename to benchmarks/CalibGA/lib/include/Date.h diff --git a/benchmarks/CalibGA/includeC/EvalGenomeInl.h b/benchmarks/CalibGA/lib/include/EvalGenomeInl.h similarity index 100% rename from benchmarks/CalibGA/includeC/EvalGenomeInl.h rename to benchmarks/CalibGA/lib/include/EvalGenomeInl.h diff --git a/benchmarks/CalibGA/includeC/G2PP.h b/benchmarks/CalibGA/lib/include/G2PP.h similarity index 100% rename from benchmarks/CalibGA/includeC/G2PP.h rename to benchmarks/CalibGA/lib/include/G2PP.h diff --git a/benchmarks/CalibGA/includeC/G2ppUtil.h b/benchmarks/CalibGA/lib/include/G2ppUtil.h similarity index 100% rename from benchmarks/CalibGA/includeC/G2ppUtil.h rename to benchmarks/CalibGA/lib/include/G2ppUtil.h diff --git a/benchmarks/CalibGA/includeC/GenAlgUtil.h b/benchmarks/CalibGA/lib/include/GenAlgUtil.h similarity index 100% rename from benchmarks/CalibGA/includeC/GenAlgUtil.h rename to benchmarks/CalibGA/lib/include/GenAlgUtil.h diff --git a/benchmarks/CalibGA/includeC/IrregShape.h b/benchmarks/CalibGA/lib/include/IrregShape.h similarity index 100% rename from benchmarks/CalibGA/includeC/IrregShape.h rename to benchmarks/CalibGA/lib/include/IrregShape.h diff --git a/benchmarks/CalibGA/includeC/KerConsts.h b/benchmarks/CalibGA/lib/include/KerConsts.h similarity index 100% rename from benchmarks/CalibGA/includeC/KerConsts.h rename to benchmarks/CalibGA/lib/include/KerConsts.h diff --git a/benchmarks/CalibGA/includeC/MathModule.h b/benchmarks/CalibGA/lib/include/MathModule.h similarity index 100% rename from benchmarks/CalibGA/includeC/MathModule.h rename to benchmarks/CalibGA/lib/include/MathModule.h diff --git a/benchmarks/CalibGA/lib/include/ParseInput.h b/benchmarks/CalibGA/lib/include/ParseInput.h new file mode 100644 index 0000000..efddda2 --- /dev/null +++ b/benchmarks/CalibGA/lib/include/ParseInput.h @@ -0,0 +1,102 @@ +#ifndef PARSE_INPUT +#define PARSE_INPUT + +#include "ParserC.h" +#include +#include +#include +#include "GenAlgUtil.h" + +//using namespace std; + +#if WITH_FLOAT + #define read_real read_float +#else + #define read_real read_double +#endif + +/***********************************/ +/********** READ DATA SET **********/ +/***********************************/ + +void readDataSet( UINT& pop_size, + UINT& num_conv_iters, + UINT& num_swap_quotes, + REAL*& swaption_quotes, // [num_swap_quotes,4] + + UINT& num_hermitians, + REAL*& hermite_coefs, // [num_hermite] + REAL*& hermite_weights, // [num_hermite] + + UINT& num_sobol_bits, + int*& sobol_dirs_vct // [num_sobol_bits] +) { + int64_t shape[3]; + bool atr_ok = true; + + if ( read_int( static_cast( &pop_size ) ) || + read_int( static_cast( &num_conv_iters ) ) ) { + fprintf(stderr, "Syntax error when reading population size or convergence-loop count!\n"); + exit(1); + } + atr_ok = (pop_size >= 64) && (num_conv_iters >= 100); + assert(atr_ok && "Population size < 64 OR convergence-loop count < 100!\n"); + + { // swaption quotes + if ( read_int( static_cast( &num_swap_quotes ) ) ) { + fprintf(stderr, "Syntax error when reading NUM_SWAP_QUOTES.\n"); + exit(1); + } + atr_ok = num_swap_quotes > 0; + assert(atr_ok && "Number of swaptions LESS or equal to ZERO!\n"); + + if ( read_array(sizeof(REAL), read_real, (void**)&swaption_quotes, shape, 2) ) { + fprintf(stderr, "Syntax error when reading the swaption quotes.\n"); + exit(1); + } + atr_ok = ( shape[1] == 4 && shape[0] == num_swap_quotes ); + assert(atr_ok && "Incorrect shape of the swaption quotes!"); + } + + { // hermitean coefficients + if ( read_int( static_cast( &num_hermitians ) ) ) { + fprintf(stderr, "Syntax error when reading number of hermitians.\n"); + exit(1); + } + atr_ok = num_hermitians > 0; + assert(atr_ok && "Number of hermitians LESS or equal to ZERO!\n"); + + if ( read_array(sizeof(REAL), read_real, (void**)&hermite_coefs, shape, 1) ) { + fprintf(stderr, "Syntax error when reading the hermitian coeficients.\n"); + exit(1); + } + atr_ok = ( shape[0] == num_hermitians ); + assert(atr_ok && "Incorrect shape of the hermitian coefficients!"); + + if ( read_array(sizeof(REAL), read_real, (void**)&hermite_weights, shape, 1) ) { + fprintf(stderr, "Syntax error when reading the hermitian weights.\n"); + exit(1); + } + atr_ok = ( shape[0] == num_hermitians ); + assert(atr_ok && "Incorrect shape of the hermitian weights!"); + } + + { // sobol direction vectors! + if ( read_int( static_cast( &num_sobol_bits ) ) ) { + fprintf(stderr, "Syntax error when reading NUM_SOBOL_BITS.\n"); + exit(1); + } + atr_ok = num_sobol_bits > 0; + assert(atr_ok && "Number of sobol bits LESS or equal to ZERO!\n"); + + if ( read_array(sizeof(int), read_int, (void**)&sobol_dirs_vct, shape, 1) ) { + fprintf(stderr, "Syntax error when reading sobol direction vectors.\n"); + exit(1); + } + atr_ok = ( shape[0] == num_sobol_bits ); + assert( atr_ok && "Incorrect shape of sobol direction vectors!" ); + } +} + +#endif // PARSE_INPUT + diff --git a/benchmarks/CalibGA/includeC/tmp/Constants.h b/benchmarks/CalibGA/lib/include/tmp/Constants.h similarity index 100% rename from benchmarks/CalibGA/includeC/tmp/Constants.h rename to benchmarks/CalibGA/lib/include/tmp/Constants.h diff --git a/benchmarks/CalibGA/includeC/tmp/DataStructConst.h b/benchmarks/CalibGA/lib/include/tmp/DataStructConst.h similarity index 100% rename from benchmarks/CalibGA/includeC/tmp/DataStructConst.h rename to benchmarks/CalibGA/lib/include/tmp/DataStructConst.h diff --git a/benchmarks/CalibGA/includeC/tmp/G2PP.h b/benchmarks/CalibGA/lib/include/tmp/G2PP.h similarity index 100% rename from benchmarks/CalibGA/includeC/tmp/G2PP.h rename to benchmarks/CalibGA/lib/include/tmp/G2PP.h From 40124adef061ca07417ae4dd870d58f978b730b3 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sat, 20 Jun 2015 14:05:08 +0200 Subject: [PATCH 027/122] LocVolCalib fixes. --- .../LocVolCalib/datasets/large/input.json | 2 +- .../LocVolCalib/datasets/large/output.json | 46 ++++++++++++------- .../implementations/futhark/instantiate | 2 +- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/benchmarks/LocVolCalib/datasets/large/input.json b/benchmarks/LocVolCalib/datasets/large/input.json index 0988c05..d0db1fc 100644 --- a/benchmarks/LocVolCalib/datasets/large/input.json +++ b/benchmarks/LocVolCalib/datasets/large/input.json @@ -1,5 +1,5 @@ { - "outer" : 128, + "outer" : 256, "num_x" : 256, "num_y" : 256, "num_t" : 64 diff --git a/benchmarks/LocVolCalib/datasets/large/output.json b/benchmarks/LocVolCalib/datasets/large/output.json index 5336d78..8ea53b5 100644 --- a/benchmarks/LocVolCalib/datasets/large/output.json +++ b/benchmarks/LocVolCalib/datasets/large/output.json @@ -1,17 +1,29 @@ -[ 0.03, 0.029208, 0.0288064, 0.0284091, 0.0280168, 0.02763, 0.0272488, 0.0268733, - 0.0265035, 0.0261398, 0.0257819, 0.0254298, 0.0250835, 0.0247429, 0.0244079, 0.0240786, - 0.0237549, 0.0234366, 0.0231239, 0.0228165, 0.0225144, 0.0222177, 0.0219261, 0.0216397, - 0.0213582, 0.0210816, 0.0208095, 0.0205413, 0.0202763, 0.0200168, 0.0197942, 0.0195152, - 0.0192728, 0.019036, 0.0188019, 0.018571, 0.0183438, 0.0181204, 0.0179008, 0.0176849, - 0.0174728, 0.0172644, 0.0170595, 0.0168582, 0.0166602, 0.0164656, 0.0162743, 0.0160862, - 0.0159012, 0.0157192, 0.0155402, 0.0153642, 0.0151911, 0.0150208, 0.0148533, 0.0146884, - 0.0145262, 0.0143665, 0.0142093, 0.0140545, 0.0139021, 0.013752, 0.0136042, 0.0134586, - 0.0133152, 0.0131739, 0.0130346, 0.0128974, 0.0127622, 0.012629, 0.0124976, 0.0123681, - 0.0122403, 0.0121144, 0.0119902, 0.0118678, 0.011747, 0.0116278, 0.0115102, 0.0113942, - 0.0112796, 0.0111666, 0.011055, 0.0109448, 0.010836, 0.0107285, 0.0106224, 0.0105175, - 0.010414, 0.0103117, 0.0102105, 0.0101106, 0.0100119, 0.00991426, 0.00981776, 0.00972235, - 0.00962805, 0.00953481, 0.00944259, 0.00935138, 0.00926115, 0.00917188, 0.00908355, 0.00899615, - 0.00890965, 0.00882403, 0.00873928, 0.00865539, 0.00857232, 0.00849007, 0.00840863, 0.00832796, - 0.00824807, 0.00816892, 0.00809052, 0.00801284, 0.00793587, 0.0078596, 0.00778404, 0.00770914, - 0.00763491, 0.00756131, 0.00748835, 0.007416, 0.00734426, 0.00727311, 0.00720255, 0.00713255 -] +[ 0.029996 , 0.029204 , 0.028803 , 0.028405 , 0.028013 , 0.027626 , 0.027245 , 0.026870 , 0.026500 , + 0.026136 , 0.025778 , 0.025426 , 0.025080 , 0.024739 , 0.024404 , 0.024075 , 0.023751 , 0.023433 , + 0.023120 , 0.022813 , 0.022511 , 0.022214 , 0.021923 , 0.021636 , 0.021355 , 0.021078 , 0.020806 , + 0.020538 , 0.020273 , 0.020014 , 0.019791 , 0.019512 , 0.019270 , 0.019033 , 0.018799 , 0.018568 , + 0.018341 , 0.018117 , 0.017898 , 0.017682 , 0.017470 , 0.017261 , 0.017056 , 0.016855 , 0.016657 , + 0.016463 , 0.016271 , 0.016083 , 0.015898 , 0.015716 , 0.015537 , 0.015361 , 0.015188 , 0.015018 , + 0.014850 , 0.014686 , 0.014523 , 0.014364 , 0.014206 , 0.014052 , 0.013899 , 0.013749 , 0.013601 , + 0.013456 , 0.013312 , 0.013171 , 0.013032 , 0.012895 , 0.012760 , 0.012626 , 0.012495 , 0.012365 , + 0.012238 , 0.012112 , 0.011988 , 0.011865 , 0.011744 , 0.011625 , 0.011508 , 0.011392 , 0.011277 , + 0.011164 , 0.011053 , 0.010942 , 0.010834 , 0.010726 , 0.010620 , 0.010515 , 0.010412 , 0.010309 , + 0.010208 , 0.010108 , 0.010010 , 0.009912 , 0.009815 , 0.009720 , 0.009626 , 0.009533 , 0.009440 , + 0.009349 , 0.009259 , 0.009170 , 0.009081 , 0.008994 , 0.008908 , 0.008822 , 0.008737 , 0.008653 , + 0.008570 , 0.008488 , 0.008407 , 0.008326 , 0.008246 , 0.008167 , 0.008089 , 0.008011 , 0.007934 , + 0.007858 , 0.007782 , 0.007707 , 0.007633 , 0.007559 , 0.007487 , 0.007414 , 0.007342 , 0.007271 , + 0.007201 , 0.007131 , 0.007061 , 0.006993 , 0.006924 , 0.006856 , 0.006789 , 0.006722 , 0.006656 , + 0.006590 , 0.006525 , 0.006460 , 0.006396 , 0.006332 , 0.006268 , 0.006205 , 0.006143 , 0.006081 , + 0.006019 , 0.005958 , 0.005897 , 0.005836 , 0.005776 , 0.005716 , 0.005657 , 0.005598 , 0.005539 , + 0.005481 , 0.005423 , 0.005365 , 0.005308 , 0.005251 , 0.005194 , 0.005138 , 0.005081 , 0.005026 , + 0.004970 , 0.004915 , 0.004860 , 0.004806 , 0.004751 , 0.004697 , 0.004643 , 0.004590 , 0.004536 , + 0.004483 , 0.004431 , 0.004378 , 0.004326 , 0.004274 , 0.004222 , 0.004170 , 0.004119 , 0.004068 , + 0.004017 , 0.003966 , 0.003915 , 0.003865 , 0.003815 , 0.003765 , 0.003715 , 0.003665 , 0.003616 , + 0.003566 , 0.003517 , 0.003468 , 0.003420 , 0.003371 , 0.003323 , 0.003274 , 0.003226 , 0.003178 , + 0.003130 , 0.003083 , 0.003035 , 0.002988 , 0.002940 , 0.002893 , 0.002846 , 0.002799 , 0.002752 , + 0.002706 , 0.002659 , 0.002613 , 0.002566 , 0.002520 , 0.002474 , 0.002428 , 0.002382 , 0.002337 , + 0.002291 , 0.002245 , 0.002200 , 0.002154 , 0.002109 , 0.002064 , 0.002019 , 0.001973 , 0.001928 , + 0.001884 , 0.001839 , 0.001794 , 0.001749 , 0.001705 , 0.001660 , 0.001616 , 0.001571 , 0.001527 , + 0.001482 , 0.001438 , 0.001394 , 0.001350 , 0.001306 , 0.001262 , 0.001218 , 0.001174 , 0.001130 , + 0.001086 , 0.001042 , 0.000998 , 0.000954 , 0.000911 , 0.000867 , 0.000823 , 0.000780 , 0.000736 , + 0.000692 , 0.000649 , 0.000605 , 0.000562 ] diff --git a/benchmarks/LocVolCalib/implementations/futhark/instantiate b/benchmarks/LocVolCalib/implementations/futhark/instantiate index 82ef9eb..75cbad8 100755 --- a/benchmarks/LocVolCalib/implementations/futhark/instantiate +++ b/benchmarks/LocVolCalib/implementations/futhark/instantiate @@ -6,4 +6,4 @@ $FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input. cp $FINPAR_IMPLEMENTATION/run . -futhark-c $FINPAR_IMPLEMENTATION/CalibVolDiff.fut +futhark-c $FINPAR_IMPLEMENTATION/CalibVolDiff.fut -o CalibVolDiff From df23a9f2bec311ec42feb7304797996b43eb50b3 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 14 Jul 2015 13:51:25 +0200 Subject: [PATCH 028/122] Comment notation changed. --- .../implementations/futhark/CalibVolDiff.fut | 75 ++++++++++--------- lib/linearise_data.py | 1 - 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut b/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut index 480b004..0b13af1 100644 --- a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut +++ b/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut @@ -10,7 +10,7 @@ initGrid(real s0, real alpha, real nu, real t, int numX, int numY, int numT) = let myY = map(fn real (int i) => toFloat(i) * dy - toFloat(myYindex) * dy + logAlpha, iota(numY)) in {myXindex, myYindex, myX, myY, myTimeline} -// make the innermost dimension of the result of size 4 instead of 3? +-- make the innermost dimension of the result of size 4 instead of 3? fun {[[real]],[[real]]} initOperator([real] x) = let n = size(0, x) in let dxu = x[1] - x[0] in @@ -40,7 +40,7 @@ fun *[[real]] setPayoff(real strike, [real] myX, [real] myY) = let myres = map(fn [real] (real xi) => replicate(n, max(xi-strike,0.0)), myX) in copy(transpose(myres)) -// Returns new myMuX, myVarX, myMuY, myVarY. +-- Returns new myMuX, myVarX, myMuY, myVarY. fun {[[real]] , [[real]] , [[real]] , [[real]]} updateParams( [real] myX, [real] myY, [real] myTimeline, int g, real alpha, real beta, real nu ) = @@ -74,10 +74,10 @@ fun *[real] tridagSeq( [real] a, *[real] b, [real] c, *[real] y ) = fun *[real] tridagPar( [real] a, *[real] b, [real] c, *[real] y ) = let n = size(0, a) in - //////////////////////////////////////////////////// - // Recurrence 1: b[i] = b[i] - a[i]*c[i-1]/b[i-1] // - // solved by scan with 2x2 matrix mult operator // - //////////////////////////////////////////////////// + ---------------------------------------------------- + -- Recurrence 1: b[i] = b[i] - a[i]*c[i-1]/b[i-1] -- + -- solved by scan with 2x2 matrix mult operator -- + ---------------------------------------------------- let b0 = b[0] in let mats = map ( fn {real,real,real,real} (int i) => if 0 < i @@ -99,10 +99,10 @@ fun *[real] tridagPar( [real] a, *[real] b, [real] c, *[real] y ) = let {t0,t1,t2,t3} = tup in (t0*b0 + t1) / (t2*b0 + t3) , scmt ) in - ////////////////////////////////////////////////////// - // Recurrence 2: y[i] = y[i] - (a[i]/b[i-1])*y[i-1] // - // solved by scan with linear func comp operator // - ////////////////////////////////////////////////////// + ------------------------------------------------------ + -- Recurrence 2: y[i] = y[i] - (a[i]/b[i-1])*y[i-1] -- + -- solved by scan with linear func comp operator -- + ------------------------------------------------------ let y0 = y[0] in let lfuns= map ( fn {real,real} (int i) => if 0 < i @@ -118,10 +118,10 @@ fun *[real] tridagPar( [real] a, *[real] b, [real] c, *[real] y ) = let {a,b} = tup in a + b*y0 , cfuns ) in - ////////////////////////////////////////////////////// - // Recurrence 3: backward recurrence solved via // - // scan with linear func comp operator // - ////////////////////////////////////////////////////// + ------------------------------------------------------ + -- Recurrence 3: backward recurrence solved via -- + -- scan with linear func comp operator -- + ------------------------------------------------------ let yn = y[n-1]/b[n-1] in let lfuns= map ( fn {real,real} (int k) => let i = n-k-1 @@ -141,14 +141,14 @@ fun *[real] tridagPar( [real] a, *[real] b, [real] c, *[real] y ) = let y = map (fn real (int i) => y[n-i-1], iota(n)) in copy(y) -/////////////////////////////////////////// -// myD,myDD : [[real,3],m] -// myMu,myVar,result : [[real,m],n] -// RETURN : [[real,m],n] -/////////////////////////////////////////// +------------------------------------------/ +-- myD,myDD : [[real,3],m] +-- myMu,myVar,result : [[real,m],n] +-- RETURN : [[real,m],n] +------------------------------------------/ fun *[[real]] explicitMethod( [[real]] myD, [[real]] myDD, [[real]] myMu, [[real]] myVar, [[real]] result ) = - // 0 <= i < m AND 0 <= j < n + -- 0 <= i < m AND 0 <= j < n let m = size(0,myD) in copy( map( fn [real] ( {[real],[real],[real]} tup ) => let {mu_row, var_row, result_row} = tup in @@ -168,12 +168,12 @@ fun *[[real]] explicitMethod( [[real]] myD, [[real]] myDD, ) ) -/////////////////////////////////////////// -// myD,myDD : [[real,3],m] -// myMu,myVar,u : [[real,m],n] -// RETURN : [[real,m],n] -/////////////////////////////////////////// -// for implicitY: should be called with transpose(u) instead of u +------------------------------------------/ +-- myD,myDD : [[real,3],m] +-- myMu,myVar,u : [[real,m],n] +-- RETURN : [[real,m],n] +------------------------------------------/ +-- for implicitY: should be called with transpose(u) instead of u fun *[[real]] implicitMethod( [[real]] myD, [[real]] myDD, [[real]] myMu, [[real]] myVar, *[[real]] u, real dtInv ) = @@ -201,7 +201,7 @@ fun *[[real]] rollback let {numX, numY} = {size(0, myX), size(0, myY)} in let dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]) in - // explicitX + -- explicitX let u = explicitMethod( myDx, myDxx, myMuX, myVarX, myResult ) in let u = map( fn [real] ({[real],[real]} tup) => let {u_row, res_row} = tup in @@ -211,16 +211,16 @@ fun *[[real]] rollback , zip(u_row,res_row) ) , zip(u,myResult) ) in - // explicitY + -- explicitY let myResultTR = transpose(myResult) in let v = explicitMethod( myDy, myDyy, myMuY, myVarY, myResultTR ) in let u = map( fn *[real] ([real] us, [real] vs) => copy(map(+, zip(us, vs))) , zip(u, transpose(v)) ) in - // implicitX + -- implicitX let u = implicitMethod( myDx, myDxx, myMuX, myVarX, u, dtInv ) in - // implicitY + -- implicitY let y = copy( map( fn [real] ({[real],[real]} uv_row) => let {u_row, v_row} = uv_row in map( fn real ({real,real} uv) => @@ -253,8 +253,13 @@ fun real value(int numX, int numY, int numT, real s0, real strike, real t, real myResult in myResult[myYindex,myXindex] -fun [real] main (int outer_loop_count, int numX, int numY, int numT, - real s0, real strike, real t, real alpha, real nu, real beta) = - let strikes = map(fn real (int i) => 0.001*toFloat(i), iota(outer_loop_count)) in - let res = map(fn real (real x) => value(numX, numY, numT, s0, x, t, alpha, nu, beta), strikes) in - res +fun [real] main (int outer_loop_count, int numX, int numY, int numT) = + let s0 = 0.03 in + let strike = 0.03 in + let t = 5.0 in + let alpha = 0.2 in + let nu = 0.6 in + let beta = 0.5 in + let strikes = map(fn real (int i) => 0.001*toFloat(i), iota(outer_loop_count)) in + let res = map(fn real (real x) => value(numX, numY, numT, s0, x, t, alpha, nu, beta), strikes) in + res diff --git a/lib/linearise_data.py b/lib/linearise_data.py index 46d5831..18bc33d 100755 --- a/lib/linearise_data.py +++ b/lib/linearise_data.py @@ -14,7 +14,6 @@ def read_json_file(filename): data = read_json_file(sys.argv[1]) for field in sys.argv[2:]: try: - print ("// " + field) print(data[field]) except KeyError: exit("Key %s not found in JSON file." % field) From 246f756bba7f8660ee05c01d7351717c35cbb0ad Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 14 Jul 2015 15:32:47 +0200 Subject: [PATCH 029/122] Update Futhark implementation of option pricing. --- .../futhark/GenericPricing.fut | 504 +++++++++++------- .../implementations/futhark/instantiate | 2 +- 2 files changed, 309 insertions(+), 197 deletions(-) diff --git a/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut b/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut index b86f7f7..216abe7 100644 --- a/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut +++ b/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut @@ -1,50 +1,101 @@ fun int grayCode(int x) = (x >> 1) ^ x -//////////////////////////////////////// -/// Sobol Generator -//////////////////////////////////////// -fun int index([int] arr, int i) = arr[i] - +---------------------------------------- +--- Sobol Generator +---------------------------------------- fun bool testBit(int n, int ind) = let t = (1 << ind) in (n & t) == t -///////////////////////////////////////////////////////////////// -//// DIFFICULT VERSION: filter is hoisted outside map: -//// less computation but variable array size! -///////////////////////////////////////////////////////////////// -//fun int xorInds([int] indices, [int] dir_vs ) = -// reduce( ^, 0, map( index(dir_vs), indices ) ) -// -//fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = -// let bits = iota ( bits_num ) in -// let indices = filter ( testBit(grayCode(n)), bits ) -// in map( xorInds(indices), dir_vs ) - - -///////////////////////////////////////////////////////////////// -//// EASY VERSION: filter is redundantly computed inside map: -//// more computation but a redofilt pattern, i.e., array -//// not instantiated! -///////////////////////////////////////////////////////////////// -fun int xorInds(int bits_num, int n, [int] dir_vs ) = - let bits = iota ( bits_num ) in - let indices = filter ( testBit(grayCode(n)), bits ) in - reduce( ^, 0, map( index(dir_vs), indices ) ) - -fun [int] sobolIndI ( int bits_num, [[int]] dir_vs, int n ) = - map( xorInds(bits_num, n), dir_vs ) -//////////////////////////////////////////////////////////////// - -fun [real] sobolIndR( int bits_num, [[int]] dir_vs, int n ) = - let divisor = 2.0 pow toFloat (bits_num) in - let arri = sobolIndI( bits_num, dir_vs, n ) in +----------------------------------------------------------------- +---- INDEPENDENT FORMULA: +---- filter is redundantly computed inside map. +---- Currently Futhark hoists it outside, but this will +---- not allow fusing the filter with reduce => redomap, +----------------------------------------------------------------- +fun int xorInds(int n, [int,num_bits] dir_vs) = + let reldv_vals = map( fn int (int dv, int i) => + if testBit(grayCode(n),i) + then dv else 0 + , zip(dir_vs,iota(num_bits)) ) in + reduce( ^, 0, reldv_vals ) + +fun [int] sobolIndI ( [[int]] dir_vs, int n ) = + map( xorInds(n), dir_vs ) + +fun [real] sobolIndR( [[int,num_bits]] dir_vs, int n ) = + let divisor = 2.0 pow toFloat (num_bits) in + let arri = sobolIndI( dir_vs, n ) in map( fn real (int x) => toFloat(x) / divisor, arri ) -//////////////////////////////////////// -/// Inverse Gaussian -//////////////////////////////////////// - -//tmp_rat_evalL :: SpecReal -> [SpecReal] -> SpecReal +-------------------------------- +---- STRENGTH-REDUCED FORMULA +-------------------------------- +fun int index_of_least_significant_0(int num_bits, int n) = + let {goon,k} = {True,0} in + loop ({goon,k,n}) = + for i < num_bits do + if(goon) + then if (n & 1) == 1 + then {True, k+1, n>>1} + else {False,k, n } + else {False,k, n } + in k + +fun [int] sobolRecI([[int,num_bits]] sob_dir_vs, [int] prev, int n) = + let bit = index_of_least_significant_0(num_bits,n) in + map (fn int ({[int],int} vct_prev) => + let {vct_row, prev} = vct_prev in + vct_row[bit] ^ prev + , zip(sob_dir_vs,prev)) + +fun [[real]] sobolRecMap( real sob_fact, [[int]] dir_vs, {int,int} lu_bds ) = + let {lb_inc, ub_exc} = lu_bds in + -- the if inside may be particularly ugly for + -- flattening since it introduces control flow! + let contribs = map( fn [int] (int k) => + if (k==0) + then sobolIndI(dir_vs,lb_inc+1) + else recM(dir_vs,k+lb_inc) + , iota(ub_exc-lb_inc) + ) in + let vct_ints = scan( fn [int] ([int] x, [int] y) => zipWith(^, x, y) + , replicate( size(0,dir_vs), 0 ) + , contribs + ) + in map( fn [real] ([int] xs) => + map ( fn real (int x) => + toFloat(x) * sob_fact + , xs) + , vct_ints) + +fun [int] sobolRecI2([[int]] sob_dirs, [int] prev, int i)= + let col = recM(sob_dirs, i) in zipWith(^,prev,col) + +fun [int] recM( [[int,num_bits]] sob_dirs, int i ) = + let bit= index_of_least_significant_0(num_bits,i) in + map( fn int([int] row) => row[bit], sob_dirs ) + +-- computes sobol numbers: n,..,n+chunk-1 +fun [[real],chunk] sobolChunk([[int,num_bits],len] dir_vs, int n, int chunk) = + let sob_fact= 1.0 / toFloat(1 << num_bits) in + let sob_beg = sobolIndI(dir_vs, n+1) in + let contrbs = map( fn [int] (int k) => + let sob = k + n in + if(k==0) then sob_beg + else recM(dir_vs, k+n) + , iota(chunk) ) in + let vct_ints= scan( fn [int] ([int] x, [int] y) => + zipWith(^, x, y) + , replicate(len, 0), contrbs ) in + map( fn [real] ([int] xs) => + map ( fn real (int x) => + toFloat(x) * sob_fact + , xs) + , vct_ints) + +---------------------------------------- +--- Inverse Gaussian +---------------------------------------- fun real polyAppr( real x, real a0, real a1, real a2, real a3, real a4, real a5, real a6, real a7, @@ -122,27 +173,30 @@ fun real tail(real r) = fun real ugaussianEl( real p ) = let dp = p - 0.5 - in //if ( fabs(dp) <= 0.425 ) - if ( ( (dp < 0.0) && (0.0 - dp <= 0.425) ) || ( (0.0 <= dp) && (dp <= 0.425) ) ) + in --if ( fabs(dp) <= 0.425 ) + if ( ( (dp < 0.0 ) && (0.0 - dp <= 0.425) ) || + ( (0.0 <= dp) && (dp <= 0.425) ) ) then smallcase(dp) - else let pp = if(dp < 0.0) then dp + 0.5 else 0.5 - dp in - let r = sqrt( - log(pp) ) in - let x = if(r <= 5.0) then intermediate(r) else tail(r) in - if(dp < 0.0) then 0.0 - x else x - -// Transforms a uniform distribution [0,1) into a gaussian distribution (-inf, +inf) + else let pp = if(dp < 0.0) then dp + 0.5 + else 0.5 - dp in + let r = sqrt( - log(pp) ) in + let x = if(r <= 5.0) then intermediate(r) + else tail(r) in + if(dp < 0.0) then 0.0 - x + else x + +-- Transforms a uniform distribution [0,1) +-- into a gaussian distribution (-inf, +inf) fun [real] ugaussian([real] ps) = map(ugaussianEl, ps) -///////////////////////////////// -/// Brownian Bridge -///////////////////////////////// - -fun [real] brownianBridgeDates ( - int num_dates, - [[int ]] bb_inds, // [3, num_dates] - [[real]] bb_data, // [3, num_dates] - [real] gauss // [num_dates] +--------------------------------- +--- Brownian Bridge +--------------------------------- +fun [real,num_dates] brownianBridgeDates ( + [[int, num_dates],3] bb_inds, + [[real,num_dates],3] bb_data, + [real,num_dates] gauss ) = let bi = bb_inds[0] in let li = bb_inds[1] in @@ -151,12 +205,11 @@ fun [real] brownianBridgeDates ( let lw = bb_data[1] in let rw = bb_data[2] in -// let gauss[ bi[0]-1 ] = sd[0] * gauss[0] in let bbrow = copy(replicate(num_dates, 0.0)) in - let bbrow[ bi[0]-1 ] = sd[0] * gauss[0] in + let bbrow[ bi[0]-1 ] = sd[0] * gauss[0] in loop (bbrow) = - for i < num_dates-1 do // use i+1 since i in 1 .. num_dates-1 + for i < num_dates-1 do -- use i+1 since i in 1 .. num_dates-1 let j = li[i+1] - 1 in let k = ri[i+1] - 1 in let l = bi[i+1] - 1 in @@ -165,13 +218,13 @@ fun [real] brownianBridgeDates ( let zi = gauss [i+1] in let tmp= rw[i+1] * wk + sd[i+1] * zi in - let bbrow[ l ] = if( (j + 1) == 0) // if(j=-1) + let bbrow[ l ] = if( j == -1) then tmp else tmp + lw[i+1] * bbrow[j] in bbrow - // This can be written as map-reduce, but it - // needs delayed arrays to be mapped nicely! + -- This can be written as map-reduce, but it + -- needs delayed arrays to be mapped nicely! in loop (bbrow) = for ii < num_dates-1 do let i = num_dates - (ii+1) in @@ -179,153 +232,212 @@ fun [real] brownianBridgeDates ( in bbrow in bbrow -// [num_dates,num_paths] -fun [[real]] brownianBridge ( - int num_paths, - int num_dates, - [[int ]] bb_inds, // [3, num_dates] - [[real]] bb_data, // [3, num_dates] - [real] gaussian_arr // [num_paths * num_dates] +fun [[real,num_und],num_dates] brownianBridge ( + int num_und, + [[int, num_dates],3] bb_inds, + [[real,num_dates],3] bb_data, + [real] gaussian_arr ) = - let gauss2d = reshape((num_dates,num_paths), gaussian_arr) in + let gauss2d = reshape((num_dates,num_und), gaussian_arr) in let gauss2dT = transpose(gauss2d) in - transpose( map( brownianBridgeDates(num_dates, bb_inds, bb_data), gauss2dT ) ) - + transpose( + map( brownianBridgeDates(bb_inds, bb_data), gauss2dT ) + ) -///////////////////////////////// -/// Black-Scholes -///////////////////////////////// - -fun real zwop(real a, real b, int j) = a * b +--------------------------------- +--- Black-Scholes +--------------------------------- fun [real] take(int n, [real] a) = let {first, rest} = split((n), a) in first -fun [real] fftmp(int num_paths, [[real]] md_c, [real] zi) = - map( fn real (int j) => - let x = map(zwop, zip(take(j+1,zi), take(j+1,md_c[j]), iota(j+1))) - in reduce(+, 0.0, x), - iota(num_paths) - ) - -fun [[real]] correlateDeltas(int num_paths, [[real]] md_c, [[real]] zds) = - map( fftmp(num_paths, md_c), zds ) - -fun [real] combineVs([real] n_row, [real] vol_row, [real] dr_row) = - map( +, zip(dr_row, map( *, zip(n_row, vol_row ) ))) - -fun [[real]] mkPrices ([real] md_starts, [[real]] md_vols, [[real]] md_drifts, [[real]] noises) = - let e_rows = map( fn [real] ([real] x) => map(exp, x), - map(combineVs, zip(noises, md_vols, md_drifts)) +fun [[real,num_und],num_dates] +correlateDeltas( [[real,num_und],num_und ] md_c, + [[real,num_und],num_dates] zds +) = + map( fn [real,num_und] ([real,num_und] zi) => + map( fn real (int j) => + let x = zipWith( *, take(j+1,zi), take(j+1,md_c[j]) ) + in reduce( +, 0.0, x ) + , iota(num_und) ) + , zds ) + +fun [real,num_und] combineVs( [real,num_und] n_row, + [real,num_und] vol_row, + [real,num_und] dr_row ) = + map(+, zip(dr_row, map(*, zip(n_row, vol_row ) ))) + +fun [[real,num_und],num_dates] +mkPrices( [real,num_und] md_starts, + [[real,num_und],num_dates] md_vols, + [[real,num_und],num_dates] md_drifts, + [[real,num_und],num_dates] noises +) = + let c_rows = map( combineVs, zip(noises, md_vols, md_drifts) ) in + let e_rows = map( fn [real] ([real] x) => map(exp, x) + , c_rows --map( combineVs, zip(noises, md_vols, md_drifts) ) ) - in scan( fn [real] ([real] x, [real] y) => map(*, zip(x, y)), md_starts, e_rows ) - -//[num_dates, num_paths] -fun [[real]] blackScholes( - int num_paths, - [[real]] md_c, //[num_paths, num_paths] - [[real]] md_vols, //[num_paths, num_dates] - [[real]] md_drifts, //[num_paths, num_dates] - [real] md_starts, //[num_paths] - [[real]] bb_arr //[num_dates,num_paths] + in scan( fn [real] ([real] x, [real] y) => zipWith(*, x, y) + , md_starts, e_rows ) + +fun [[real,num_und],num_dates] blackScholes( + [[real,num_und],num_und ] md_c, + [[real,num_und],num_dates] md_vols, + [[real,num_und],num_dates] md_drifts, + [real,num_und] md_starts, + [[real,num_und],num_dates] bb_arr ) = - let noises = correlateDeltas(num_paths, md_c, bb_arr) + let noises = correlateDeltas(md_c, bb_arr) in mkPrices(md_starts, md_vols, md_drifts, noises) -//////////////////////////////////////// -// MAIN -//////////////////////////////////////// - -fun [real] main(int contract_number, - int num_mc_it, - int num_dates, - int num_und, - int num_models, // Unused? - int num_bits, - [[int]] dir_vs, - [[[real]]] all_md_c, - [[[real]]] all_md_vols, - [[[real]]] all_md_drifts, - [[real]] all_md_st, - [[real]] all_md_detvals, - [[real]] all_md_disc, - [[int]] bb_inds, - [[real]] bb_data) = - let md_c = all_md_c[0] in - let md_vols = all_md_vols[0] in - let md_drifts = all_md_drifts[0] in - let md_st = all_md_st[0] in - let md_detvals = all_md_detvals[0] in - let md_disc = all_md_disc[0] in - let sobol_mat = map ( sobolIndR(num_bits, dir_vs), map(fn int (int x) => x + 1, iota(num_mc_it)) ) in - let gauss_mat = map ( ugaussian, sobol_mat ) in - let bb_mat = map ( brownianBridge( num_und, num_dates, bb_inds, bb_data ), gauss_mat ) in - let bs_mat = map ( blackScholes( num_und, md_c, md_vols, md_drifts, md_st ), bb_mat ) in - - let payoff = - if contract_number == 1 then - let payoffs = map ( payoff1(md_disc, md_detvals), bs_mat ) in - reduce ( +, 0.0, payoffs ) - else if contract_number == 2 then - let payoffs = map ( payoff2(md_disc), bs_mat ) in - reduce ( +, 0.0, payoffs ) - else if contract_number == 3 then - let payoffs = map ( payoff3(md_disc), bs_mat ) in - reduce ( +, 0.0, payoffs ) - else 0.0 in - [ payoff / toFloat(num_mc_it) ] - -//////////////////////////////////////// -// PAYOFF FUNCTION -//////////////////////////////////////// - -// This function is super weird, but a faithful translation of the -// Haskell version... -fun real payoff1 ([real] md_disc, [real] md_detvals, [[real]] xss) = - let detval = md_detvals[0] in - let amount = (xss[0,0] - 4000.0) * detval in - let amount2 = if amount < 0.0 then 0.0 else amount in - trajInner(amount2, 0, md_disc) +---------------------------------------- +-- MAIN +---------------------------------------- +fun [real] mainInd( + int contract_number, + int num_mc_it, + [[int,num_bits]] dir_vs_nosz, + [[[real,num_und],num_und ],num_models] md_cs, + [[[real,num_und],num_dates],num_models] md_vols, + [[[real,num_und],num_dates],num_models] md_drifts, + [[real,num_und],num_models] md_sts, + [[real],num_models] md_detvals, + [[real],num_models] md_discts, + [[int, num_dates],3] bb_inds, + [[real,num_dates],3] bb_data +) = + let dir_vs = reshape( (num_dates*num_und, num_bits), dir_vs_nosz ) in + + let sobol_mat = map ( sobolIndR(dir_vs) + , map( fn int (int x) => x + 1, iota(num_mc_it) ) + ) in + + let gauss_mat = map ( ugaussian, sobol_mat ) in + + let bb_mat = map ( brownianBridge( num_und, bb_inds, bb_data ), gauss_mat ) in + + let payoffs = map ( fn [real] ([[real]] bb_row) => + let market_params = zip(md_cs, md_vols, md_drifts, md_sts) in + let bd_row = map (fn [[real]] ({[[real]],[[real]],[[real]],[real]} m) => + let {c,vol,drift,st} = m in + blackScholes(c, vol, drift, st, bb_row) + , market_params) + in + let payoff_params = zip(md_discts, md_detvals, bd_row) in + map (fn real ({[real],[real],[[real]]} p) => + let {disct, detval, bd} = p in + genericPayoff(contract_number, disct, detval, bd) + , payoff_params) + , bb_mat) + in + let payoff = reduce ( fn [real] ([real] x, [real] y) => + zipWith(+, x, y) + , replicate(num_models, 0.0) + , payoffs ) + in map (fn real (real price) => price / toFloat(num_mc_it), payoff) + + + +fun [real] main( + int contract_number, + int num_mc_it, + [[int,num_bits]] dir_vs_nosz, + [[[real,num_und],num_und ],num_models] md_cs, + [[[real,num_und],num_dates],num_models] md_vols, + [[[real,num_und],num_dates],num_models] md_drifts, + [[real,num_und],num_models] md_sts, + [[real],num_models] md_detvals, + [[real],num_models] md_discts, + [[int, num_dates],3] bb_inds, + [[real,num_dates],3] bb_data +) = + let sobvctsz = num_dates*num_und in + let dir_vs = reshape( (sobvctsz,num_bits), dir_vs_nosz ) in + let sobol_mat = streamMapMax ( fn [[real,sobvctsz]] (int chunk, [int] ns) => + sobolChunk(dir_vs, ns[0], chunk) + , iota(num_mc_it) ) in + + let gauss_mat = map ( ugaussian, sobol_mat ) in + + let bb_mat = map ( brownianBridge( num_und, bb_inds, bb_data ), gauss_mat ) in + + let payoffs = map ( fn [real] ([[real]] bb_row) => + let market_params = zip(md_cs, md_vols, md_drifts, md_sts) in + let bd_row = map (fn [[real]] ({[[real]],[[real]],[[real]],[real]} m) => + let {c,vol,drift,st} = m in + blackScholes(c, vol, drift, st, bb_row) + , market_params) + in + let payoff_params = zip(md_discts, md_detvals, bd_row) in + map (fn real ({[real],[real],[[real]]} p) => + let {disct, detval, bd} = p in + genericPayoff(contract_number, disct, detval, bd) + , payoff_params) + , bb_mat) + in + let payoff = reduce( fn [real] ([real] x, [real] y) => + zipWith(+, x, y) + , replicate(num_models, 0.0) + , payoffs ) + in map (fn real (real price) => price / toFloat(num_mc_it), payoff) + + +---------------------------------------- +-- PAYOFF FUNCTIONS +---------------------------------------- +fun real genericPayoff(int contract, [real] md_disct, [real] md_detval, [[real]] xss) = + if (contract == 1) then payoff1(md_disct, md_detval, xss) + else if (contract == 2) then payoff2(md_disct, xss) + else if (contract == 3) then payoff3(md_disct, xss) + else 0.0 + +fun real payoff1([real] md_disct, [real] md_detval, [[real]] xss) = +-- invariant: xss is a 1x1 matrix + let detval = md_detval[0] in + let amount = ( xss[0,0] - 4000.0 ) * detval in + let amount0= if (0.0 < amount) then amount else 0.0 + in trajInner(amount0, 0, md_disct) fun real payoff2 ([real] md_disc, [[real]] xss) = -// invariant: length(xss) == 5, i.e., 5x3 matrix - let divs = [ 1.0/3758.05, 1.0/11840.0, 1.0/1200.0 ] in - let xss_div = map( fn [real] ([real] xs) => map(*, zip(xs, divs)), xss ) in - let mins = map( MIN, xss_div ) - in if( 1.0 <= mins[0] ) then trajInner(1150.0, 0, md_disc) - else if( 1.0 <= mins[1] ) then trajInner(1300.0, 1, md_disc) - else if( 1.0 <= mins[2] ) then trajInner(1450.0, 2, md_disc) - else if( 1.0 <= mins[3] ) then trajInner(1600.0, 3, md_disc) - else if( 1.0 <= mins[4] ) then trajInner(1750.0, 4, md_disc) - else if( 0.75 < mins[4] ) then trajInner(1000.0, 4, md_disc) - else trajInner(1000.0 * mins[4], 4, md_disc) - -fun real payoff3 ([real] md_disc, [[real]] xss) = - // invariant: size(1,xss) == 3. - let x3309 = reduce(||, False, - map (fn bool ([real] xs) => - xs[0] <= 2630.6349999999998 || - xs[1] <= 8288.0 || - xs[2] <= 840.0, - xss)) in - let goto_40 = (x3309 && - (xss[366,0] < 3758.05 || - xss[366,2] < 1200.0 || - xss[366,1] < 11840.0)) in - let price1 = trajInner(100.0, 0, md_disc) in - let price2 = - if goto_40 then let m1 = min((xss[366,2] / 1200.00) - 1.0, - (xss[366,0] / 3758.05) - 1.0) in - let m2 = min((xss[366,1] / 11840.00) - 1.0, - m1) in - let amount = 1000.0 * (1.0 + m2) in - trajInner(amount, 1, md_disc) - else trajInner(1000.0, 1, md_disc) in - price1 + price2 - -fun real min(real x, real y) = - if x < y then x else y +-- invariant: xss is a 5x3 matrix + let {date, amount} = + if (1.0 <= fminPayoff(xss[0])) then {0, 1150.0} + else if (1.0 <= fminPayoff(xss[1])) then {1, 1300.0} + else if (1.0 <= fminPayoff(xss[2])) then {2, 1450.0} + else if (1.0 <= fminPayoff(xss[3])) then {3, 1600.0} + else let x50 = fminPayoff(xss[4]) in + let val = if ( 1.0 <= x50 ) then 1750.0 + else if ( 0.75 < x50 ) then 1000.0 + else x50*1000.0 + in {4, val} + in trajInner(amount, date, md_disc) + +fun real payoff3([real] md_disct, [[real]] xss) = +-- invariant: xss is a 367x3 matrix + let conds = map (fn bool ([real] x) => (x[0] <= 2630.6349999999998) || + (x[1] <= 8288.0) || + (x[2] <= 840.0) + , xss) in + let cond = reduce (||, False, conds) in + let price1= trajInner(100.0, 0, md_disct) in + let goto40= cond && + ( (xss[366,0] < 3758.05) || + (xss[366,1] < 11840.0) || + (xss[366,2] < 1200.0 ) ) in + let amount= if goto40 + then 1000.0 * fminPayoff(xss[366]) + else 1000.0 in + let price2 = trajInner(amount, 1, md_disct) in + price1 + price2 + +fun real fminPayoff([real] xs) = +-- MIN( zipWith(/, xss, {3758.05, 11840.0, 1200.0}) ) + let {a,b,c} = { xs[0]/3758.05, xs[1]/11840.0, xs[2]/1200.0} in + if a < b then if a < c then a else c + else if b < c then b else c fun real MIN([real] arr) = reduce( fn real (real x, real y) => if(x input.data +$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data cp $FINPAR_IMPLEMENTATION/run . From cf79b7c3af8dcae4a4f4b7605c5a103ca435be29 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 24 Jul 2015 13:16:12 +0200 Subject: [PATCH 030/122] removing redundant files. --- Makefile | 128 -------------------- finpar | 353 ------------------------------------------------------- 2 files changed, 481 deletions(-) delete mode 100644 Makefile delete mode 100755 finpar diff --git a/Makefile b/Makefile deleted file mode 100644 index ede2024..0000000 --- a/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -# Supposed to be the Centralised makefile for benchmarks -# BUT IT IS NOT IMPLEMENTED RIGHT NOW. RATHER GO AND MAKE -# EACH BENCHMARK (VERSION) INDIVIDUALLY IN ITS OWN FOLDER, -# PLEASE READ the README.md file!!!!! -# -# This makefile is common infrastructure to compile and run all benchmarks. -# -# It recursively calls make in specified subdirectories with the -# benchmark programs, and expects that each such directory contains a -# makefile with the following targets: -# -# compile the benchmark -# run_X run the benchmark with data set X -# (where X is in {small,medium,large}) -# clean -# -# Some centralised targets are defined here: -# run_all: runs all benchmarks with all data -# clean: calls make clean in all configured subdirectories -# OptionPricing: compile all programs in OptionPricing subdir -# - - -################################################################# - -# As per today, we have the following working directories: - -# Option Pricing -# ./OptionPricing/OrigCpp -- sequential, original C(++) code -# ./OptionPricing/CppOpenMP -- OpenMP version -# ./OptionPricing/CppOpenCL -- GPU version using OpenCL -# ./OptionPricing/HaskellLH -- Haskell version documenting all parallelism. -# -# Local Volatility Calibration -# ./LocVolCalib/OrigCpp -- sequential, original C(++) code -# ./LocVolCalib/COpenMP -- OpenMP C version of the code -# ./LocVolCalib/AllParOpenCLMP -- parallelizing the outer two loops in OpenCL and OpenMP -# ./LocVolCalib/OutParOpenCLMP -- parallelizing the whole loop nest in OpenCL and OpenMP -# ./LocVolCalib/HaskellLH -- Haskell version documenting all parallelism. -# -# Interest Rate Calibration: -# ./InterestCalib/OrigCpp -- sequential C++ code (translated from the original Caml code) -# ./InterestCalib/CppOpenMP -- OpenMP version, in which only the outermost loop is parallel -# ./InterestCalib/CppOpenCL -- OpenCL version, which needs to exploit parallelism on all levels. -# ./InterestCalib/HaskellLH -- Haskell version documenting all parallelism. -# - -BENCHMARKS =OptionPricing #LocVolCalib #InterestCalib - -VERSIONS_OptionPricing = OptionPricing/OrigCpp OptionPricing/CppOpenMP \ - OptionPricing/HaskellLH OptionPricing/CppOpenCL - -VERSIONS_LocVolCalib = LocVolCalib/OrigCpp LocVolCalib/COpenMP LocVolCalib/AllParOpenCLMP \ - LocVolCalib/HaskellLH LocVolCalib/OutParOpenCLMP - -VERSIONS_InterestCalib = InterestCalib/OrigCpp InterestCalib/CppOpenMP \ - InterestCalib/CppOpenCL InterestCalib/HaskellLH - -include platform.mk - -####################### rules start here ######################## - -# default: help text -.PHONY: help -help: - @echo "\tFor now, please read the makefile before using it" - @echo "\t XXX Help text should be added soon here" - -all : $(BENCHMARKS) run_all - -run_all :: - @echo "Running all benchmarks" - -OptionPricing: $(VERSIONS_OptionPricing) - -LocVolCalib: $(VERSIONS_LocVolCalib) - -InterestCalib: $(VERSIONS_InterestCalib) - - -################## target construction functions ################ -# : -# $(MAKE) -C - -#run_ : -# make -C run_ - -# XXX BTW some renaming/reducing dir.s will be appropriate... -# */Data/[small|medium|large][in|out] is good enough - -define runRule -# arg.s: benchmark/version, Category (small,medium,large) -#$$(warning runRule($(1),$(2))) - -.PHONY: run_$(1)_$(2) -run_$(1)_$(2): $(1) - $$(MAKE) -C $(1) run_$(2) -run_all :: run_$(1)_$(2) - -endef - -define mkStdRule -# arg.: Benchmark/Version# -#$$(warning mkStdRule($(1))) - -.PHONY: $(1) -# building the target -$(1): - $$(MAKE) -C $(1) - -# running small,medium,large -$$(eval $$(call runRule,$(1),small)) -$$(eval $$(call runRule,$(1),medium)) -$$(eval $$(call runRule,$(1),large)) - -# and cleaning... -clean :: - $$(MAKE) -C $(1) clean -endef - -################## constructing the targets ################ - -$(foreach B,$(VERSIONS_OptionPricing),$(eval $(call mkStdRule,$(B)))) -$(foreach B,$(VERSIONS_LocVolCalib),$(eval $(call mkStdRule,$(B)))) - -$(foreach B,$(VERSIONS_InterestCalib),$(eval $(call mkStdRule,$(B)))) - -# custom rules would go here as well diff --git a/finpar b/finpar deleted file mode 100755 index 021c58f..0000000 --- a/finpar +++ /dev/null @@ -1,353 +0,0 @@ -#!/usr/bin/env python - -import os -import subprocess -import json -import sys - -def executable(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - -class Implementation: - def __init__(self, finpar_lib_dir, benchmark_lib_dir, name, directory): - if os.path.isdir(directory): - self.directory = directory - else: - if os.path.isfile(directory): - raise Exception("File %s exists, but should be an implementation directory" % directory) - else: - raise Exception("Implementation directory %s does not exist " % directory) - - self.directory = directory - self.name = name - self.finpar_lib_dir = finpar_lib_dir - self.benchmark_lib_dir = benchmark_lib_dir - - instantiatefile = os.path.join(self.directory, "instantiate") - if not executable(instantiatefile): - raise Exception("%s is not an executable file" % instantiatefile) - self.instantiatefile = instantiatefile - - def instantiate(self, where, input_data, platform_file): - if not os.path.isdir(where): - os.mkdir(where) - - # We use the current environment as a template, and then - # extend it with some new variables. - instantiate_env = os.environ.copy() - instantiate_env["FINPAR_LIB_DIR"] = self.finpar_lib_dir - instantiate_env["FINPAR_BENCHMARK_LIB_DIR"] = self.benchmark_lib_dir - instantiate_env["FINPAR_IMPLEMENTATION"] = self.directory - instantiate_env["FINPAR_INPUT"] = input_data - instantiate_env["FINPAR_PLATFORM"] = platform_file - - proc = subprocess.Popen(self.instantiatefile, - env=instantiate_env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - close_fds=True, - cwd=where) - (stdoutdata, stderrdata) = proc.communicate(input=None) - return (proc.returncode, stdoutdata, stderrdata) - -class Benchmark: - # In the constructor, we do some basic sanity-checking. The - # primary purpose here is to provide better error messages than if - # we fail to read files later down the line. - def __init__(self, finpardir, name, directory): - self.finpardir = finpardir - self.name = name - - if os.path.isdir(directory): - self.directory = directory - else: - raise Exception("Benchmark directory %s does not exist" % directory) - dircontents = os.listdir(self.directory) - - # The lib directories do not have to exist. - self.benchmark_lib_dir = os.path.join(self.directory, "lib") - self.finpar_lib_dir = os.path.join(self.finpardir, "lib") - - if "implementations" in dircontents: - self.__gather_implementations() - else: - raise Exception("No implementation directory in %s" % directory) - - if "datasets" in dircontents: - self.datasets = os.path.join(self.directory, "datasets") - self.__gather_datasets() - else: - raise Exception("No datasets directory in %s" % directory) - - def __gather_implementations(self): - self.implementations = [] - for impl in os.listdir(os.path.join(self.directory, "implementations")): - implpath = os.path.join(self.directory, "implementations", impl) - if os.path.isdir(implpath): - self.implementations.append(Implementation(self.finpar_lib_dir, - self.benchmark_lib_dir, - impl, - os.path.join(self.directory, "implementations", impl))) - - def __gather_datasets(self): - self.datasets = {} - for dataset in os.listdir(os.path.join(self.directory, "datasets")): - datasetpath = os.path.join(self.directory, "datasets", dataset) - if os.path.isdir(datasetpath): - inputfile = os.path.join(self.directory, "datasets", dataset, "input.json") - outputfile = os.path.join(self.directory, "datasets", dataset, "output.json") - if not os.path.isfile(inputfile): - raise Exception("File %s missing or not a file." % inputfile) - if not os.path.isfile(outputfile): - raise Exception("File %s missing or not a file." % outputfile) - - self.datasets[dataset] = { 'input_file' : inputfile, - 'expected_output' : read_json_file(outputfile) - } - -def desc_triple(benchmark, implementation, dataset): - return "Benchmark %s, implementation %s, dataset %s" % (benchmark, implementation, dataset) - -def note_result(results, benchmark, implementation, dataset, runtime): - results[(benchmark,implementation,dataset)] = runtime - -def run_some_benchmark_implementations(finpar_dir, - workdir, - benchmarkdir, - platform, - run_implementation_fn, - use_dataset_fn): - b = Benchmark(finpar_dir, os.path.basename(benchmarkdir), benchmarkdir) - insts = [] - failed_insts = [] - results = {} - - for impl in b.implementations: - if not run_implementation_fn(impl): - continue - for dataset in b.datasets: - if not use_dataset_fn(dataset): - continue - instdir = os.path.join(workdir, - "%s-%s-%s" % (b.name, impl.name, dataset)) - print("Instantiating in %s" % instdir) - (retcode, stdout, stderr) = impl.instantiate(instdir, b.datasets[dataset]['input_file'], platform) - if retcode != 0: - failed_insts.append({ 'benchmark' : b.name, - 'implementation' : impl.name, - 'dataset' : dataset, - 'instantiation_directory' : instdir, - 'retcode' : retcode, - 'stdout' : stdout, - 'stderr' : stderr}) - print("Spoiler: failed") - else: - insts.append({ 'benchmark' : b.name, - 'implementation' : impl.name, - 'dataset' : dataset, - 'instantiation_directory' : instdir, - 'expected_output' : b.datasets[dataset]['expected_output'] - }) - - for inst in insts: - instdir = inst['instantiation_directory'] - print("\nRunning %s" % instdir) - stdoutpath = os.path.join(instdir, "stdout.log") - stderrpath = os.path.join(instdir, "stderr.log") - with open(stdoutpath, "w") as stdout: - with open(stderrpath, "w") as stderr: - print("Output can be found in %s and %s" % (stdoutpath, stderrpath)) - try: - proc = subprocess.Popen(os.path.join(instdir, "run"), - stdout=stdout, - stderr=stderr, - stdin=subprocess.PIPE, - close_fds=True, - cwd=instdir) - proc.stdin.close() # Make sure stdin EOFs. - proc.wait() - except: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "could not run") - continue - - if proc.returncode != 0: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "non-zero exit code") - continue - - try: - runtime = read_runtime(instdir) - except IOError: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "no runtime measurement") - continue - except ValueError: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "non-integer runtime measurement") - continue - - try: - result = read_json_file(os.path.join(instdir, "result.json")) - expected = inst['expected_output'] - if compare_json(result, expected): - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - runtime) - else: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "invalid result") - except (IOError, ValueError): - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "cannot read result") - return (results, failed_insts) - -def read_runtime(instdir): - with open(os.path.join(instdir, "runtime.txt"), "r") as file: - return int(file.read()) - -def read_json_file(filename): - with open(filename, "r") as file: - return json.loads(file.read()) - -epsilon = 0.001 - -# Generic comparison function using epsilon for comparing floats. -def compare_json(json1, json2): - if type(json1) != type(json2): - return False - - if type(json1) is float: - return abs(json1-json2) < epsilon - - if type(json1) is list: - if len(json1) != len(json2): - return False - for x,y in zip(json1, json2): - if not compare_json(x,y): - return False - return True - - if type(json1) is dict: - keys1 = json1.keys() - keys2 = json2.keys() - keys1.sort() - keys2.sort() - if keys1 == keys2: - for key in keys1: - if not compare_json(json1[key], json2[key]): - return False - return True - else: - return False - - return json1 == json2 - -def what_to_run(): - if len(sys.argv) == 1: - return ("benchmarks/CalibVolDiff", None, None) - elif len(sys.argv) == 2: - return (sys.argv[1], None, None) - elif len(sys.argv) == 3: - return (sys.argv[1], sys.argv[2].split(','), None) - elif len(sys.argv) == 4: - return (sys.argv[1], sys.argv[2].split(','), sys.argv[3].split(',')) - else: - exit("Usage: %s [benchmark] [implementation1,implementation2,...] [dataset1,dataset2,...]" % - sys.argv[0]) - -if __name__ == '__main__': - (benchmark, implementations, datasets) = what_to_run() - instantiations_dir = "instantiations" - platform_file = "config/platform_example.json" - - print("Assuming I am being run from main finpar directory.") - print("Will run benchmark %s." % benchmark) - - if implementations is None: - print("Will run all implementations.") - else: - print("Will run these implementations: %s" % implementations) - - if datasets is None: - print("Will use all datasets.") - else: - print("Will use these datasets: %s" % datasets) - - print("Will instantiate in %s." % instantiations_dir) - print("Will use platform configuration %s." % platform_file) - finpar_dir = os.getcwd() - - def run_implementation_fn(impl): - if implementations is None: - return True - else: - return impl.name in implementations - - def use_dataset_fn(dataset): - if datasets is None: - return True - else: - return dataset in datasets - - (results, failed_to_instantiate) = ( - run_some_benchmark_implementations(finpar_dir, - os.path.join(finpar_dir, instantiations_dir), - os.path.join(finpar_dir, benchmark), - os.path.join(finpar_dir, platform_file), - run_implementation_fn, - use_dataset_fn) - ) - - for failed in failed_to_instantiate: - print("Failed to instantiate implementation %s with dataset %s; exit code %d." % - (failed['implementation'], failed['dataset'], failed['retcode'])) - print("Stdout\n") - print(failed['stdout']) - print("Stderr\n") - print(failed['stderr']) - print("") - - successful = {} - failed = {} - - for result in results: - if type(results[result]) is int: - successful[result] = results[result] - else: - failed[result] = results[result] - - print "\nFailed:" - for f in failed: - (benchmark, implementation, dataset) = f - print("%s: %s" % - (desc_triple(benchmark, implementation, dataset), - failed[f])) - - print "\nSucceeded:" - for s in successful: - (benchmark, implementation, dataset) = s - print("%s: %s" % - (desc_triple(benchmark, implementation, dataset), - successful[s])) From 89dcfac103efbef909e74a687861b96ce3600e05 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 24 Jul 2015 13:17:19 +0200 Subject: [PATCH 031/122] Changed name of executable --- finpar_old | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100755 finpar_old diff --git a/finpar_old b/finpar_old new file mode 100755 index 0000000..80264f9 --- /dev/null +++ b/finpar_old @@ -0,0 +1,355 @@ +#!/usr/bin/env python + +import os +import subprocess +import json +import sys + +def executable(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + +class Implementation: + def __init__(self, finpar_lib_dir, benchmark_lib_dir, name, directory): + if os.path.isdir(directory): + self.directory = directory + else: + if os.path.isfile(directory): + raise Exception("File %s exists, but should be an implementation directory" % directory) + else: + raise Exception("Implementation directory %s does not exist " % directory) + + self.directory = directory + self.name = name + self.finpar_lib_dir = finpar_lib_dir + self.benchmark_lib_dir = benchmark_lib_dir + + instantiatefile = os.path.join(self.directory, "instantiate") + if not executable(instantiatefile): + raise Exception("%s is not an executable file" % instantiatefile) + self.instantiatefile = instantiatefile + + def instantiate(self, where, input_data, platform_file): + if not os.path.isdir(where): + os.mkdir(where) + + # We use the current environment as a template, and then + # extend it with some new variables. + instantiate_env = os.environ.copy() + instantiate_env["FINPAR_LIB_DIR"] = self.finpar_lib_dir + instantiate_env["FINPAR_BENCHMARK_LIB_DIR"] = self.benchmark_lib_dir + instantiate_env["FINPAR_IMPLEMENTATION"] = self.directory + instantiate_env["FINPAR_INPUT"] = input_data + instantiate_env["FINPAR_PLATFORM"] = platform_file + + # Here we are running the "instantiate" program with appropriate vars. "instantiate" should be replaced by a call to make. + proc = subprocess.Popen(self.instantiatefile, + env=instantiate_env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + close_fds=True, + cwd=where) + (stdoutdata, stderrdata) = proc.communicate(input=None) + # returncode = 0 upon success. If retcode = 0, then stdout & stderr are empty. + return (proc.returncode, stdoutdata, stderrdata) + +class Benchmark: + # In the constructor, we do some basic sanity-checking. The + # primary purpose here is to provide better error messages than if + # we fail to read files later down the line. + def __init__(self, finpardir, name, directory): + self.finpardir = finpardir + self.name = name + + if os.path.isdir(directory): + self.directory = directory + else: + raise Exception("Benchmark directory %s does not exist" % directory) + dircontents = os.listdir(self.directory) + + # The lib directories do not have to exist. + self.benchmark_lib_dir = os.path.join(self.directory, "lib") + self.finpar_lib_dir = os.path.join(self.finpardir, "lib") + + if "implementations" in dircontents: + self.__gather_implementations() + else: + raise Exception("No implementation directory in %s" % directory) + + if "datasets" in dircontents: + self.datasets = os.path.join(self.directory, "datasets") + self.__gather_datasets() + else: + raise Exception("No datasets directory in %s" % directory) + + def __gather_implementations(self): + self.implementations = [] + for impl in os.listdir(os.path.join(self.directory, "implementations")): + implpath = os.path.join(self.directory, "implementations", impl) + if os.path.isdir(implpath): + self.implementations.append(Implementation(self.finpar_lib_dir, + self.benchmark_lib_dir, + impl, + os.path.join(self.directory, "implementations", impl))) + + def __gather_datasets(self): + self.datasets = {} + for dataset in os.listdir(os.path.join(self.directory, "datasets")): + datasetpath = os.path.join(self.directory, "datasets", dataset) + if os.path.isdir(datasetpath): + inputfile = os.path.join(self.directory, "datasets", dataset, "input.json") + outputfile = os.path.join(self.directory, "datasets", dataset, "output.json") + if not os.path.isfile(inputfile): + raise Exception("File %s missing or not a file." % inputfile) + if not os.path.isfile(outputfile): + raise Exception("File %s missing or not a file." % outputfile) + + self.datasets[dataset] = { 'input_file' : inputfile, + 'expected_output' : read_json_file(outputfile) + } + +def desc_triple(benchmark, implementation, dataset): + return "Benchmark %s, implementation %s, dataset %s" % (benchmark, implementation, dataset) + +def note_result(results, benchmark, implementation, dataset, runtime): + results[(benchmark,implementation,dataset)] = runtime + +def run_some_benchmark_implementations(finpar_dir, + workdir, + benchmarkdir, + platform, + run_implementation_fn, + use_dataset_fn): + b = Benchmark(finpar_dir, os.path.basename(benchmarkdir), benchmarkdir) + insts = [] + failed_insts = [] + results = {} + + for impl in b.implementations: + if not run_implementation_fn(impl): + continue + for dataset in b.datasets: + if not use_dataset_fn(dataset): + continue + instdir = os.path.join(workdir, + "%s-%s-%s" % (b.name, impl.name, dataset)) + print("Instantiating in %s" % instdir) + (retcode, stdout, stderr) = impl.instantiate(instdir, b.datasets[dataset]['input_file'], platform) + if retcode != 0: + failed_insts.append({ 'benchmark' : b.name, + 'implementation' : impl.name, + 'dataset' : dataset, + 'instantiation_directory' : instdir, + 'retcode' : retcode, + 'stdout' : stdout, + 'stderr' : stderr}) + print("Spoiler: failed") + else: + insts.append({ 'benchmark' : b.name, + 'implementation' : impl.name, + 'dataset' : dataset, + 'instantiation_directory' : instdir, + 'expected_output' : b.datasets[dataset]['expected_output'] + }) + + for inst in insts: + instdir = inst['instantiation_directory'] + print("\nRunning %s" % instdir) + stdoutpath = os.path.join(instdir, "stdout.log") + stderrpath = os.path.join(instdir, "stderr.log") + with open(stdoutpath, "w") as stdout: + with open(stderrpath, "w") as stderr: + print("Output can be found in %s and %s" % (stdoutpath, stderrpath)) + try: + proc = subprocess.Popen(os.path.join(instdir, "run"), + stdout=stdout, + stderr=stderr, + stdin=subprocess.PIPE, + close_fds=True, + cwd=instdir) + proc.stdin.close() # Make sure stdin EOFs. + proc.wait() + except: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "could not run") + continue + + if proc.returncode != 0: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "non-zero exit code") + continue + + try: + runtime = read_runtime(instdir) + except IOError: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "no runtime measurement") + continue + except ValueError: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "non-integer runtime measurement") + continue + + try: + result = read_json_file(os.path.join(instdir, "result.json")) + expected = inst['expected_output'] + if compare_json(result, expected): + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + runtime) + else: + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "invalid result") + except (IOError, ValueError): + note_result(results, + inst['benchmark'], + inst['implementation'], + inst['dataset'], + "cannot read result") + return (results, failed_insts) + +def read_runtime(instdir): + with open(os.path.join(instdir, "runtime.txt"), "r") as file: + return int(file.read()) + +def read_json_file(filename): + with open(filename, "r") as file: + return json.loads(file.read()) + +epsilon = 0.001 + +# Generic comparison function using epsilon for comparing floats. +def compare_json(json1, json2): + if type(json1) != type(json2): + return False + + if type(json1) is float: + return abs(json1-json2) < epsilon + + if type(json1) is list: + if len(json1) != len(json2): + return False + for x,y in zip(json1, json2): + if not compare_json(x,y): + return False + return True + + if type(json1) is dict: + keys1 = json1.keys() + keys2 = json2.keys() + keys1.sort() + keys2.sort() + if keys1 == keys2: + for key in keys1: + if not compare_json(json1[key], json2[key]): + return False + return True + else: + return False + + return json1 == json2 + +def what_to_run(): + if len(sys.argv) == 1: + return ("benchmarks/CalibVolDiff", None, None) + elif len(sys.argv) == 2: + return (sys.argv[1], None, None) + elif len(sys.argv) == 3: + return (sys.argv[1], sys.argv[2].split(','), None) + elif len(sys.argv) == 4: + return (sys.argv[1], sys.argv[2].split(','), sys.argv[3].split(',')) + else: + exit("Usage: %s [benchmark] [implementation1,implementation2,...] [dataset1,dataset2,...]" % + sys.argv[0]) + +if __name__ == '__main__': + (benchmark, implementations, datasets) = what_to_run() + instantiations_dir = "instantiations" + platform_file = "config/platform_example.json" + + print("Assuming I am being run from main finpar directory.") + print("Will run benchmark %s." % benchmark) + + if implementations is None: + print("Will run all implementations.") + else: + print("Will run these implementations: %s" % implementations) + + if datasets is None: + print("Will use all datasets.") + else: + print("Will use these datasets: %s" % datasets) + + print("Will instantiate in %s." % instantiations_dir) + print("Will use platform configuration %s." % platform_file) + finpar_dir = os.getcwd() + + def run_implementation_fn(impl): + if implementations is None: + return True + else: + return impl.name in implementations + + def use_dataset_fn(dataset): + if datasets is None: + return True + else: + return dataset in datasets + + (results, failed_to_instantiate) = ( + run_some_benchmark_implementations(finpar_dir, + os.path.join(finpar_dir, instantiations_dir), + os.path.join(finpar_dir, benchmark), + os.path.join(finpar_dir, platform_file), + run_implementation_fn, + use_dataset_fn) + ) + + for failed in failed_to_instantiate: + print("Failed to instantiate implementation %s with dataset %s; exit code %d." % + (failed['implementation'], failed['dataset'], failed['retcode'])) + print("Stdout\n") + print(failed['stdout']) + print("Stderr\n") + print(failed['stderr']) + print("") + + successful = {} + failed = {} + + for result in results: + if type(results[result]) is int: + successful[result] = results[result] + else: + failed[result] = results[result] + + print "\nFailed:" + for f in failed: + (benchmark, implementation, dataset) = f + print("%s: %s" % + (desc_triple(benchmark, implementation, dataset), + failed[f])) + + print "\nSucceeded:" + for s in successful: + (benchmark, implementation, dataset) = s + print("%s: %s" % + (desc_triple(benchmark, implementation, dataset), + successful[s])) From 3039b9c641e1fb497fabe9a5edac513e9362ccfb Mon Sep 17 00:00:00 2001 From: Thor Date: Mon, 27 Jul 2015 18:16:46 +0200 Subject: [PATCH 032/122] README.md now basically explains how hipermark works --- benchmarks/LocVolCalib/README.txt | 53 - benchmarks/LocVolCalib/ToDo.txt | 28 - .../LocVolCalib/datasets/large/input.json | 6 - .../LocVolCalib/datasets/large/output.json | 29 - .../LocVolCalib/datasets/medium/input.json | 6 - .../LocVolCalib/datasets/medium/output.json | 17 - .../LocVolCalib/datasets/small/input.json | 6 - .../LocVolCalib/datasets/small/output.json | 3 - .../cpp_openclmp_all/CrankNicolson.cl | 1043 --------- .../implementations/cpp_openclmp_all/Makefile | 42 - .../cpp_openclmp_all/PrepareKernels.h | 1576 ------------- .../cpp_openclmp_all/Vect_CPU.h | 159 -- .../cpp_openclmp_all/Vect_GPU.h | 188 -- .../cpp_openclmp_all/VolCalibAll.cpp | 166 -- .../cpp_openclmp_all/VolCalibInit.h | 127 - .../cpp_openclmp_all/instantiate | 28 - .../cpp_openclmp_outer/CrankNicolson.cl | 287 --- .../cpp_openclmp_outer/Makefile | 53 - .../cpp_openclmp_outer/PrepareKernels.h | 529 ----- .../cpp_openclmp_outer/Vect_CPU.h | 122 - .../cpp_openclmp_outer/Vect_GPU.h | 178 -- .../cpp_openclmp_outer/VolCalibInit.h | 137 -- .../cpp_openclmp_outer/VolCalibOuter.cpp | 168 -- .../cpp_openclmp_outer/instantiate | 29 - .../implementations/cpp_openmp_naive/Makefile | 23 - .../cpp_openmp_naive/VolCalibOrig.cpp | 349 --- .../cpp_openmp_naive/instantiate | 24 - .../implementations/cpp_sequential/Makefile | 36 - .../implementations/cpp_sequential/VolCalib | Bin 40968 -> 0 bytes .../cpp_sequential/VolCalibOrig.cpp | 318 --- .../cpp_sequential/instantiate | 15 - .../implementations/cpp_sequential/run | 3 - .../implementations/futhark/CalibVolDiff | Bin 25696 -> 0 bytes .../implementations/futhark/CalibVolDiff.c | 2077 ----------------- .../implementations/futhark/CalibVolDiff.fut | 265 --- .../implementations/futhark/instantiate | 9 - .../LocVolCalib/implementations/futhark/run | 5 - .../implementations/haskell_lh/VolCalib.hs | 441 ---- .../implementations/haskell_lh/instantiate | 11 - .../implementations/haskell_lh/run | 5 - .../LocVolCalib/lib/include/Constants.h | 42 - .../LocVolCalib/lib/include/DataStructConst.h | 91 - .../LocVolCalib/lib/include/ParPrefixUtil.h | 323 --- .../LocVolCalib/lib/include/ParseInput.h | 58 - .../implementations/cpp_openmp/instantiate | 20 +- 45 files changed, 10 insertions(+), 9085 deletions(-) delete mode 100644 benchmarks/LocVolCalib/README.txt delete mode 100644 benchmarks/LocVolCalib/ToDo.txt delete mode 100644 benchmarks/LocVolCalib/datasets/large/input.json delete mode 100644 benchmarks/LocVolCalib/datasets/large/output.json delete mode 100644 benchmarks/LocVolCalib/datasets/medium/input.json delete mode 100644 benchmarks/LocVolCalib/datasets/medium/output.json delete mode 100644 benchmarks/LocVolCalib/datasets/small/input.json delete mode 100644 benchmarks/LocVolCalib/datasets/small/output.json delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/CrankNicolson.cl delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/PrepareKernels.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Vect_CPU.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Vect_GPU.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibInit.h delete mode 100755 benchmarks/LocVolCalib/implementations/cpp_openclmp_all/instantiate delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/CrankNicolson.cl delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/PrepareKernels.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Vect_CPU.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Vect_GPU.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibInit.h delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp delete mode 100755 benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/instantiate delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp delete mode 100755 benchmarks/LocVolCalib/implementations/cpp_openmp_naive/instantiate delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile delete mode 100755 benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalib delete mode 100644 benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp delete mode 100755 benchmarks/LocVolCalib/implementations/cpp_sequential/instantiate delete mode 100755 benchmarks/LocVolCalib/implementations/cpp_sequential/run delete mode 100755 benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff delete mode 100644 benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.c delete mode 100644 benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut delete mode 100755 benchmarks/LocVolCalib/implementations/futhark/instantiate delete mode 100755 benchmarks/LocVolCalib/implementations/futhark/run delete mode 100644 benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs delete mode 100755 benchmarks/LocVolCalib/implementations/haskell_lh/instantiate delete mode 100755 benchmarks/LocVolCalib/implementations/haskell_lh/run delete mode 100644 benchmarks/LocVolCalib/lib/include/Constants.h delete mode 100644 benchmarks/LocVolCalib/lib/include/DataStructConst.h delete mode 100644 benchmarks/LocVolCalib/lib/include/ParPrefixUtil.h delete mode 100644 benchmarks/LocVolCalib/lib/include/ParseInput.h diff --git a/benchmarks/LocVolCalib/README.txt b/benchmarks/LocVolCalib/README.txt deleted file mode 100644 index 848f0be..0000000 --- a/benchmarks/LocVolCalib/README.txt +++ /dev/null @@ -1,53 +0,0 @@ -FIXME: this README is outdated. - -1. This is a benchmark received from Nordea, via Prof. Brian Vinter. - Here is Christian's (Andreetta) guess about what the application is about: - " The task is stochastic volatility calibration, i.e., given a set of - (observed) prices of contracts, we identify the parameters of a model - of such prices, as a function of volatility (unknown), time and strikes (known), - and unobserved parameters like alpha, beta, nu, etc. - - In this case, the volatility is modelled as a system of continuous - partial differential equations, which are solved via Crank-Nicolson's - finite differences method. - - The model seems to be a variation of SABR. - " - -2. STRUCTURE: - - a) `NordeaOrig' folder contains the original sequential code, which can be simply - compiled by: `$ g++ HiperfitExample1.cpp' - - b) `VectOuters' folder contains the GPU parallel version of the code, in which - two (outer) dimensions of parallelism are exploited, but the inner dimension, - corresponding to TRIDAG is sequentially executed. - - The CPU execution executes in parallel the outermost loop (OpenMP). - - The degree of parallelism is sensitive to the following parameters, set in - `DataStructConst.h' file: OUTER_LOOP_COUNT, NUM_X, NUM_Y, which are all set - by default to 128, but can be varied. The degree of exploited parallelism is: - OUTER_LOOP_COUNT * MIN(NUM_X, NUM_Y). - - If you wish the result to not be printed, set DEBUG to 0 in DataStructConst.h, - and if you wish GPU hardware info, define DEBUG_PRINT_GPU_INFO. - - To build for CPU execution, set OMP_NUM_THREADS, and: - $make cpu - To build for GPU execution: - $make gpu - - To run: - $./nordea - - c) `VectAll' folder contains the GPU versions that exploits all parallel dimensions - of parallelism, i.e., TRIDAG is parallelized as a combination of scan with - 2x2 matrix multiplication and linear function composition, respectively. - - It follows that it works well even with smaller values for the parallelism-degree - sensitive parameters, e.g., OUTER_LOOP_COUNT x NUM_X x NUM_Y = 128 x 32 x 32. - - The rest is as with `VectOuters', e.g., in the CPU version the outermost loop - (OUTER_LOOP_COUNT) is executed in parallel via OpenMP. - diff --git a/benchmarks/LocVolCalib/ToDo.txt b/benchmarks/LocVolCalib/ToDo.txt deleted file mode 100644 index aa6a98a..0000000 --- a/benchmarks/LocVolCalib/ToDo.txt +++ /dev/null @@ -1,28 +0,0 @@ -0. Test on different OpSys: Ubuntu, Mac, Windows - Test on different hardware: AMD GPU & NVIDIA GPU - (Intel Phi?) - -1. For both VectAll and VectOuters, check whether the GPU - code is specialized for NVIDIA hardware constants, - such as WARP == 32. (Meaning, test it on AMD GPU) - -2. VectOuters and VectAll: - Currently all the result arrays are copied - back to CPU space, but only a small part - of it is actually required. This filtering - can be done on GPU so as to optimize - communication costs. - -3. Make the seguential overhead, e.g., allocation of CPU/GPU arrays, - close to negligible by increasing the NUM_T, especially for - the Medium and Small datasets. - -4. Source code focusing on readability (not performance). - -5. CONTENT-ORIENTED: - -- eliminate some of the restrictions for VectAll, e.g., - arbitrary size of NUM_X and NUM_Y which leads to - ``global'' segmented scan (in which the segments have - regular sizes). - -- irregular segmented scan, in which there are no restrictions - on the size of the segments. diff --git a/benchmarks/LocVolCalib/datasets/large/input.json b/benchmarks/LocVolCalib/datasets/large/input.json deleted file mode 100644 index d0db1fc..0000000 --- a/benchmarks/LocVolCalib/datasets/large/input.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "outer" : 256, - "num_x" : 256, - "num_y" : 256, - "num_t" : 64 -} diff --git a/benchmarks/LocVolCalib/datasets/large/output.json b/benchmarks/LocVolCalib/datasets/large/output.json deleted file mode 100644 index 8ea53b5..0000000 --- a/benchmarks/LocVolCalib/datasets/large/output.json +++ /dev/null @@ -1,29 +0,0 @@ -[ 0.029996 , 0.029204 , 0.028803 , 0.028405 , 0.028013 , 0.027626 , 0.027245 , 0.026870 , 0.026500 , - 0.026136 , 0.025778 , 0.025426 , 0.025080 , 0.024739 , 0.024404 , 0.024075 , 0.023751 , 0.023433 , - 0.023120 , 0.022813 , 0.022511 , 0.022214 , 0.021923 , 0.021636 , 0.021355 , 0.021078 , 0.020806 , - 0.020538 , 0.020273 , 0.020014 , 0.019791 , 0.019512 , 0.019270 , 0.019033 , 0.018799 , 0.018568 , - 0.018341 , 0.018117 , 0.017898 , 0.017682 , 0.017470 , 0.017261 , 0.017056 , 0.016855 , 0.016657 , - 0.016463 , 0.016271 , 0.016083 , 0.015898 , 0.015716 , 0.015537 , 0.015361 , 0.015188 , 0.015018 , - 0.014850 , 0.014686 , 0.014523 , 0.014364 , 0.014206 , 0.014052 , 0.013899 , 0.013749 , 0.013601 , - 0.013456 , 0.013312 , 0.013171 , 0.013032 , 0.012895 , 0.012760 , 0.012626 , 0.012495 , 0.012365 , - 0.012238 , 0.012112 , 0.011988 , 0.011865 , 0.011744 , 0.011625 , 0.011508 , 0.011392 , 0.011277 , - 0.011164 , 0.011053 , 0.010942 , 0.010834 , 0.010726 , 0.010620 , 0.010515 , 0.010412 , 0.010309 , - 0.010208 , 0.010108 , 0.010010 , 0.009912 , 0.009815 , 0.009720 , 0.009626 , 0.009533 , 0.009440 , - 0.009349 , 0.009259 , 0.009170 , 0.009081 , 0.008994 , 0.008908 , 0.008822 , 0.008737 , 0.008653 , - 0.008570 , 0.008488 , 0.008407 , 0.008326 , 0.008246 , 0.008167 , 0.008089 , 0.008011 , 0.007934 , - 0.007858 , 0.007782 , 0.007707 , 0.007633 , 0.007559 , 0.007487 , 0.007414 , 0.007342 , 0.007271 , - 0.007201 , 0.007131 , 0.007061 , 0.006993 , 0.006924 , 0.006856 , 0.006789 , 0.006722 , 0.006656 , - 0.006590 , 0.006525 , 0.006460 , 0.006396 , 0.006332 , 0.006268 , 0.006205 , 0.006143 , 0.006081 , - 0.006019 , 0.005958 , 0.005897 , 0.005836 , 0.005776 , 0.005716 , 0.005657 , 0.005598 , 0.005539 , - 0.005481 , 0.005423 , 0.005365 , 0.005308 , 0.005251 , 0.005194 , 0.005138 , 0.005081 , 0.005026 , - 0.004970 , 0.004915 , 0.004860 , 0.004806 , 0.004751 , 0.004697 , 0.004643 , 0.004590 , 0.004536 , - 0.004483 , 0.004431 , 0.004378 , 0.004326 , 0.004274 , 0.004222 , 0.004170 , 0.004119 , 0.004068 , - 0.004017 , 0.003966 , 0.003915 , 0.003865 , 0.003815 , 0.003765 , 0.003715 , 0.003665 , 0.003616 , - 0.003566 , 0.003517 , 0.003468 , 0.003420 , 0.003371 , 0.003323 , 0.003274 , 0.003226 , 0.003178 , - 0.003130 , 0.003083 , 0.003035 , 0.002988 , 0.002940 , 0.002893 , 0.002846 , 0.002799 , 0.002752 , - 0.002706 , 0.002659 , 0.002613 , 0.002566 , 0.002520 , 0.002474 , 0.002428 , 0.002382 , 0.002337 , - 0.002291 , 0.002245 , 0.002200 , 0.002154 , 0.002109 , 0.002064 , 0.002019 , 0.001973 , 0.001928 , - 0.001884 , 0.001839 , 0.001794 , 0.001749 , 0.001705 , 0.001660 , 0.001616 , 0.001571 , 0.001527 , - 0.001482 , 0.001438 , 0.001394 , 0.001350 , 0.001306 , 0.001262 , 0.001218 , 0.001174 , 0.001130 , - 0.001086 , 0.001042 , 0.000998 , 0.000954 , 0.000911 , 0.000867 , 0.000823 , 0.000780 , 0.000736 , - 0.000692 , 0.000649 , 0.000605 , 0.000562 ] diff --git a/benchmarks/LocVolCalib/datasets/medium/input.json b/benchmarks/LocVolCalib/datasets/medium/input.json deleted file mode 100644 index 4b6f586..0000000 --- a/benchmarks/LocVolCalib/datasets/medium/input.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "outer" : 128, - "num_x" : 256, - "num_y" : 32, - "num_t" : 64 -} diff --git a/benchmarks/LocVolCalib/datasets/medium/output.json b/benchmarks/LocVolCalib/datasets/medium/output.json deleted file mode 100644 index 4d5f9c1..0000000 --- a/benchmarks/LocVolCalib/datasets/medium/output.json +++ /dev/null @@ -1,17 +0,0 @@ -[ 0.03, 0.0292079, 0.0288058, 0.028408, 0.0280152, 0.0276279, 0.0272462, 0.0268701, - 0.0264998, 0.0261355, 0.025777, 0.0254243, 0.0250773, 0.024736, 0.0244004, 0.0240704, - 0.0237459, 0.0234269, 0.0231134, 0.0228053, 0.0225025, 0.022205, 0.0219126, 0.0216253, - 0.0213431, 0.0210657, 0.0207928, 0.0205238, 0.0202581, 0.0199978, 0.0197739, 0.0194946, - 0.0192514, 0.0190136, 0.0187787, 0.018547, 0.0183189, 0.0180947, 0.0178743, 0.0176577, - 0.0174448, 0.0172356, 0.0170299, 0.0168278, 0.016629, 0.0164336, 0.0162415, 0.0160526, - 0.0158668, 0.0156841, 0.0155044, 0.0153276, 0.0151536, 0.0149826, 0.0148144, 0.0146488, - 0.0144858, 0.0143253, 0.0141674, 0.0140119, 0.0138588, 0.013708, 0.0135595, 0.0134132, - 0.0132691, 0.0131271, 0.0129872, 0.0128494, 0.0127136, 0.0125796, 0.0124477, 0.0123175, - 0.0121892, 0.0120627, 0.0119379, 0.0118149, 0.0116936, 0.0115739, 0.0114558, 0.0113392, - 0.0112242, 0.0111107, 0.0109986, 0.0108879, 0.0107787, 0.0106708, 0.0105642, 0.010459, - 0.010355, 0.0102523, 0.0101509, 0.0100506, 0.00995151, 0.00985357, 0.00975677, 0.00966107, - 0.00956649, 0.00947299, 0.00938053, 0.00928908, 0.00919862, 0.00910914, 0.00902062, 0.00893303, - 0.00884636, 0.00876059, 0.00867569, 0.00859167, 0.00850848, 0.00842613, 0.00834459, 0.00826384, - 0.00818388, 0.00810468, 0.00802623, 0.00794852, 0.00787153, 0.00779524, 0.00771969, 0.00764481, - 0.0075706, 0.00749704, 0.00742412, 0.00735183, 0.00728016, 0.00720909, 0.00713861, 0.00706872 -] diff --git a/benchmarks/LocVolCalib/datasets/small/input.json b/benchmarks/LocVolCalib/datasets/small/input.json deleted file mode 100644 index e14df83..0000000 --- a/benchmarks/LocVolCalib/datasets/small/input.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "outer" : 16, - "num_x" : 32, - "num_y" : 256, - "num_t" : 256 -} diff --git a/benchmarks/LocVolCalib/datasets/small/output.json b/benchmarks/LocVolCalib/datasets/small/output.json deleted file mode 100644 index a316bb0..0000000 --- a/benchmarks/LocVolCalib/datasets/small/output.json +++ /dev/null @@ -1,3 +0,0 @@ -[ 0.0300001, 0.0290001, 0.0280001, 0.0270001, 0.026, 0.0251064, 0.0247889, 0.0244714, - 0.0241539, 0.0238364, 0.0235189, 0.0232014, 0.0228839, 0.0225664, 0.0222744, 0.02199 -] diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/CrankNicolson.cl b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/CrankNicolson.cl deleted file mode 100644 index a06a183..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/CrankNicolson.cl +++ /dev/null @@ -1,1043 +0,0 @@ -#include "Constants.h" - - -#if (WITH_FLOATS) - typedef float4 REAL4; - typedef float2 REAL2; - typedef float3 REAL3; -#else - typedef double4 REAL4; - typedef double2 REAL2; - typedef double3 REAL3; -#endif - -/**************************************************************************/ -/**************** SHARED-MEMORY ACCESSOR FUNCTIONS ************************/ -/**************************************************************************/ - -#define WITH_INTERLEAVED_BANKS4 1 -#define WITH_INTERLEAVED_BANKS2 0 - -#if WITH_INTERLEAVED_BANKS2 -inline void store2(REAL2 val, unsigned int ind, __local REAL* cache) { - ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+1) ); - cache[ind] = val.x; - ind += WORKGROUP_SIZE; - cache[ind] = val.y; -} - -inline REAL2 load2(unsigned int ind, __local REAL* cache) { - ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+1) ); - REAL2 val; - val.x = cache[ind]; - ind += WORKGROUP_SIZE; - val.y = cache[ind]; - return val; -} -#else -inline void store2(REAL2 val, unsigned int ind, volatile __local REAL2* cache) { - cache[ind] = val; -} - -inline REAL2 load2(unsigned int ind, volatile __local REAL2* cache) { - return cache[ind]; -} -#endif - - -#if WITH_INTERLEAVED_BANKS4 -inline void store4(REAL4 val, unsigned int ind, __local REAL* cache) { - //ind = (ind / WORKGROUP_SIZE)*(WORKGROUP_SIZE) * 4 + (ind % WORKGROUP_SIZE); - ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+2) ); - cache[ind] = val.x; - ind += WORKGROUP_SIZE; - cache[ind] = val.y; - ind += WORKGROUP_SIZE; - cache[ind] = val.z; - ind += WORKGROUP_SIZE; - cache[ind] = val.w; -} - -inline REAL4 load4(unsigned int ind, __local REAL* cache) { - REAL4 val; - //ind = (ind / WORKGROUP_SIZE)*(WORKGROUP_SIZE) * 4 + (ind % WORKGROUP_SIZE); - ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+2) ); - val.x = cache[ind]; - ind += WORKGROUP_SIZE; - val.y = cache[ind]; - ind += WORKGROUP_SIZE; - val.z = cache[ind]; - ind += WORKGROUP_SIZE; - val.w = cache[ind]; - return val; -} -#else -inline void store4(REAL4 val, unsigned int ind, volatile __local REAL4* cache) { - cache[ind] = val; -} - -inline REAL4 load4(unsigned int ind, volatile __local REAL4* cache) { - return cache[ind]; -} -#endif -/**************************************************************************/ -/*********** PREPARE FOR TRIDAG X *****************************************/ -/**************************************************************************/ -__kernel void prepare_tridag_x ( - /*** Read-Only Scalars ***/ - __global RWScalars* ro_scals, // __constant - /*** Read-Only Arrays ***/ - __global REAL* myX, - __global REAL3* myDx, - __global REAL3* myDxx, - __constant REAL* myY, - __constant REAL* myDy, - __constant REAL* myDyy, - /*** Read-Write Temporary Arrays ***/ - __global REAL* a, - __global REAL* b, - __global REAL* c, - __global REAL* y, - __global REAL* u, - __global REAL* v, - __global REAL4* scan_tmp, - /*** Temporary Array in Shared Space ***/ - __local REAL* cache_tmp, - /*** The Result Array ***/ - __global REAL* res_arr -) { - REAL3 myDy_elem, myDyy_elem, myres_elem; - REAL cur_myVar = ro_scals->nu; - REAL cur_myMu = 0.0; - - unsigned int glob_ind = get_global_id(2) * get_global_size(1) * get_global_size(0); - const unsigned int ind = glob_ind + get_global_id(1)*get_global_size(0) + get_global_id(0); - - REAL tmp = 0.0; - - cur_myVar *= cur_myVar; - - // second loop - { - myres_elem = (REAL3)( (get_global_id(1)!=0) ? res_arr[ind - get_global_size(0)] : 0.0, - res_arr[ind], - (get_global_id(1) != get_global_size(1)-1) ? res_arr[ind + get_global_size(0)] : 0.0 - ); - - myDy_elem = (REAL3)( myDy[get_global_id(1)<<2], myDy[ (get_global_id(1)<<2)+1], myDy[(get_global_id(1)<<2)+2] ); - myDyy_elem = (REAL3)( myDyy[get_global_id(1)<<2], myDyy[(get_global_id(1)<<2)+1], myDyy[(get_global_id(1)<<2)+2] ); - - myDy_elem = cur_myMu*myDy_elem + 0.5*cur_myVar*myDyy_elem; - myDy_elem *= myres_elem; - tmp += myDy_elem.x + myDy_elem.y + myDy_elem.z; - - v[glob_ind + get_global_id(0)*get_global_size(1) + get_global_id(1)] = tmp; - } - - glob_ind = get_local_id(2)*get_local_size(1)*get_local_size(0) + get_local_id(1)*get_local_size(0) + get_local_id(0); - - // first loop - cur_myMu = 0.0; // X - cur_myVar = exp( 2 * ( ro_scals->beta*log(myX[get_global_id(0)]) + - myY[get_global_id(1)] - 0.5*cur_myVar*ro_scals->timeline_i // cur_myVar == nu*nu - ) - ); - { - // CACHING ASSUMES ALL ELEMENTS IN X DIMENSION fit in the LOCALGROUP! - cache_tmp[glob_ind] = res_arr[ ind ]; - - myDy_elem = myDx[ get_global_id(0) ]; - myDyy_elem = myDxx[ get_global_id(0) ]; - - barrier(CLK_LOCAL_MEM_FENCE); - - - myres_elem = (REAL3)( (get_global_id(0)!=0) ? cache_tmp[ glob_ind - 1 ] : 0.0, - cache_tmp[ glob_ind ], - (get_global_id(0) != get_global_size(0)-1) ? cache_tmp[ glob_ind + 1 ] : 0.0 - ); - - tmp += ro_scals->dtInv*myres_elem.y; - myDy_elem = 0.5*( cur_myMu*myDy_elem + 0.5*cur_myVar*myDyy_elem ); - - c[ind] = - myDy_elem.z; - - barrier(CLK_GLOBAL_MEM_FENCE); - - a[ind] = - myDy_elem.x; // b[ind] = ro_scals->dtInv - myDy_elem.y; - - myDyy_elem = myDy_elem*myres_elem; - tmp += myDyy_elem.x + myDyy_elem.y + myDyy_elem.z; - } - - u[ind] = tmp; - - - - tmp = ro_scals->dtInv - myDy_elem.y; - - // third loop - if( get_global_id(0) > 0 ) { - scan_tmp[ind] = (REAL4) ( tmp, myDy_elem.x * c[ind-1], 1.0, 0.0 ); - } else { // i == get_global_id(0) == 0 - y[ind] = tmp; // = b [ind] - scan_tmp[ind] = (REAL4) ( tmp, 0.0, 0.0, tmp ); - } -} - - -/**************************************************************************/ -/*********** IN-BETWEEN TRIDAGS -- i.e., prepare for TRIDAG Y *************/ -/**************************************************************************/ -//#define USE_LOCAL_Y - -__kernel void prepare_tridag_y ( - /*** Read-Only Scalars ***/ - __global RWScalars* ro_scals, // __constant - /*** Read-Only Arrays ***/ - __global REAL3* myDy, - __global REAL3* myDyy, - /*** Read-Write Temporary Arrays ***/ - __global REAL* a, - __global REAL* b, - __global REAL* c, - __global REAL* u, - __global REAL* v, - __global REAL* y, - __global REAL4* scan_tmp, - /*** Temporary Array in Shared Space ***/ - __local REAL* cache_tmp -) { - - // !!!0 <-> j; 1<-> i; 2 <-> k!!! - const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) - + get_global_id(1) * get_global_size(0) + get_global_id(0); - // + get_global_id(1)*NUM_Y + get_global_id(0); - const unsigned int glob_ind = get_local_id(2)*get_local_size(1)*get_local_size(0) - + get_local_id(1)*get_local_size(0) + get_local_id(0); - REAL3 myDy_elem; - REAL dt_inv = ro_scals->dtInv; - - REAL cur_myMuY = 0.0; - REAL cur_myVarY = ro_scals->nu; cur_myVarY *= cur_myVarY*0.5; //nu*nu; - - myDy_elem = 0.5*( cur_myMuY*myDy [get_global_id(0)] + cur_myVarY*myDyy[get_global_id(0)] ); - -#ifdef USE_LOCAL_Y - cache_tmp[glob_ind] = - myDy_elem.z; -#endif - - a[ind] = - myDy_elem.x; c[ind] = - myDy_elem.z; - - // NUM_X = get_global_size(1) - v[ind] = dt_inv * - u[ get_global_id(2)* get_global_size(1) * get_global_size(0) + - get_global_id(0)*get_global_size(1) + get_global_id(1) ] - - 0.5*v[ind]; // y[j] = dtInv*u[j][i] - 0.5*v[i][j]; - -#ifdef USE_LOCAL_Y - barrier(CLK_LOCAL_MEM_FENCE); -#endif - - // third loop - if( get_global_id(0) > 0 ) { -#ifdef USE_LOCAL_Y - scan_tmp[ind] = (REAL4) ( dt_inv - myDy_elem.y, myDy_elem.x * cache_tmp[glob_ind-1], 1.0, 0.0 ); -#else - const REAL elem = - 0.5*(cur_myMuY*myDy[get_global_id(0)-1].z + cur_myVarY*myDyy[get_global_id(0)-1].z); - scan_tmp[ind] = (REAL4) ( dt_inv - myDy_elem.y, myDy_elem.x * elem, 1.0, 0.0 ); -#endif - //scan_tmp[ind] = (REAL4) ( dt_inv - myDy_elem.y, myDy_elem.x*c[ind-1], 1.0, 0.0 ); - - } else { // j == get_global_id(0) == 0 - y[ind] = dt_inv - myDy_elem.y; //b[ind]; - scan_tmp[ind] = (REAL4) ( dt_inv - myDy_elem.y, 0.0, 0.0, dt_inv - myDy_elem.y ); - } -} - - -/**********************************************************************/ -/************* TRIDAG KERNELS *****************************************/ -/**********************************************************************/ - -/*************************************/ -/*** 1. Scan with Matrix Multiply ****/ -/*************************************/ - -/** - * Multiplies 2x2 matrixes `a' and `b' and - * stores the result in(-place in) `a'. - */ -inline REAL4 matmult2(REAL4 a, REAL4 b) { - REAL val = (a.x*b.x + a.y*b.z); - - a = (REAL4) (val, a.x*b.y + a.y*b.w, a.z*b.x + a.w*b.z, a.z*b.y + a.w*b.w); - val = 1.0/val; - return a * val; -} - - - -//#define LOG2_WARP_SIZE 5U -//#define WARP_SIZE (1U << LOG2_WARP_SIZE) - -#if WITH_INTERLEAVED_BANKS4 -inline REAL4 warpScanInclMatMult(REAL4 idata, volatile __local REAL4 *l_Data4, uint size){ - volatile __local REAL* l_Data = (volatile __local REAL*) l_Data4; - - uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); - store4( (REAL4)(1.0, 0.0, 0.0, 1.0), pos, l_Data ); - pos += size; - store4( idata, pos, l_Data ); - - if(size >= 2) { REAL4 tmp = matmult2( load4(pos, l_Data),load4(pos-1, l_Data) ); store4(tmp, pos, l_Data); } - if(size >= 4) { REAL4 tmp = matmult2( load4(pos, l_Data),load4(pos-2, l_Data) ); store4(tmp, pos, l_Data); } - if(size >= 8) { REAL4 tmp = matmult2( load4(pos, l_Data),load4(pos-4, l_Data) ); store4(tmp, pos, l_Data); } - if(size >= 16) { REAL4 tmp = matmult2( load4(pos, l_Data),load4(pos-8, l_Data) ); store4(tmp, pos, l_Data); } -#if WARP == 32 - if(size >= 32) { REAL4 tmp = matmult2( load4(pos, l_Data),load4(pos-16,l_Data) ); store4(tmp, pos, l_Data); } -#endif - return load4(pos, l_Data); -} -#else -inline REAL4 warpScanInclMatMult(REAL4 idata, volatile __local REAL4 *l_Data, uint size){ - uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); - l_Data[pos] = (REAL4)(1.0, 0.0, 0.0, 1.0); - pos += size; - l_Data[pos] = idata; - - if(size >= 2) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-1] ); - if(size >= 4) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-2] ); - if(size >= 8) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-4] ); - if(size >= 16) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-8] ); -#if WARP == 32 - if(size >= 32) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-16]); -#endif - return l_Data[pos]; -} -#endif - -//Vector scan: the array to be scanned is stored -//in work-item private memory as uint4 -inline REAL4 scanMatMultInclLocal(REAL4 idata4, __local REAL4 *l_Data, uint size){ - if(size > WARP){ - //Bottom-level inclusive warp scan - REAL4 warpResult = warpScanInclMatMult(idata4, l_Data, WARP); - - //Save top elements of each warp for exclusive warp scan - //sync to wait for warp scans to complete (because l_Data is being overwritten) - barrier(CLK_LOCAL_MEM_FENCE); - if( (get_local_id(0) & (WARP - 1)) == (WARP - 1) ) { -#if WITH_INTERLEAVED_BANKS4 - store4(warpResult, get_local_id(0) >> lgWARP, (__local REAL*)l_Data); -#else - l_Data[get_local_id(0) >> lgWARP] = warpResult; -#endif - } - //wait for warp scans to complete - barrier(CLK_LOCAL_MEM_FENCE); - - if( get_local_id(0) < (WORKGROUP_SIZE >> lgWARP) ){ -#if WITH_INTERLEAVED_BANKS4 - REAL4 val = load4(get_local_id(0), (__local REAL*)l_Data); - store4( warpScanInclMatMult(val, l_Data, size >> lgWARP), get_local_id(0), (__local REAL*)l_Data); -#else - //grab top warp elements - REAL4 val = l_Data[get_local_id(0)]; - //calculate inclusive scan and write back to shared memory - l_Data[get_local_id(0)] = warpScanInclMatMult(val, l_Data, size >> lgWARP); -#endif - } - - //return updated warp scans with exclusive scan results - barrier(CLK_LOCAL_MEM_FENCE); - - //if( (get_local_id(0) >> LOG2_WARP_SIZE) > 0 ) - if( ( (get_local_id(0) & (size-1)) >> lgWARP ) > 0 ) { -#if WITH_INTERLEAVED_BANKS4 - REAL4 tmp = load4( (get_local_id(0) >> lgWARP) - 1, (__local REAL*)l_Data ); - warpResult = matmult2( warpResult, tmp ); -#else - warpResult = matmult2( warpResult, l_Data[ (get_local_id(0) >> lgWARP) - 1] ); -#endif - } - - return warpResult; - }else{ - return warpScanInclMatMult(idata4, l_Data, size); - } -} - -__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) -void scanMatMultIncl( - __global REAL4 *data, - __local REAL4 *l_Data, - uint size -){ - //Load data - REAL4 idata4 = data[get_global_id(0)]; - - //Calculate exclusive scan - REAL4 odata4 = scanMatMultInclLocal( idata4, l_Data, size ); - - //Write back - data[get_global_id(0)] = odata4; -} - - -/*************************************************/ -/*** 1. Scan with Linear Function Composition ****/ -/*************************************************/ - -// Linear Function Composition and Scan -inline REAL2 linfuncomp(REAL2 ab2, REAL2 ab1) { - ab2.x = ab2.y * ab1.x + ab2.x; - ab2.y = ab2.y * ab1.y; - return ab2; -} - -#if WITH_INTERLEAVED_BANKS2 -inline REAL2 warpScanInclLinFunComp(REAL2 idata, volatile __local REAL2 *l_Data2, uint size){ - volatile __local REAL* l_Data = (volatile __local REAL*) l_Data2; - - uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); - store2( (REAL2)(0.0, 1.0), pos, l_Data ); - pos += size; - store2( idata, pos, l_Data ); - - if(size >= 2) { REAL2 tmp = linfuncomp( load2(pos, l_Data),load2(pos-1, l_Data) ); store2(tmp, pos, l_Data); } - if(size >= 4) { REAL2 tmp = linfuncomp( load2(pos, l_Data),load2(pos-2, l_Data) ); store2(tmp, pos, l_Data); } - if(size >= 8) { REAL2 tmp = linfuncomp( load2(pos, l_Data),load2(pos-4, l_Data) ); store2(tmp, pos, l_Data); } - if(size >= 16) { REAL2 tmp = linfuncomp( load2(pos, l_Data),load2(pos-8, l_Data) ); store2(tmp, pos, l_Data); } -#if WARP == 32 - if(size >= 32) { REAL2 tmp = linfuncomp( load2(pos, l_Data),load2(pos-16,l_Data) ); store2(tmp, pos, l_Data); } -#endif - return load2(pos, l_Data); -} -#else -inline REAL2 warpScanInclLinFunComp(REAL2 idata, volatile __local REAL2 *l_Data, uint size){ - uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); - l_Data[pos] = (REAL2)(0.0, 1.0); - pos += size; - l_Data[pos] = idata; - - if(size >= 2) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-1] ); - if(size >= 4) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-2] ); - if(size >= 8) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-4] ); - if(size >= 16) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-8] ); -#if WARP == 32 - if(size >= 32) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-16]); -#endif - return l_Data[pos]; -} -#endif - -inline REAL2 scanLinFunCompInclLocal(REAL2 idata4, __local REAL2 *l_Data, uint size){ - if(size > WARP){ - //Bottom-level inclusive warp scan - REAL2 warpResult = warpScanInclLinFunComp(idata4, l_Data, WARP); - - //Save top elements of each warp for exclusive warp scan - //sync to wait for warp scans to complete (because l_Data is being overwritten) - barrier(CLK_LOCAL_MEM_FENCE); - if( (get_local_id(0) & (WARP - 1)) == (WARP - 1) ) { -#if WITH_INTERLEAVED_BANKS2 - store2(warpResult, get_local_id(0) >> lgWARP, (__local REAL*)l_Data); -#else - l_Data[get_local_id(0) >> lgWARP] = warpResult; -#endif - } - - //wait for warp scans to complete - barrier(CLK_LOCAL_MEM_FENCE); - - if( get_local_id(0) < (WORKGROUP_SIZE / WARP) ){ -#if WITH_INTERLEAVED_BANKS2 - REAL2 val = load2(get_local_id(0), (__local REAL*)l_Data); - store2( warpScanInclLinFunComp(val, l_Data, size >> lgWARP), get_local_id(0), (__local REAL*)l_Data); -#else - //grab top warp elements - REAL2 val = l_Data[get_local_id(0)]; - //calculate inclusive scan and write back to shared memory - l_Data[get_local_id(0)] = warpScanInclLinFunComp(val, l_Data, size >> lgWARP); -#endif - } - - //return updated warp scans with exclusive scan results - barrier(CLK_LOCAL_MEM_FENCE); - - if( ( (get_local_id(0) & (size-1)) >> lgWARP ) > 0 ) { -#if WITH_INTERLEAVED_BANKS2 - REAL2 tmp = load2( (get_local_id(0) >> lgWARP) - 1, (__local REAL*)l_Data ); - warpResult = linfuncomp( warpResult, tmp ); -#else - warpResult = linfuncomp( warpResult, l_Data[ (get_local_id(0) >> lgWARP) - 1] ); -#endif - } - return warpResult; - }else{ - return warpScanInclLinFunComp(idata4, l_Data, size); - } -} - - -__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) -void scanLinFunCompIncl( - __global REAL2 *data, - __local REAL2 *l_Data, - uint size -){ - //Load data - REAL2 idata4 = data[get_global_id(0)]; - - //Calculate exclusive scan - REAL2 odata4 = scanLinFunCompInclLocal( idata4, l_Data, size ); - - //Write back - data[get_global_id(0)] = odata4; -} - - -/*************************************/ -/*** 2. TRIDAG - in between scans ****/ -/*************************************/ - -inline REAL map_matmult(REAL4 tmp, REAL val1) { - - REAL nom = tmp.x*val1+tmp.y; - REAL denom = tmp.z*val1+tmp.w; - - return nom/denom; - - //REAL denom = tmp.z*val1+tmp.w*val2; - //REAL nom = (tmp.x/denom)*val1 + (tmp.y/denom)*val2; - //return nom; -} - -__kernel void conclude_matmult ( - /*** Read-Write Temporary Arrays ***/ - __global REAL* b, - __global REAL* d, - __global REAL* y, - __global REAL* u, - __global REAL4* scan_tmp -) { - unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) - + get_global_id(1) * get_global_size(0); - REAL b0 = u[ind]; //b[ ind ]; - ind += get_global_id(0); - - if(get_global_id(0) > 0) { - u[ind] = map_matmult( scan_tmp[ind], b0 ); - } else { - y[ind] = d[ind]; - } -} - - -__kernel void prelude_fwd_fun_comp ( - /*** Read-Write Temporary Arrays ***/ - __global REAL* a, - __global REAL* d, - __global REAL* u, - __global REAL2* scan_tmp -) { - const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) - + get_global_id(1) * get_global_size(0) + get_global_id(0); - - if( get_global_id(0) > 0 ) { - scan_tmp[ind] = (REAL2) ( d[ind], (0.0 - (a[ind]/u[ind-1])) ); - } else { - scan_tmp[ind] = (REAL2) (0.0, 1.0); - } -} - -///// - -__kernel void post_fwd_fun_comp ( - /*** Read-Write Temporary Arrays ***/ - __global REAL* y, - __global REAL2* scan_tmp -) { - unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) - + get_global_id(1) * get_global_size(0); - - REAL y0 = y[ ind ]; - - ind += get_global_id(0); - - if( get_global_id(0) > 0 ) { - REAL2 fun = scan_tmp[ind]; - y[ind] = fun.x + y0 * fun.y; - } -} - -__kernel void prelude_bwd_fun_comp ( - /*** Read-Write Temporary Arrays ***/ - __global REAL* c, - __global REAL* y, - __global REAL* u, - __global REAL2* scan_tmp -) { - const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) - + get_global_id(1) * get_global_size(0) + get_global_id(0); - const unsigned int inv_ind = ind - 2*get_global_id(0) + get_global_size(0) - 2; - - if( get_global_id(0) < get_global_size(0) - 1 ) { - scan_tmp[ind] = (REAL2)(y[inv_ind]/u[inv_ind], 0.0 - c[inv_ind]/u[inv_ind]); - } else { // get_global_id(0) == get_global_size(0) - 1 - scan_tmp[ind] = (REAL2)(0.0, 1.0); - y[ind] = y[ind]/u[ind]; - } -} - -/** - * 1. map back the result from the (bacward) parallel prefix - * with linear function composition - * 2. update the RW scalars rw_scals->dtInv and rw_scals->timeline_i - */ -__kernel void post_bwd_fun_comp ( - __global REAL* y, - __global REAL2* scan_tmp -) { - // map back the result from the (bacward) parallel prefix - // with linear function composition - - const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) - + get_global_id(1) * get_global_size(0) + get_global_id(0); - const unsigned int inv_ind = ind - 2*get_global_id(0) + get_global_size(0) - 2; - - REAL ynm1 = y[inv_ind + get_global_id(0) + 1]; - - if( get_global_id(0) < get_global_size(0) - 1 ) { - REAL2 fun = scan_tmp[ind]; - y[inv_ind] = fun.x + ynm1 * fun.y; - } -} - - -/*********************************************/ -/*********** Matrix Transposition ************/ -/*********************************************/ - -// This kernel is optimized to ensure all global reads and writes are coalesced, -// and to avoid bank conflicts in shared memory. The shared memory array is sized -// to (BLOCK_DIM+1)*BLOCK_DIM. This pads each row of the 2D block in shared memory -// so that bank conflicts do not occur when threads address the array column-wise. -inline void transposeMatrix( - __global REAL *odata, - __global REAL *idata, - unsigned int width, - unsigned int height, - __local REAL* block) -{ - unsigned int xIndex, yIndex; - - // adjust the input and output arrays for the third dimension! - yIndex = get_global_id(2) * width * height; - odata = odata + yIndex; - idata = idata + yIndex; - - // read the matrix tile into shared memory - xIndex = get_global_id(0); - yIndex = get_global_id(1); - - if((xIndex < width) && (yIndex < height)) - { - unsigned int index_in = yIndex * width + xIndex; - block[get_local_id(1)*(BLOCK_DIM+1)+get_local_id(0)] = idata[index_in]; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // write the transposed matrix tile to global memory - xIndex = get_group_id(1) * BLOCK_DIM + get_local_id(0); - yIndex = get_group_id(0) * BLOCK_DIM + get_local_id(1); - if((xIndex < height) && (yIndex < width)) - { - unsigned int index_out = yIndex * height + xIndex; - odata[index_out] = block[get_local_id(0)*(BLOCK_DIM+1)+get_local_id(1)]; - } -} - -__kernel void transpose( - __global REAL *odata, - __global REAL *idata, - //int offset, - unsigned int width, - unsigned int height, - __local REAL* block) -{ - transposeMatrix( odata, idata, width, height, block ); -} - -__kernel void transposeUpdateScalars( - __global REAL *odata, - __global REAL *idata, - //int offset, - unsigned int width, - unsigned int height, - __local REAL* block, - __global RWScalars* ro_scals, // __constant - __constant REAL* timeline -) { - transposeMatrix( odata, idata, width, height, block ); - //odata[get_global_id(2)*get_global_size(1)*get_global_size(0) + get_global_id(1)*get_global_size(0) + get_global_id(0)] - // = 33.33; - - // update time-loop-variant scalars - if(get_global_id(2) + get_global_id(1) + get_global_id(0) == 0) { - int t_ind = --ro_scals->t_ind; - ro_scals->dtInv = 1.0 / ( timeline[t_ind+1] - timeline[t_ind] ); - ro_scals->timeline_i = timeline[ t_ind ]; - } -} - - -/***************************************************************/ -/**************** INLINED TRIDAG VERSION ***********************/ -/***************************************************************/ - -inline void tridag_inline_local ( - /*** Read-Write Temporary Arrays ***/ -// __global REAL* a, - REAL a_elem, -// __global REAL* c, - REAL c_elem, -// __global REAL* d, - REAL d_elem, - __global REAL* y, -// __global REAL4* scan_tmp4, - REAL4 data4, - const unsigned int SIZE, -/*** Temporary Array in Shared Space ***/ - __local REAL* cache_tmp, // size: [8*WORKSIZE*sizeof(REAL)] - const size_t first_id, - REAL b0, - REAL d0 -) { - //const size_t first_id = get_global_id(0) - (get_global_id(0) & (SIZE-1)); - //REAL b0; - - { // SCAN with matrix multiplication - __local REAL4* l_data = (__local REAL4*)cache_tmp; - - //Calculate exclusive scan - data4 = scanMatMultInclLocal( data4, l_data, SIZE ); - barrier(CLK_LOCAL_MEM_FENCE); // IMPORTANT! - - REAL data = map_matmult( data4, b0 ); - cache_tmp[get_local_id(0)] = data; - barrier(CLK_LOCAL_MEM_FENCE); - } - - { // Forward scan with linear function composition - REAL2 data2; - // prepare for scan - if(get_global_id(0) == first_id) { - //y[get_global_id(0)] = d0; //d[get_global_id(0)]; // y[ind] = d[ind]; - data2 = (REAL2) (0.0, 1.0); - } else { - data2 = (REAL2) ( d_elem, (0.0 - (a_elem/cache_tmp[get_local_id(0)-1])) ); - } - - {//Calculate exclusive scan - __local REAL2* l_Data = ((__local REAL2*)cache_tmp) + get_local_size(0); - data2 = scanLinFunCompInclLocal( data2, l_Data, SIZE ); - } - - //POST FWD MAP: y[ind] = fun.x + y0 * fun.y; - //y[get_global_id(0)] = data2.x + d0 * data2.y; - { - cache_tmp[get_local_size(0) + get_local_id(0)] = data2.x + d0 * data2.y; - barrier(CLK_LOCAL_MEM_FENCE); - } - } - - { // Backward scan with linear function composition - const unsigned int inv_ind = (SIZE-1) - (get_global_id(0) & (SIZE-1)); - REAL2 data2; - - unsigned int local_offset = get_local_id(0) - (get_local_id(0) & (SIZE-1)); - b0 = cache_tmp[local_offset + get_local_size(0) + (SIZE-1)]/cache_tmp[local_offset + (SIZE-1)]; - - // prepare for scan! - if(get_global_id(0) == first_id) { - data2 = (REAL2) (0.0, 1.0); - } else { - REAL myu = cache_tmp[local_offset + inv_ind]; - data2 = (REAL2) ( cache_tmp[local_offset + inv_ind + get_local_size(0)] / myu, - 0.0 - c_elem / myu ); - //0.0 - c[first_id + inv_ind]/myu ); - } - - {// BACKWARD SCAN with linear function compsition - __local REAL2* l_Data = ((__local REAL2*)cache_tmp) + get_local_size(0); - data2 = scanLinFunCompInclLocal( data2, l_Data, SIZE ); - } - - // //POST BWD MAP: y[ind] = fun.x + y0 * fun.y; - y[first_id + inv_ind] = data2.x + b0 * data2.y; - } - -} - -__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) -void tridag_inlined ( - /*** Read-Write Temporary Arrays ***/ - __global REAL* a, - __global REAL* c, - __global REAL* d, - __global REAL* y, - __global REAL* u, - __global REAL4* scan_tmp4, - const unsigned int SIZE, -/*** Temporary Array in Shared Space ***/ - __local REAL* cache_tmp // size: [8*WORKSIZE*sizeof(REAL)] -) { - const size_t first_id = get_global_id(0) - (get_global_id(0) & (SIZE-1)); - //const unsigned int inv_ind = (SIZE-1) - (get_global_id(0) & (SIZE-1)); - - tridag_inline_local ( - a[get_global_id(0)], - c[first_id + (SIZE-1) - (get_global_id(0) & (SIZE-1))], - //(get_global_id(0) != first_id) ? c[first_id + (SIZE-1) - (get_global_id(0) & (SIZE-1))] : 0.0, //c - d[get_global_id(0)], - y, - scan_tmp4[get_global_id(0)], - SIZE, - cache_tmp, - first_id, - scan_tmp4[first_id].x, - d[first_id] - ); -} - - - -/***************************************************************/ -/************* TWO KERNELS VERSION: X & Y **********************/ -/***************************************************************/ - -__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) -void nordea_kernel_x ( - /*** Read-Only Scalars ***/ - __constant RWScalars* ro_scals, // __constant - /*** Read-Only Arrays ***/ - __global REAL* myX, - __global REAL3* myDx, - __global REAL3* myDxx, - __constant REAL* myY, - __constant REAL* myDy, - __constant REAL* myDyy, - /*** Read-Write Temporary Arrays ***/ - __global REAL* u, - __global REAL* v, - /*** Temporary Array in Shared Space ***/ - __local REAL* cache_tmp, - /*** The Result Array ***/ - __global REAL* res_arr -) { - - REAL3 myD_elem; - - unsigned int ind_x = get_global_id(0) & (ro_scals->NUM_X-1); - unsigned int ind_y = (get_global_id(0) & (ro_scals->NUM_XY-1)) / ro_scals->NUM_X; - - REAL tmp = 0.0; - - { - // I. second loop - REAL3 myres_elem; - REAL cur_myMu = 0.0; - REAL cur_myVar = ro_scals->nu; - cur_myVar *= cur_myVar; - - myres_elem = (REAL3)( myDyy[ind_y<<2], myDyy[(ind_y<<2)+1], myDyy[(ind_y<<2)+2] ); - myD_elem = (REAL3)( myDy [ind_y<<2], myDy [(ind_y<<2)+1], myDy [(ind_y<<2)+2] ); - - myD_elem = cur_myMu*myD_elem + 0.5*cur_myVar*myres_elem; - - myres_elem = (REAL3)( (ind_y != 0) ? res_arr[get_global_id(0) - ro_scals->NUM_X] : 0.0, - res_arr[get_global_id(0)], - (ind_y != ro_scals->NUM_Y-1) ? res_arr[get_global_id(0) + ro_scals->NUM_X] : 0.0 - ); - - myD_elem *= myres_elem; - tmp += myD_elem.x + myD_elem.y + myD_elem.z; - -#if TRANSPOSE_UV - v[ get_global_id(0) ] = tmp; -#else - v[ (get_global_id(0)/ro_scals->NUM_XY)*ro_scals->NUM_XY + ind_x*ro_scals->NUM_Y + ind_y] = tmp; -#endif - - // II. first loop - cur_myMu = 0.0; // X - cur_myVar = exp( 2 * ( ro_scals->beta*log(myX[ind_x]) + - myY[ind_y] - 0.5*cur_myVar*ro_scals->timeline_i // cur_myVar == nu*nu - ) - ); - // CACHING ASSUMES ALL ELEMENTS IN X DIMENSION fit in the LOCALGROUP! - cache_tmp[get_local_id(0)] = res_arr[ get_global_id(0) ]; - - myD_elem = myDx[ ind_x ]; - - barrier(CLK_LOCAL_MEM_FENCE); - - - myres_elem = (REAL3)( (ind_x!=0) ? cache_tmp[ get_local_id(0) - 1 ] : 0.0, - cache_tmp[ get_local_id(0) ], - (ind_x != ro_scals->NUM_X-1) ? cache_tmp[ get_local_id(0) + 1 ] : 0.0 - ); - - tmp += ro_scals->dtInv*myres_elem.y; - myD_elem = 0.5*( cur_myMu*myD_elem + 0.5*cur_myVar*myDxx[ ind_x ] ); - - // write in cache the values of c! - cache_tmp[get_local_size(0) + get_local_id(0)] = - myD_elem.z; // c[get_global_id(0)] = - myD_elem.z; - - barrier(CLK_LOCAL_MEM_FENCE); - - myres_elem = myD_elem*myres_elem; - tmp += myres_elem.x + myres_elem.y + myres_elem.z; - - //a[get_global_id(0)] = - myD_elem.x; // b[ind] = ro_scals->dtInv - myDy_elem.y; - myD_elem.x = - myD_elem.x; // holds `a[glb_ind]' - } - - - { - // prepare for and call TRIDAG - REAL4 scan_elem; - //u[get_global_id(0)] = tmp; //u[j*NUM_X + i] = tmp1 + tmp2; //u[j][i] = tmp1 + tmp2; - myD_elem.z = tmp; - - tmp = ro_scals->dtInv - myD_elem.y; // b[ind] = tmp; - - //barrier(CLK_LOCAL_MEM_FENCE); - - - // third loop - if( ind_x > 0 ) { - myD_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) - 1]; // i.e., c[glob_ind-1] - scan_elem = (REAL4) ( tmp, 0.0 - myD_elem.x * myD_elem.y, 1.0, 0.0 ); - myD_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) + (ro_scals->NUM_X-1) - 2*ind_x]; // i.e., c[glb_ind_inv] - } else { // i == get_global_id(0) == 0 - scan_elem = (REAL4) ( tmp, 0.0, 0.0, tmp ); //(REAL4) ( 1.0, 0.0, 0.0, 1.0 ); - myD_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) + (ro_scals->NUM_X-1) ]; - - cache_tmp[get_local_id(0) ] = tmp; - cache_tmp[get_local_id(0) + 1] = myD_elem.z; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - tmp = cache_tmp[get_local_id(0) - ind_x ]; - REAL d0 = cache_tmp[get_local_id(0) - ind_x + 1]; - - barrier(CLK_LOCAL_MEM_FENCE); - - // CALL TRIDAG - tridag_inline_local ( - myD_elem.x, // a[glb_ind] - myD_elem.y, // c[glb_ind_inv] - myD_elem.z, // d[glb_ind] == u[glb_ind] - u, // y - scan_elem, // scan_tmp[glb_ind] - ro_scals->NUM_X, // SIZE - cache_tmp, // cache - get_global_id(0) - ind_x, // first_id - tmp, // b0 - d0 // d0 - ); - } -} - -//////////////////////////////////////////////////////////////// -////////// AND KERNEL FOR THE Y-INNERMOST DIMENSION //////////// -//////////////////////////////////////////////////////////////// - -__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) -void nordea_kernel_y ( - /*** Read-Only Scalars ***/ - __constant RWScalars* ro_scals, // __constant - /*** Read-Only Arrays ***/ - __global REAL3* myDy, - __global REAL3* myDyy, - /*** Read-Write Temporary Arrays ***/ - __global REAL* u, - __global REAL* v, - /*** Temporary Array in Shared Space ***/ - __local REAL* cache_tmp // SIZE: 8 * WORKGROUP_SIZE * sizeof(REAL) -) { - - REAL3 myDy_elem; - - unsigned int ind_y = get_global_id(0) & (ro_scals->NUM_Y-1); - unsigned int ind_x = (get_global_id(0) & (ro_scals->NUM_XY-1)) / ro_scals->NUM_Y; - - { - REAL dt_inv = ro_scals->dtInv; -#if TRANSPOSE_UV - REAL my_u = u[get_global_id(0)]; -#else - REAL my_u = u[ (get_global_id(0)/ro_scals->NUM_XY)*ro_scals->NUM_XY + - ind_y * ro_scals->NUM_X + ind_x ]; -#endif - - REAL tmp = 0.0; - REAL cur_myVarY = ro_scals->nu; cur_myVarY *= cur_myVarY*0.5; //nu*nu; - - myDy_elem = 0.0 - 0.5*( tmp*myDy[ind_y] + cur_myVarY*myDyy[ind_y] ); - - // a[ind] = myDy_elem.x; c[ind] = myDy_elem.z; - cache_tmp[get_local_size(0) + get_local_id(0)] = myDy_elem.z; // c[ind] - myDy_elem.y = dt_inv + myDy_elem.y; // b[ind] - - - //v[get_global_id(0)] = dt_inv * my_u - 0.5 * v[get_global_id(0)]; - myDy_elem.z = dt_inv * my_u - 0.5 * v[get_global_id(0)]; // i.e., v[ind] - - if(ind_y == 0) { - cache_tmp[get_local_id(0) ] = myDy_elem.y; // b0 - cache_tmp[get_local_id(0) + 1] = myDy_elem.z; // d0, i.e., v[0] - } - - } - - barrier(CLK_LOCAL_MEM_FENCE); - - { - REAL4 scan_elem; - REAL b0, d0; - - // third loop - if( ind_y > 0 ) { - scan_elem = (REAL4) ( myDy_elem.y, 0.0 - myDy_elem.x * cache_tmp[get_local_size(0)+get_local_id(0)-1], 1.0, 0.0 ); - } else { - scan_elem = (REAL4) ( 1.0, 0.0, 0.0, 1.0 ); - } - - myDy_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) + (ro_scals->NUM_Y-1) - 2*ind_y]; // i.e., c[ind_inv] - - b0 = cache_tmp[get_local_id(0) - ind_y ]; - d0 = cache_tmp[get_local_id(0) - ind_y + 1]; // d0 - - barrier(CLK_LOCAL_MEM_FENCE); - - // CALL TRIDAG - tridag_inline_local ( - myDy_elem.x, // a[glb_ind] - myDy_elem.y, // c[glb_ind_inv] - myDy_elem.z, // d[glb_ind] == v[glb_ind] - v, // y - scan_elem, // scan_tmp[glb_ind] - ro_scals->NUM_Y, // SIZE - cache_tmp, // cache - get_global_id(0) - ind_y, // first_id - b0, // b0 - d0 // d0 - ); - } -} diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile deleted file mode 100644 index e07480b..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -include setup.mk - -ifndef ($(HAVE_GPU)) -include platform.mk -endif - -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ - -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ - -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ - -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) - -SOURCES_CPP =VolCalibAll.cpp -HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h ../includeC/Constants.h \ - ../includeC/ParseInput.h ../includeC/DataStructConst.h ../includeC/ParPrefixUtil.h -OBJECTS =VolCalibAll.o -EXECUTABLE =VolCalib - -ifeq ($(HAVE_GPU),1) -default: gpu -else -# cannot build this one... -no-gpu: - @echo "\n*** No GPU configured, cannot build `pwd` ***\n" - exit 1 -endif - -#.cpp.o: $(SOURCES_CPP) $(HELPERS) -# $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -#$(OBJECTS) -cpu: - $(CXX) $(CXXFLAGS) -D IS_GPU=0 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) - -gpu: - $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) - -clean: - rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt - @# clean nVidia compiler cache - rm -rf $(HOME)/.nv/ComputeCache/* - diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/PrepareKernels.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/PrepareKernels.h deleted file mode 100644 index d76d963..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/PrepareKernels.h +++ /dev/null @@ -1,1576 +0,0 @@ -/***********************************************************/ -/*************** Helper DATA STRUCTURES ********************/ -/***********************************************************/ - -// GPU BUFFERS -struct oclNordeaArrays { - /* RO scalars */ - cl_mem ro_scals; - - /* RO arrays */ - cl_mem timeline; // [NUM_T] - - cl_mem myX; // [NUM_X] - cl_mem myDx; // [NUM_X * 3] - cl_mem myDxx; // [NUM_X * 3] - - cl_mem myY; // [NUM_Y] - cl_mem myDy; // [NUM_Y * 3] - cl_mem myDyy; // [NUM_Y * 3] - - /* TRIDAG helpers */ - cl_mem a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem tmp4; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem tmp2; // [2 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - cl_mem res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - /* WRITE ONLY OUTPUT stored in "res"*/ - //cl_mem res; -}; - -// CPU BUFFERS -struct NordeaArrays { - /* RO arrays */ - REAL* timeline; // [NUM_T] - - REAL* myX; // [NUM_X] - REAL* myDx; // [NUM_X * 3] - REAL* myDxx; // [NUM_X * 3] - - REAL* myY; // [NUM_Y] - REAL* myDy; // [NUM_Y * 3] - REAL* myDyy; // [NUM_Y * 3] - - /* TRIDAG helpers are created on GPU only! no need for them to exist in main memory*/ - REAL* a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* tmp; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - REAL* res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - /* NOT USED FOR NOW! WRITE ONLY OUTPUT stored in "res"*/ - //REAL* res; -}; - -// GPU KERNELS -typedef struct { - // PRE/POST TRIDAG KERNELS - cl_kernel ckPreTridagX; // NUM_X x NUM_Y x OUTER_LOOP_COUNT - cl_kernel ckPreTridagY; // NUM_Y x NUM_X x OUTER_LOOP_COUNT - cl_kernel ckMatTranspUpdate; - - cl_kernel ckMatTransposeU; - cl_kernel ckMatTransposeV; - - // TRIDAG KERNELS - cl_kernel ckTridagMatMult [2]; // scan with matrix multiplication: - cl_kernel ckConcludeMatMult[2]; - - cl_kernel ckPreludeFwdFunComp[2]; - cl_kernel ckTridagFwdFunComp[2]; // scan with linear function composition - cl_kernel ckPostFwdFunComp[2]; - - cl_kernel ckPreludeBwdFunComp[2]; - cl_kernel ckPostBwdFunComp[2]; - - cl_kernel ckTridagAllOpt[2]; - - cl_kernel ckNordeaKernelX; - cl_kernel ckNordeaKernelY; - - size_t GWS_XYZ [3]; - size_t LWS_XYZ [3]; - - size_t GWS_YXZ [3]; - size_t LWS_YXZ [3]; - - // NOT USED - //cl_kernel ckMatTransp; // NUM_Y x NUM_X x OUTER_LOOP_COUNT -} GPUkernels __attribute__ ((aligned (32))); - -/******************************************************/ -/******* compute global/local grid dimensions *********/ -/******************************************************/ - -static void local_block_size( - size_t size_x, size_t size_y, size_t size_z, - size_t& loc_x, size_t& loc_y, size_t& loc_z -) { - bool ok = is_pow2(size_x) && is_pow2(size_y); - assert( ok && "Global Size X or Y is not a power of 2!"); - assert( size_x * size_y >= WORKGROUP_SIZE && "NUM_X * NUM_Y < WORKGROUP_SIZE!!!"); - - loc_x = WORKGROUP_SIZE; loc_y = 1; loc_z = 1; - while(size_x / loc_x == 0) { - loc_x /= 2; - loc_y *= 2; - } - - ok = is_pow2(loc_x) && is_pow2(loc_y) && (loc_x*loc_y == WORKGROUP_SIZE) && (loc_x <= size_x) && (loc_y <= size_y); - assert( ok && "Local Block Size is not a power of 2!"); -} - - -void initGPUgrid ( GPUkernels& kernels ) { - { // find a convenient local block size - size_t loc_x, loc_y, loc_z; - - kernels.GWS_XYZ[0] = NUM_X; kernels.GWS_XYZ[1] = NUM_Y; kernels.GWS_XYZ[2] = OUTER_LOOP_COUNT; - kernels.GWS_YXZ[0] = NUM_Y; kernels.GWS_YXZ[1] = NUM_X; kernels.GWS_YXZ[2] = OUTER_LOOP_COUNT; - - local_block_size(NUM_X, NUM_Y, OUTER_LOOP_COUNT, loc_x, loc_y, loc_z); - kernels.LWS_XYZ[0] = loc_x; kernels.LWS_XYZ[1] = loc_y; kernels.LWS_XYZ[2] = loc_z; - - local_block_size(NUM_Y, NUM_X, OUTER_LOOP_COUNT, loc_y, loc_x, loc_z); - kernels.LWS_YXZ[0] = loc_y; kernels.LWS_YXZ[1] = loc_x; kernels.LWS_YXZ[2] = loc_z; - } - -} - -/************************************************************/ -/*************** KERNELS OTHER THAN TRIDAG ****************** -/************************************************************/ - -cl_kernel make_prepare_tridag_X( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs, - size_t* globalWorkSize, - size_t* localWorkSize -) { - cl_kernel ckPreTridagX = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckPreTridagX = clCreateKernel(cpProgram, "prepare_tridag_x", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - { // 1. RO SCALARS // - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); - } - - { // 2. RO ARRAYS // - //ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.timeline); - - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myX); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDx); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDxx); - - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myY); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); - } - - { // 3. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); - } - -#if 1 - { // 4. LOCAL (PRIVATE ARRAYS) - const int PRIV_MULT = sizeof(REAL) * localWorkSize[0] * localWorkSize[1] * localWorkSize[2]; - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, PRIV_MULT, NULL); - } -#endif - { // 5. OUT ARRAY! - ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.res_arr ); - } -#if 0 - { // Finally, enqueue kernel - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreTridagX, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckPreTridagX; -} - -void run_prepare_tridag_X( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreTridagX, 3, NULL, - kernels.GWS_XYZ, kernels.LWS_XYZ, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - -/////////////////////////// -/// NORDEA_ALL_KERNEL_X /// -/////////////////////////// - -cl_kernel make_NordeaKernelX( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs -) { - cl_kernel ckAllX = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckAllX = clCreateKernel(cpProgram, "nordea_kernel_x", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - // 1. RO SCALARS // - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); - - // 2. RO ARRAYS // - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myX); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDx); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDxx); - - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myY); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); - - // 3. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); - - // 4. LOCAL (PRIVATE ARRAYS) - const int PRIV_MULT = sizeof(REAL) * 8 * WORKGROUP_SIZE; - ciErr1 |= clSetKernelArg(ckAllX, counter++, PRIV_MULT, NULL); - - // 5. OUT ARRAY! - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.res_arr ); - - oclCheckError(ciErr1, CL_SUCCESS); - - return ckAllX; -} - -void run_NordeaKernelX( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelX, 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL); - - ciErr1 |= clFinish(cqCommandQueue); - - oclCheckError(ciErr1, CL_SUCCESS); -} - - -////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////// - -cl_kernel make_prepare_tridag_Y( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - size_t* globalWorkSize, - size_t* localWorkSize -) { - cl_kernel ckPreTridagY = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckPreTridagY = clCreateKernel(cpProgram, "prepare_tridag_y", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - { // 1. RO SCALARS // here we do not have to reload ro_scals! - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); - } - - { // 2. RO ARRAYS // - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); - } - - { // 3. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); - } -#if 1 - { // 4. LOCAL (PRIVATE ARRAYS) - const int PRIV_MULT = sizeof(REAL) * localWorkSize[0] * localWorkSize[1] * localWorkSize[2]; - ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, PRIV_MULT, NULL); - } -#endif -#if 0 - { // Finally, enqueue kernel - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreTridagY, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckPreTridagY; -} - -void run_prepare_tridag_Y( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreTridagY, 3, NULL, - &kernels.GWS_YXZ[0], &kernels.LWS_YXZ[0], 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - - -/////////////////////////// -/// NORDEA_ALL_KERNEL_X /// -/////////////////////////// - -cl_kernel make_NordeaKernelY( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs -) { - cl_kernel ckAllY = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckAllY = clCreateKernel(cpProgram, "nordea_kernel_y", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - // 1. RO SCALARS // - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); - - // 2. RO ARRAYS // - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); - - // 3. GPU-ONLY GLOBAL ARRAYS // -#if TRANSPOSE_UV - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); // y <- u^T - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); // u <- v^T -#else - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); -#endif - - // 4. LOCAL (PRIVATE ARRAYS) - const int PRIV_MULT = sizeof(REAL) * 8 * WORKGROUP_SIZE; - ciErr1 |= clSetKernelArg(ckAllY, counter++, PRIV_MULT, NULL); - - oclCheckError(ciErr1, CL_SUCCESS); - - return ckAllY; -} - -void run_NordeaKernelY( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelY, 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL); - - ciErr1 |= clFinish(cqCommandQueue); - - oclCheckError(ciErr1, CL_SUCCESS); -} - - -/************************************************************/ -/******************** TRIDAG KERNELS ************************/ -/************************************************************/ - - - -/** - * Parallel Prefix with matrix multiplication - */ -cl_kernel make_MatMultScan( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - const unsigned int* NUM_P -) { - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - cl_kernel ckTridagMatMultX = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckTridagMatMultX = clCreateKernel(cpProgram, "scanMatMultIncl", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - { // 1. GPU-ONLY GLOBAL ARRAYS /(4 * NUM_X * NUM_Y * OUTER_LOOP_COUNT) - ciErr1 |= clSetKernelArg(ckTridagMatMultX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); - } - - { // 2. LOCAL: 8 * sizeof(REAL) * worksize - const int PRIV_MULT = sizeof(REAL) * 8 * localWorkSize; - ciErr1 |= clSetKernelArg(ckTridagMatMultX, counter++, PRIV_MULT, NULL); - } - - { // 1. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckTridagMatMultX, counter++, sizeof(uint), (void *)NUM_P); - } - -#if 0 - { // Finally, the array size: - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckTridagMatMultX, 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckTridagMatMultX; -} - -void run_MatMultScan( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckTridagMatMult[X], 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - - - -/** - * Parallel Prefix with linear function composition - */ -cl_kernel make_FwdFunCompScan( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - const unsigned int* NUM_P -) { - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - cl_kernel ckTridagFwdFunComp = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; - unsigned long int cur_size; - - // find kernel - ckTridagFwdFunComp = clCreateKernel(cpProgram, "scanLinFunCompIncl", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - // 1. GPU-ONLY GLOBAL ARRAYS /(4 * NUM_X * NUM_Y * OUTER_LOOP_COUNT) - ciErr1 |= clSetKernelArg(ckTridagFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); - - // 2. LOCAL: 4 * sizeof(REAL) * worksize - const int PRIV_MULT = sizeof(REAL) * 4 * localWorkSize; - ciErr1 |= clSetKernelArg(ckTridagFwdFunComp, counter++, PRIV_MULT, NULL); - - // 1. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckTridagFwdFunComp, counter++, sizeof(uint), (void *)NUM_P); - - // Finally, the array size: -#if 0 - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckTridagFwdFunComp, 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckTridagFwdFunComp; -} - -void run_FwdFunCompScan( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckTridagFwdFunComp[X], 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -/** - * Mapping back the results of parallel prefix with matrix multiplication - */ -cl_kernel make_conclude_matmult ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - cl_mem d, - cl_mem y, - cl_mem u -) { - cl_kernel ckConcludeMatMult = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckConcludeMatMult = clCreateKernel(cpProgram, "conclude_matmult", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b ); // b - ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&d ); - ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&y ); - ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&u ); - ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); - - -#if 0 - { // Finally, enqueue kernel! - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckConcludeMatMult, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckConcludeMatMult; -} - - -void run_conclude_matmult( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; - size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckConcludeMatMult[X], 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - -/** - * Preparing for parallel prefix with linear function composition - * (i.e., filling in ocl_arrs.tmp) - */ -cl_kernel make_preludeFwdMapFunComp ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - cl_mem d, - cl_mem u -) { - cl_kernel ckPreludeFwdFunComp = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckPreludeFwdFunComp = clCreateKernel(cpProgram, "prelude_fwd_fun_comp", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a ); // b - ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&d ); - ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&u ); - ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); - - -#if 0 - { // Finally, enqueue kernel! - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreludeFwdFunComp, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckPreludeFwdFunComp; -} - -void run_preludeFwdMapFunComp( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; - size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreludeFwdFunComp[X], 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - -/** - * Mapping back the results of parallel prefix with linear function composition - */ -cl_kernel make_postFwdMapFunComp ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - cl_mem y -) { - cl_kernel ckPostFwdFunComp = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckPostFwdFunComp = clCreateKernel(cpProgram, "post_fwd_fun_comp", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - ciErr1 |= clSetKernelArg(ckPostFwdFunComp, counter++, sizeof(cl_mem), (void*)&y ); - ciErr1 |= clSetKernelArg(ckPostFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); - -#if 0 - { // Finally, enqueue kernel! - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPostFwdFunComp, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckPostFwdFunComp; -} - -void run_postFwdMapFunComp ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; - size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPostFwdFunComp[X], 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - - -/** - * Preparing for forward-parallel prefix with linear function composition - * (i.e., filling in ocl_arrs.tmp) - */ -cl_kernel make_preludeBwdMapFunComp ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - cl_mem y, - cl_mem u -) { - cl_kernel ckPreludeBwdFunComp = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckPreludeBwdFunComp = clCreateKernel(cpProgram, "prelude_bwd_fun_comp", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c ); // b - ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&y ); - ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&u ); - ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); - -#if 0 - { // Finally, enqueue kernel! - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreludeBwdFunComp, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckPreludeBwdFunComp; -} - -void run_preludeBwdMapFunComp ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; - size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreludeBwdFunComp[X], 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -/** - * Mapping back the results of parallel prefix with linear function composition - */ -cl_kernel make_postBwdMapFunComp ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - cl_mem y -) { - cl_kernel ckPostBwdFunComp = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckPostBwdFunComp = clCreateKernel(cpProgram, "post_bwd_fun_comp", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&y ); - ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2 ); - //ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals); - //ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.timeline); - -#if 0 - { // Finally, enqueue kernel! - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPostBwdFunComp, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - } -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckPostBwdFunComp; -} - -void run_postBwdMapFunComp ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; - size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; - - assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPostBwdFunComp[X], 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -//////////////////////////////////////////////////////// -//////////////////////////////////////////////////////// -//////////////////////////////////////////////////////// - -/** - * Mapping back the results of parallel prefix with matrix multiplication - */ -cl_kernel make_TRIDAG_ALL_OPT ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - cl_mem d, - cl_mem y, - cl_mem u, - const unsigned int* NUM_P -) { - cl_kernel ckTridagAll = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckTridagAll = clCreateKernel(cpProgram, "tridag_inlined", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a ); // a - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c ); // c - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&d ); - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&y ); - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&u ); - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(uint) , (void *)NUM_P ); - - { - const int PRIV_MULT = sizeof(REAL) * 8 * WORKGROUP_SIZE; - ciErr1 |= clSetKernelArg(ckTridagAll, counter++, PRIV_MULT, NULL); - } - - oclCheckError(ciErr1, CL_SUCCESS); - - return ckTridagAll; -} - - -void run_TRIDAG_ALL_OPT ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - int X -) { - cl_int ciErr1; - - size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - //size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; - //size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; - - assert( (X==0 || X==1) && "INVALID TRIDAG_ALL_OPT Kernel!"); - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckTridagAllOpt[X], 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL ); - - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - - - - - -/***************************************************/ -/********* Segmented Matrix Transposition ********/ -/***************************************************/ - -cl_kernel make_transposeGPU( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - cl_mem inp_arr, - cl_mem out_arr, - const unsigned int* size_x, - const unsigned int* size_y, - const unsigned int* size_z, - const char* kernel_name -// size_t* globalWorkSize, -// size_t* localWorkSize -) { - cl_kernel ckMatTransp = NULL; - cl_int ciErr1, ciErr2; - unsigned int counter = 0; - - ckMatTransp = clCreateKernel(cpProgram, kernel_name, &ciErr1); // "transposeUpdateScalars" - oclCheckError(ciErr1, CL_SUCCESS); - - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &out_arr); // input array - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &inp_arr); // output array - //ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), &offset); - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_x); // size of 0 dim - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_y); // size of 1 dim - - // shared memory space - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, (BLOCK_DIM + 1) * BLOCK_DIM * sizeof(REAL), 0 ); - -#if 0 - // enqueue kernel - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckMatTransp, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); -#endif - oclCheckError(ciErr1, CL_SUCCESS); - - return ckMatTransp; -} - -void run_transposeGPU ( - cl_command_queue& cqCommandQueue, - cl_kernel kernel, - size_t* globalWorkSize - -) { - cl_int ciErr1; - size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernel, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -cl_kernel make_transposeGPU_WithUpdate( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - cl_mem inp_arr, - cl_mem out_arr, - const unsigned int* size_x, - const unsigned int* size_y, - const unsigned int* size_z, - oclNordeaArrays& ocl_arrs -// size_t* globalWorkSize, -// size_t* localWorkSize -) { - cl_int ciErr1; - cl_kernel kernel = make_transposeGPU( - cqCommandQueue, cpProgram, inp_arr, - out_arr, size_x, size_y, size_z, "transposeUpdateScalars" - ); - - ciErr1 = clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *) &ocl_arrs.ro_scals); - ciErr1 = clSetKernelArg(kernel, 6, sizeof(cl_mem), (void *) &ocl_arrs.timeline); - oclCheckError(ciErr1, CL_SUCCESS); - - return kernel; -} - -void run_transposeGPU_WithUpdate ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - size_t* globalWorkSize = kernels.GWS_YXZ; - size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; - //size_t* localWorkSize = kernels.LWS_YXZ; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckMatTranspUpdate, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -/**********************************************************/ -/**************** MAKE ALL KERNELS ************************/ -/**********************************************************/ - -void make_TRIDAG( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - oclNordeaArrays& ocl_arrs, - GPUkernels& kernels, - const int X -) { - assert( (X==0 || X==1) && "INVALID argument X to make_TRIDAG Kernels!"); - - cl_mem d; cl_mem y; cl_mem u; - const unsigned int* NUM_P = NULL; - //size_t* globalWorkSize = NULL; - //size_t* localWorkSize = NULL; - - if(X == 0) { - // first tridag run: d <- u; y <- u; u <- y NUM_P <- &NUM_X - d = ocl_arrs.u; y = ocl_arrs.u; u = ocl_arrs.y; NUM_P = &NUM_X; - //globalWorkSize = kernels.GWS_XYZ; - //localWorkSize = kernels.LWS_XYZ; - } else { // X == 1 - // second tridag run: d <- v; y <- y; u <- u NUM_P <- &NUM_Y - d = ocl_arrs.v; y = ocl_arrs.v; u = ocl_arrs.y; NUM_P = &NUM_Y; //y = ocl_arrs.y; u = ocl_arrs.u; - //globalWorkSize = kernels.GWS_XYZ; - //localWorkSize = kernels.LWS_XYZ; - } - - - // scan with matrix multiply! - kernels.ckTridagMatMult[X] = make_MatMultScan ( - cqCommandQueue, cpProgram, ocl_arrs, NUM_P - ); - - // map the results of the parallel prefix with matrix multiplication! - kernels.ckConcludeMatMult[X] = make_conclude_matmult ( - cqCommandQueue, cpProgram, ocl_arrs, d, y, u - ); - - // prepare for forward scan with function composition! - kernels.ckPreludeFwdFunComp[X] = make_preludeFwdMapFunComp ( - cqCommandQueue, cpProgram, ocl_arrs, d, u - ); - - // (forward) scan with function composition! - kernels.ckTridagFwdFunComp[X] = make_FwdFunCompScan ( - cqCommandQueue, cpProgram, ocl_arrs, NUM_P - ); - - // post_fwd_fun_comp - kernels.ckPostFwdFunComp[X] = make_postFwdMapFunComp ( - cqCommandQueue, cpProgram, ocl_arrs, y - ); - - // prepare for backward scan with linear-function composition - kernels.ckPreludeBwdFunComp[X] = make_preludeBwdMapFunComp ( - cqCommandQueue, cpProgram, ocl_arrs, y, u - ); - - // (backward) scan with function composition! - // have already been computed in "kernels.ckTridagFwdFunComp[X]" needs to be run twice!!! - //kernels.ckTridagFwdFunComp2[X] = make_FwdFunCompScan ( - // cqCommandQueue, cpProgram, ocl_arrs, NUM_P - // ); - - // post_bwd_fun_comp - kernels.ckPostBwdFunComp[X] = make_postBwdMapFunComp ( - cqCommandQueue, cpProgram, ocl_arrs, y - ); - - ///////////////////////// - // Finally, TRIDAG ALL // - ///////////////////////// - kernels.ckTridagAllOpt[X] = make_TRIDAG_ALL_OPT ( - cqCommandQueue, cpProgram, ocl_arrs, d, y, u, NUM_P - ); -} - - -void make_kernels ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs, - GPUkernels& kernels -) { - initGPUgrid ( kernels ); - - kernels.ckPreTridagX = make_prepare_tridag_X ( - cqCommandQueue, - cpProgram, - ro_scal, - ocl_arrs, - kernels.GWS_XYZ, - kernels.LWS_XYZ - ); - - make_TRIDAG( cqCommandQueue, cpProgram, ocl_arrs, kernels, 0 ); - - kernels.ckPreTridagY = make_prepare_tridag_Y ( - cqCommandQueue, - cpProgram, - ocl_arrs, - kernels.GWS_YXZ, - kernels.LWS_YXZ - ); - - make_TRIDAG( cqCommandQueue, cpProgram, ocl_arrs, kernels, 1 ); - -#if TRANSPOSE_UV - kernels.ckMatTranspUpdate = make_transposeGPU_WithUpdate ( - cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.res_arr, // ocl_arrs.y - &NUM_Y, &NUM_X, &OUTER_LOOP_COUNT, ocl_arrs - ); -#else - // transpose y into res_arr - kernels.ckMatTranspUpdate = make_transposeGPU_WithUpdate ( - cqCommandQueue, cpProgram, ocl_arrs.v, ocl_arrs.res_arr, // ocl_arrs.y - &NUM_Y, &NUM_X, &OUTER_LOOP_COUNT, ocl_arrs - ); -#endif - - ////////////////////////////////// - // Finally, Finally, TRIDAG ALL // - ////////////////////////////////// - kernels.ckNordeaKernelX = make_NordeaKernelX ( - cqCommandQueue, cpProgram, ro_scal, ocl_arrs - ); - - kernels.ckNordeaKernelY = make_NordeaKernelY ( - cqCommandQueue, cpProgram, ro_scal, ocl_arrs - ); - - // transpose U into Y - kernels.ckMatTransposeU = make_transposeGPU ( - cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.y, - &NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" - ); - - // transpose V into U - kernels.ckMatTransposeV = make_transposeGPU ( - cqCommandQueue, cpProgram, ocl_arrs.v, ocl_arrs.u, - &NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" - ); - -} - - -/**********************************************************/ -/********************* RUN KERNELS ************************/ -/**********************************************************/ - -void run_TRIDAG( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - const int X -) { - assert( (X==0 || X==1) && "INVALID argument X to make_TRIDAG Kernels!"); - -#ifdef TRIDAG_ALL_OPT_ON - run_TRIDAG_ALL_OPT( cqCommandQueue, kernels, X ); -#else - // scan with matrix multiply! - run_MatMultScan( cqCommandQueue, kernels, X ); - - // map the results of the parallel prefix with matrix multiplication! - run_conclude_matmult( cqCommandQueue, kernels, X ); - - - // prepare for forward scan with function composition! - run_preludeFwdMapFunComp( cqCommandQueue, kernels, X ); - - // (forward) scan with function composition! - run_FwdFunCompScan( cqCommandQueue, kernels, X); - - // post_fwd_fun_comp - run_postFwdMapFunComp( cqCommandQueue, kernels, X ); - - // prepare for backward scan with linear-function composition - run_preludeBwdMapFunComp( cqCommandQueue, kernels, X ); - - // (backward) scan with function composition! - run_FwdFunCompScan( cqCommandQueue, kernels, X ); - - // post_bwd_fun_comp - run_postBwdMapFunComp( cqCommandQueue, kernels, X ); -#endif -} - -void run_GPUkernels_one_time_iteration ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { -#ifdef MOST_OPTIMISED_ON - run_NordeaKernelX( cqCommandQueue, kernels ); - -#if TRANSPOSE_UV - run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeU, kernels.GWS_XYZ ); // y <- transpose(u) - run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeV, kernels.GWS_XYZ ); // u <- transpose(v) -#endif - - run_NordeaKernelY( cqCommandQueue, kernels ); - -#else - - run_prepare_tridag_X( cqCommandQueue, kernels ); - - run_TRIDAG( cqCommandQueue, kernels, 0); - - run_prepare_tridag_Y( cqCommandQueue, kernels ); - - run_TRIDAG( cqCommandQueue, kernels, 1); -#endif - - run_transposeGPU_WithUpdate( cqCommandQueue, kernels ); -} - -/**********************************************************/ -/******************* RELEASE KERNELS **********************/ -/**********************************************************/ - -void release_all_kernels ( GPUkernels& kernels ) { - clReleaseKernel(kernels.ckPreTridagX); - clReleaseKernel(kernels.ckPreTridagY); - clReleaseKernel(kernels.ckMatTranspUpdate); - - clReleaseKernel(kernels.ckTridagMatMult[0]); - clReleaseKernel(kernels.ckTridagMatMult[1]); - - clReleaseKernel(kernels.ckConcludeMatMult[0]); - clReleaseKernel(kernels.ckConcludeMatMult[1]); - - clReleaseKernel(kernels.ckPreludeFwdFunComp[0]); - clReleaseKernel(kernels.ckPreludeFwdFunComp[1]); - - clReleaseKernel(kernels.ckTridagFwdFunComp[0]); - clReleaseKernel(kernels.ckTridagFwdFunComp[1]); - - clReleaseKernel(kernels.ckPostFwdFunComp[0]); - clReleaseKernel(kernels.ckPostFwdFunComp[1]); - - clReleaseKernel(kernels.ckPreludeBwdFunComp[0]); - clReleaseKernel(kernels.ckPreludeBwdFunComp[1]); - - clReleaseKernel(kernels.ckPostBwdFunComp[0]); - clReleaseKernel(kernels.ckPostBwdFunComp[1]); - - clReleaseKernel(kernels.ckTridagAllOpt[0]); - clReleaseKernel(kernels.ckTridagAllOpt[1]); - - clReleaseKernel(kernels.ckNordeaKernelX); - clReleaseKernel(kernels.ckNordeaKernelY); - - clReleaseKernel(kernels.ckMatTransposeU); - clReleaseKernel(kernels.ckMatTransposeV); -} - -void release_all_GPU_resources( - cl_command_queue& cqCommandQueue, - cl_context& cxGPUContext, - cl_program cpProgram, - cl_device_id* cdDevices, - oclNordeaArrays& ocl_arrs, - GPUkernels& kernels -) { - - shrLog(stdlog, "Release Kernels...\n"); - release_all_kernels( kernels ); - - shrLog(stdlog, "Release CPU buffers and OpenCL objects...\n"); - clReleaseProgram(cpProgram); - - clReleaseMemObject(ocl_arrs.ro_scals); - clReleaseMemObject(ocl_arrs.timeline); - - clReleaseMemObject(ocl_arrs.a); - clReleaseMemObject(ocl_arrs.b); - clReleaseMemObject(ocl_arrs.c); - - clReleaseMemObject(ocl_arrs.y); - clReleaseMemObject(ocl_arrs.u); - clReleaseMemObject(ocl_arrs.v); - - clReleaseMemObject(ocl_arrs.tmp2); - clReleaseMemObject(ocl_arrs.tmp4); - clReleaseMemObject(ocl_arrs.res_arr); - - clReleaseMemObject(ocl_arrs.myX); - clReleaseMemObject(ocl_arrs.myDx); - clReleaseMemObject(ocl_arrs.myDxx); - - clReleaseMemObject(ocl_arrs.myY); - clReleaseMemObject(ocl_arrs.myDy); - clReleaseMemObject(ocl_arrs.myDyy); - - clReleaseCommandQueue(cqCommandQueue); - free(cdDevices); - clReleaseContext(cxGPUContext); -} - - -/**********************************************************/ -/******************* DEBUG TESTING **********************/ -/**********************************************************/ - -void testMatMultScan ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - cl_context& cxGPUContext -) { - //const unsigned NUM_X = 64, NUM_Y = 1; - - cl_mem cl_tmp; cl_int ciErr; - REAL* tmp = new REAL[NUM_X*NUM_Y*4]; - - for(int i=0; i4) - for( k=0; k4) - for( k=0; k4) - for( k=0; k4) - for( k=0; k4) - for( k=0; k( USER_MEM * 101.0 / 100.0 ); - const size_t lb = static_cast( USER_MEM * 99.0 / 100.0 ); - if ( !(glob_mem_size >= lb && glob_mem_size <= ub) ) { - fprintf(stderr, "WARNING! Querried GPU global memory %lu DIFFERS from what user declared: [%ld,%ld]!\n", - glob_mem_size, lb, ub); - glob_mem_size = static_cast(USER_MEM); - fprintf(stderr, "Using user-declared size for global memory: %lu\n", glob_mem_size); - } - } - - cl_ulong glob_mem_required = 15 * OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(REAL); - assert( glob_mem_required <= glob_mem_size && "Not Enough Global Memory. A possible fix is to strip-mine all kernels.\n" ); - //fprintf(stderr, "GPU global memory: %lu, needed: %lu bytes\n", glob_mem_size, glob_mem_required); -} - - -void makeOclBuffers ( - cl_context cxGPUContext, - cl_command_queue& cqCommandQueue, - RWScalars& ro_scal, - NordeaArrays& cpu_arrs, - oclNordeaArrays& ocl_arrs -) { - cl_int ciErr; - cl_int ciErr2; - unsigned long int cur_size; - - /*********************/ - /*** 1. RO scalars ***/ - /*********************/ - { - cur_size = sizeof(RWScalars); - ocl_arrs.ro_scals = clCreateBuffer( - cxGPUContext, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 - ); - - ciErr = ciErr2; - ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, - cur_size, &ro_scal, 0, NULL, NULL); - //oclCheckError(ciErr, CL_SUCCESS); - } - - /*********************/ - /*** 1. RO Arrays! ***/ - /*********************/ - { - cur_size = NUM_T*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(timeline); - - cur_size = NUM_X*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myX); - - cur_size *= REAL3_CT; - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDx); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDxx); - - cur_size = NUM_Y*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myY); - - cur_size *= REAL3_CT; - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDy); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDyy); - } - - //oclCheckError(ciErr, CL_SUCCESS); - - /*********************/ - /*** 1. RW Arrays! ***/ - /*********************/ - { - cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(REAL); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(a); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(b); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(c); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(y); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(u); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(v); - - cur_size *= 2; - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(tmp2); - - cur_size *= 2; - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(tmp4); - } - - { // Finally the result array (i.e., Read-Write but needs to be brought back to CPU in the end) - cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(REAL); - CREATE_AND_ENQUEUE_OUT_CL_BUFFER(res_arr); - } - - oclCheckError(ciErr, CL_SUCCESS); - - //shrLog("Before EXITING ALLOC ARRAYS!!! ...\n"); - -} - -#define USE_GPU_ITER 1 - -//extern "C" -unsigned long int -runOnGPU ( RWScalars& ro_scal, NordeaArrays& cpu_arrs, oclNordeaArrays& ocl_arrs ) { - cl_context cxGPUContext; // OpenCL context - cl_command_queue cqCommandQueue[16]; // OpenCL command que - cl_uint nDevice; // OpenCL device count - cl_device_id* cdDevices; // OpenCL device list - cl_program cpProgram; // OpenCL program - GPUkernels kernels; // OpenCL kernel - const unsigned int dev_id = GPU_DEV_ID; - - assert(GPU_DEV_ID >= 0 && "GPU DEVICE ID < 0 !\n"); - - { // initialize the loop-variant scalars! - ro_scal.t_ind = NUM_T - 2; - ro_scal.dtInv = 1.0/(cpu_arrs.timeline[ro_scal.t_ind+1]-cpu_arrs.timeline[ro_scal.t_ind]); - ro_scal.timeline_i = cpu_arrs.timeline[ro_scal.t_ind]; - } - - { // making command queue, building program, etc - char compile_opts[128]; - sprintf( compile_opts, "-D lgWARP=%d", lgWARP ); - - build_for_GPU( - cxGPUContext, cqCommandQueue, - nDevice, cdDevices, cpProgram, dev_id, compile_opts, "", "CrankNicolson" - ); - - verifyEnoughResources(cdDevices[dev_id]); - } - - // allocate space for the RO and RW arrays on GPU! - makeOclBuffers ( - cxGPUContext, cqCommandQueue[dev_id], ro_scal, cpu_arrs, ocl_arrs - ); - - - { // make all kernels! - make_kernels( cqCommandQueue[dev_id], cpProgram, ro_scal, ocl_arrs, kernels ); - } - - unsigned long int elapsed; - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - // now execute kernels and record the time! - for(int t_ind = NUM_T-2; t_ind>=0; --t_ind) { - run_GPUkernels_one_time_iteration ( cqCommandQueue[dev_id], kernels ); - } // END TIME LOOP! - - - { // WRITE BACK THE RESULT ARRAY TO CPU !!! // - cl_int ciErr; - const unsigned int ARR_SIZE = NUM_X * NUM_Y * OUTER_LOOP_COUNT * sizeof(REAL); - ciErr = clEnqueueReadBuffer ( - cqCommandQueue[dev_id], ocl_arrs.res_arr, CL_TRUE, - 0, ARR_SIZE, cpu_arrs.res_arr, 0, NULL, NULL - ); - oclCheckError(ciErr, CL_SUCCESS); - - // RELEASE ALL GPU RESOURCES - release_all_GPU_resources ( - cqCommandQueue[dev_id], cxGPUContext, cpProgram, cdDevices, ocl_arrs, kernels - ); - } - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; - - return elapsed; -} - -#endif // end include NORDEA_GPU diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp deleted file mode 100644 index 51406e1..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "Constants.h" -#include "DataStructConst.h" -#include "ParseInput.h" -#include "VolCalibInit.h" -#include "Vect_CPU.h" -#include "Vect_GPU.h" - -#include "Util.h" -#include "ParseInput.h" - -unsigned long int -whole_loop_nest ( - REAL* res, - const REAL* strikes, - const REAL s0, - const REAL t, - const REAL alpha, - const REAL nu, - const REAL beta -) { - // loop index - unsigned int i; - unsigned long int elapsed; - //const unsigned int NUM_XY = NUM_X*NUM_Y; - - // arrays: - REAL *a = NULL, *b = NULL, *c = NULL, - *y = NULL, *u = NULL, *v = NULL, - *scan_tmp = NULL; - - { // allocate arrays - a = new REAL __attribute__ ((aligned (32))) [OUTER_LOOP_COUNT*NUM_XY]; - b = new REAL[OUTER_LOOP_COUNT*NUM_XY]; - c = new REAL[OUTER_LOOP_COUNT*NUM_XY]; - - y = new REAL[OUTER_LOOP_COUNT*NUM_XY]; - u = new REAL[OUTER_LOOP_COUNT*NUM_XY]; - v = new REAL[OUTER_LOOP_COUNT*NUM_XY]; - - scan_tmp = new REAL[4*OUTER_LOOP_COUNT*NUM_XY]; - } - - // parallel! - whole_loop_nest_init ( s0, t, alpha, nu, beta ); - - // parallel! - for( i=0; i 0 ) { - RWScalars ro_scal; - NordeaArrays cpu_arrs; - oclNordeaArrays ocl_arrs; - - { // init arrays - cpu_arrs.myX = myX; cpu_arrs.myDx = myDx; cpu_arrs.myDxx = myDxx; - cpu_arrs.myY = myY; cpu_arrs.myDy = myDy; cpu_arrs.myDyy = myDyy; - cpu_arrs.timeline = myTimeline; - cpu_arrs.a = a; cpu_arrs.b = b; cpu_arrs.c = c; - cpu_arrs.y = y; cpu_arrs.u = u; cpu_arrs.v = v; - cpu_arrs.tmp = scan_tmp; - cpu_arrs.res_arr = &myResArr[0]; - } - - { // init scalars - ro_scal.NUM_X = NUM_X; ro_scal.NUM_Y = NUM_Y; ro_scal.NUM_XY = NUM_X * NUM_Y; - ro_scal.alpha = alpha; ro_scal.beta = beta; ro_scal.nu = nu; - } - - { // SAFETY CHECK! - bool is_safe = (NUM_X <= WORKGROUP_SIZE) && (NUM_Y <= WORKGROUP_SIZE) && - is_pow2(NUM_X) && is_pow2(NUM_Y) && - (WORKGROUP_SIZE % NUM_X == 0) && (WORKGROUP_SIZE % NUM_Y == 0); - assert(is_safe && "NOT SAFE TO PARALLELISE ON GPU!"); - } - - elapsed = runOnGPU ( ro_scal, cpu_arrs, ocl_arrs ); - } else { - // CPU instrumentation here: - - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - for(int t_ind = NUM_T-2; t_ind>=0; --t_ind) { - - iteration_expanded_CPU ( - t_ind, alpha, beta, nu, - a, b, c, y, u, v, scan_tmp - ); - } - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; - } - - for( i=0; i(s0/dx); - - for( i=0; i input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run <=0; i-=WARP) { - y[i] = (y[i] - c[i]*y[i+WARP]) / u[i]; - } -} - -/**************************************************************************/ -/*********** PREPARE FOR TRIDAG X *****************************************/ -/**************************************************************************/ - -__kernel void nordea_kernel_x ( - /*** Read-Only Scalars ***/ - __constant RWScalars* ro_scals, - /*** Read-Only Arrays ***/ - __constant REAL* myX, - __constant REAL* myDx, - __constant REAL* myDxx, - __global REAL* myY, - __global REAL4* myDy, - __global REAL4* myDyy, - /*** Read-Write Temporary Arrays ***/ - __global REAL* a, - __global REAL* b, - __global REAL* c, - __global REAL* y, - __global REAL* u, - __global REAL* v, - /*** The Result Array ***/ - __global REAL* res_arr -) { - unsigned int ind, i, ind_rev; - //const unsigned int step_rev = ro_scals->NUM_Y; //(ro_scals->NUM_Y << LOG2_WARP_SIZE); - REAL cur_myVar, cur_myMu, exp_add; - REAL4 myDy_el; - - { // cur_myVarY = nu*nu; cur_myMuY = 0.0; compute ind_y and exp_add - cur_myVar = ro_scals->nu; cur_myVar *= cur_myVar; - cur_myMu = 0.0; - - //ind_y = get_global_id(0) & (ro_scals->NUM_Y - 1); - exp_add = myY[get_global_id(0) & (ro_scals->NUM_Y - 1)] - 0.5*cur_myVar*ro_scals->timeline_i; - } - - { // adjust arrays: except for `res_arr' and `v' which are accesses as `v[i,j]', hence memory is already coalesced! - unsigned int offset = (get_global_id(0)>>lgWARP); - offset *= ( ro_scals->NUM_X << lgWARP ); - offset += ( get_global_id(0) & (WARP-1) ); - - a += offset; - b += offset; - c += offset; - y += offset; - u += offset; - } - - { // computing myDy_el = (cur_myMuY*myDy[j] + 0.5*cur_myVarY*myDyy[j]) - i = get_global_id(0) & (ro_scals->NUM_Y - 1); - myDy_el = cur_myMu*myDy[i] + (0.5*cur_myVar)*myDyy[i]; - //i = REAL3_CT*(get_global_id(0) & (ro_scals->NUM_Y - 1)); - //myDy_el = (REAL4)(myDyy[i], myDyy[i+1], myDyy[i+2], 1.0); - //myDy_el = myDy_el * (0.5*cur_myVar); - //myDy_el += cur_myMu*((REAL4)(myDy[i], myDy[i+1], myDy[i+2], 1.0)); - } - - - ind_rev = (get_global_id(0)/ro_scals->NUM_Y)*ro_scals->NUM_XY + (get_global_id(0) & (ro_scals->NUM_Y - 1)); - for( i=0, ind=0; iNUM_X; i++, ind+=WARP, ind_rev+=ro_scals->NUM_Y ) { - myDy_el.w = 0.0; - - { // comput cur_myMy and cur_myVar - cur_myMu = 0.0; // X - cur_myVar = exp( 2 * ( ro_scals->beta*log(myX[i]) + exp_add ) ); - //cur_myVar = exp(2*(ro_scals->beta*log(myX[i]) + myY[get_global_id(0) & (ro_scals->NUM_Y - 1)] - 0.5*ro_scals->nu*ro_scals->nu*ro_scals->timeline_i)); - } - - { // compute v[i, j] - if( (ind_rev & (ro_scals->NUM_Y-1)) != 0 ) myDy_el.w += myDy_el.x*res_arr[ind_rev-1]; //[(j-1)*NUM_X+i]; - myDy_el.w += myDy_el.y*res_arr[ind_rev ]; // [j*NUM_X+i]; - if( (ind_rev & (ro_scals->NUM_Y-1)) != ro_scals->NUM_Y-1 ) myDy_el.w += myDy_el.z*res_arr[ind_rev+1]; //[(j+1)*NUM_X+i]; - - //v[k*NUM_X*NUM_Y + i*NUM_Y + j] = tmp; // v[i*NUM_Y + j] = tmp; //v[i][j] = tmp2; - - v[ ind_rev ] = myDy_el.w; - } - - { // compute u, a, b, c - const unsigned int im3 = REAL3_CT*i; - - if(i!=0) - myDy_el.w += 0.5*(cur_myMu*myDx[im3 ] + 0.5*cur_myVar*myDxx[im3 ])*res_arr[ind_rev-ro_scals->NUM_Y]; //[j*NUM_X+i-1]; - - // tmp += ro_scals->dtInv * res_arr[ind]; WAS included in the next line! - myDy_el.w += ( 0.5*(cur_myMu*myDx[im3+1] + 0.5*cur_myVar*myDxx[im3+1]) + ro_scals->dtInv)*res_arr[ind_rev ]; //[j*NUM_X+i]; - - if(i!=ro_scals->NUM_X-1) - myDy_el.w += 0.5*(cur_myMu*myDx[im3+2] + 0.5*cur_myVar*myDxx[im3+2])*res_arr[ind_rev+ro_scals->NUM_Y]; //[j*NUM_X+i+1]; - - u[ind] = myDy_el.w; - - // compute a,b,c - a[ind] = 0.0 - 0.5*(cur_myMu*myDx[im3 ] + 0.5*cur_myVar*myDxx[im3 ]); // a[j*NUM_X+i] = ... - b[ind] = ro_scals->dtInv - 0.5*(cur_myMu*myDx[im3+1] + 0.5*cur_myVar*myDxx[im3+1]); // b[j*NUM_X+i] = ... - c[ind] = 0.0 - 0.5*(cur_myMu*myDx[im3+2] + 0.5*cur_myVar*myDxx[im3+2]); // c[j*NUM_X+i] = ... - } - } - - tridag_seq(a, b, c, u, ro_scals->NUM_X, u, y); -} - - -/**************************************************************************/ -/*********** IN-BETWEEN TRIDAGS -- i.e., prepare for TRIDAG Y *************/ -/**************************************************************************/ - -__kernel void nordea_kernel_y ( - /*** Read-Only Scalars ***/ - __constant RWScalars* ro_scals, // __constant - /*** Read-Only Arrays ***/ - __constant REAL* myDy, - __constant REAL* myDyy, - /*** Read-Write Temporary Arrays ***/ - __global REAL* a, - __global REAL* b, - __global REAL* c, - __global REAL* u, - __global REAL* v, - __global REAL* y -) { - //const unsigned int step_rev = ro_scals->NUM_X; //(ro_scals->NUM_X << LOG2_WARP_SIZE); - unsigned int ind, ind_rev, i; - REAL cur_myVar, cur_myMu; - - { // cur_myVarY = nu*nu; cur_myMuY = 0.0; compute ind_y and exp_add - cur_myVar = ro_scals->nu; cur_myVar *= cur_myVar; - cur_myMu = 0.0; - } - - { // adjust arrays! except for `u' whose access pattern is `u[j,i]' which is already coalesced! - unsigned int offset = (get_global_id(0)>>lgWARP); - offset *= ( ro_scals->NUM_Y << lgWARP ); - offset += ( get_global_id(0) & (WARP-1) ); - - a += offset; - b += offset; - c += offset; - y += offset; - v += offset; - } - - ind_rev = (get_global_id(0)/ro_scals->NUM_X)*ro_scals->NUM_XY + (get_global_id(0) & (ro_scals->NUM_X - 1)); // should step with `NUM_Y*32' - for( i=0, ind=0; iNUM_Y; i++, ind+=WARP, ind_rev+=ro_scals->NUM_X) { - unsigned int im3 = REAL3_CT*i; - - a[ind] = 0.0 - 0.5*(cur_myMu*myDy[im3 ] + 0.5*cur_myVar*myDyy[im3 ]); // a[i*NUM_Y+j] = ... - b[ind] = ro_scals->dtInv - 0.5*(cur_myMu*myDy[im3+1] + 0.5*cur_myVar*myDyy[im3+1]); // b[i*NUM_Y+j] = ... - c[ind] = 0.0 - 0.5*(cur_myMu*myDy[im3+2] + 0.5*cur_myVar*myDyy[im3+2]); // c[i*NUM_Y+j] = ... - - v[ind] = ro_scals->dtInv * u[ind_rev] - 0.5 * v[ind]; - //u[ (get_global_id(0)/ro_scals->NUM_XY)*ro_scals->NUM_XY + i*ro_scals->NUM_X + ind_x] - - } - - tridag_seq(a, b, c, v, ro_scals->NUM_Y, v, y); -} - - -/*********************************************/ -/*********** Matrix Transposition ************/ -/*********************************************/ - -// This kernel is optimized to ensure all global reads and writes are coalesced, -// and to avoid bank conflicts in shared memory. The shared memory array is sized -// to (BLOCK_DIM+1)*BLOCK_DIM. This pads each row of the 2D block in shared memory -// so that bank conflicts do not occur when threads address the array column-wise. -inline void transposeMatrix( - __global REAL *odata, - __global REAL *idata, - unsigned int width, - unsigned int height, - __local REAL* block) -{ - unsigned int xIndex, yIndex; - - // adjust the input and output arrays for the third dimension! - yIndex = get_global_id(2) * width * height; - odata = odata + yIndex; - idata = idata + yIndex; - - // read the matrix tile into shared memory - xIndex = get_global_id(0); - yIndex = get_global_id(1); - - if((xIndex < width) && (yIndex < height)) - { - unsigned int index_in = yIndex * width + xIndex; - block[get_local_id(1)*(BLOCK_DIM+1)+get_local_id(0)] = idata[index_in]; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // write the transposed matrix tile to global memory - xIndex = get_group_id(1) * BLOCK_DIM + get_local_id(0); - yIndex = get_group_id(0) * BLOCK_DIM + get_local_id(1); - if((xIndex < height) && (yIndex < width)) - { - unsigned int index_out = yIndex * height + xIndex; - odata[index_out] = block[get_local_id(0)*(BLOCK_DIM+1)+get_local_id(1)]; - } -} - -__kernel void transpose( - __global REAL *odata, - __global REAL *idata, - //int offset, - unsigned int width, - unsigned int height, - __local REAL* block) -{ - transposeMatrix( odata, idata, width, height, block ); -} - -__kernel void transposeUpdateScalars( - __global REAL *odata, - __global REAL *idata, - //int offset, - unsigned int width, - unsigned int height, - __local REAL* block, - __global RWScalars* ro_scals, // __constant - __constant REAL* timeline -) { - transposeMatrix( odata, idata, width, height, block ); - - // update time-loop-variant scalars - if(get_global_id(2) + get_global_id(1) + get_global_id(0) == 0) { - int t_ind = --ro_scals->t_ind; - ro_scals->dtInv = 1.0 / ( timeline[t_ind+1] - timeline[t_ind] ); - ro_scals->timeline_i = timeline[ t_ind ]; - } -} - - - diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile deleted file mode 100644 index e1e31ef..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -include setup.mk - -ifndef ($(HAVE_GPU)) -include platform.mk -endif - -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ - -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ - -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ - -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) - -SOURCES_CPP =VolCalibOuter.cpp -HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h ../includeC/Constants.h \ - ../includeC/ParseInput.h ../includeC/DataStructConst.h ../includeC/ParPrefixUtil.h -OBJECTS =VolCalibOuter.o -EXECUTABLE =VolCalib - - -ifeq ($(HAVE_GPU),1) -default: gpu -else -# cannot build this one... -no-gpu: - @echo "\n*** No GPU configured, cannot build `pwd` ***\n" -endif - - -#.cpp.o: -# $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< - -#$(OBJECTS) -cpu: - $(CXX) $(CXXFLAGS) -D IS_GPU=0 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) - -gpu: - $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) - - -run_small: - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt - @# clean nVidia compiler cache - rm -rf $(HOME)/.nv/ComputeCache/* - diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/PrepareKernels.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/PrepareKernels.h deleted file mode 100644 index 13a39bd..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/PrepareKernels.h +++ /dev/null @@ -1,529 +0,0 @@ -#ifndef PREPARE_KERNELS -#define PREPARE_KERNELS - -/************************************************************/ -/*************** HELPER DATA STRUCTURES ******************/ -/************************************************************/ - -// GPU BUFFERS -struct oclNordeaArrays { - /* RO scalars */ - cl_mem ro_scals; - - /* RO arrays */ - cl_mem timeline; // [NUM_T] - - cl_mem myX; // [NUM_X] - cl_mem myDx; // [NUM_X * 3] - cl_mem myDxx; // [NUM_X * 3] - - cl_mem myY; // [NUM_Y] - cl_mem myDy; // [NUM_Y * 3] - cl_mem myDyy; // [NUM_Y * 3] - - /* TRIDAG helpers */ - cl_mem a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem tmp4; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] - cl_mem tmp2; // [2 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - cl_mem res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - /* WRITE ONLY OUTPUT stored in "res"*/ - //cl_mem res; -}; - -// CPU BUFFERS -struct NordeaArrays { - /* RO arrays */ - REAL* timeline; // [NUM_T] - - REAL* myX; // [NUM_X] - REAL* myDx; // [NUM_X * 3] - REAL* myDxx; // [NUM_X * 3] - - REAL* myY; // [NUM_Y] - REAL* myDy; // [NUM_Y * 3] - REAL* myDyy; // [NUM_Y * 3] - - /* TRIDAG helpers are created on GPU only! no need for them to exist in main memory*/ - REAL* a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - REAL* tmp; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - REAL* res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] - - /* NOT USED FOR NOW! WRITE ONLY OUTPUT stored in "res"*/ - //REAL* res; -}; - -// GPU KERNELS -typedef struct { - cl_kernel ckMatTranspUpdate; - cl_kernel ckMatTransposeU; - cl_kernel ckMatTransposeV; - - // TRIDAG KERNELS - cl_kernel ckNordeaKernelX; // OUTER_LOOP_COUNT x NUM_Y - cl_kernel ckNordeaKernelY; // OUTER_LOOP_COUNT x NUM_X - - size_t FORM_32X [3]; - size_t FORM_32Y [3]; - size_t FORM_Y32 [3]; -} GPUkernels __attribute__ ((aligned (32))); - -/******************************************************/ -/******* compute global/local grid dimensions *********/ -/******************************************************/ - -static bool is_pow2(unsigned int x) { - while(x > 1) { - if( x & 1 ) return false; - x = x >> 1; - } - return true; -} - -void initGPUgrid ( GPUkernels& kernels ) { - // fill transposition layouts! - - bool is_safe = ( (OUTER_LOOP_COUNT*NUM_X) % NUM_Y == 0 ) && - //( (OUTER_LOOP_COUNT*NUM_Y) % NUM_X == 0 ) && - ( (OUTER_LOOP_COUNT*NUM_X) % WORKGROUP_SIZE == 0 ) && - ( (OUTER_LOOP_COUNT*NUM_Y) % WORKGROUP_SIZE == 0 ) && - ( NUM_X % 32 == 0 && NUM_Y % 32 == 0); - assert( is_safe && "CANNOT EXECUTE ON GPU: sizes do not match!"); - - kernels.FORM_32X[0] = 32; kernels.FORM_32X[1] = NUM_X; kernels.FORM_32X[2] = (OUTER_LOOP_COUNT*NUM_Y)/32; - kernels.FORM_32Y[0] = 32; kernels.FORM_32Y[1] = NUM_Y; kernels.FORM_32Y[2] = (OUTER_LOOP_COUNT*NUM_X)/32; - kernels.FORM_Y32[0] = NUM_Y; kernels.FORM_Y32[1] = 32; kernels.FORM_Y32[2] = (OUTER_LOOP_COUNT*NUM_X)/32; -} - -/************************************************************/ -/*************** KERNELS OTHER THAN TRIDAG ****************** -/************************************************************/ - -/////////////////////////// -/// NORDEA_ALL_KERNEL_X /// -/////////////////////////// - -cl_kernel make_NordeaKernelX( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs -) { - //size_t* globalWorkSize, - //size_t* localWorkSize - cl_kernel ckAllX = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckAllX = clCreateKernel(cpProgram, "nordea_kernel_x", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - // 1. RO SCALARS // - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); - - // 2. RO ARRAYS // - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myX); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDx); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDxx); - - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myY); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); - - // 3. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); - - // 4. OUT ARRAY! - ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.res_arr ); - - oclCheckError(ciErr1, CL_SUCCESS); - - return ckAllX; -} - -void run_NordeaKernelX( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - size_t globalWorkSize = NUM_Y * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelX, 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL); - ciErr1 |= clFinish(cqCommandQueue); - - oclCheckError(ciErr1, CL_SUCCESS); -} - -/////////////////////////// -/// NORDEA_ALL_KERNEL_Y /// -/////////////////////////// - -cl_kernel make_NordeaKernelY( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs -) { - cl_kernel ckAllY = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - unsigned int counter = 0; // ro_scals - - ///// - ckAllY = clCreateKernel(cpProgram, "nordea_kernel_y", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - - unsigned long int cur_size; - - // 1. RO SCALARS // - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); - - // 2. RO ARRAYS // - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); - - // 3. GPU-ONLY GLOBAL ARRAYS // - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); - - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); // y <- u^T - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); // u <- v^T - ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); - - oclCheckError(ciErr1, CL_SUCCESS); - - return ckAllY; -} - -void run_NordeaKernelY( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - cl_int ciErr1; - size_t globalWorkSize = NUM_X * OUTER_LOOP_COUNT; - size_t localWorkSize = WORKGROUP_SIZE; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelY, 1, NULL, - &globalWorkSize, &localWorkSize, 0, NULL, NULL); - - ciErr1 |= clFinish(cqCommandQueue); - - oclCheckError(ciErr1, CL_SUCCESS); -} - -/***************************************************/ -/********* Segmented Matrix Transposition ********/ -/***************************************************/ - -cl_kernel make_transposeGPU( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - cl_mem inp_arr, - cl_mem out_arr, - size_t* size_x, - size_t* size_y, - size_t* size_z, - const char* kernel_name -// size_t* globalWorkSize, -// size_t* localWorkSize -) { - cl_kernel ckMatTransp = NULL; - cl_int ciErr1, ciErr2; - unsigned int counter = 0; - - ckMatTransp = clCreateKernel(cpProgram, kernel_name, &ciErr1); // "transposeUpdateScalars" - oclCheckError(ciErr1, CL_SUCCESS); - - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &out_arr); // input array - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &inp_arr); // output array - //ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), &offset); - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_x); // size of 0 dim - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_y); // size of 1 dim - - // shared memory space - ciErr1 |= clSetKernelArg(ckMatTransp, counter++, (BLOCK_DIM + 1) * BLOCK_DIM * sizeof(REAL), 0 ); - - oclCheckError(ciErr1, CL_SUCCESS); - - return ckMatTransp; -} - -void run_transposeGPU ( - cl_command_queue& cqCommandQueue, - cl_kernel kernel, - size_t* globalWorkSize - -) { - cl_int ciErr1; - size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernel, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -cl_kernel make_transposeGPU_WithUpdate( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - cl_mem inp_arr, - cl_mem out_arr, - size_t* size_x, - size_t* size_y, - size_t* size_z, - oclNordeaArrays& ocl_arrs -// size_t* globalWorkSize, -// size_t* localWorkSize -) { - cl_int ciErr1; - cl_kernel kernel = make_transposeGPU( - cqCommandQueue, cpProgram, inp_arr, - out_arr, size_x, size_y, size_z, "transposeUpdateScalars" - ); - - ciErr1 = clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *) &ocl_arrs.ro_scals); - ciErr1 = clSetKernelArg(kernel, 6, sizeof(cl_mem), (void *) &ocl_arrs.timeline); - oclCheckError(ciErr1, CL_SUCCESS); - - return kernel; -} - -void run_transposeGPU_WithUpdate ( - cl_command_queue& cqCommandQueue, - cl_kernel kernel, - size_t* globalWorkSize -) { - cl_int ciErr1; - size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; - //size_t* localWorkSize = kernels.LWS_YXZ; - - ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernel, 3, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - ciErr1 |= clFinish(cqCommandQueue); - oclCheckError(ciErr1, CL_SUCCESS); -} - -/**********************************************************/ -/**************** MAKE ALL KERNELS ************************/ -/**********************************************************/ - -void make_kernels ( - cl_command_queue& cqCommandQueue, - cl_program cpProgram, - RWScalars& ro_scal, - oclNordeaArrays& ocl_arrs, - GPUkernels& kernels -) { - initGPUgrid ( kernels ); - - // First Kernel - kernels.ckNordeaKernelX = make_NordeaKernelX ( - cqCommandQueue, cpProgram, ro_scal, ocl_arrs - ); - - // Second Kernel - kernels.ckNordeaKernelY = make_NordeaKernelY ( - cqCommandQueue, cpProgram, ro_scal, ocl_arrs - ); - - { // matrix transpose!!! - // transpose U into Y - kernels.ckMatTransposeU = make_transposeGPU ( - cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.y, - &kernels.FORM_32X[0], &kernels.FORM_32X[1], &kernels.FORM_32X[2], "transpose" - //&NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" - ); - - // transpose V into U - kernels.ckMatTransposeV = make_transposeGPU ( - cqCommandQueue, cpProgram, ocl_arrs.v, ocl_arrs.u, - &kernels.FORM_Y32[0], &kernels.FORM_Y32[1], &kernels.FORM_Y32[2], "transpose" - //&NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" - ); - - - // Transpose into res_arr and update induction variables! - kernels.ckMatTranspUpdate = make_transposeGPU_WithUpdate ( - cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.res_arr, // ocl_arrs.y - &kernels.FORM_32Y[0], &kernels.FORM_32Y[1], &kernels.FORM_32Y[2], ocl_arrs - //&NUM_Y, &NUM_X, &OUTER_LOOP_COUNT, ocl_arrs - ); - } -} - - -/**********************************************************/ -/********************* RUN KERNELS ************************/ -/**********************************************************/ - -void run_GPUkernels_one_time_iteration ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels -) { - size_t globalWorkSize[3]; - - run_NordeaKernelX( cqCommandQueue, kernels ); - run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeU, kernels.FORM_32X ); // y <- transpose(u) - run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeV, kernels.FORM_Y32 ); // u <- transpose(v) - run_NordeaKernelY( cqCommandQueue, kernels ); - run_transposeGPU_WithUpdate( cqCommandQueue, kernels.ckMatTranspUpdate, kernels.FORM_32Y); -} - -/**********************************************************/ -/******************* RELEASE KERNELS **********************/ -/**********************************************************/ - -void release_all_kernels ( GPUkernels& kernels ) { - clReleaseKernel(kernels.ckNordeaKernelX); - - clReleaseKernel(kernels.ckMatTransposeU); - clReleaseKernel(kernels.ckMatTransposeV); - - clReleaseKernel(kernels.ckNordeaKernelY); - - clReleaseKernel(kernels.ckMatTranspUpdate); -} - -void release_all_GPU_resources( - cl_command_queue& cqCommandQueue, - cl_context& cxGPUContext, - cl_program cpProgram, - cl_device_id* cdDevices, - oclNordeaArrays& ocl_arrs, - GPUkernels& kernels -) { - - shrLog(stdlog, "Release Kernels...\n"); - release_all_kernels( kernels ); - - shrLog(stdlog, "Release CPU buffers and OpenCL objects...\n"); - clReleaseProgram(cpProgram); - - clReleaseMemObject(ocl_arrs.ro_scals); - clReleaseMemObject(ocl_arrs.timeline); - - clReleaseMemObject(ocl_arrs.a); - clReleaseMemObject(ocl_arrs.b); - clReleaseMemObject(ocl_arrs.c); - - clReleaseMemObject(ocl_arrs.y); - clReleaseMemObject(ocl_arrs.u); - clReleaseMemObject(ocl_arrs.v); - - clReleaseMemObject(ocl_arrs.res_arr); - - clReleaseMemObject(ocl_arrs.myX); - clReleaseMemObject(ocl_arrs.myDx); - clReleaseMemObject(ocl_arrs.myDxx); - - clReleaseMemObject(ocl_arrs.myY); - clReleaseMemObject(ocl_arrs.myDy); - clReleaseMemObject(ocl_arrs.myDyy); - - clReleaseCommandQueue(cqCommandQueue); - free(cdDevices); - clReleaseContext(cxGPUContext); -} - - -/*****************************************************************/ -/************ DEBUGGING ******************************************/ -/*****************************************************************/ - - -void run_trimmed_GPUkernels_one_time_iteration ( - cl_command_queue& cqCommandQueue, - GPUkernels& kernels, - NordeaArrays& cpu_arrs, - oclNordeaArrays& ocl_arrs, - int time_ind, - const REAL alpha, - const REAL beta, - const REAL nu -) { - run_NordeaKernelX( cqCommandQueue, kernels ); - run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeU, kernels.FORM_32X ); // y <- transpose(u) - run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeV, kernels.FORM_Y32 ); // u <- transpose(v) - run_NordeaKernelY( cqCommandQueue, kernels ); - run_transposeGPU_WithUpdate( cqCommandQueue, kernels.ckMatTranspUpdate, kernels.FORM_32Y); - - cl_int ciErr; - const unsigned int ARR_SIZE = NUM_X * NUM_Y * OUTER_LOOP_COUNT * sizeof(REAL); -#if 1 - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.a, CL_TRUE, 0, ARR_SIZE, cpu_arrs.a, 0, NULL, NULL ); - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.b, CL_TRUE, 0, ARR_SIZE, cpu_arrs.b, 0, NULL, NULL ); - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.c, CL_TRUE, 0, ARR_SIZE, cpu_arrs.c, 0, NULL, NULL ); - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.u, CL_TRUE, 0, ARR_SIZE, cpu_arrs.u, 0, NULL, NULL ); - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.v, CL_TRUE, 0, ARR_SIZE, cpu_arrs.v, 0, NULL, NULL ); - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.y, CL_TRUE, 0, ARR_SIZE, cpu_arrs.y, 0, NULL, NULL ); - ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.res_arr, CL_TRUE, 0, ARR_SIZE, cpu_arrs.res_arr, 0, NULL, NULL ); -#endif - - oclCheckError(ciErr, CL_SUCCESS); - - // now the rest of the code! - unsigned int i, j, k; - - REAL dtInv = 1.0/(cpu_arrs.timeline[time_ind+1]-cpu_arrs.timeline[time_ind]); - - REAL *res_arr = cpu_arrs.res_arr, *a = cpu_arrs.a, - *b = cpu_arrs.b, *c = cpu_arrs.c, *u = cpu_arrs.u, - *v = cpu_arrs.v, *y = cpu_arrs.y; - - unsigned int cos_test_ind = 3*NUM_XY + 23*NUM_X + 211, cos_test_ind_rev = 3*NUM_XY + 211*NUM_Y + 23; - - - { // transpose u: u is in form: [i/32, j, i%32] - // and needs to be brought to form [i/32, i%32, j], a.k.a. [i,j] - const unsigned int ID = OUTER_LOOP_COUNT * NUM_X / 32; - for( k=0; k=0; --time_ind) { - - - unsigned int i, j, k; - - REAL dtInv = 1.0/(myTimeline[time_ind+1]-myTimeline[time_ind]); - - REAL *res_arr = &myResArr[0]; - -#pragma omp parallel for default(shared) schedule(static) private(k,j,i) if(OUTER_LOOP_COUNT>4) - for( k=0; k4) - for( k=0; k4) - for( k=0; k( USER_MEM * 101.0 / 100.0 ); - const size_t lb = static_cast( USER_MEM * 99.0 / 100.0 ); - if ( !(glob_mem_size >= lb && glob_mem_size <= ub) ) { - fprintf(stderr, "WARNING! Querried GPU global memory %lu DIFFERS from what user declared: [%ld,%ld]!\n", - glob_mem_size, lb, ub); - glob_mem_size = static_cast(USER_MEM); - fprintf(stderr, "Using user-declared size for global memory: %lu\n", glob_mem_size); - } - } - - cl_ulong glob_mem_required = 8 * OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(REAL); - assert( glob_mem_required <= glob_mem_size && "Not Enough Global Memory. A possible fix is to strip-mine all kernels.\n" ); - //fprintf(stderr, "GPU global memory: %lu, needed: %lu bytes\n", glob_mem_size, glob_mem_required); -} - -void makeOclBuffers ( - cl_context cxGPUContext, - cl_command_queue& cqCommandQueue, - RWScalars& ro_scal, - NordeaArrays& cpu_arrs, - oclNordeaArrays& ocl_arrs -) { - cl_int ciErr; - cl_int ciErr2; - unsigned long int cur_size; - - /*********************/ - /*** 1. RO scalars ***/ - /*********************/ - { - cur_size = sizeof(RWScalars); - ocl_arrs.ro_scals = clCreateBuffer( - cxGPUContext, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 - ); - - ciErr = ciErr2; - ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, - cur_size, &ro_scal, 0, NULL, NULL); - //oclCheckError(ciErr, CL_SUCCESS); - } - - /*********************/ - /*** 1. RO Arrays! ***/ - /*********************/ - { - cur_size = NUM_T*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(timeline); - - cur_size = NUM_X*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myX); - - cur_size *= REAL3_CT; - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDx); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDxx); - - cur_size = NUM_Y*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myY); - - cur_size *= REAL3_CT; - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDy); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDyy); - } - - //oclCheckError(ciErr, CL_SUCCESS); - - /*********************/ - /*** 1. RW Arrays! ***/ - /*********************/ - { - cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(REAL); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(a); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(b); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(c); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(y); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(u); - CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(v); - } - - { // Finally the result array (i.e., Read-Write but needs to be brought back to CPU in the end) - cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(REAL); - CREATE_AND_ENQUEUE_OUT_CL_BUFFER(res_arr); - } - - oclCheckError(ciErr, CL_SUCCESS); - - //shrLog("Before EXITING ALLOC ARRAYS!!! ...\n"); - -} - -//extern "C" -unsigned long int -runOnGPU ( RWScalars& ro_scal, NordeaArrays& cpu_arrs, oclNordeaArrays& ocl_arrs ) { - cl_context cxGPUContext; // OpenCL context - cl_command_queue cqCommandQueue[16]; // OpenCL command que - cl_uint nDevice; // OpenCL device count - cl_device_id* cdDevices; // OpenCL device list - cl_program cpProgram; // OpenCL program - GPUkernels kernels; // OpenCL kernel - unsigned int dev_id = GPU_DEV_ID; - - assert(GPU_DEV_ID >= 0 && "GPU DEVICE ID < 0 !\n"); - - { // initialize the loop-variant scalars! - ro_scal.t_ind = NUM_T - 2; - ro_scal.dtInv = 1.0/(cpu_arrs.timeline[ro_scal.t_ind+1]-cpu_arrs.timeline[ro_scal.t_ind]); - ro_scal.timeline_i = cpu_arrs.timeline[ro_scal.t_ind]; - } - - { // making command queue, building program, etc - char compile_opts[128]; - sprintf( compile_opts, "-D lgWARP=%d", lgWARP ); - - build_for_GPU( - cxGPUContext, cqCommandQueue, - nDevice, cdDevices, cpProgram, dev_id, compile_opts, "", "CrankNicolson" - ); - - verifyEnoughResources(cdDevices[dev_id]); - } - - // allocate space for the RO and RW arrays on GPU! - makeOclBuffers ( - cxGPUContext, cqCommandQueue[dev_id], ro_scal, cpu_arrs, ocl_arrs - ); - - - // make all kernels! - make_kernels( cqCommandQueue[dev_id], cpProgram, ro_scal, ocl_arrs, kernels ); - - unsigned long int elapsed; - { // now execute kernels! - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - for(int t_ind = NUM_T-2; t_ind>=0; --t_ind) { - run_GPUkernels_one_time_iteration ( cqCommandQueue[dev_id], kernels ); - } // END TIME LOOP! - - - { // WRITE BACK THE RESULT ARRAY TO CPU !!! // - cl_int ciErr; - const unsigned int ARR_SIZE = NUM_X * NUM_Y * OUTER_LOOP_COUNT * sizeof(REAL); - ciErr = clEnqueueReadBuffer ( - cqCommandQueue[dev_id], ocl_arrs.res_arr, CL_TRUE, - 0, ARR_SIZE, cpu_arrs.res_arr, 0, NULL, NULL - ); - oclCheckError(ciErr, CL_SUCCESS); - - // RELEASE ALL GPU RESOURCES - release_all_GPU_resources ( - cqCommandQueue[dev_id], cxGPUContext, cpProgram, cdDevices, ocl_arrs, kernels - ); - } - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; - } - - return elapsed; -} - -#endif // end include NORDEA_GPU diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibInit.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibInit.h deleted file mode 100644 index e6aa566..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibInit.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef NORDEA_INIT -#define NORDEA_INIT - -#include "DataStructConst.h" - -/////////////////////////////////////////////////////// -//// INITIALISATION ! -/////////////////////////////////////////////////////// - -void initGrid( - const REAL s0, - const REAL alpha, - const REAL nu, - const REAL t, - const unsigned int numX, - const unsigned int numY, - const unsigned int numT -) { - unsigned int i; - - for( i=0; i(s0/dx); - - for( i=0; i 0) { - for(unsigned int i=0; i 0 ) { - RWScalars ro_scal; - NordeaArrays cpu_arrs; - oclNordeaArrays ocl_arrs; - - { // init arrays - cpu_arrs.myX = myX; cpu_arrs.myDx = myDx; cpu_arrs.myDxx = myDxx; - cpu_arrs.myY = myY; cpu_arrs.myDy = myDy; cpu_arrs.myDyy = myDyy; - cpu_arrs.timeline = myTimeline; - cpu_arrs.a = a; cpu_arrs.b = b; cpu_arrs.c = c; - cpu_arrs.y = y; cpu_arrs.u = u; cpu_arrs.v = v; - cpu_arrs.res_arr = &myResArr[0]; - } - - { // init scalars - ro_scal.NUM_X = NUM_X; ro_scal.NUM_Y = NUM_Y; ro_scal.NUM_XY = NUM_X * NUM_Y; - ro_scal.alpha = alpha; ro_scal.beta = beta; ro_scal.nu = nu; - } - - { // SAFETY CHECK! - bool is_safe = ( (OUTER_LOOP_COUNT*NUM_X) % NUM_Y == 0 ) && - ( (OUTER_LOOP_COUNT*NUM_Y) % NUM_X == 0 ) && - ( (OUTER_LOOP_COUNT*NUM_X) % WORKGROUP_SIZE == 0 ) && - ( (OUTER_LOOP_COUNT*NUM_Y) % WORKGROUP_SIZE == 0 ) && - ( is_pow2(NUM_X) && is_pow2(NUM_Y) ) && - ( NUM_X % 32 == 0 && NUM_Y % 32 == 0) ; - - assert(is_safe && "NOT SAFE TO PARALLELISE ON GPU!"); - } - - elapsed = runOnGPU ( ro_scal, cpu_arrs, ocl_arrs ); - - for( i=0; i=0; --t_ind) { - iteration_expanded_CPU ( - t_ind, alpha, beta, nu, - a, b, c, y, u, v - ); - } - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; - - for( i=0; i input.data - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run < -#include - -typedef double REAL; -#define WORKGROUP_SIZE 512 - -#include "Util.h" -#include "ParseInput.h" - -using namespace std; - -struct PrivGlobs { - - // grid - vector myX; - vector myY; - vector myTimeline; - unsigned myXindex; - unsigned myYindex; - - // variable - vector > myResult; - - // coeffs - vector > myMuX; - vector > myVarX; - vector > myMuY; - vector > myVarY; - - // operators - vector > myDx; - vector > myDxx; - - vector > myDy; - vector > myDyy; -} __attribute__ ((aligned (128))); - - - - - -/***********************************/ - -void updateParams(const unsigned g, const double alpha, const double beta, const double nu, PrivGlobs& globs) -{ - for(unsigned i=0;i(s0/dx); - - for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) -{ - const unsigned n = x.size(); - - Dx.resize(n); - Dxx.resize(n); - - for(unsigned i=0;i& a, - const vector& b, - const vector& c, - const vector& r, - const int n, - vector& u, - vector& uu) -{ - int i, offset; - REAL beta; - - u[0] = r[0]; - uu[0] = b[0]; - - for(i=1; i=0; i--) { - u[i] = (u[i] - c[i]*u[i+1]) / uu[i]; - } -} - - -void -rollback( const unsigned g, PrivGlobs& globs ) { - unsigned numX = globs.myX.size(), - numY = globs.myY.size(); - - unsigned numZ = max(numX,numY); - - int k, l; - unsigned i, j; - - int kl, ku, ll, lu; - - double dtInv = 1.0/(globs.myTimeline[g+1]-globs.myTimeline[g]); - - vector > u(numY,vector(numX)), v(numX,vector(numY)); - vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); - - // explicit x - for(i=0;i=0;--i) - { - updateParams(i,alpha,beta,nu,globs); - rollback(i, globs); - } - - return globs.myResult[globs.myXindex][globs.myYindex]; -} - -double* run_CPUkernel( - const unsigned int& outer, - const unsigned int& numX, - const unsigned int& numY, - const unsigned int& numT, - const double& s0, - const double& t, - const double& alpha, - const double& nu, - const double& beta, - const vector& strikes, - vector& res -) { -#pragma omp parallel for default(shared) schedule(static) if(outer>4) - for( unsigned i = 0; i < outer; ++ i ) { - res[i] = value( s0, strikes[i], t, alpha, nu, beta, - numX, numY, numT ); - } -} - - -int main() -{ - unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; - const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; - - cout<<"\n// Running Original (Parallel) Volatility-Calibration Benchmark"< strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); - - for(unsigned i=0;i input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run < Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalib b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalib deleted file mode 100755 index c2bf4ac7ae98011bd2b9b94e86d8fd4292c84c06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40968 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 diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp deleted file mode 100644 index cd6fcbd..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include -#include - -#define WITH_FLOATS 0 -#define WORKGROUP_SIZE 512 - -typedef double REAL; - -#include "Util.h" -#include "ParseInput.h" - -using namespace std; - -// grid -vector myX, myY, myTimeline; -unsigned myXindex, myYindex; - -// variable -vector > myResult; - -// coeffs -vector > myMuX, myVarX, myMuY, myVarY; - -// operators -vector > myDx, myDxx, myDy, myDyy; - - - - -/***********************************/ - -void updateParams(const unsigned g, const double alpha, const double beta, const double nu) -{ - for(unsigned i=0;i(s0/dx); - - for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) -{ - const unsigned n = x.size(); - - Dx.resize(n); - Dxx.resize(n); - - for(unsigned i=0;i& a, - const vector& b, - const vector& c, - const vector& r, - const int n, - vector& u, - vector& uu) -{ - int i, offset; - REAL beta; - - u[0] = r[0]; - uu[0] = b[0]; - - for(i=1; i=0; i--) { - u[i] = (u[i] - c[i]*u[i+1]) / uu[i]; - } -} - -void -rollback(const unsigned g) -{ - unsigned numX = myX.size(), - numY = myY.size(); - - unsigned numZ = max(numX,numY); - - int k, l; - unsigned i, j; - - int kl, ku, ll, lu; - - double dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]); - - vector > u(numY,vector(numX)), v(numX,vector(numY)); - - vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); - - // explicit x - for(i=0;i=0;--i) - { - updateParams(i,alpha,beta,nu); - rollback(i); - } - - return myResult[myXindex][myYindex]; -} - -int main() -{ - unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; - const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; - - fprintf(stdout, "\n// Original (Sequential) Volatility Calibration Benchmark:\n"); - readDataSet( OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T ); - - vector strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); - - for(unsigned i=0;i input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk - -make diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/run b/benchmarks/LocVolCalib/implementations/cpp_sequential/run deleted file mode 100755 index c409dcd..0000000 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat input.data | ./VolCalib diff --git a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff b/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff deleted file mode 100755 index 917712579571b87ed9792a7e504d5998e759dadc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25696 zcmcJ14|r77weOiEz{sDRiGrqzWom~uu@VwQOcXCOVFG7xf>DAE6`6$mF{vSm$wbk% z5bq?`(=d^?+?Muv`||Gf_R{Mjp4! z8tGG-Q8ZIUaS8zGDC-tkzeTGQa5Ej2a%595@i@gd!K8~wx`?DR(?KbinVS7$-}sp> z`A$!Bqr|eCiQ*OCBdO2@U}f(GYnbm{Xdv`1bc>9c9yh>>nVNKWf{t>2)yE+bXE!#i zo;P=PW6i9_hNkwlv(^^Qn>BB4UR!hC93emP*u}+5mkSD0A5N6m_EdbRGS>gsx7Tmq z`u9I9|LN~{EZ#HseBV<)xG;xxU&qJPzhZML9X3ZAVKeaIlY8xk>2=Gi97SikryGz< zzkOhE`K4gxDZoa9KRX8ez!>mJfIIO?eQE$0jsK}J;9nm@&d0{UcZ`AGGzR|7W8g=| zz`u43{BHx_iBIbDJ^-Wjw|)%x*)iZV$7r{I4E(3ZfIl$?d>-IVd{Upk17I}y9~}d} z1aK!lsZT2aqw&cbqhA-sz<(R?EahuT@9mYyDe#-d^E?v5x1_)?1AoG|roa`<(>0uy z^OS(Eyfjc#+gf{HLtC)6wY+p;V{=n&dDZI1S|t#;Z%uPkpe)_8cS*d3 zja6-JwQUCZsKm8vTa>m3T7z{;WAl9?$5yM2R%_Qb1VMX8prt)nt<*KQ)Hb2DhPLMF zqM|@sbyZWH!kYT3R;9JJsYGirSPk#Y-pP@9#vcWGc!LN5oC8&(GOBFfe%d|tTq4dG#W7;9%re9{A zX@`V636M`j@}Gb*L`XdQEO5E>iMjy`Jh8;0=BNd3u4N<`w7{+FTGRq(+vYQ5ftz!T zb;B0;WhOFHIlstbq6KcZz_})vkHZ3=Yyy#HTi_V5#N)KUGZRon$+5t#IkQ zLJK_0!pCiaTm6(~fnQ<4FSEe8W}8oi1wPFLBCWK*ue8AHE%0m$yu||lngzbr0>8!r z@36qFi~i#l__Y>%E%bq1>mGM%fm6}CBEfOdk5Q?GcH4JZkdTev^afDkGmqn2o#94~ z<$5B;2IF{U9%7j$8ygVi7g?sM#v-D;lVzG{Y^x|g&oWIj)+@@tXPMI>wo#P-g=Ly( ztV5Llfn}OitVNW6&9a^4N>Tn9%QVGUnJE8+Wtw2jEy{n(GEFa*FUpUwOp}W_MY)w_ znp(^u%HL<1CKgjfc{R&4t=P~-0A_xVWtvoMP?YatnWhvQ5alH-(}ZFXQ7&egrW4yL z%D1pglZo|;@*I|FDzS~Cd_BuFkywW)U&r!QEVqdA)hyFgVwIwNImH?OOjWqw*_tF5-1}y4VAhpLDU=?x$T8{*0OxbY*ux z>0+M+GF#HUE>qgP3#Yyx1CW}ymUrgweO5a&B|0eD_lanmqO>$ zOz2X(+S!l*r=L+P5(G;fYNr=fXmUyogbSU|u<~1)t#)1`t4l@o_@rv5+I8le2K78t zZyPVVJ0j2090=W+j(+H;!|id8elYj-@ExD$9_fpvh5Brvi)r3)Mwm)^uno$0K(B*! zYSRy0j@!di4-}lMQ>VULr?$LKgBxVqzW-vKy5iN)UYi!$ z3AL|!S`+YA`%?58KzO4`H14S$jA6 z%5a&j=(Tl=1={4-h!%>Z6=5*<1NX%w+{|@o`^&kVQSaPUr{+b}pUf~+TJExU2VH*B zf!DM@&JmidalzoO#|W*M`J#ZVcn$dhe0F0%4;m`U*<(>OxC?YY&NY|n3~iw}n`z@D!_h5iP6WY{xQyAnfD@d|CaR8cz*e?u5Gq=!*ks$kgv zny8{-CsV?>yHJhxr~DW`#4zq;6c~7gL}?T#H1K2;82K^8Z{%_(P)s9FM#?FAL+$(? z(Db*x;d|ox5nM4h_d7cTz< zcHZ(f92!Ra3j!mY0Mot>5#$88HVt{$_e(JJ75mK@;DLhb)QVT-GcVtHF8krHv1XGlCGl6?7iSJQp_%MbMCSCCw zN4R{N;_a>x6Csi?z#7^R4A8zPJpVnY3i@BM+gAB@S18>M-jGp);9@o0dT{%8|H_Xeab*F`c4-RP67j>AQPtR~^-Nkkva1n49JD72V7hV*! z{|Z{4zOx&A5R3Kf#_)wMWT-uNBD4?RegX5t(XQ~j#O@0(cN~ntkft5HK^W9brs3da zX?}g60IOWi(KBAvacu}tdX=4_KDx`dKrsiE=dnO?g*~8!BKg9wz3QrC0Gx!$lI^%9 zWDDRfIEkENSXKJ)`3$w3vd38iAHV8NWU}0ty;&7ULH)J>sgCatvrQmmRSW|BCt$5) za5LrXcfi$SL@4C6>H;`|GuN}MwNU_eA>$qb(N5yQ2N;myqK^REqjp_~pgTPG6>2^_ z)#vSA>B=dHc*9GF{ndN>-boMbwZlS6ZPC)|{aW=ozYY1A-}WK3HaUV`XG4tXd%+8> zuKW|y7g4n`qYsL(h3DJQ9z13aB&mQZR=omgmZ0F6atkG=;LuH;k%y?J>{Lcpu_3mQ z*Z>TBiY~10#CWLuc9R46mC1(cwa^LhJrKQ8)RINI*H!Q9p6b$chYy%`O)o<$F>S{6hQ%`V>xi`+ z`C3?WAa&dIp-^<(!Du+Bq!mOk5WS@9#L6-#rlSaI=i5iQTO;;DOt6;F0+-7g3~ z>kTg%4!7F-{+#Zw-U-iDaLBacgFf4^&-R&SyC@8K038>Gd<5*04f!B!9EJ>SUSh~T zVaN~Uj2LpQkxw;bPpTn%5{B##MQyNKx+eAUZC5LbC%jk~LW{6!RBayBqz@1MKb!Pg zkP4H&8zy}yVbYJ1qp)US*G4F?4RV=Q?G^~asykh*pkc$vf()u1Gk^DOu{hFx_L}BS zM}+cQ39|N*JuZ7S<%a`RrmX-f&S?C0rl(n|3iap0JYKOM1_$(&gBXuTL^RuAkaV= zy-|?;m6di@esiR}5k%1|Ok~j_AvOUqd3s%y(bFF$x3Z0BZ=?Xr(2eMx6kr8`Ta$oZ zSAO(2Nf79a40Qm}eIY5y9v&$Vv%WzRZAO7ed<7IOPX&^4K?-mS$*&(_ca)S@v)uiZ z%Vf6|NYsAX2wpasojFB3IaW?Ui1a3bhOC2R_6o{gFyk=+Wy=8`Y>^`mvw;zCbA~}yEh1vE7d>Hx;MEvn);CX%r2}JeS_&GUHdilj!iByC%=tIxjuwWr2z-d z+yNw@+OQIIx?0ehKE$AoCS%m#NC7p9LFd-s&DUz-4B?nqk&Oz!Ey`>?sO8R(OI06X zLr?~6nciT8s$a8VzI3|wp)#Byjy-tH^f>5ADC!DP@Y{xnR!O*tm%G;&_RbqN15Ynh zkVB-kK=SJQ;Qt`Dr|~!Um3p!`p$I>90_EqooqpJ~Q335V4pKY%n zlH{{fsIr3wApL0HUpxVD+#4ubo!jX=r=WEup- zaM5gth8Acnnk~ZiJCG&aTGV=Uco@ifQ4Gwpu8l%?r~-AxBRaMT9ajLT=^I=fL;`!- zmS*eo>PHV^TsFAsQIFUKO?Xjbiy)&RgYfoHN!K~-n>Gm<;e@7bzYbozCjf#{eUQ9* zku51e+;{pE7k3ROVhTWhq#W+pQxF=FOXr`FhK6lCpvtnToj=9-WoQ^Hah3=B9jAjO z>~*p{*x%SiDT5{KWuC}n9riF;9_(8lLW$X&9XuQ=8Vb(!=sWc@p4>Af;UyP62V))_ z1bMLUUl^W#S^K);@YER^&gCd2LOT)pXJuUB3q|ajE#|T9DlLktog2Z5iy{O?M7Q&d z8rZY$xTe3DI4T=Z7Y#rL^|3h!9l5W2ZHl672T#gk+rf-DOD-umRB)^yUU10s96%jd z2li>emd>riu-4ta_WJ~U)|+go&4?OFkr$?|ly0My+`Wg7F0dgiq4 zI<;;IPZWp1oW9sl^ae363L+RPO+T}4x;mo+^>hkpn(aIUG$K<^(cbkZA%NX)>+=^K zXg>h8xG_SEwSJD%Xogo}BB4>bBM?66+Kg7IKek??f8xj4?>=Np_4jFzTUlFetk*sr z8iU;sWX#GkX2Dcofd}UognB_Nd307-)f{&1JDo00WyE~2FYFE+83;>OA|lDcxgCnP zr8`NtYFI#W)E*mjZ^nWp`f0!Z9*u1aTBDPtc%YJ^!xI^T4VF(#mv2m1TkDmT34}Vv9U682)aW^D`M?^jn?PL{>8#0b-p@*}$zXOzM@a`&kB!~eKTt0O*J^kiP5eeWOb zI9Vf&+IcQZbjSw@R_w#)6-H+a-inUs18PqewBZfkg%ai?Pm@JQR!kj0 z*<-g2(-RfF$Wu2*<2Wd21$G-1U{`UFeJCHNwEtKOL0NXM?T3i&(T76qRxiSku9xu+ zfa}IaF`Ul|MH||o3EBZI(ZBHNA4IQ!LWEkW2DN7~@;Z^LeO1p?d^dvGXL^xFD=LajFBEjmI*0P}DayF6~>D)t)m?c05! zKIrmrY0&|-s|fR%%Ibx5R#j43FD5!8LFmj6TX05Seh-shgnZOvS6uCR3@=?c&A8L! zWGqAK*Pn8=Kvnd&T!d))6-Z(172t|>MOr;Gg@pL@w>d!zNn|_9tQ*<7jpkI+xcMsS zI)zTnJqm#!i`sJ)UVE`gqbaZ~!A==Qj4|9Ky5mRXHnta@pH4*D16*D@m{ruNoKMB! z$#CorKaO&XF|+pS`-IZ_e+8}W_I&yU71wuSM(%)DKcPM|kbBUhKC|DpPsA2bW<^HY znS~gVUGR~%lA=B9pP>dt6bkcU(+E`!{S_RGKJhL!UGA#a^ru}%DHrq;K?(_|Vfe2B zl!Pu08}fm>BjY0GFeaFo^B4Xy=A7Rss>q2mBp*y~A7VF6FVv5&exW|W_mS*@(G#QFhLnt3@;Q;% z9Zf$S{X2+;fpHrh?b@$)7QzQmSL{A(3L;RaV*(JC!xsua=id#}bKC&KUxkxaNBJHU zSHO%{#E9zeN0G9wPl^z%;1CzV9MQrHBJ3*I?*#(;=}jNj zFz21DM4(zJ$5UOAaTS694aXxu(nKE&!B=HmiJct)S#Geon7;O6{2g55nFK0~37lVofa1D2WMCQh=98Q%`ZU3|>zf%X7HW z$tmar9s;VIKXL+@Ua`#ZZ~MJirW|U|8FoZJV@4ea5#ErAz&cpHt{hDT5iLJKnEuZap ziS1P{EYGe!@fW<(wXPPVBnJo7m$GVcOXjZy`X;f`(qk7yXs-^e z5oE%RDnrSm##orkE#n{6QH<#=PC4P!Fg$q8cv`I9$kTCgbu6YQ!N_5gHXx z=xs9Xk;w3mS#$SFckz#6CjA9%A_6OTmlGj};X$E>0}Q)YuW>o((n$gFopO0 zF5rgi0volnAHNQv2OJNdX}C+b;VA~`~jXtDIbmUnP zEu#VGe3kbmd}nd%?eB`L%i|brrEu_@=mEBZMh}dRM*sOui@d=qj%=mi3Cm%a`J~v> zfwgzM@R1cl8HmNfvf!L5;#~O2E5uvAR6mL1Mw)%XQGT-iFhWBI{NxMfHs7HkOtd3F z%u&03fB=y$83zpc6DU|2}b}u<%L@(XBYy@1!<=nuW;s)j#(~qa_U-l&J zUtYD&4e}SN!NUB4ILnB39>-9J@B<5U9m8TQ+HyB?t8pBlc7}vpPYH_H9XP`ln>T$Y z&rG-%h9Wg2u{k)M-a&5_(?3EkgSqv{QHE4onuLZ&Y^m#6F^#`$%wxZS1`GDbuDB47 zKPOl#%pvMiV(0KS{5eRV#Q0wPIrK$|y@Q;!^IHHN={zH_=#P($$N*OoJWGlv6EXZo zuon(OG&p+UC!x`KbzS^m5FF?K^ z5`6%zL|^_>94qnZL$Ndrr-Awqs!tv+h`=p&{_nwfJT?e#8D1F2vg?iw{29s@Rh(3@ zPcV7~k(eFf)Hb2*vj|ay8<_Sl#!hS|)7Ya?ju|AL_Hzkl8hZ-S`!-=Hx1b>-_j_>I zCdPFObD~GTVNUdD6LNHV`@|^9jZdk5wnYDs`e^|YRjnYUeh7;i1D>%JueAlMKJ$8Uh7=zcd~C(7JD0{xzqv;~tDOqU6txVl)ggx>d3c*T+xh(zj(C-|=Ip zOY}V&0bfnA1vbD?lUPcxVkdYZ=Q0-bGa%qa%i z2nKG-2A;8`Z*mO-uBC5qMVaaYTJFB*1j(PTm2nAzH3hKK-jbHop zsiC9j0;+BpcrKbQI3Ps+^dn7wd;338G<_!~LjCKIO@BK&bOaXt=tWM594^+_)8V@j zzZW|P3`ivah-DqI|HORe#+#nQjO4A8Haf*%j36ZT8{u_E zP7df-Oj;w1iM|a1AqKI_;1C$QYTJOur$h8oE7%#k90L%|0BUz(w3J=Ld@x4sww^1U z=yTuppQ7)KaF#iu_XE)wXq&)Ib-j!fl9tzzwbfjSvEV{byx%azbH>gO!F=2AR-)em%~_Rkz_x$By;51O&FV#>g@!XV{k;dT5o5rg@n+q-gB9^XEXti| zOi}LL#a&As4y%mvcGfS~9{o@-=(~t>_4jx*-4|WJQ~ZM$gVPe+CYju@|GXDrCEM?~ z?ch`=er}(&9E8y(4E4Qx$8875_OWPb$2N_EEl}FWo%}iI63jj#L44re*dw4Bk%v>~ zWA*xe5O+}CkMT>kT^mR0KUTjN;cu0rSNxG`V*$TWw$|UdPtDu^NCx)0aIipJ0z`o% zs?lP_NQ+ABnq+*fASn9xqo>5Z{NCRp_abXuI1v)f1md034ZqtFVOnVU#{ii9SvS&Z(o3q$1 zFro{fDa&}mZ5H4cbjzY`Xczw7g@V2d@Ap{NkKO}pjM|94mPKDABHW;%Z_s~qxl@VG z735cF)%(tQm)M-`e+>=K4o*0k9U7h(JO-qfiKGH4G#qa~adID$pn4A){C8C7{jm&G z-LtE1<1(%Lp=?dRpxyeAJ$RkgJwa2SX>;JbDL=jpzj0|Fr-c?~+bEV{j~d>a=nvU} z^$_-F3!*O{VmI2rBK_oU^i=$wS@;L}tLEyreEM7BFkjQZz<>kuZ4Z9x6uq33@T+!M zk)~&0c?AGJOf1pQMvsWPU3f!;w@rIcjlkQmXZAmf{TJhz1ss>eBx1~QP{|}@ck19y} zT~WC_Tf22RUgtQ3ulkXKF<6eB!t3$n9H{#siWVx#w&AG67lKGO@%whId#;N$;i=<0 zZc&2QYu(G8zV0A&S~Pd3+Vueh#p}%Aw>_Z`Z0w9d`3o#+d(-e!7XKbrlStDi?`;1Q z7lHXM4oCDKUgfLP)6rie#r_1F+TGcf@Ph_Ng)el7E^HcL|8BbprRZAZp-@DNXa-7c zZvfsk2417UGrAgty{2}vgU3i{iyhU^Y9Vwp#w~yiCt1Md&u*5}I@=x50+W?qf{Oka zkJ^nOrjQ}WC=_vY1$~8y3W}4RbsK5VKK)f1vrqqG`7)n=u2kP$a0-^J@s~UH==E&I zIzR7J(Z@}Km1R6r=I0GWY6en@eNF`&BVH@WZyQf6pTN4OeY_UhV>|g9Q?Vy91?H`& z^%Z>}Iu=wh2%2ROFh1KI7-Ig|Am5Mk0C8HD1Bf`n&SqUyKY$K|@jA$>zb}squpf=i z!5YcKUQBar^EDlZdr7fedwMg0TfUb)_l$n!Hn zV)2{LO+gc%zw*`O*+Ar1ft(^w5O9po9MwVxKa1q< zQnw%LIu?axBwyD7!5UZPfN+yAk@gcD6U`9G0KX$O=rjrH?rP*yo>$C-;x0XS;&>9%&bvnRx2|b>y(-JKet*bZ*8wt7F9L2DfqKe zrLM8LDu}-rSsR#p<2=QKKca2r->f=kwmGYU{I08NXsoTtn+S}X^5-i2Gh6)iZB^@i zftzl+IjMMazVdKj-pzCHeKY=~sCG?D@Zp@9ZMn+Kym@uX4Nm+C=)$U|rsklNe_spU zx8O4oqSZ_ks#KI^4>tv?);h&sw>lrH2NM3;7Jp!S9}ppdGP}NcP3`QeV0~5F?AF?r z=C;{&4NWaot+Q9xHdWWJscOByZMMI;`tIh&g;n^|*x3zhS{iHD)PgDd1nhQ@w%$Km z)B?-f0ObLA%bc5UDJY!9?;?uw-`CDfb8oq6)*O5n-1y(wPQko_TjmwbVsf+S5qmYX zfZvKT*DVsoB~!ah9WtFNQ^iapig*SWeEz$S4wbGh6MQ;4^E?v1&`6DM&IN4G@z=k` z9SRwi6j?ljQjWm|wrkRFA)}JtACKpNcyM1lUIwC{o{7hY0pIvB%7FJGtw*{Q zX$R5)q??frA>E49aW)=jFy}-%h%_JRFj6;C9*S2Yyd6o zx)td*q#f9_^4O*Kvv|A(X+BO4HzSQ8jUX+<#+0WBgGe2acMvOTFVZpuEKznE&r~B( zY>(Wf*w#91*G!&Z-)NiQAe?^}`qPi%@#`fHlhN@N#f3WYccgobzABlHMVZ-4)JYH7 zJCp@i-+KLxuIo&CFEWMD-DL#GhkRG!lMgr#*vyCUAU-*Oi@$@_G99Ivb|J?Gz=?ki zk?+iO_$2%(6v;mo{{_I^fTy?gxO6CJ%p7LV2!5y|Qei-RT@tz*G6mmH5ku zFCXg44|ogkzd;!K6-ui>4~&QPji~QH{VIYytWPVQm}y@+$&+bk{RY%WP+yv;uS2yD zZ!*CfpQlkjg!%)p6{R@S@kCm2W_C}ymgx*<6ldma80X2%e{8%bvoJK_uFSIZ)qut4;MW4%yBev5UrB375P*I^mgdRK4y7;7bf*0vGuxZ#K>vxi0eBm~0^YO08~zG-$AMRgbE+?E zcRt$9z?|9#yiX|~l(d2JJ(ljxbcQmZg0vq^%ycfy%!cGbeQ8yeBFDuG`p0+2GQt@MJ^nDV7y?l3H%D-3u=)!#-)VgEXJjT&s=rn_-e z<#V1L2cJstff_D-ZgvaU;5;KW5oij0QqzYFurgVuTPC_iZi+0QbsOcc$+CG5keJJW zne%{tm(Nxl6Y-(l^D*l`xfpL|xiZa-?~%KSwv02%{2d{mjcINsiMs|KmI4do20UBT zD#|pOnh8`Qo-Io%MQZAX2lsraH$Hf!D4wfiS}2z+6Ml4pThy3xS4uq77n$v2k0|<6 zFY&Qc6lJsBAz8jo)=M`3?TLBcQffo*%W*v?)A5ts0_94XeoLnFWV%SEcgwU+rVq;W zF`52CroWZxA7r{$rblG@zD&=_bo^x5zD&O*(|IyoB-6WPS|`&7Wt!T*#S0hS;>_{Z zu5PGma?Z^w%A13bCD+I)DV2qJb7vK>4jDzsYkPQ2uxd5ZV5^bVn>j?awXH2m9s;qCR`tr7pz^2Z$zXGsB5mN3RWq3we^9z)~YqNf%+QInk9n*L3Atb zcM%k3{`=KH1NW*m4b^D684U52Ct5K$u5N2n@~WHHFsx10=V;}0dXF^sB~`q`W%{V_ zbY=di@Qj2XurfO zm<*q+49Izu44eiS27jTk6P=}6&35|X!s7?Yc?7@OX={A2ESY}{cPTAniQ|0ISl%`BkDpS_IJPGejfqNu8b)EdK;Quvco0MNJKT4f|U#icr z>3g0%|jFmbrd~Y&Zzu3-b@P5H3OX=0z$c;R&Av>BLh%p+UKMT^!FR_O+ zg3qPnenH}=%AW~AZKI643-HUK|DnHe3rZ22AvfEE%Q(VZ9~TI?Ku!9(a}0Rh7;wf1 zmnU&B3cm#0ISTyW0Uzz2v3`MnsonDLAK9;bIlh-kp6^ONTcn-XCHzx?e`&*Zbew!z z3f-de8xkc`!UrV(aT3n^5Q(o88TexFfVyu1?m!g8*L>DzmcX|{jJ!v{FZDl*$H2d5 z4EO^AK1CUna*90_n&=n<|JM?~MdF+B;_oDUqlAmSANc&o7<~4P0sre5@C$%bKdJtQ z`){F7seeto> zxI0Cjl_q|QeSTlS&EAZpKa%*BDSl4}+&O}l$o>5oeEwq$_K$5@COZ<)nZc!oj#K>h}B8;a0E60G}AmEqAMRNpvin3Me&GeJrG5FjI z_^9_cR<{P*g6%j=lrPeK%k~Ma9?Bd z>Z-;-O|ZGOEl}0IRzZ}D^V=X!pXbe+HwTEk3xQ>+5jRsRfyMqiiaq|o z9g7w%D=80@dy4%f0p1%~6A-8Epb_^rR=2ea>BX&$ZnyQ?MtRv}GEm$&nG8z3YBHtv zOYYJ%?xak{=LW;LO;V93<$+-HBEBHFagK4*Wimdl)Jz7n)YjgQ>obj0c3fzAA6_ho ze%Im{UJ2BS9gK1RWip|m2jim4lp1*{XEM}mf){$C4eNcGVR@YCHEtbExzsdJ)7BiQuWG8ng{Q`i zp(6}%V<&F`6_<_%+S_Vtj2lfy5P0RM#ky#k@}kic9C?>$GE@u|UkbI|-_X+5QdNz~ zYTRj>jE9Ma8DJQ@snK9-dsDSB+`Jw&g&=@kt0WMOh?`W!jisU}Ho^fKNn2uw1VhV^ zVX#=@tD|J*f&(sC6*t6=b|q}mJ+33PH!HmLb);&0V9e@Z=QE-kqw&X zpg<8%s{R@JS4u>)eUskof2X7`mU!lQOrbAy*%E!k%x7jk$C|_+P ziSN|$*HL4oH_vwlBt72?S|5ijnCT{zt@LIb+940tTjyG-8QUg5zfPey&x_8w4LmcR zGO1GK??naMH}#)5SMnGXy@?8=oZ9}D6ngXg$-H0xxIvcqPHq1WDfH$!RfpFgaitKL z<7YCAAd`uYoF<8LlP#Kok&2&Mei>*uO-s<5?;*B+Mf#(lrT)zJ&GV&gUy=Sz(9-ry zdh;ADBIyUo9FJ+Aru^nOypK9-`{sFD?-D_luy><0V*e(elPUD(x!e{>A2kVOYSNkM z*%W$n|Ge>bgTR#2WMk5q<@3l8X7=CQuk=cKr->-jRDL|@WB>D0@J#x|PY-0hRHvXJ zC<`C6ZHXe1Kgss(CV{L>DGEL*Q$%1!{RTmY^aDKin1zqof75?)eva0DJr5M|JYYIL LqnMCe7M1@CeGhc5 diff --git a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.c b/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.c deleted file mode 100644 index 4f0446e..0000000 --- a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.c +++ /dev/null @@ -1,2077 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -struct tuple_int_mem_int { - int elem_0; - unsigned char* elem_1; - int elem_2; -}; -static struct tuple_int_mem_int futhark_main(int outer_loop_count_8, - int numX_12, int numY_13, - int numT_14, double s0_15, - double strike_17, double t_25, - double alpha_26, double nu_31, - double beta_32); -float futhark_toFloat32(int x) -{ - return x; -} -int futhark_trunc32(float x) -{ - return x; -} -float futhark_log32(float x) -{ - return log(x); -} -float futhark_sqrt32(float x) -{ - return sqrt(x); -} -float futhark_exp32(float x) -{ - return exp(x); -} -double futhark_toFloat64(int x) -{ - return x; -} -int futhark_trunc64(double x) -{ - return x; -} -double futhark_log64(double x) -{ - return log(x); -} -double futhark_sqrt64(double x) -{ - return sqrt(x); -} -double futhark_exp64(double x) -{ - return exp(x); -} -int timeval_subtract(struct timeval* result, struct timeval* t2, - struct timeval* t1) -{ - unsigned int resolution = 1000000; - long diff = t2->tv_usec + resolution * t2->tv_sec - (t1->tv_usec + - resolution * - t1->tv_sec); - - result->tv_sec = diff / resolution; - result->tv_usec = diff % resolution; - return diff < 0; -} -struct array_reader { - char* elems; - int64_t n_elems_space; - int64_t elem_size; - int64_t n_elems_used; - int64_t* shape; - int(* elem_reader)(void*); -}; -int peekc() - -{ - int c = getchar(); - - ungetc(c, stdin); - return c; -} -void skipspaces() - -{ - int c = getchar(); - - if (isspace(c)) { - skipspaces(); - } else if (c == '/') { - // Skip to end of line. - for (; c != '\n' && c != EOF; c = getchar()) - ; - // Next line may have more spaces. - skipspaces(); - } else if (c != EOF) { - ungetc(c, stdin); - } -} -int read_elem(struct array_reader* reader) -{ - int ret; - - if (reader->n_elems_used == reader->n_elems_space) { - reader->n_elems_space *= 2; - reader->elems = realloc(reader->elems, reader->n_elems_space * - reader->elem_size); - } - ret = reader->elem_reader(reader->elems + reader->n_elems_used * - reader->elem_size); - if (ret == 0) { - reader->n_elems_used++; - } - return ret; -} -int read_array_elems(struct array_reader* reader, int dims) -{ - int c; - int ret; - int first = 1; - char* knows_dimsize = calloc(dims, sizeof(char)); - int cur_dim = dims - 1; - int64_t* elems_read_in_dim = calloc(dims, sizeof(int64_t)); - - while (1) { - skipspaces(); - c = getchar(); - if (c == ']') { - if (knows_dimsize[cur_dim]) { - if (reader->shape[cur_dim] != elems_read_in_dim[cur_dim]) { - ret = 1; - break; - } - } else { - knows_dimsize[cur_dim] = 1; - reader->shape[cur_dim] = elems_read_in_dim[cur_dim]; - } - if (cur_dim == 0) { - ret = 0; - break; - } else { - cur_dim--; - elems_read_in_dim[cur_dim]++; - } - } else if (c == ',') { - skipspaces(); - c = getchar(); - if (c == '[') { - if (cur_dim == dims - 1) { - ret = 1; - break; - } - first = 1; - cur_dim++; - elems_read_in_dim[cur_dim] = 0; - } else if (cur_dim == dims - 1) { - ungetc(c, stdin); - ret = read_elem(reader); - if (ret != 0) { - break; - } - elems_read_in_dim[cur_dim]++; - } else { - ret = 1; - break; - } - } else if (c == EOF) { - ret = 1; - break; - } else if (first) { - if (c == '[') { - if (cur_dim == dims - 1) { - ret = 1; - break; - } - cur_dim++; - elems_read_in_dim[cur_dim] = 0; - } else { - ungetc(c, stdin); - ret = read_elem(reader); - if (ret != 0) { - break; - } - elems_read_in_dim[cur_dim]++; - first = 0; - } - } else { - ret = 1; - break; - } - } - free(knows_dimsize); - free(elems_read_in_dim); - return ret; -} -int read_array(int64_t elem_size, int(* elem_reader)(void*), void** data, - int64_t* shape, int64_t dims) -{ - int ret; - struct array_reader reader; - int64_t read_dims = 0; - - while (1) { - int c; - - skipspaces(); - c = getchar(); - if (c == '[') { - read_dims++; - } else { - if (c != EOF) { - ungetc(c, stdin); - } - break; - } - } - if (read_dims != dims) { - return 1; - } - reader.shape = shape; - reader.n_elems_used = 0; - reader.elem_size = elem_size; - reader.n_elems_space = 16; - reader.elems = calloc(elem_size, reader.n_elems_space); - reader.elem_reader = elem_reader; - ret = read_array_elems(&reader, dims); - *data = reader.elems; - return ret; -} -int read_int(void* dest) -{ - skipspaces(); - if (scanf("%d", (int*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_char(void* dest) -{ - skipspaces(); - if (scanf("%c", (char*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_double(void* dest) -{ - skipspaces(); - if (scanf("%lf", (double*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_float(void* dest) -{ - skipspaces(); - if (scanf("%f", (float*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_bool(void* dest) -{ - char b[4]; - - skipspaces(); - if (scanf("%4c", b) == 1) { - if (strncmp(b, "True", 4) == 0) { - *(int*) dest = 1; - return 0; - } else if (strncmp(b, "Fals", 4) == 0 && getchar() == 'e') { - *(int*) dest = 0; - return 0; - } else { - return 1; - } - } else { - return 1; - } -} -static struct tuple_int_mem_int futhark_main(int outer_loop_count_8, - int numX_12, int numY_13, - int numT_14, double s0_15, - double strike_17, double t_25, - double alpha_26, double nu_31, - double beta_32) -{ - int out_memsize_78; - unsigned char* out_mem_77; - int out_arrsize_98; - double res_37; - - res_37 = futhark_log64(alpha_26); - - double x_61; - - x_61 = futhark_toFloat64(numT_14); - - double y_97; - - y_97 = x_61 - 1.0; - - int bytes_42; - - bytes_42 = 8 * numT_14; - - unsigned char* mem_51; - - mem_51 = malloc(bytes_42); - for (int i_0 = 0; i_0 < numT_14; i_0++) { - double y_99; - - y_99 = futhark_toFloat64(i_0); - - double x_100; - - x_100 = t_25 * y_99; - - double res_101; - - res_101 = x_100 / y_97; - *(double*) &mem_51[i_0 * 1 * 8 + 0] = res_101; - } - - double x_103; - - x_103 = 20.0 * alpha_26; - - double x_104; - - x_104 = x_103 * s0_15; - - double y_105; - - y_105 = futhark_sqrt64(t_25); - - double res_106; - - res_106 = x_104 * y_105; - - double x_107; - - x_107 = 10.0 * nu_31; - - double res_108; - - res_108 = x_107 * y_105; - - double y_109; - - y_109 = futhark_toFloat64(numX_12); - - double res_110; - - res_110 = res_106 / y_109; - - double y_111; - - y_111 = futhark_toFloat64(numY_13); - - double res_112; - - res_112 = res_108 / y_111; - - double arg_113; - - arg_113 = s0_15 / res_110; - - int res_115; - - res_115 = futhark_trunc64(arg_113); - - int res_116; - - res_116 = numY_13 / 2 - (numY_13 % 2 != 0 && numY_13 % 2 < 0 != 2 < - 0 ? 1 : 0); - - double x_118; - - x_118 = futhark_toFloat64(res_115); - - double y_119; - - y_119 = x_118 * res_110; - - int bytes_157; - - bytes_157 = 8 * numX_12; - - unsigned char* mem_159; - - mem_159 = malloc(bytes_157); - for (int i_4 = 0; i_4 < numX_12; i_4++) { - double x_121; - - x_121 = futhark_toFloat64(i_4); - - double x_122; - - x_122 = x_121 * res_110; - - double x_123; - - x_123 = x_122 - y_119; - - double res_124; - - res_124 = x_123 + s0_15; - *(double*) &mem_159[i_4 * 1 * 8 + 0] = res_124; - } - - double x_127; - - x_127 = futhark_toFloat64(res_116); - - double y_128; - - y_128 = x_127 * res_112; - - int bytes_173; - - bytes_173 = 8 * numY_13; - - unsigned char* mem_174; - - mem_174 = malloc(bytes_173); - for (int i_9 = 0; i_9 < numY_13; i_9++) { - double x_130; - - x_130 = futhark_toFloat64(i_9); - - double x_131; - - x_131 = x_130 * res_112; - - double x_132; - - x_132 = x_131 - y_128; - - double res_133; - - res_133 = x_132 + res_37; - *(double*) &mem_174[i_9 * 1 * 8 + 0] = res_133; - } - - unsigned char* mem_186; - - mem_186 = malloc(24); - *(double*) &mem_186[0 * 1 * 8 + 0] = 0.0; - *(double*) &mem_186[1 * 1 * 8 + 0] = 0.0; - *(double*) &mem_186[2 * 1 * 8 + 0] = 0.0; - - unsigned char* mem_190; - - mem_190 = malloc(24); - for (int i_147 = 0; i_147 < 3; i_147++) { - *(double*) &mem_190[8 * i_147] = *(double*) &mem_186[8 * i_147]; - } - - int n_215; - - n_215 = numX_12 - 2; - - int x_192; - - x_192 = 8 * n_215; - - int bytes_191; - - bytes_191 = x_192 * 3; - - unsigned char* mem_193; - - mem_193 = malloc(bytes_191); - for (int i_18 = 0; i_18 < n_215; i_18++) { - int res_220; - - res_220 = i_18 + 1; - - double x_337; - - x_337 = *(double*) &mem_159[res_220 * 1 * 8 + 0]; - - int i_340; - - i_340 = res_220 - 1; - - double y_341; - - y_341 = *(double*) &mem_159[i_340 * 1 * 8 + 0]; - - double res_342; - - res_342 = x_337 - y_341; - - int i_343; - - i_343 = res_220 + 1; - - double x_345; - - x_345 = *(double*) &mem_159[i_343 * 1 * 8 + 0]; - - double res_349; - - res_349 = x_345 - x_337; - - double y_387; - - y_387 = res_342 + res_349; - - double x_423; - - x_423 = 2.0 / res_342; - - double arr_elem_424; - - arr_elem_424 = x_423 / y_387; - - double x_425; - - x_425 = 1.0 / res_342; - - double y_426; - - y_426 = 1.0 / res_349; - - double y_427; - - y_427 = x_425 + y_426; - - double x_428; - - x_428 = -2.0 * y_427; - - double arr_elem_429; - - arr_elem_429 = x_428 / y_387; - - double x_430; - - x_430 = 2.0 / res_349; - - double arr_elem_431; - - arr_elem_431 = x_430 / y_387; - *(double*) &mem_193[(i_18 * 3 + 0 * 1) * 8 + 0] = arr_elem_424; - *(double*) &mem_193[(i_18 * 3 + 1 * 1) * 8 + 0] = arr_elem_429; - *(double*) &mem_193[(i_18 * 3 + 2 * 1) * 8 + 0] = arr_elem_431; - } - - int i_435; - - i_435 = numX_12 - 1; - - char x_436; - - x_436 = 0 <= i_435; - - int bounds_check_437; - - if (!x_436) { - fprintf(stderr, "Assertion %s at %s failed.\n", "x_436", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:27:18-27:19"); - abort(); - } - - int conc_tmp_447; - - conc_tmp_447 = 1 + n_215; - - int conc_tmp_449; - - conc_tmp_449 = conc_tmp_447 + 1; - - int x_209; - - x_209 = 8 * conc_tmp_447; - - int bytes_204; - - bytes_204 = x_209 * 3; - - unsigned char* mem_210; - - mem_210 = malloc(bytes_204); - - int tmp_offs_153; - - tmp_offs_153 = 0; - memmove(mem_210 + (0 + tmp_offs_153 * 3 * 8), mem_190 + 0, 3 * - sizeof(double)); - tmp_offs_153 = tmp_offs_153 + 1; - memmove(mem_210 + (0 + tmp_offs_153 * 3 * 8), mem_193 + 0, n_215 * 3 * - sizeof(double)); - tmp_offs_153 = tmp_offs_153 + n_215; - - int x_212; - - x_212 = 8 * conc_tmp_449; - - int bytes_211; - - bytes_211 = x_212 * 3; - - unsigned char* mem_216; - - mem_216 = malloc(bytes_211); - - int tmp_offs_154; - - tmp_offs_154 = 0; - memmove(mem_216 + (0 + tmp_offs_154 * 3 * 8), mem_210 + 0, conc_tmp_447 * - 3 * sizeof(double)); - tmp_offs_154 = tmp_offs_154 + conc_tmp_447; - memmove(mem_216 + (0 + tmp_offs_154 * 3 * 8), mem_190 + 0, 3 * - sizeof(double)); - tmp_offs_154 = tmp_offs_154 + 1; - - int n_464; - - n_464 = numY_13 - 2; - - int x_218; - - x_218 = 8 * n_464; - - int bytes_217; - - bytes_217 = x_218 * 3; - - unsigned char* mem_219; - - mem_219 = malloc(bytes_217); - for (int i_22 = 0; i_22 < n_464; i_22++) { - int res_467; - - res_467 = i_22 + 1; - - double x_468; - - x_468 = *(double*) &mem_174[res_467 * 1 * 8 + 0]; - - int i_469; - - i_469 = res_467 - 1; - - double y_470; - - y_470 = *(double*) &mem_174[i_469 * 1 * 8 + 0]; - - double res_471; - - res_471 = x_468 - y_470; - - int i_472; - - i_472 = res_467 + 1; - - double x_473; - - x_473 = *(double*) &mem_174[i_472 * 1 * 8 + 0]; - - double res_474; - - res_474 = x_473 - x_468; - - double y_480; - - y_480 = res_471 + res_474; - - double x_489; - - x_489 = 2.0 / res_471; - - double arr_elem_490; - - arr_elem_490 = x_489 / y_480; - - double x_491; - - x_491 = 1.0 / res_471; - - double y_494; - - y_494 = 1.0 / res_474; - - double y_495; - - y_495 = x_491 + y_494; - - double x_496; - - x_496 = -2.0 * y_495; - - double arr_elem_497; - - arr_elem_497 = x_496 / y_480; - - double x_498; - - x_498 = 2.0 / res_474; - - double arr_elem_499; - - arr_elem_499 = x_498 / y_480; - *(double*) &mem_219[(i_22 * 3 + 0 * 1) * 8 + 0] = arr_elem_490; - *(double*) &mem_219[(i_22 * 3 + 1 * 1) * 8 + 0] = arr_elem_497; - *(double*) &mem_219[(i_22 * 3 + 2 * 1) * 8 + 0] = arr_elem_499; - } - - int i_503; - - i_503 = numY_13 - 1; - - char x_504; - - x_504 = 0 <= i_503; - - int bounds_check_505; - - if (!x_504) { - fprintf(stderr, "Assertion %s at %s failed.\n", "x_504", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:27:18-27:19"); - abort(); - } - - int conc_tmp_515; - - conc_tmp_515 = 1 + n_464; - - int conc_tmp_517; - - conc_tmp_517 = conc_tmp_515 + 1; - - int x_226; - - x_226 = 8 * conc_tmp_515; - - int bytes_225; - - bytes_225 = x_226 * 3; - - unsigned char* mem_227; - - mem_227 = malloc(bytes_225); - - int tmp_offs_156; - - tmp_offs_156 = 0; - memmove(mem_227 + (0 + tmp_offs_156 * 3 * 8), mem_190 + 0, 3 * - sizeof(double)); - tmp_offs_156 = tmp_offs_156 + 1; - memmove(mem_227 + (0 + tmp_offs_156 * 3 * 8), mem_219 + 0, n_464 * 3 * - sizeof(double)); - tmp_offs_156 = tmp_offs_156 + n_464; - - int x_229; - - x_229 = 8 * conc_tmp_517; - - int bytes_228; - - bytes_228 = x_229 * 3; - - unsigned char* mem_230; - - mem_230 = malloc(bytes_228); - - int tmp_offs_158; - - tmp_offs_158 = 0; - memmove(mem_230 + (0 + tmp_offs_158 * 3 * 8), mem_227 + 0, conc_tmp_515 * - 3 * sizeof(double)); - tmp_offs_158 = tmp_offs_158 + conc_tmp_515; - memmove(mem_230 + (0 + tmp_offs_158 * 3 * 8), mem_190 + 0, 3 * - sizeof(double)); - tmp_offs_158 = tmp_offs_158 + 1; - - int bound_521; - - bound_521 = numT_14 - 1; - - int x_522; - - x_522 = numT_14 - 2; - - double replicate_v_524; - - replicate_v_524 = nu_31 * nu_31; - - double x_527; - - x_527 = 0.5 * nu_31; - - double x_528; - - x_528 = x_527 * nu_31; - - char zip_cmp_530; - - zip_cmp_530 = conc_tmp_449 == numX_12; - - int zip_assert_531; - - if (!zip_cmp_530) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_530", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:165:21-165:24"); - abort(); - } - - int y_532; - - y_532 = conc_tmp_449 - 1; - - int y_536; - - y_536 = conc_tmp_517 - 1; - - char zip_cmp_537; - - zip_cmp_537 = numY_13 == conc_tmp_517; - - int zip_assert_538; - - if (!zip_cmp_537) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_537", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:219:18-219:21"); - abort(); - } - - char zip_cmp_542; - - zip_cmp_542 = numX_12 == conc_tmp_449; - - int zip_assert_543; - - if (!zip_cmp_542) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_542", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:188:25-188:28"); - abort(); - } - - char x_549; - - x_549 = 0 <= res_116; - - char x_555; - - x_555 = 0 <= res_115; - - char y_556; - - y_556 = res_115 < numX_12; - - char assert_arg_557; - - assert_arg_557 = x_555 && y_556; - - int bounds_check_558; - - if (!assert_arg_557) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_557", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:254:5-254:13"); - abort(); - } - - double x_566; - - x_566 = 0.5 * replicate_v_524; - - char y_569; - - y_569 = res_116 < numY_13; - - char assert_arg_570; - - assert_arg_570 = x_549 && y_569; - - int bounds_check_571; - - if (!assert_arg_570) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_570", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:254:5-254:13"); - abort(); - } - - int bytes_231; - - bytes_231 = 8 * outer_loop_count_8; - - unsigned char* mem_232; - - mem_232 = malloc(bytes_231); - - int bytes_235; - - bytes_235 = bytes_157 * numY_13; - - unsigned char* mem_237; - - mem_237 = malloc(bytes_235); - - int bytes_242; - - bytes_242 = bytes_173 * numX_12; - - unsigned char* mem_244; - - mem_244 = malloc(bytes_242); - - int bytes_247; - - bytes_247 = bytes_173 * conc_tmp_449; - - unsigned char* mem_249; - - mem_249 = malloc(bytes_247); - - unsigned char* mem_253; - - mem_253 = malloc(bytes_157); - - unsigned char* mem_266; - - mem_266 = malloc(bytes_247); - - int bytes_267; - - bytes_267 = bytes_157 * conc_tmp_517; - - unsigned char* mem_269; - - mem_269 = malloc(bytes_267); - - unsigned char* mem_280; - - mem_280 = malloc(bytes_267); - - unsigned char* mem_283; - - mem_283 = malloc(bytes_247); - - unsigned char* mem_287; - - mem_287 = malloc(x_212); - - unsigned char* mem_293; - - mem_293 = malloc(x_212); - - unsigned char* mem_295; - - mem_295 = malloc(bytes_157); - - unsigned char* mem_297; - - mem_297 = malloc(bytes_157); - - unsigned char* mem_299; - - mem_299 = malloc(bytes_157); - - unsigned char* mem_313; - - mem_313 = malloc(bytes_157); - - int bytes_329; - - bytes_329 = x_212 * numY_13; - - unsigned char* mem_331; - - mem_331 = malloc(bytes_329); - - unsigned char* mem_348; - - mem_348 = malloc(bytes_329); - - unsigned char* mem_351; - - mem_351 = malloc(bytes_173); - - unsigned char* mem_353; - - mem_353 = malloc(bytes_173); - - unsigned char* mem_355; - - mem_355 = malloc(bytes_173); - - unsigned char* mem_370; - - mem_370 = malloc(bytes_235); - - unsigned char* mem_374; - - mem_374 = malloc(bytes_173); - - unsigned char* mem_376; - - mem_376 = malloc(bytes_173); - - unsigned char* double_buffer_mem_41; - - double_buffer_mem_41 = malloc(bytes_242); - - unsigned char* mem_395; - - mem_395 = malloc(bytes_242); - for (int i_136 = 0; i_136 < outer_loop_count_8; i_136++) { - double y_575; - - y_575 = futhark_toFloat64(i_136); - - double res_578; - - res_578 = 1.0e-3 * y_575; - for (int i_28 = 0; i_28 < numX_12; i_28++) { - double xi_581; - - xi_581 = *(double*) &mem_159[i_28 * 1 * 8 + 0]; - - double arg_587; - - arg_587 = xi_581 - res_578; - - char cond_588; - - cond_588 = 0.0 < arg_587; - - double res_591; - - if (cond_588) { - res_591 = arg_587; - } else { - res_591 = 0.0; - } - for (int i_166 = 0; i_166 < numY_13; i_166++) { - *(double*) &mem_237[(i_28 * numY_13 + i_166 * 1) * 8 + 0] = - res_591; - } - } - for (int i_167 = 0; i_167 < numY_13; i_167++) { - for (int i_168 = 0; i_168 < numX_12; i_168++) { - *(double*) &mem_244[8 * (numX_12 * i_167) + 8 * i_168] = - *(double*) &mem_237[8 * (numY_13 * i_168) + 8 * i_167]; - } - } - - unsigned char* myResult_mem_398; - unsigned char* myResult_mem_246; - - myResult_mem_246 = mem_244; - for (int i_601 = 0; i_601 < bound_521; i_601++) { - int res_602; - - res_602 = x_522 - i_601; - - double y_603; - - y_603 = *(double*) &mem_51[res_602 * 1 * 8 + 0]; - - double y_604; - - y_604 = x_528 * y_603; - - int i_605; - - i_605 = res_602 + 1; - - double x_606; - - x_606 = *(double*) &mem_51[i_605 * 1 * 8 + 0]; - - double y_618; - - y_618 = x_606 - y_603; - - double res_619; - - res_619 = 1.0 / y_618; - for (int i_44 = 0; i_44 < numY_13; i_44++) { - double yj_620; - - yj_620 = *(double*) &mem_174[i_44 * 1 * 8 + 0]; - for (int i_34 = 0; i_34 < numX_12; i_34++) { - double xi_639; - - xi_639 = *(double*) &mem_159[i_34 * 1 * 8 + 0]; - - double y_640; - - y_640 = futhark_log64(xi_639); - - double x_642; - - x_642 = beta_32 * y_640; - - double x_643; - - x_643 = x_642 + yj_620; - - double y_644; - - y_644 = x_643 - y_604; - - double arg_645; - - arg_645 = 2.0 * y_644; - - double res_646; - - res_646 = futhark_exp64(arg_645); - *(double*) &mem_253[i_34 * 1 * 8 + 0] = res_646; - } - for (int i_40 = 0; i_40 < conc_tmp_449; i_40++) { - double tup_653; - - tup_653 = *(double*) &mem_253[i_40 * 1 * 8 + 0]; - - char cond_657; - - cond_657 = 0 < i_40; - - double x_658; - - x_658 = 0.5 * tup_653; - - int i_660; - - i_660 = i_40 - 1; - - double res_668; - - if (cond_657) { - double y_662; - - y_662 = *(double*) &mem_216[(i_40 * 3 + 0 * 1) * 8 + 0]; - - double y_663; - - y_663 = x_658 * y_662; - - double y_665; - - y_665 = *(double*) &myResult_mem_246[(i_44 * numX_12 + - i_660 * 1) * 8 + - 0]; - - double res_666; - - res_666 = y_663 * y_665; - res_668 = res_666; - } else { - res_668 = 0.0; - } - - char cond_669; - - cond_669 = i_40 < y_532; - - int i_671; - - i_671 = i_40 + 1; - - char y_672; - - y_672 = i_671 < numX_12; - - double res_679; - - if (cond_669) { - double y_674; - - y_674 = *(double*) &mem_216[(i_40 * 3 + 2 * 1) * 8 + 0]; - - double y_675; - - y_675 = x_658 * y_674; - - int bounds_check_676; - - if (!y_672) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_672", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:161:69-161:79"); - abort(); - } - - double y_677; - - y_677 = *(double*) &myResult_mem_246[(i_44 * numX_12 + - i_671 * 1) * 8 + - 0]; - - double res_678; - - res_678 = y_675 * y_677; - res_679 = res_678; - } else { - res_679 = 0.0; - } - - double y_682; - - y_682 = *(double*) &mem_216[(i_40 * 3 + 1 * 1) * 8 + 0]; - - double y_683; - - y_683 = x_658 * y_682; - - double y_686; - - y_686 = *(double*) &myResult_mem_246[(i_44 * numX_12 + - i_40 * 1) * 8 + 0]; - - double res_687; - - res_687 = y_683 * y_686; - - double x_688; - - x_688 = res_668 + res_687; - - double res_689; - - res_689 = x_688 + res_679; - *(double*) &mem_249[(i_44 * conc_tmp_449 + i_40 * 1) * 8 + - 0] = res_689; - } - } - memmove(mem_266 + 0, mem_249 + 0, numY_13 * conc_tmp_449 * - sizeof(double)); - for (int i_53 = 0; i_53 < numX_12; i_53++) { - for (int i_49 = 0; i_49 < conc_tmp_517; i_49++) { - char cond_707; - - cond_707 = 0 < i_49; - - int i_709; - - i_709 = i_49 - 1; - - double res_748; - - if (cond_707) { - double y_711; - - y_711 = *(double*) &mem_230[(i_49 * 3 + 0 * 1) * 8 + 0]; - - double y_717; - - y_717 = x_566 * y_711; - - double y_746; - - y_746 = *(double*) &myResult_mem_246[(i_709 * numX_12 + - i_53 * 1) * 8 + - 0]; - - double res_747; - - res_747 = y_717 * y_746; - res_748 = res_747; - } else { - res_748 = 0.0; - } - - char cond_749; - - cond_749 = i_49 < y_536; - - int i_750; - - i_750 = i_49 + 1; - - char y_751; - - y_751 = i_750 < numY_13; - - double res_776; - - if (cond_749) { - double y_754; - - y_754 = *(double*) &mem_230[(i_49 * 3 + 2 * 1) * 8 + 0]; - - double y_763; - - y_763 = x_566 * y_754; - - int bounds_check_764; - - if (!y_751) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_751", - "/home/athas/repos/finpar/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut:161:69-161:79"); - abort(); - } - - double y_767; - - y_767 = *(double*) &myResult_mem_246[(i_750 * numX_12 + - i_53 * 1) * 8 + - 0]; - - double res_771; - - res_771 = y_763 * y_767; - res_776 = res_771; - } else { - res_776 = 0.0; - } - - double y_782; - - y_782 = *(double*) &mem_230[(i_49 * 3 + 1 * 1) * 8 + 0]; - - double y_792; - - y_792 = x_566 * y_782; - - double y_796; - - y_796 = *(double*) &myResult_mem_246[(i_49 * numX_12 + - i_53 * 1) * 8 + 0]; - - double res_797; - - res_797 = y_792 * y_796; - - double x_805; - - x_805 = res_748 + res_797; - - double res_809; - - res_809 = x_805 + res_776; - *(double*) &mem_269[(i_53 * conc_tmp_517 + i_49 * 1) * 8 + - 0] = res_809; - } - } - memmove(mem_280 + 0, mem_269 + 0, numX_12 * conc_tmp_517 * - sizeof(double)); - for (int i_72 = 0; i_72 < numY_13; i_72++) { - double yj_846; - - yj_846 = *(double*) &mem_174[i_72 * 1 * 8 + 0]; - - int x_140; - - x_140 = i_72 * numX_12; - for (int i_57 = 0; i_57 < conc_tmp_449; i_57++) { - double tup_906; - - tup_906 = *(double*) &mem_266[(i_72 * conc_tmp_449 + i_57 * - 1) * 8 + 0]; - - double tup_907; - - tup_907 = *(double*) &myResult_mem_246[(i_72 * numX_12 + - i_57 * 1) * 8 + 0]; - - int flat_index_142; - - flat_index_142 = x_140 + i_57; - - int i_143; - - i_143 = flat_index_142 / numX_12 - (flat_index_142 % - numX_12 != 0 && - flat_index_142 % - numX_12 < 0 != numX_12 < - 0 ? 1 : 0); - - int y_144; - - y_144 = i_143 * numX_12; - - int i_remnant_145; - - i_remnant_145 = flat_index_142 - y_144; - - double y_908; - - y_908 = *(double*) &mem_280[(i_remnant_145 * conc_tmp_517 + - i_143 * 1) * 8 + 0]; - - double x_909; - - x_909 = res_619 * tup_907; - - double y_910; - - y_910 = 0.5 * tup_906; - - double res_911; - - res_911 = x_909 + y_910; - - double res_912; - - res_912 = res_911 + y_908; - *(double*) &mem_287[i_57 * 1 * 8 + 0] = res_912; - } - memmove(mem_293 + 0, mem_287 + 0, conc_tmp_449 * - sizeof(double)); - for (int i_62 = 0; i_62 < numX_12; i_62++) { - double xi_916; - - xi_916 = *(double*) &mem_159[i_62 * 1 * 8 + 0]; - - double y_917; - - y_917 = futhark_log64(xi_916); - - double x_918; - - x_918 = beta_32 * y_917; - - double x_919; - - x_919 = x_918 + yj_846; - - double y_920; - - y_920 = x_919 - y_604; - - double arg_921; - - arg_921 = 2.0 * y_920; - - double res_922; - - res_922 = futhark_exp64(arg_921); - - double x_923; - - x_923 = 0.5 * res_922; - - int x_149; - - x_149 = i_62 * 3; - - int i_152; - - i_152 = x_149 / 3 - (x_149 % 3 != 0 && x_149 % 3 < 0 != 3 < - 0 ? 1 : 0); - - double y_924; - - y_924 = *(double*) &mem_216[(i_152 * 3 + 0 * 1) * 8 + 0]; - - double y_925; - - y_925 = x_923 * y_924; - - double y_926; - - y_926 = 0.5 * y_925; - - double res_927; - - res_927 = 0.0 - y_926; - - int flat_index_160; - - flat_index_160 = x_149 + 1; - - int i_161; - - i_161 = flat_index_160 / 3 - (flat_index_160 % 3 != 0 && - flat_index_160 % 3 < 0 != 3 < - 0 ? 1 : 0); - - int y_162; - - y_162 = i_161 * 3; - - int i_remnant_163; - - i_remnant_163 = flat_index_160 - y_162; - - double y_928; - - y_928 = *(double*) &mem_216[(i_161 * 3 + i_remnant_163 * - 1) * 8 + 0]; - - double y_929; - - y_929 = x_923 * y_928; - - double y_930; - - y_930 = 0.5 * y_929; - - double res_931; - - res_931 = res_619 - y_930; - - int flat_index_169; - - flat_index_169 = x_149 + 2; - - int i_170; - - i_170 = flat_index_169 / 3 - (flat_index_169 % 3 != 0 && - flat_index_169 % 3 < 0 != 3 < - 0 ? 1 : 0); - - int y_171; - - y_171 = i_170 * 3; - - int i_remnant_172; - - i_remnant_172 = flat_index_169 - y_171; - - double y_932; - - y_932 = *(double*) &mem_216[(i_170 * 3 + i_remnant_172 * - 1) * 8 + 0]; - - double y_933; - - y_933 = x_923 * y_932; - - double y_934; - - y_934 = 0.5 * y_933; - - double res_935; - - res_935 = 0.0 - y_934; - *(double*) &mem_295[i_62 * 1 * 8 + 0] = res_927; - *(double*) &mem_297[i_62 * 1 * 8 + 0] = res_931; - *(double*) &mem_299[i_62 * 1 * 8 + 0] = res_935; - } - memmove(mem_313 + 0, mem_297 + 0, numX_12 * sizeof(double)); - for (int i_945 = 0; i_945 < i_435; i_945++) { - int res_946; - - res_946 = i_945 + 1; - - double x_947; - - x_947 = *(double*) &mem_295[res_946 * 1 * 8 + 0]; - - int i_948; - - i_948 = res_946 - 1; - - double y_949; - - y_949 = *(double*) &mem_313[i_948 * 1 * 8 + 0]; - - double res_950; - - res_950 = x_947 / y_949; - - double x_951; - - x_951 = *(double*) &mem_313[res_946 * 1 * 8 + 0]; - - double y_952; - - y_952 = *(double*) &mem_299[i_948 * 1 * 8 + 0]; - - double y_953; - - y_953 = res_950 * y_952; - - double lw_val_954; - - lw_val_954 = x_951 - y_953; - *(double*) &mem_313[res_946 * 1 * 8 + 0] = lw_val_954; - - double x_956; - - x_956 = *(double*) &mem_293[res_946 * 1 * 8 + 0]; - - double y_957; - - y_957 = *(double*) &mem_293[i_948 * 1 * 8 + 0]; - - double y_958; - - y_958 = res_950 * y_957; - - double lw_val_959; - - lw_val_959 = x_956 - y_958; - *(double*) &mem_293[res_946 * 1 * 8 + 0] = lw_val_959; - } - - double x_963; - - x_963 = *(double*) &mem_293[i_435 * 1 * 8 + 0]; - - double y_964; - - y_964 = *(double*) &mem_313[i_435 * 1 * 8 + 0]; - - double lw_val_965; - - lw_val_965 = x_963 / y_964; - *(double*) &mem_293[i_435 * 1 * 8 + 0] = lw_val_965; - for (int i_222 = 0; i_222 < conc_tmp_449; i_222++) { - *(double*) &mem_283[8 * (i_72 * conc_tmp_449) + 8 * i_222] = - *(double*) &mem_293[8 * i_222]; - } - for (int j_968 = 0; j_968 < i_435; j_968++) { - int res_969; - - res_969 = n_215 - j_968; - - double x_970; - - x_970 = *(double*) &mem_283[(i_72 * conc_tmp_449 + res_969 * - 1) * 8 + 0]; - - double x_971; - - x_971 = *(double*) &mem_299[res_969 * 1 * 8 + 0]; - - int i_972; - - i_972 = res_969 + 1; - - double y_973; - - y_973 = *(double*) &mem_283[(i_72 * conc_tmp_449 + i_972 * - 1) * 8 + 0]; - - double y_974; - - y_974 = x_971 * y_973; - - double x_975; - - x_975 = x_970 - y_974; - - double y_976; - - y_976 = *(double*) &mem_313[res_969 * 1 * 8 + 0]; - - double lw_val_977; - - lw_val_977 = x_975 / y_976; - *(double*) &mem_283[(i_72 * conc_tmp_449 + res_969 * 1) * - 8 + 0] = lw_val_977; - } - } - for (int i_80 = 0; i_80 < conc_tmp_449; i_80++) { - int x_176; - - x_176 = i_80 * conc_tmp_517; - for (int i_76 = 0; i_76 < numY_13; i_76++) { - double uv_987; - - uv_987 = *(double*) &mem_283[(i_76 * conc_tmp_449 + i_80 * - 1) * 8 + 0]; - - int flat_index_178; - - flat_index_178 = x_176 + i_76; - - int i_179; - - i_179 = flat_index_178 / conc_tmp_517 - (flat_index_178 % - conc_tmp_517 != - 0 && - flat_index_178 % - conc_tmp_517 < 0 != - conc_tmp_517 < - 0 ? 1 : 0); - - int y_180; - - y_180 = i_179 * conc_tmp_517; - - int i_remnant_181; - - i_remnant_181 = flat_index_178 - y_180; - - double uv_988; - - uv_988 = *(double*) &mem_280[(i_179 * conc_tmp_517 + - i_remnant_181 * 1) * 8 + 0]; - - double x_989; - - x_989 = res_619 * uv_987; - - double y_990; - - y_990 = 0.5 * uv_988; - - double res_991; - - res_991 = x_989 - y_990; - *(double*) &mem_331[(i_80 * numY_13 + i_76 * 1) * 8 + 0] = - res_991; - } - } - memmove(mem_348 + 0, mem_331 + 0, conc_tmp_449 * numY_13 * - sizeof(double)); - for (int i_84 = 0; i_84 < numY_13; i_84++) { - int x_185; - - x_185 = i_84 * 3; - - int i_188; - - i_188 = x_185 / 3 - (x_185 % 3 != 0 && x_185 % 3 < 0 != 3 < - 0 ? 1 : 0); - - double y_997; - - y_997 = *(double*) &mem_230[(i_188 * 3 + 0 * 1) * 8 + 0]; - - double y_998; - - y_998 = x_566 * y_997; - - double y_999; - - y_999 = 0.5 * y_998; - - double res_1000; - - res_1000 = 0.0 - y_999; - - int flat_index_196; - - flat_index_196 = x_185 + 1; - - int i_197; - - i_197 = flat_index_196 / 3 - (flat_index_196 % 3 != 0 && - flat_index_196 % 3 < 0 != 3 < - 0 ? 1 : 0); - - int y_198; - - y_198 = i_197 * 3; - - int i_remnant_199; - - i_remnant_199 = flat_index_196 - y_198; - - double y_1001; - - y_1001 = *(double*) &mem_230[(i_197 * 3 + i_remnant_199 * 1) * - 8 + 0]; - - double y_1002; - - y_1002 = x_566 * y_1001; - - double y_1003; - - y_1003 = 0.5 * y_1002; - - double res_1004; - - res_1004 = res_619 - y_1003; - - int flat_index_205; - - flat_index_205 = x_185 + 2; - - int i_206; - - i_206 = flat_index_205 / 3 - (flat_index_205 % 3 != 0 && - flat_index_205 % 3 < 0 != 3 < - 0 ? 1 : 0); - - int y_207; - - y_207 = i_206 * 3; - - int i_remnant_208; - - i_remnant_208 = flat_index_205 - y_207; - - double y_1005; - - y_1005 = *(double*) &mem_230[(i_206 * 3 + i_remnant_208 * 1) * - 8 + 0]; - - double y_1006; - - y_1006 = x_566 * y_1005; - - double y_1007; - - y_1007 = 0.5 * y_1006; - - double res_1008; - - res_1008 = 0.0 - y_1007; - *(double*) &mem_351[i_84 * 1 * 8 + 0] = res_1000; - *(double*) &mem_353[i_84 * 1 * 8 + 0] = res_1004; - *(double*) &mem_355[i_84 * 1 * 8 + 0] = res_1008; - } - for (int i_94 = 0; i_94 < numX_12; i_94++) { - for (int i_240 = 0; i_240 < numY_13; i_240++) { - *(double*) &mem_374[8 * i_240] = *(double*) &mem_348[8 * - (numY_13 * - i_94) + - 8 * - i_240]; - } - memmove(mem_376 + 0, mem_353 + 0, numY_13 * sizeof(double)); - for (int i_1016 = 0; i_1016 < i_503; i_1016++) { - int res_1017; - - res_1017 = i_1016 + 1; - - double x_1018; - - x_1018 = *(double*) &mem_351[res_1017 * 1 * 8 + 0]; - - int i_1019; - - i_1019 = res_1017 - 1; - - double y_1020; - - y_1020 = *(double*) &mem_376[i_1019 * 1 * 8 + 0]; - - double res_1021; - - res_1021 = x_1018 / y_1020; - - double x_1022; - - x_1022 = *(double*) &mem_376[res_1017 * 1 * 8 + 0]; - - double y_1023; - - y_1023 = *(double*) &mem_355[i_1019 * 1 * 8 + 0]; - - double y_1024; - - y_1024 = res_1021 * y_1023; - - double lw_val_1025; - - lw_val_1025 = x_1022 - y_1024; - *(double*) &mem_376[res_1017 * 1 * 8 + 0] = lw_val_1025; - - double x_1027; - - x_1027 = *(double*) &mem_374[res_1017 * 1 * 8 + 0]; - - double y_1028; - - y_1028 = *(double*) &mem_374[i_1019 * 1 * 8 + 0]; - - double y_1029; - - y_1029 = res_1021 * y_1028; - - double lw_val_1030; - - lw_val_1030 = x_1027 - y_1029; - *(double*) &mem_374[res_1017 * 1 * 8 + 0] = lw_val_1030; - } - - double x_1034; - - x_1034 = *(double*) &mem_374[i_503 * 1 * 8 + 0]; - - double y_1035; - - y_1035 = *(double*) &mem_376[i_503 * 1 * 8 + 0]; - - double lw_val_1036; - - lw_val_1036 = x_1034 / y_1035; - *(double*) &mem_374[i_503 * 1 * 8 + 0] = lw_val_1036; - for (int i_245 = 0; i_245 < numY_13; i_245++) { - *(double*) &mem_370[8 * (numY_13 * i_94) + 8 * i_245] = - *(double*) &mem_374[8 * i_245]; - } - for (int j_1039 = 0; j_1039 < i_503; j_1039++) { - int res_1040; - - res_1040 = n_464 - j_1039; - - double x_1041; - - x_1041 = *(double*) &mem_370[(i_94 * numY_13 + res_1040 * - 1) * 8 + 0]; - - double x_1042; - - x_1042 = *(double*) &mem_355[res_1040 * 1 * 8 + 0]; - - int i_1043; - - i_1043 = res_1040 + 1; - - double y_1044; - - y_1044 = *(double*) &mem_370[(i_94 * numY_13 + i_1043 * 1) * - 8 + 0]; - - double y_1045; - - y_1045 = x_1042 * y_1044; - - double x_1046; - - x_1046 = x_1041 - y_1045; - - double y_1047; - - y_1047 = *(double*) &mem_376[res_1040 * 1 * 8 + 0]; - - double lw_val_1048; - - lw_val_1048 = x_1046 / y_1047; - *(double*) &mem_370[(i_94 * numY_13 + res_1040 * 1) * 8 + - 0] = lw_val_1048; - } - } - for (int i_250 = 0; i_250 < numY_13; i_250++) { - for (int i_251 = 0; i_251 < numX_12; i_251++) { - *(double*) &mem_395[8 * (numX_12 * i_250) + 8 * i_251] = - *(double*) &mem_370[8 * (numY_13 * i_251) + 8 * i_250]; - } - } - memmove(double_buffer_mem_41 + 0, mem_395 + 0, numY_13 * numX_12 * - sizeof(double)); - - unsigned char* myResult_mem_tmp_175; - - myResult_mem_tmp_175 = double_buffer_mem_41; - myResult_mem_246 = myResult_mem_tmp_175; - } - myResult_mem_398 = myResult_mem_246; - - double res_1054; - - res_1054 = *(double*) &myResult_mem_398[(res_116 * numX_12 + res_115 * - 1) * 8 + 0]; - *(double*) &mem_232[i_136 * 1 * 8 + 0] = res_1054; - } - out_mem_77 = mem_232; - out_memsize_78 = bytes_231; - out_arrsize_98 = outer_loop_count_8; - - struct tuple_int_mem_int retval_0; - - retval_0.elem_0 = out_memsize_78; - retval_0.elem_1 = out_mem_77; - retval_0.elem_2 = out_arrsize_98; - return retval_0; -} -int main(int argc, char** argv) -{ - struct timeval t_start, t_end, t_diff; - unsigned long elapsed_usec; - - { - int out_memsize_78; - unsigned char* out_mem_77; - int out_arrsize_98; - int outer_loop_count_8; - int numX_12; - int numY_13; - int numT_14; - double s0_15; - double strike_17; - double t_25; - double alpha_26; - double nu_31; - double beta_32; - struct tuple_int_mem_int main_ret_1; - - if (read_int(&outer_loop_count_8) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&numX_12) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&numY_13) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&numT_14) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_double(&s0_15) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "float64"); - exit(1); - } - if (read_double(&strike_17) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "float64"); - exit(1); - } - if (read_double(&t_25) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "float64"); - exit(1); - } - if (read_double(&alpha_26) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "float64"); - exit(1); - } - if (read_double(&nu_31) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "float64"); - exit(1); - } - if (read_double(&beta_32) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "float64"); - exit(1); - } - gettimeofday(&t_start, NULL); - main_ret_1 = futhark_main(outer_loop_count_8, numX_12, numY_13, numT_14, - s0_15, strike_17, t_25, alpha_26, nu_31, - beta_32); - gettimeofday(&t_end, NULL); - out_memsize_78 = main_ret_1.elem_0; - out_mem_77 = main_ret_1.elem_1; - out_arrsize_98 = main_ret_1.elem_2; - { - if (out_arrsize_98 == 0) { - printf("empty(%s)", "float64"); - } else { - int print_i_2; - - putchar('['); - for (print_i_2 = 0; print_i_2 < out_arrsize_98; print_i_2++) { - double* print_elem_3 = (double*) out_mem_77 + print_i_2 * 1; - - printf("%.6f", *print_elem_3); - if (print_i_2 != out_arrsize_98 - 1) { - printf(", "); - } - } - putchar(']'); - } - } - printf("\n"); - } - ; - if (argc == 3 && strcmp(argv[1], "-t") == 0) { - FILE * runtime_file; - runtime_file = fopen(argv[2], "w"); - if (runtime_file == NULL) { - fprintf(stderr, "Cannot open %s: %s\n", argv[2], strerror(errno)); - exit(1); - } - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed_usec = t_diff.tv_sec * 1e6 + t_diff.tv_usec; - fprintf(runtime_file, "%ld\n", elapsed_usec / 1000); - fclose(runtime_file); - } - return 0; -} diff --git a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut b/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut deleted file mode 100644 index 0b13af1..0000000 --- a/benchmarks/LocVolCalib/implementations/futhark/CalibVolDiff.fut +++ /dev/null @@ -1,265 +0,0 @@ -fun {int,int,[real],[real],[real]} -initGrid(real s0, real alpha, real nu, real t, int numX, int numY, int numT) = - let logAlpha = log(alpha) in - let myTimeline = map(fn real (int i) => t * toFloat(i) / (toFloat(numT) - 1.0), iota(numT)) in - let {stdX, stdY} = {20.0 * alpha * s0 * sqrt(t), - 10.0 * nu * sqrt(t)} in - let {dx, dy} = {stdX / toFloat(numX), stdY / toFloat(numY)} in - let {myXindex, myYindex} = {trunc(s0 / dx), numY / 2} in - let myX = map(fn real (int i) => toFloat(i) * dx - toFloat(myXindex) * dx + s0, iota(numX)) in - let myY = map(fn real (int i) => toFloat(i) * dy - toFloat(myYindex) * dy + logAlpha, iota(numY)) in - {myXindex, myYindex, myX, myY, myTimeline} - --- make the innermost dimension of the result of size 4 instead of 3? -fun {[[real]],[[real]]} initOperator([real] x) = - let n = size(0, x) in - let dxu = x[1] - x[0] in - let dxl = 0.0 in - let Dxlow = [[0.0, -1.0 / dxu, 1.0 / dxu]] in - let Dxxlow = [[0.0, 0.0, 0.0]] in - let Dxmids = map(fn {[real],[real]} (int i) => - let dxl = x[i] - x[i-1] in - let dxu = x[i+1] - x[i] in - { [ -dxu/dxl/(dxl+dxu), (dxu/dxl - dxl/dxu)/(dxl+dxu), dxl/dxu/(dxl+dxu) ], - [ 2.0/dxl/(dxl+dxu), -2.0*(1.0/dxl + 1.0/dxu)/(dxl+dxu), 2.0/dxu/(dxl+dxu) ] } - , map (+ (1), iota(n-2))) in - let {Dxmid, Dxxmid} = unzip(Dxmids) in - let dxl = x[n-1] - x[n-2] in - let dxu = 0.0 in - let Dxhigh = [[-1.0 / dxl, 1.0 / dxl, 0.0 ]] in - let Dxxhigh= [[0.0, 0.0, 0.0 ]] in - let Dx = concat(concat(Dxlow, Dxmid), Dxhigh) in - let Dxx = concat(concat(Dxxlow, Dxxmid), Dxxhigh) - in {Dx, Dxx} - -fun real max(real x, real y) = if y < x then x else y -fun int maxInt(int x, int y) = if y < x then x else y - -fun *[[real]] setPayoff(real strike, [real] myX, [real] myY) = - let n = size(0, myY) in - let myres = map(fn [real] (real xi) => replicate(n, max(xi-strike,0.0)), myX) in - copy(transpose(myres)) - --- Returns new myMuX, myVarX, myMuY, myVarY. -fun {[[real]] , [[real]] , [[real]] , [[real]]} -updateParams( [real] myX, [real] myY, [real] myTimeline, - int g, real alpha, real beta, real nu ) = - let { numX, numY } = { size(0,myX), size(0,myY) } in - let myMuY = replicate(numX, replicate(numY, 0.0 )) in - let myVarY = replicate(numX, replicate(numY, nu*nu)) in - let myMuX = replicate(numY, replicate(numX, 0.0 )) in - let myVarX = map( fn [real] (real yj) => - map ( fn real (real xi) => - exp(2.0*(beta*log(xi) + yj - 0.5*nu*nu*myTimeline[g])) - , myX ) - , myY ) - in { myMuX, myVarX, myMuY, myVarY } - -fun *[real] tridagSeq( [real] a, *[real] b, [real] c, *[real] y ) = - let n = size(0, a) in - loop ({y, b}) = - for i < n-1 do - let i = i + 1 in - let beta = a[i] / b[i-1] in - let b[i] = b[i] - beta*c[i-1] in - let y[i] = y[i] - beta*y[i-1] - in {y, b} - in - let y[n-1] = y[n-1]/b[n-1] in - loop (y) = for j < n - 1 do - let i = n - 2 - j in - let y[i] = (y[i] - c[i]*y[i+1]) / b[i] - in y - in y - -fun *[real] tridagPar( [real] a, *[real] b, [real] c, *[real] y ) = - let n = size(0, a) in - ---------------------------------------------------- - -- Recurrence 1: b[i] = b[i] - a[i]*c[i-1]/b[i-1] -- - -- solved by scan with 2x2 matrix mult operator -- - ---------------------------------------------------- - let b0 = b[0] in - let mats = map ( fn {real,real,real,real} (int i) => - if 0 < i - then {b[i], 0.0-a[i]*c[i-1], 1.0, 0.0} - else {1.0, 0.0, 0.0, 1.0} - , iota(n) ) in - let scmt = scan( fn {real,real,real,real} ( {real,real,real,real} a, - {real,real,real,real} b ) => - let {a0,a1,a2,a3} = a in - let {b0,b1,b2,b3} = b in - let val = 1.0/(a0*b0) in - { (b0*a0 + b1*a2)*val, - (b0*a1 + b1*a3)*val, - (b2*a0 + b3*a2)*val, - (b2*a1 + b3*a3)*val - } - , {1.0, 0.0, 0.0, 1.0}, mats ) in - let b = map ( fn real ({real,real,real,real} tup) => - let {t0,t1,t2,t3} = tup in - (t0*b0 + t1) / (t2*b0 + t3) - , scmt ) in - ------------------------------------------------------ - -- Recurrence 2: y[i] = y[i] - (a[i]/b[i-1])*y[i-1] -- - -- solved by scan with linear func comp operator -- - ------------------------------------------------------ - let y0 = y[0] in - let lfuns= map ( fn {real,real} (int i) => - if 0 < i - then {y[i], 0.0-a[i]/b[i-1]} - else {0.0, 1.0 } - , iota(n) ) in - let cfuns= scan( fn {real,real} ({real,real} a, {real,real} b) => - let {a0,a1} = a in - let {b0,b1} = b in - { b0 + b1*a0, a1*b1 } - , {0.0, 1.0}, lfuns ) in - let y = map ( fn real ({real,real} tup) => - let {a,b} = tup in - a + b*y0 - , cfuns ) in - ------------------------------------------------------ - -- Recurrence 3: backward recurrence solved via -- - -- scan with linear func comp operator -- - ------------------------------------------------------ - let yn = y[n-1]/b[n-1] in - let lfuns= map ( fn {real,real} (int k) => - let i = n-k-1 - in if 0 < k - then {y[i]/b[i], 0.0-c[i]/b[i]} - else {0.0, 1.0 } - , iota(n) ) in - let cfuns= scan( fn {real,real} ({real,real} a, {real,real} b) => - let {a0,a1} = a in - let {b0,b1} = b in - {b0 + b1*a0, a1*b1} - , {0.0, 1.0}, lfuns ) in - let y = map ( fn real ({real,real} tup) => - let {a,b} = tup in - a + b*yn - , cfuns ) in - let y = map (fn real (int i) => y[n-i-1], iota(n)) in - copy(y) - -------------------------------------------/ --- myD,myDD : [[real,3],m] --- myMu,myVar,result : [[real,m],n] --- RETURN : [[real,m],n] -------------------------------------------/ -fun *[[real]] explicitMethod( [[real]] myD, [[real]] myDD, - [[real]] myMu, [[real]] myVar, [[real]] result ) = - -- 0 <= i < m AND 0 <= j < n - let m = size(0,myD) in - copy( map( fn [real] ( {[real],[real],[real]} tup ) => - let {mu_row, var_row, result_row} = tup in - map( fn real ({[real], [real], real, real, int} tup) => - let { dx, dxx, mu, var, j } = tup in - let c1 = if 0 < j - then ( mu*dx[0] + 0.5*var*dxx[0] ) * result_row[j-1] - else 0.0 in - let c3 = if j < (m-1) - then ( mu*dx[2] + 0.5*var*dxx[2] ) * result_row[j+1] - else 0.0 in - let c2 = ( mu*dx[1] + 0.5*var*dxx[1] ) * result_row[j ] - in c1 + c2 + c3 - , zip( myD, myDD, mu_row, var_row, iota(m) ) - ) - , zip( myMu, myVar, result ) - ) - ) - -------------------------------------------/ --- myD,myDD : [[real,3],m] --- myMu,myVar,u : [[real,m],n] --- RETURN : [[real,m],n] -------------------------------------------/ --- for implicitY: should be called with transpose(u) instead of u -fun *[[real]] implicitMethod( [[real]] myD, [[real]] myDD, - [[real]] myMu, [[real]] myVar, - *[[real]] u, real dtInv ) = - map( fn *[real] ( {[real],[real],*[real]} tup ) => - let {mu_row,var_row,u_row} = tup in - let abc = map( fn {real,real,real} ({real,real,[real],[real]} tup) => - let {mu, var, d, dd} = tup in - { 0.0 - 0.5*(mu*d[0] + 0.5*var*dd[0]) - , dtInv - 0.5*(mu*d[1] + 0.5*var*dd[1]) - , 0.0 - 0.5*(mu*d[2] + 0.5*var*dd[2]) - } - , zip(mu_row, var_row, myD, myDD) - ) in - let {a,b,c} = unzip(abc) in - if 1==1 then tridagSeq( a, copy(b), c, u_row ) - else tridagPar( a, copy(b), c, u_row ) - , zip(myMu,myVar,u) - ) - -fun *[[real]] rollback - ([real] myX, [real] myY, [real] myTimeline, *[[real]] myResult, - [[real]] myMuX, [[real]] myDx, [[real]] myDxx, [[real]] myVarX, - [[real]] myMuY, [[real]] myDy, [[real]] myDyy, [[real]] myVarY, int g) = - - let {numX, numY} = {size(0, myX), size(0, myY)} in - let dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]) in - - -- explicitX - let u = explicitMethod( myDx, myDxx, myMuX, myVarX, myResult ) in - let u = map( fn [real] ({[real],[real]} tup) => - let {u_row, res_row} = tup in - map (fn real ({real,real} tup) => - let {u_el,res_el} = tup - in dtInv*res_el + 0.5*u_el - , zip(u_row,res_row) ) - , zip(u,myResult) ) - in - -- explicitY - let myResultTR = transpose(myResult) in - let v = explicitMethod( myDy, myDyy, myMuY, myVarY, myResultTR ) in - let u = map( fn *[real] ([real] us, [real] vs) => - copy(map(+, zip(us, vs))) - , zip(u, transpose(v)) - ) in - -- implicitX - let u = implicitMethod( myDx, myDxx, myMuX, myVarX, u, dtInv ) in - -- implicitY - let y = copy( map( fn [real] ({[real],[real]} uv_row) => - let {u_row, v_row} = uv_row in - map( fn real ({real,real} uv) => - let {u_el,v_el} = uv - in dtInv*u_el - 0.5*v_el - , zip(u_row,v_row) - ) - , zip(transpose(u),v) - ) ) - in - let myResultTR = implicitMethod( myDy, myDyy, myMuY, myVarY, y, dtInv ) - in transpose(myResultTR) - -fun real value(int numX, int numY, int numT, real s0, real strike, real t, real alpha, real nu, real beta) = - let {myXindex, myYindex, myX, myY, myTimeline} = - initGrid(s0, alpha, nu, t, numX, numY, numT) in - let {myDx, myDxx} = initOperator(myX) in - let {myDy, myDyy} = initOperator(myY) in - let myResult = setPayoff(strike, myX, myY) in - - loop (myResult) = - for i < numT - 1 do - let i = numT-2-i in - let {myMuX, myVarX, myMuY, myVarY} = - updateParams(myX, myY, myTimeline, i, alpha, beta, nu) in - let myResult = rollback(myX, myY, myTimeline, myResult, - myMuX, myDx, myDxx, myVarX, - myMuY, myDy, myDyy, myVarY, i) in - - myResult in - myResult[myYindex,myXindex] - -fun [real] main (int outer_loop_count, int numX, int numY, int numT) = - let s0 = 0.03 in - let strike = 0.03 in - let t = 5.0 in - let alpha = 0.2 in - let nu = 0.6 in - let beta = 0.5 in - let strikes = map(fn real (int i) => 0.001*toFloat(i), iota(outer_loop_count)) in - let res = map(fn real (real x) => value(numX, numY, numT, s0, x, t, alpha, nu, beta), strikes) in - res diff --git a/benchmarks/LocVolCalib/implementations/futhark/instantiate b/benchmarks/LocVolCalib/implementations/futhark/instantiate deleted file mode 100755 index 75cbad8..0000000 --- a/benchmarks/LocVolCalib/implementations/futhark/instantiate +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -set -e - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data - -cp $FINPAR_IMPLEMENTATION/run . - -futhark-c $FINPAR_IMPLEMENTATION/CalibVolDiff.fut -o CalibVolDiff diff --git a/benchmarks/LocVolCalib/implementations/futhark/run b/benchmarks/LocVolCalib/implementations/futhark/run deleted file mode 100755 index 66c288c..0000000 --- a/benchmarks/LocVolCalib/implementations/futhark/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -./CalibVolDiff -t runtime.txt < input.data > result.json diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs b/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs deleted file mode 100644 index 5e99209..0000000 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs +++ /dev/null @@ -1,441 +0,0 @@ -module Main where - -import Control.DeepSeq -import Control.Applicative -import Control.Monad -import Data.Maybe -import System.CPUTime - ------------------------------------- ---- Requires the installation of --- ---- Parsec package, i.e., --- ---- cabal install parsec --- ------------------------------------- - -import Text.Parsec hiding (optional, (<|>), token) -import Text.Parsec.String - -import Data.Bits -import Data.List -import Prelude - ------------------------------- ---- Parser-related Helpers --- ------------------------------- -signed :: Parser String -> Parser String -signed p = (char '-' >> (('-':) <$> p)) <|> p - -whitespace :: Parser () -whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) - -lexeme :: Parser a -> Parser a -lexeme p = p <* whitespace - -token :: String -> Parser () -token = void . lexeme . string - -readInt :: Parser Int -readInt = lexeme $ read <$> signed (many1 digit) - -readDouble :: Parser Double -readDouble = lexeme $ read <$> signed (s2 <|> s1) - where s1 = do bef <- many1 digit - aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) - return $ bef ++ aft - s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit - -readArray :: Parser a -> Parser [a] -readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") - ---------------------------------------------- ---- Definition of lish-homomorphic reduce --- ---- requires a binary associative op --- ---------------------------------------------- - -reduce :: (a -> a -> a) -> a -> [a] -> a -reduce bop ne lst = foldl bop ne lst - ---------------------------------------------- ---------------------------------------------- - -initGrid :: Double -> Double -> Double -> Double - -> Int -> Int -> Int - -> ( Int, Int, [Double], [Double], [Double], - [[Double]], [[Double]], [[Double]], [[Double]] ) -initGrid s0 alpha nu t num_x num_y num_t = - let logAlpha = log alpha - myTimeline = map (\i -> t * (fromIntegral i) / ((fromIntegral num_t) - 1.0)) [0..num_t-1] - stdX = 20.0 * alpha * s0 * (sqrt t) - stdY = 10.0 * nu * (sqrt t) - (dx, dy) = (stdX / fromIntegral num_x, stdY / fromIntegral num_y) - (myXindex, myYindex) = (truncate (s0 / dx), num_y `div` 2) - myX = map (\i -> (fromIntegral i) * dx - (fromIntegral myXindex) * dx + s0 ) [0..num_x-1] - myY = map (\i -> (fromIntegral i) * dy - (fromIntegral myYindex) * dy + logAlpha) [0..num_y-1] - xXy = replicate num_x (replicate num_y 0.0) - (myMuX, myVarX, myMuY, myVarY) = (xXy, xXy, xXy, xXy) - in (myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY) - ---------------------------------------------- ---------------------------------------------- - ---------------------------------------------- ---------------------------------------------- - -initOperator :: [Double] - -> ( [(Double,Double,Double)], [(Double,Double,Double)] ) -initOperator x = - let n = length x - mid_x = zip3 x (tail x) (tail (tail x)) - - dxu = (x !! 1) - (x !! 0) - dxl = 0.0 - dxlow = (0.0, -1.0 / dxu, 1.0 / dxu) - dxxlow = (0.0, 0.0, 0.0) - - --- Implements a parallel loop such as: --- - --- doall i = 2, N-1, 1 --- - --- (a,b,c) = f(x[i-1], x[i], x[i+1]) --- - --- res[i-1] = (a,b,c) --- - dxmid = map (\(xim1, xi, xip1) -> - let (dxl, dxu) = (xi - xim1, xip1 - xi) - dxlpxu = dxl + dxu - in ( (-dxu/dxl ) / dxlpxu, - ( dxu/dxl - dxl/dxu) / dxlpxu, - ( dxl/dxu ) / dxlpxu - ) - ) mid_x - dxxmid = map (\(xim1, xi, xip1) -> - let (dxl, dxu) = (xi - xim1, xip1 - xi) - dxlpxu = dxl + dxu - in ( ( 2.0/dxl ) / dxlpxu, - -2.0*(1.0/dxl+1.0/dxu) / dxlpxu, - ( 2.0/dxu ) / dxlpxu - ) - ) mid_x - dxll = (x !! (n-1)) - (x !! (n-2)) - dxul = 0.0 - dxhigh = [(-1.0 / dxll, 1.0 / dxll, 0.0)] - dxxhigh= [(0.0, 0.0, 0.0)] - in ( dxlow : (dxmid++dxhigh), dxxlow : (dxxmid++dxxhigh) ) - ------------------------------------------------ ---- A tail-recursive function modeling a --- ---- do loop that goes from i = 0 to bound-1 --- ------------------------------------------------ - -doLoop :: Int -> Int - -> ( [Double], [(Double,Double,Double)], [(Double,Double,Double)], - [Double], [(Double,Double,Double)], [(Double,Double,Double)], - [Double], Double, Double, Double ) - -> ([[Double]], [[Double]], [[Double]], [[Double]], [[Double]]) - -> ([[Double]], [[Double]], [[Double]], [[Double]], [[Double]]) -doLoop i bound loop_ros loop_variants = - if i == bound - then loop_variants - else let (myResult, myMuX, myVarX, myMuY, myVarY) = loop_variants - - ( myX, myDx, myDxx, myY, myDy, myDyy, - myTimeline, alpha, beta, nu ) = loop_ros - - j = (bound-1-i) - - (myMuX', myVarX', myMuY', myVarY') = - updateParams myX myY myTimeline j alpha beta nu - - - - myResult'= rollback j myX myY myTimeline myResult - myMuX' myDx myDxx myVarX' - myMuY' myDy myDyy myVarY' - - loop_variants' = (myResult', myMuX', myVarX', myMuY', myVarY') - - in -- Hack to avoid space leak - myResult' `deepseq` myMuX' `deepseq` myVarX' `deepseq` myMuY' `deepseq` myVarY' `deepseq` - doLoop (i+1) bound loop_ros loop_variants' - ---------------------------------------------- ---------------------------------------------- - -updateParams :: [Double] -> [Double] -> [Double] -> Int -> Double -> Double -> Double - -> ( [[Double]], [[Double]], [[Double]], [[Double]] ) -updateParams myX myY myTimeline g alpha beta nu = - unzip4 $ map (\ xi -> unzip4 $ - map (\ yj -> let b = beta * log(xi) + yj - c = 0.5 * nu * nu * (myTimeline !! g) - in ( 0.0, exp (2.0 * (b - c) ), 0.0, nu * nu ) - ) myY - ) myX ---------------------------------------------- ---- Helpers for the rollback function --- ---- ToDo: make them nice!!! --- ---------------------------------------------- - --- explicitX = explicitXY dt_inv 0.5 (transpose my_result) (transpose myMuX) (transpose myVarX) myDx myDxx --- explicitY = explicitXY 0.0 1.0 my_result myMuY myVarY myDy myDyy -explicitXY :: Double -> Double - -> [[Double]] -> [[Double]] -> [[Double]] - -> [ (Double,Double,Double) ] - -> [ (Double,Double,Double) ] - -> [[Double]] -explicitXY dt_inv fact my_result myMuY myVarY myDy myDyy = - map (\ tup_i -> - let (res_row, myMuY_row, myVarY_row) = tup_i - res_row3 = zip3 (0.0:res_row) res_row ((tail res_row) ++ [0.0]) - - in map (\ ((myDy_i, myDyy_i, myMuY_ij, myVarY_ij),(r_jm1, r_j, r_jp1)) -> - let ((dy0, dy1, dy2), (dyy0, dyy1, dyy2)) = (myDy_i, myDyy_i) - res0 = dt_inv * r_j - res1 = fact * (myMuY_ij*dy0 + 0.5*myVarY_ij*dyy0) * r_jm1 - res2 = fact * (myMuY_ij*dy2 + 0.5*myVarY_ij*dyy2) * r_jp1 - res3 = fact * (myMuY_ij*dy1 + 0.5*myVarY_ij*dyy1) * r_j - in res0 + res1 + res2 + res3 - - ) (zip (zip4 myDy myDyy myMuY_row myVarY_row) res_row3) - - ) (zip3 my_result myMuY myVarY) - ------------------------------------------- ---- loop-like definition for explicitX --- ---- inneficient due to list traversal --- ---- to find every index. --- ---- Same is possible for explicitY0 --- ------------------------------------------- -explicitX0 :: Int -> Int -> Double -> [[Double]] -> [[Double]] - -> [ (Double,Double,Double) ] -> [ (Double,Double,Double) ] -> [[Double]] - -> [[Double]] -explicitX0 num_x num_y dt_inv my_result - myMuX myDx myDxx myVarX = - map (\ j -> - map (\ i -> let res0 = dt_inv * ((my_result !! i) !! j) -- my_result[i,j] - ((dx0, dx1, dx2), (dxx0, dxx1, dxx2)) = (myDx !! i, myDxx !! i) - - myMuX_ij = ( myMuX !! i) !! j -- myMuX[i,j] - myVarX_ij = (myVarX !! i) !! j -- myVarX[i,j] - - res1 = if i == 0 then 0.0 - else 0.5 * (myMuX_ij*dx0 + 0.5*myVarX_ij*dxx0) * - ((my_result !! (i-1)) !! j) -- my_result[i-1, j] - res2 = if i == num_x - 1 then 0.0 - else 0.5 * (myMuX_ij*dx2 + 0.5*myVarX_ij*dxx2) * - ((my_result !! (i+1)) !! j) -- my_result[i+1,j] - - res3 = 0.5 * (myMuX_ij*dx1 + 0.5*myVarX_ij*dxx1) * - ((my_result !! i) !! j) -- my_result[i ,j] - - in res0 + res1 + res2 + res3 - - - ) [0..num_x-1] - - ) [0..num_y-1] - -tridag :: [Double] -> [Double] -> [Double] -> [Double] - -> ( [Double], [Double] ) -tridag a b c r = - let u0 = head r - uu0 = head b - - -- scanl's binary operator is NOT associative - uu = scanl (\ uuim1 (ai, bi, cim1) -> - let beta = ai / uuim1 - in bi - beta*cim1 - ) uu0 (zip3 (tail a) (tail b) c) - - -- scanl's binary operator is NOT associative - u = scanl (\ uim1 (ai, ri, uuim1) -> - let beta = ai / uuim1 - in ri - beta*uim1 - ) u0 (zip3 (tail a) (tail r) uu) - - ur = reverse u - uur = reverse uu - ur0'= (head ur) / (head uur) - ur' = scanl (\ uip1 (uri, uuri, cri) -> - (uri - cri*uip1) / uuri - ) ur0' (zip3 (tail ur) (tail uur) (tail $ reverse c)) - in (reverse ur', uu) - - -tridagPar :: [Double] -> [Double] -> [Double] -> [Double] - -> ( [Double], [Double] ) -tridagPar a b c r = - let -- u0 = head r - -- uu0 = head b - u0 = head b - uu0 = head r - - -- creating the 2x2 matrices - mats = map (\(ai,bi,cim1)-> (bi, -ai*cim1, 1.0, 0.0)) (zip3 (tail a) (tail b) c) - -- scan with 2x2 matrix multiplication - scanmat = scanl (\(x1,y1,z1,w1) (x2,y2,z2,w2) -> - let dv = 1.0/(x1*x2) - in ( (x1*x2+y1*z2)*dv, - (x1*y2+y1*w2)*dv, - (z1*x2+w1*z2)*dv, - (z1*y2+w1*w2)*dv ) - ) (1.0, 0.0, 0.0, 1.0) mats - - -- compute the first recurrence result - uu = map (\(x,y,z,w) -> (x*u0 + y) / (z*u0 + w) ) scanmat - - -- compute the second recurrence - pairs = map (\(ai,ri,uuim1)->(ri, -ai/uuim1)) (zip3 (tail a) (tail r) uu) - - scanpairs = scanl (\ (x1,y1) (x2,y2) -> (x2+y2*x1, y1*y2) ) (0.0,1.0) pairs - - u = map (\(x,y) -> x + u0*y) scanpairs - - -- backwards recurrence - ur = reverse u - uur = reverse uu - ur0'= (head ur) / (head uur) - - pairsr = map (\(uri, uuri, cri)->(uri/uuri, -cri/uuri)) (zip3 (tail ur) (tail uur) (tail $ reverse c)) - scanpairsr = scanl (\ (x1,y1) (x2,y2) -> (x2+y2*x1, y1*y2) ) (0.0,1.0) pairsr - ur' = map (\(x,y) -> x + ur0'*y) scanpairsr - - in (reverse ur', uu) - ---------------------------------------------- ---- rollback: the brain of the program --- ---------------------------------------------- - -rollback :: Int -> [Double] -> [Double] -> [Double] -> [[Double]] - -> [[Double]] -> [(Double,Double,Double)] -> [(Double,Double,Double)] -> [[Double]] - -> [[Double]] -> [(Double,Double,Double)] -> [(Double,Double,Double)] -> [[Double]] - -> [[Double]] - -rollback g myX myY myTimeline myResult - myMuX myDx myDxx myVarX - myMuY myDy myDyy myVarY = - - let (numX, numY) = (length myX, length myY) - numZ = max numX numY - dtInv = 1.0 / ( (myTimeline !! (g+1)) - (myTimeline !! g) ) - - u0= explicitXY dtInv 0.5 (transpose myResult) (transpose myMuX) (transpose myVarX) myDx myDxx - v0= explicitXY 0.0 1.0 myResult myMuY myVarY myDy myDyy - - u1= map (\ (us, vs) -> zipWith (+) us vs ) - (zip u0 (transpose v0)) - - u2= map (\ t -> let (uj, myDx, myDxx, myMuX, myVarX) = t - (a,b,c) = unzip3 $ - map (\ tt -> let (myDx, myDxx, myMuX, myVarX) = tt - (dx0, dx1, dx2 ) = myDx - (dxx0, dxx1, dxx2) = myDxx - in ( -0.5*(myMuX*dx0 + 0.5*myVarX*dxx0), - dtInv - 0.5*(myMuX*dx1 + 0.5*myVarX*dxx1), - -0.5*(myMuX*dx2+0.5*myVarX*dxx2) ) ) - (zip4 myDx myDxx myMuX myVarX) - - (uj', yy) = tridag a b c uj -- tridagPar a b c uj - in uj' ) - (zip5 u1 (replicate numY myDx) (replicate numY myDxx) (transpose myMuX) (transpose myVarX)) - - in map (\ t -> let (ui, vi, myDy, myDyy, myMuY, myVarY) = t - (a,b,c) = unzip3 $ - map (\ tt -> let (myDy, myDyy, myMuY, myVarY) = tt - (dy0, dy1, dy2 ) = myDy - (dyy0, dyy1, dyy2) = myDyy - in ( -0.5*(myMuY*dy0+0.5*myVarY*dyy0), - dtInv - 0.5*(myMuY*dy1+0.5*myVarY*dyy1), - -0.5*(myMuY*dy2+0.5*myVarY*dyy2) ) ) - (zip4 myDy myDyy myMuY myVarY) - - y = map (\ (u,v) -> dtInv * u - 0.5 * v) (zip ui vi) - - (ri, yy) = tridag a b c y -- tridagPar a b c y - in ri ) - (zip6 (transpose u2) v0 (replicate numX myDy) (replicate numX myDyy) myMuY myVarY) - ---------------------------------------------- ---------------------------------------------- - -------------------------------------------------- ---- Cosmin ToDo: make MyX & MyY & myTimeline --- ---- vectors instead of lists --- -------------------------------------------------- - -value :: (Double, Double, Double, Double, Double) - -> (Int, Int, Int, Int) -> Double - -> Double -value params it_spaces strike = - let (outer, num_x, num_y, num_t) = it_spaces - (s0, t, alpha, nu, beta) = params - - (myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY) = - initGrid s0 alpha nu t num_x num_y num_t - (myDx, myDxx) = initOperator myX - (myDy, myDyy) = initOperator myY - - my_result_ini = map (\ xi -> replicate num_y (max (xi - strike) 0.0 )) myX - - loop_variants = (my_result_ini, myMuX, myVarX, myMuY, myVarY) - loop_ros = (myX, myDx, myDxx, myY, myDy, myDyy, myTimeline, alpha, beta, nu) - - (my_result,_,_,_,_) = doLoop 0 (num_t-1) loop_ros loop_variants - - in (my_result !! myXindex) !! myYindex -- my_result[myXindex, myYindex] - ------------------------------------------------- ---- Main Entry Point: volatility calibration --- ------------------------------------------------- -compute :: (Int, Int, Int, Int) - -> (Double, Double, Double, Double, Double) - -> [Double] -compute it_spaces params = - let (s0, t, alpha, nu, beta) = params - (outer, num_x, num_y, num_t) = it_spaces - strikes = map (\i -> 0.001 * (fromIntegral i)) [0..outer-1] - res = map (value params it_spaces) strikes - in res - ----------------------------------------------- ---- Formatting the Output of the Benchmark --- ----------------------------------------------- -validate :: [Double] -> [Double] -> (Int,Int,Int,Int) -> [String] -validate res_ref res info= - let errs = map abs $ zipWith (-) res_ref res - err = reduce max 0.0 errs - (outer, num_x, num_y, num_t) = info - in ["// Generic Pricing Haskell Benchmark (List-Homomorphism Style):", - "// OUTER: " ++ show outer ++ ", NUM_X: " ++ show num_x ++ - ", NUM_Y: " ++ show num_y ++ ", NUM_T: " ++ show num_t, - ( if err <= 0.00001 -- 0.0005 - then "1\t\t// VALID Result," - else "0\t\t// INVALID Result," ), - "0\t\t// Runtime in microseconds,", - "1\t\t// CPU Threads,", - show res ++ "\t// Volatility Calibration Result."] - - ------------------------------------------ ---- Entry point for Generic Pricing --- ---- The only place where using Monads,--- ---- e.g., parsing Dataset from StdIn --- ------------------------------------------ -main :: IO () -main = do s <- getContents - case parse run "input" s of - Left e -> error $ show e - Right m -> do (v,runtime) <- m - writeFile "result.json" $ show v - writeFile "runtime.txt" $ show runtime - where run = do whitespace - outer <- readInt - num_x <- readInt - num_y <- readInt - num_t <- readInt - - let params = (0.03, 5.0, 0.2, 0.6, 0.5) --(s0, t, alpha, nu, beta) - - return $ do - start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. - let v = compute (outer, num_x, num_y, num_t) params - end <- v `deepseq` getCPUTime - return (v, (end - start) `div` 1000000000) - --- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs --- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/instantiate b/benchmarks/LocVolCalib/implementations/haskell_lh/instantiate deleted file mode 100755 index 4d2f324..0000000 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/instantiate +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -set -e # Die on error. - -impl_dir=$FINPAR_IMPLEMENTATION -input=$FINPAR_INPUT - -cp $impl_dir/*hs . -cp $impl_dir/run . -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data -ghc -Wall -O2 -msse2 -rtsopts VolCalib.hs -o VolCalib diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/run b/benchmarks/LocVolCalib/implementations/haskell_lh/run deleted file mode 100755 index baa6480..0000000 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -./VolCalib +RTS -K128m -RTS < input.data diff --git a/benchmarks/LocVolCalib/lib/include/Constants.h b/benchmarks/LocVolCalib/lib/include/Constants.h deleted file mode 100644 index 8fd8365..0000000 --- a/benchmarks/LocVolCalib/lib/include/Constants.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -#define WITH_FLOATS 1 - -#define REAL3_CT 4 -#define TRANSPOSE_UV 1 - -#if (WITH_FLOATS) - typedef float REAL; - typedef unsigned int ULONG; -#else - #pragma OPENCL EXTENSION cl_khr_fp64: enable - typedef double REAL; - typedef unsigned long ULONG; -#endif - -#define WARP (1< -#include - -#include -#include -#include -#include - -#include - -using namespace std; - -/////////////////////////////////////////////////////// -//// FLAGS and CONSTANT SCALARS! -/////////////////////////////////////////////////////// - -#define TRIDAG_ALL_OPT_ON -#define MOST_OPTIMISED_ON - -//#define IS_GPU -//#define DEBUG_PRINT_GPU_INFO - -unsigned int OUTER_LOOP_COUNT; //128; //1024; //100; -unsigned int NUM_X ; //256; //256; //64; //256; -unsigned int NUM_Y ; //32; //32; //32; -unsigned int NUM_T ; //64; //64; //64; -unsigned int NUM_XY ; //NUM_X*NUM_Y; - -/////////////////////////////////////////////////////// -//// GLOBAL ARRAYS ! -/////////////////////////////////////////////////////// - -/// grid /// -REAL* myX ; // 1-dim, size: NUM_X -REAL* myY ; // 1-dim, size: NUM_Y -REAL* myTimeline; // 1-dim, size: NUM_T - -unsigned int myXindex, myYindex; - -/// variable /// -REAL* myResArr; //[OUTER_LOOP_COUNT * NUM_Y * NUM_X]; // 3-dim, size: OUTER_LOOP_COUNT x NUM_Y x NUM_X - - -/// coeffs /// -REAL *myMuX, *myVarX; // 2-dim, size: NUM_X x NUM_Y -REAL *myMuY, *myVarY; // 2-dim, size: NUM_X x NUM_Y - -// operators -REAL *myDx, *myDxx; // 2-dim, size: NUM_X x REAL3_CT -REAL *myDy, *myDyy; // 2-dim, size: NUM_Y x REAL3_CT - -void allocGlobArrs() { - myX = new REAL[NUM_X]; - myY = new REAL[NUM_Y]; - myTimeline = new REAL[NUM_T]; - - myMuX = new REAL[NUM_X * NUM_Y]; - myVarX= new REAL[NUM_X * NUM_Y]; - myMuY = new REAL[NUM_X * NUM_Y]; - myVarY= new REAL[NUM_X * NUM_Y]; - - myDx = new REAL[NUM_X * REAL3_CT]; - myDxx = new REAL[NUM_X * REAL3_CT]; - myDy = new REAL[NUM_Y * REAL3_CT]; - myDyy = new REAL[NUM_Y * REAL3_CT]; - - myResArr = new REAL[OUTER_LOOP_COUNT * NUM_Y * NUM_X]; -} - -void deallocGlobArrs() { - delete[] myX; - delete[] myY; - delete[] myTimeline; - - delete[] myMuX; - delete[] myVarX; - delete[] myMuY; - delete[] myVarY; - - delete[] myDx; - delete[] myDxx; - delete[] myDy; - delete[] myDyy; - - delete[] myResArr; -} - -#endif // end include NORDEA_DATA_STRUCT diff --git a/benchmarks/LocVolCalib/lib/include/ParPrefixUtil.h b/benchmarks/LocVolCalib/lib/include/ParPrefixUtil.h deleted file mode 100644 index 3c8fa9f..0000000 --- a/benchmarks/LocVolCalib/lib/include/ParPrefixUtil.h +++ /dev/null @@ -1,323 +0,0 @@ -#ifndef PAR_PREFIX_UTIL -#define PAR_PREFIX_UTIL - -#include -#include - -// TIMING - -typedef struct timeb mlfi_timeb; -#define mlfi_ftime ftime - -#define mlfi_diff_time(t1,t2) \ - (t1.time - t2.time) * 1000 + (t1.millitm - t2.millitm) - -////////////////////////////////////////// -/// CLASSIC, SEQUENTIAL TRIDAG -////////////////////////////////////////// -void tridag( - REAL* a, - REAL* b, - REAL* c, - REAL* d, - int n, - REAL* y, - REAL* u) -{ - int i; - double beta; - - y[0] = d[0]; - u[0] = b[0]; - - for(i=1; i=0; i--) { - y[i] = (y[i] - c[i]*y[i+1]) / u[i]; - } -} - -///////////////////////////////////////////////////////////// - -/** - * Multiplies 2x2 matrixes `a' and `b' and - * stores the result in(-place in) `a'. - */ -void matmult2(REAL* a, REAL* b) { - REAL a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - val = 1.0/(a0*b[0]); - //val = 1.0/(a0*b[0]+a1*b[2]); - a[0] = (a0*b[0] + a1*b[2])*val; - a[1] = (a0*b[1] + a1*b[3])*val; - a[2] = (a2*b[0] + a3*b[2])*val; - a[3] = (a2*b[1] + a3*b[3])*val; -} - - -void scan_matmult_2by2(REAL* tmp, int N) { - REAL* prev = NULL; - - for(int i=1; i=0; i--, k+=2) { // NEW k=2 - tmp[k] = y[i]/u[i]; - tmp[k+1] = 0.0 - c[i]/u[i]; - } - - // backward scan with linear function composition on tmp - scan_linfuncomp(tmp, n); // NEW: n - - // map the result back: - for(i=n-2,k=2; i>=0; i--, k+=2) { // NEW k=2 - y[i] = map_linfuncomp(tmp+k, y[n-1]); - } - } -} - -void test_matmult(){ - int N = 16; - REAL* arr = new REAL[N*4]; - REAL* tmp = arr; - for(int i=0; i=0; i--, k+=2) { - tmp[k] = y[i]/u[i]; - tmp[k+1] = 0.0 - c[i]/u[i]; - } - - // forward scan with linear function composition on tmp - scan_linfuncomp(tmp, n-1); - - // map the result back: - for(i=n-2,k=0; i>=0; i--, k+=2) { - y[i] = map_linfuncomp(tmp+k, y[n-1]); - } - } -} - -inline void tridag_seq_32( - REAL* a, - REAL* b, - REAL* c, - REAL* d, - int n, - REAL* y, - REAL* u) -{ - int i, UB, offset; - REAL beta; - - y[0] = d[0]; - u[0] = b[0]; - - UB = n << 5; - for(i=32; i=0; i-=32) { - y[i] = (y[i] - c[i]*y[i+32]) / u[i]; - } -} - -inline void tridag_seq_1( - REAL* a, - REAL* b, - REAL* c, - REAL* d, - int n, - REAL* y, - REAL* u) -{ - int i, UB, offset; - REAL beta; - - y[0] = d[0]; - u[0] = b[0]; - - UB = n << 5; - for(i=1; i=0; i--) { - y[i] = (y[i] - c[i]*y[i+1]) / u[i]; - } -} - -#endif // end include PAR_PREFIX_UTIL - diff --git a/benchmarks/LocVolCalib/lib/include/ParseInput.h b/benchmarks/LocVolCalib/lib/include/ParseInput.h deleted file mode 100644 index 8453724..0000000 --- a/benchmarks/LocVolCalib/lib/include/ParseInput.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef PARSE_INPUT -#define PARSE_INPUT - -#include "ParserC.h" -#include "Util.h" -#include -#include -#include - -using namespace std; - -#include - -#if WITH_FLOATS - #define read_real read_float -#else - #define read_real read_double -#endif - -const float EPS = 0.00001; - -/***********************************/ -/********** READ DATA SET **********/ -/***********************************/ - -void readDataSet( unsigned int& outer, - unsigned int& num_X, - unsigned int& num_Y, - unsigned int& num_T -) { - if( read_int( static_cast( &outer ) ) || - read_int( static_cast( &num_X ) ) || - read_int( static_cast( &num_Y ) ) || - read_int( static_cast( &num_T ) ) ) { - - fprintf(stderr, "Syntax error when reading the dataset, i.e., four ints.\n"); - exit(1); - } - - { // check dataset invariants: - bool atr_ok = true; - - atr_ok = outer > 0; - assert(atr_ok && "Outer loop count less than 0!"); - - atr_ok = (num_X > 0) && (num_X <= WORKGROUP_SIZE) && is_pow2(num_X); - assert(atr_ok && "Illegal NUM_X value!"); - - atr_ok = (num_Y > 0) && (num_Y <= WORKGROUP_SIZE) && is_pow2(num_Y); - assert(atr_ok && "Illegal NUM_X value!"); - - atr_ok = num_T > 0; - assert(atr_ok && "NUM_T value less or equal to zero!!"); - } -} - -#endif // PARSE_INPUT - diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate index b6df103..aae6162 100755 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate @@ -2,17 +2,17 @@ set -e -cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/include/ParserC.h . -cp $FINPAR_LIB_DIR/include/Util.h . -cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . -cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . -cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile . +cp $HIPERMARK_LIB_DIR/setup.mk . +cp $HIPERMARK_LIB_DIR/include/ParserC.h . +cp $HIPERMARK_LIB_DIR/include/Util.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/Constants.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/Optimizations.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/ParseInput.h . +cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data +$HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk +NCORES=$($HIPERMARK_LIB_DIR/json_get.py $HIPERMARK_PLATFORM num_cores) cat > run < Date: Thu, 30 Jul 2015 16:50:22 +0200 Subject: [PATCH 033/122] This repository works as Thor's testing ground for hipermark. Works with current hipermark program. --- .gitignore | 3 + benchmarks/CalibVolDiff/README.txt | 53 +++ benchmarks/CalibVolDiff/ToDo.txt | 28 ++ .../CalibVolDiff/datasets/medium/input.json | 6 + .../CalibVolDiff/datasets/medium/output.json | 17 + .../CalibVolDiff/datasets/small/input.json | 6 + .../CalibVolDiff/datasets/small/output.json | 3 + .../implementations/cpp_sequential/Makefile | 36 ++ .../cpp_sequential/VolCalibOrig.cpp | 318 +++++++++++++++++ .../cpp_sequential/instantiate | 15 + .../cpp_sequential/instantiate_data | 7 + .../implementations/cpp_sequential/run | 3 + .../CalibVolDiff/lib/include/Constants.h | 42 +++ .../lib/include/DataStructConst.h | 91 +++++ .../CalibVolDiff/lib/include/ParPrefixUtil.h | 323 ++++++++++++++++++ .../CalibVolDiff/lib/include/ParseInput.h | 58 ++++ .../cpp_openmp/instantiate_data | 18 + .../lib/{ => include}/Constants.h | 0 .../lib/{ => include}/Optimizations.h | 0 .../lib/{ => include}/ParseInput.h | 0 .../lib/{ => include}/TimeHelper.h | 0 21 files changed, 1027 insertions(+) create mode 100644 benchmarks/CalibVolDiff/README.txt create mode 100644 benchmarks/CalibVolDiff/ToDo.txt create mode 100644 benchmarks/CalibVolDiff/datasets/medium/input.json create mode 100644 benchmarks/CalibVolDiff/datasets/medium/output.json create mode 100644 benchmarks/CalibVolDiff/datasets/small/input.json create mode 100644 benchmarks/CalibVolDiff/datasets/small/output.json create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_sequential/run create mode 100644 benchmarks/CalibVolDiff/lib/include/Constants.h create mode 100644 benchmarks/CalibVolDiff/lib/include/DataStructConst.h create mode 100644 benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h create mode 100644 benchmarks/CalibVolDiff/lib/include/ParseInput.h create mode 100755 benchmarks/OptionPricing/implementations/cpp_openmp/instantiate_data rename benchmarks/OptionPricing/lib/{ => include}/Constants.h (100%) rename benchmarks/OptionPricing/lib/{ => include}/Optimizations.h (100%) rename benchmarks/OptionPricing/lib/{ => include}/ParseInput.h (100%) rename benchmarks/OptionPricing/lib/{ => include}/TimeHelper.h (100%) diff --git a/.gitignore b/.gitignore index d245830..7c68cb7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ GenericPricing/HaskellLH/GenPricing GenericPricing/Orig_COpenMp/GenPricing CalibVolDiff/Original/CalibVol +# all instantiations +instantiations/* + # emacs backups *~ diff --git a/benchmarks/CalibVolDiff/README.txt b/benchmarks/CalibVolDiff/README.txt new file mode 100644 index 0000000..848f0be --- /dev/null +++ b/benchmarks/CalibVolDiff/README.txt @@ -0,0 +1,53 @@ +FIXME: this README is outdated. + +1. This is a benchmark received from Nordea, via Prof. Brian Vinter. + Here is Christian's (Andreetta) guess about what the application is about: + " The task is stochastic volatility calibration, i.e., given a set of + (observed) prices of contracts, we identify the parameters of a model + of such prices, as a function of volatility (unknown), time and strikes (known), + and unobserved parameters like alpha, beta, nu, etc. + + In this case, the volatility is modelled as a system of continuous + partial differential equations, which are solved via Crank-Nicolson's + finite differences method. + + The model seems to be a variation of SABR. + " + +2. STRUCTURE: + + a) `NordeaOrig' folder contains the original sequential code, which can be simply + compiled by: `$ g++ HiperfitExample1.cpp' + + b) `VectOuters' folder contains the GPU parallel version of the code, in which + two (outer) dimensions of parallelism are exploited, but the inner dimension, + corresponding to TRIDAG is sequentially executed. + + The CPU execution executes in parallel the outermost loop (OpenMP). + + The degree of parallelism is sensitive to the following parameters, set in + `DataStructConst.h' file: OUTER_LOOP_COUNT, NUM_X, NUM_Y, which are all set + by default to 128, but can be varied. The degree of exploited parallelism is: + OUTER_LOOP_COUNT * MIN(NUM_X, NUM_Y). + + If you wish the result to not be printed, set DEBUG to 0 in DataStructConst.h, + and if you wish GPU hardware info, define DEBUG_PRINT_GPU_INFO. + + To build for CPU execution, set OMP_NUM_THREADS, and: + $make cpu + To build for GPU execution: + $make gpu + + To run: + $./nordea + + c) `VectAll' folder contains the GPU versions that exploits all parallel dimensions + of parallelism, i.e., TRIDAG is parallelized as a combination of scan with + 2x2 matrix multiplication and linear function composition, respectively. + + It follows that it works well even with smaller values for the parallelism-degree + sensitive parameters, e.g., OUTER_LOOP_COUNT x NUM_X x NUM_Y = 128 x 32 x 32. + + The rest is as with `VectOuters', e.g., in the CPU version the outermost loop + (OUTER_LOOP_COUNT) is executed in parallel via OpenMP. + diff --git a/benchmarks/CalibVolDiff/ToDo.txt b/benchmarks/CalibVolDiff/ToDo.txt new file mode 100644 index 0000000..aa6a98a --- /dev/null +++ b/benchmarks/CalibVolDiff/ToDo.txt @@ -0,0 +1,28 @@ +0. Test on different OpSys: Ubuntu, Mac, Windows + Test on different hardware: AMD GPU & NVIDIA GPU + (Intel Phi?) + +1. For both VectAll and VectOuters, check whether the GPU + code is specialized for NVIDIA hardware constants, + such as WARP == 32. (Meaning, test it on AMD GPU) + +2. VectOuters and VectAll: + Currently all the result arrays are copied + back to CPU space, but only a small part + of it is actually required. This filtering + can be done on GPU so as to optimize + communication costs. + +3. Make the seguential overhead, e.g., allocation of CPU/GPU arrays, + close to negligible by increasing the NUM_T, especially for + the Medium and Small datasets. + +4. Source code focusing on readability (not performance). + +5. CONTENT-ORIENTED: + -- eliminate some of the restrictions for VectAll, e.g., + arbitrary size of NUM_X and NUM_Y which leads to + ``global'' segmented scan (in which the segments have + regular sizes). + -- irregular segmented scan, in which there are no restrictions + on the size of the segments. diff --git a/benchmarks/CalibVolDiff/datasets/medium/input.json b/benchmarks/CalibVolDiff/datasets/medium/input.json new file mode 100644 index 0000000..4b6f586 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/medium/input.json @@ -0,0 +1,6 @@ +{ + "outer" : 128, + "num_x" : 256, + "num_y" : 32, + "num_t" : 64 +} diff --git a/benchmarks/CalibVolDiff/datasets/medium/output.json b/benchmarks/CalibVolDiff/datasets/medium/output.json new file mode 100644 index 0000000..4d5f9c1 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/medium/output.json @@ -0,0 +1,17 @@ +[ 0.03, 0.0292079, 0.0288058, 0.028408, 0.0280152, 0.0276279, 0.0272462, 0.0268701, + 0.0264998, 0.0261355, 0.025777, 0.0254243, 0.0250773, 0.024736, 0.0244004, 0.0240704, + 0.0237459, 0.0234269, 0.0231134, 0.0228053, 0.0225025, 0.022205, 0.0219126, 0.0216253, + 0.0213431, 0.0210657, 0.0207928, 0.0205238, 0.0202581, 0.0199978, 0.0197739, 0.0194946, + 0.0192514, 0.0190136, 0.0187787, 0.018547, 0.0183189, 0.0180947, 0.0178743, 0.0176577, + 0.0174448, 0.0172356, 0.0170299, 0.0168278, 0.016629, 0.0164336, 0.0162415, 0.0160526, + 0.0158668, 0.0156841, 0.0155044, 0.0153276, 0.0151536, 0.0149826, 0.0148144, 0.0146488, + 0.0144858, 0.0143253, 0.0141674, 0.0140119, 0.0138588, 0.013708, 0.0135595, 0.0134132, + 0.0132691, 0.0131271, 0.0129872, 0.0128494, 0.0127136, 0.0125796, 0.0124477, 0.0123175, + 0.0121892, 0.0120627, 0.0119379, 0.0118149, 0.0116936, 0.0115739, 0.0114558, 0.0113392, + 0.0112242, 0.0111107, 0.0109986, 0.0108879, 0.0107787, 0.0106708, 0.0105642, 0.010459, + 0.010355, 0.0102523, 0.0101509, 0.0100506, 0.00995151, 0.00985357, 0.00975677, 0.00966107, + 0.00956649, 0.00947299, 0.00938053, 0.00928908, 0.00919862, 0.00910914, 0.00902062, 0.00893303, + 0.00884636, 0.00876059, 0.00867569, 0.00859167, 0.00850848, 0.00842613, 0.00834459, 0.00826384, + 0.00818388, 0.00810468, 0.00802623, 0.00794852, 0.00787153, 0.00779524, 0.00771969, 0.00764481, + 0.0075706, 0.00749704, 0.00742412, 0.00735183, 0.00728016, 0.00720909, 0.00713861, 0.00706872 +] diff --git a/benchmarks/CalibVolDiff/datasets/small/input.json b/benchmarks/CalibVolDiff/datasets/small/input.json new file mode 100644 index 0000000..e14df83 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/small/input.json @@ -0,0 +1,6 @@ +{ + "outer" : 16, + "num_x" : 32, + "num_y" : 256, + "num_t" : 256 +} diff --git a/benchmarks/CalibVolDiff/datasets/small/output.json b/benchmarks/CalibVolDiff/datasets/small/output.json new file mode 100644 index 0000000..a316bb0 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/small/output.json @@ -0,0 +1,3 @@ +[ 0.0300001, 0.0290001, 0.0280001, 0.0270001, 0.026, 0.0251064, 0.0247889, 0.0244714, + 0.0241539, 0.0238364, 0.0235189, 0.0232014, 0.0228839, 0.0225664, 0.0222744, 0.02199 +] diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile new file mode 100644 index 0000000..0ddc64c --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile @@ -0,0 +1,36 @@ +include setup.mk + +ifndef ($(HAVE_GPU)) +include platform.mk +endif + +INCLUDES += -I../includeC + +SOURCES_CPP =VolCalibOrig.cpp +HELPERS =../includeC/ParseInput.h +OBJECTS =VolCalibOrig.o +EXECUTABLE =VolCalib + +#g++ -I. -I/usr/local/cuda/include -O3 NordeaVect.cpp -lOpenCL +default: cpu + +.cpp.o: $(SOURCES_CPP) $(HELPERS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< + +cpu: $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + + +run_small: $(EXECUTABLE) + cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_medium: $(EXECUTABLE) + cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_large: $(EXECUTABLE) + cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp new file mode 100644 index 0000000..94662d3 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp @@ -0,0 +1,318 @@ +#include +#include + +#define WITH_FLOATS 0 +#define WORKGROUP_SIZE 512 + +typedef double REAL; + +#include "Util.h" +#include "ParseInput.h" + +using namespace std; + +// grid +vector myX, myY, myTimeline; +unsigned myXindex, myYindex; + +// variable +vector > myResult; + +// coeffs +vector > myMuX, myVarX, myMuY, myVarY; + +// operators +vector > myDx, myDxx, myDy, myDyy; + + + + +/***********************************/ + +void updateParams(const unsigned g, const double alpha, const double beta, const double nu) +{ + for(unsigned i=0;i(s0/dx); + + for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) +{ + const unsigned n = x.size(); + + Dx.resize(n); + Dxx.resize(n); + + for(unsigned i=0;i& a, + const vector& b, + const vector& c, + const vector& r, + const int n, + vector& u, + vector& uu) +{ + int i, offset; + REAL beta; + + u[0] = r[0]; + uu[0] = b[0]; + + for(i=1; i=0; i--) { + u[i] = (u[i] - c[i]*u[i+1]) / uu[i]; + } +} + +void +rollback(const unsigned g) +{ + unsigned numX = myX.size(), + numY = myY.size(); + + unsigned numZ = max(numX,numY); + + int k, l; + unsigned i, j; + + int kl, ku, ll, lu; + + double dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]); + + vector > u(numY,vector(numX)), v(numX,vector(numY)); + + vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); + + // explicit x + for(i=0;i=0;--i) + { + updateParams(i,alpha,beta,nu); + rollback(i); + } + + return myResult[myXindex][myYindex]; +} + +int main() +{ + unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; + const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; + + fprintf(stdout, "\n// Original (Sequential) Volatility Calibration Benchmark:\n"); + readDataSet( OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T ); + + vector strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); + + for(unsigned i=0;i platform.mk + +make diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data new file mode 100755 index 0000000..1054784 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +mkdir -p datasets/$HIPERMARK_INPUT_NAME + +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT outer num_x num_y num_t > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/run b/benchmarks/CalibVolDiff/implementations/cpp_sequential/run new file mode 100755 index 0000000..c9863c8 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/run @@ -0,0 +1,3 @@ +#!/bin/sh + +cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalib diff --git a/benchmarks/CalibVolDiff/lib/include/Constants.h b/benchmarks/CalibVolDiff/lib/include/Constants.h new file mode 100644 index 0000000..8fd8365 --- /dev/null +++ b/benchmarks/CalibVolDiff/lib/include/Constants.h @@ -0,0 +1,42 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#define WITH_FLOATS 1 + +#define REAL3_CT 4 +#define TRANSPOSE_UV 1 + +#if (WITH_FLOATS) + typedef float REAL; + typedef unsigned int ULONG; +#else + #pragma OPENCL EXTENSION cl_khr_fp64: enable + typedef double REAL; + typedef unsigned long ULONG; +#endif + +#define WARP (1< +#include + +#include +#include +#include +#include + +#include + +using namespace std; + +/////////////////////////////////////////////////////// +//// FLAGS and CONSTANT SCALARS! +/////////////////////////////////////////////////////// + +#define TRIDAG_ALL_OPT_ON +#define MOST_OPTIMISED_ON + +//#define IS_GPU +//#define DEBUG_PRINT_GPU_INFO + +unsigned int OUTER_LOOP_COUNT; //128; //1024; //100; +unsigned int NUM_X ; //256; //256; //64; //256; +unsigned int NUM_Y ; //32; //32; //32; +unsigned int NUM_T ; //64; //64; //64; +unsigned int NUM_XY ; //NUM_X*NUM_Y; + +/////////////////////////////////////////////////////// +//// GLOBAL ARRAYS ! +/////////////////////////////////////////////////////// + +/// grid /// +REAL* myX ; // 1-dim, size: NUM_X +REAL* myY ; // 1-dim, size: NUM_Y +REAL* myTimeline; // 1-dim, size: NUM_T + +unsigned int myXindex, myYindex; + +/// variable /// +REAL* myResArr; //[OUTER_LOOP_COUNT * NUM_Y * NUM_X]; // 3-dim, size: OUTER_LOOP_COUNT x NUM_Y x NUM_X + + +/// coeffs /// +REAL *myMuX, *myVarX; // 2-dim, size: NUM_X x NUM_Y +REAL *myMuY, *myVarY; // 2-dim, size: NUM_X x NUM_Y + +// operators +REAL *myDx, *myDxx; // 2-dim, size: NUM_X x REAL3_CT +REAL *myDy, *myDyy; // 2-dim, size: NUM_Y x REAL3_CT + +void allocGlobArrs() { + myX = new REAL[NUM_X]; + myY = new REAL[NUM_Y]; + myTimeline = new REAL[NUM_T]; + + myMuX = new REAL[NUM_X * NUM_Y]; + myVarX= new REAL[NUM_X * NUM_Y]; + myMuY = new REAL[NUM_X * NUM_Y]; + myVarY= new REAL[NUM_X * NUM_Y]; + + myDx = new REAL[NUM_X * REAL3_CT]; + myDxx = new REAL[NUM_X * REAL3_CT]; + myDy = new REAL[NUM_Y * REAL3_CT]; + myDyy = new REAL[NUM_Y * REAL3_CT]; + + myResArr = new REAL[OUTER_LOOP_COUNT * NUM_Y * NUM_X]; +} + +void deallocGlobArrs() { + delete[] myX; + delete[] myY; + delete[] myTimeline; + + delete[] myMuX; + delete[] myVarX; + delete[] myMuY; + delete[] myVarY; + + delete[] myDx; + delete[] myDxx; + delete[] myDy; + delete[] myDyy; + + delete[] myResArr; +} + +#endif // end include NORDEA_DATA_STRUCT diff --git a/benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h b/benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h new file mode 100644 index 0000000..3c8fa9f --- /dev/null +++ b/benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h @@ -0,0 +1,323 @@ +#ifndef PAR_PREFIX_UTIL +#define PAR_PREFIX_UTIL + +#include +#include + +// TIMING + +typedef struct timeb mlfi_timeb; +#define mlfi_ftime ftime + +#define mlfi_diff_time(t1,t2) \ + (t1.time - t2.time) * 1000 + (t1.millitm - t2.millitm) + +////////////////////////////////////////// +/// CLASSIC, SEQUENTIAL TRIDAG +////////////////////////////////////////// +void tridag( + REAL* a, + REAL* b, + REAL* c, + REAL* d, + int n, + REAL* y, + REAL* u) +{ + int i; + double beta; + + y[0] = d[0]; + u[0] = b[0]; + + for(i=1; i=0; i--) { + y[i] = (y[i] - c[i]*y[i+1]) / u[i]; + } +} + +///////////////////////////////////////////////////////////// + +/** + * Multiplies 2x2 matrixes `a' and `b' and + * stores the result in(-place in) `a'. + */ +void matmult2(REAL* a, REAL* b) { + REAL a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + val = 1.0/(a0*b[0]); + //val = 1.0/(a0*b[0]+a1*b[2]); + a[0] = (a0*b[0] + a1*b[2])*val; + a[1] = (a0*b[1] + a1*b[3])*val; + a[2] = (a2*b[0] + a3*b[2])*val; + a[3] = (a2*b[1] + a3*b[3])*val; +} + + +void scan_matmult_2by2(REAL* tmp, int N) { + REAL* prev = NULL; + + for(int i=1; i=0; i--, k+=2) { // NEW k=2 + tmp[k] = y[i]/u[i]; + tmp[k+1] = 0.0 - c[i]/u[i]; + } + + // backward scan with linear function composition on tmp + scan_linfuncomp(tmp, n); // NEW: n + + // map the result back: + for(i=n-2,k=2; i>=0; i--, k+=2) { // NEW k=2 + y[i] = map_linfuncomp(tmp+k, y[n-1]); + } + } +} + +void test_matmult(){ + int N = 16; + REAL* arr = new REAL[N*4]; + REAL* tmp = arr; + for(int i=0; i=0; i--, k+=2) { + tmp[k] = y[i]/u[i]; + tmp[k+1] = 0.0 - c[i]/u[i]; + } + + // forward scan with linear function composition on tmp + scan_linfuncomp(tmp, n-1); + + // map the result back: + for(i=n-2,k=0; i>=0; i--, k+=2) { + y[i] = map_linfuncomp(tmp+k, y[n-1]); + } + } +} + +inline void tridag_seq_32( + REAL* a, + REAL* b, + REAL* c, + REAL* d, + int n, + REAL* y, + REAL* u) +{ + int i, UB, offset; + REAL beta; + + y[0] = d[0]; + u[0] = b[0]; + + UB = n << 5; + for(i=32; i=0; i-=32) { + y[i] = (y[i] - c[i]*y[i+32]) / u[i]; + } +} + +inline void tridag_seq_1( + REAL* a, + REAL* b, + REAL* c, + REAL* d, + int n, + REAL* y, + REAL* u) +{ + int i, UB, offset; + REAL beta; + + y[0] = d[0]; + u[0] = b[0]; + + UB = n << 5; + for(i=1; i=0; i--) { + y[i] = (y[i] - c[i]*y[i+1]) / u[i]; + } +} + +#endif // end include PAR_PREFIX_UTIL + diff --git a/benchmarks/CalibVolDiff/lib/include/ParseInput.h b/benchmarks/CalibVolDiff/lib/include/ParseInput.h new file mode 100644 index 0000000..8453724 --- /dev/null +++ b/benchmarks/CalibVolDiff/lib/include/ParseInput.h @@ -0,0 +1,58 @@ +#ifndef PARSE_INPUT +#define PARSE_INPUT + +#include "ParserC.h" +#include "Util.h" +#include +#include +#include + +using namespace std; + +#include + +#if WITH_FLOATS + #define read_real read_float +#else + #define read_real read_double +#endif + +const float EPS = 0.00001; + +/***********************************/ +/********** READ DATA SET **********/ +/***********************************/ + +void readDataSet( unsigned int& outer, + unsigned int& num_X, + unsigned int& num_Y, + unsigned int& num_T +) { + if( read_int( static_cast( &outer ) ) || + read_int( static_cast( &num_X ) ) || + read_int( static_cast( &num_Y ) ) || + read_int( static_cast( &num_T ) ) ) { + + fprintf(stderr, "Syntax error when reading the dataset, i.e., four ints.\n"); + exit(1); + } + + { // check dataset invariants: + bool atr_ok = true; + + atr_ok = outer > 0; + assert(atr_ok && "Outer loop count less than 0!"); + + atr_ok = (num_X > 0) && (num_X <= WORKGROUP_SIZE) && is_pow2(num_X); + assert(atr_ok && "Illegal NUM_X value!"); + + atr_ok = (num_Y > 0) && (num_Y <= WORKGROUP_SIZE) && is_pow2(num_Y); + assert(atr_ok && "Illegal NUM_X value!"); + + atr_ok = num_T > 0; + assert(atr_ok && "NUM_T value less or equal to zero!!"); + } +} + +#endif // PARSE_INPUT + diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate_data b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate_data new file mode 100755 index 0000000..76e52cd --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate_data @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +# This instantiate file only compiles the data and not the program. +# It also creates a run file that can execute the binary with the specified input. + +# The dataset file should be compiled to a specific dataset folder. This folder can be +# made in the hipermark script and a process with that new folder as path can be started. +# This process compiles the data. This means that the run script should not be compiled +# in this script. The run file must be implementation dependent and not dataset dependent. +# So the dataset name is set in the script and not here. +#DATASET_NAME="input.data" +HIPERMARK_LIB_DIR=/home/thor/Documents/Uni/hiperfit/finpar/lib +HIPERMARK_INPUT=/home/thor/Documents/Uni/hiperfit/finpar/benchmarks/OptionPricing/datasets/small/input.json +HIPERMARK_PLATFORM=/home/thor/Documents/Uni/hiperfit/finpar/config/platform_example.json + +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > $DATASET_NAME diff --git a/benchmarks/OptionPricing/lib/Constants.h b/benchmarks/OptionPricing/lib/include/Constants.h similarity index 100% rename from benchmarks/OptionPricing/lib/Constants.h rename to benchmarks/OptionPricing/lib/include/Constants.h diff --git a/benchmarks/OptionPricing/lib/Optimizations.h b/benchmarks/OptionPricing/lib/include/Optimizations.h similarity index 100% rename from benchmarks/OptionPricing/lib/Optimizations.h rename to benchmarks/OptionPricing/lib/include/Optimizations.h diff --git a/benchmarks/OptionPricing/lib/ParseInput.h b/benchmarks/OptionPricing/lib/include/ParseInput.h similarity index 100% rename from benchmarks/OptionPricing/lib/ParseInput.h rename to benchmarks/OptionPricing/lib/include/ParseInput.h diff --git a/benchmarks/OptionPricing/lib/TimeHelper.h b/benchmarks/OptionPricing/lib/include/TimeHelper.h similarity index 100% rename from benchmarks/OptionPricing/lib/TimeHelper.h rename to benchmarks/OptionPricing/lib/include/TimeHelper.h From 576209a027a255dd041df301bacea0e80a32f618 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 7 Aug 2015 16:24:11 +0200 Subject: [PATCH 034/122] Working with finpar for the three implementations of CalibVolDiff present in this rep.: cpp_seq, cpp_openmp_naive, haskell_lh --- .../implementations/cpp_openmp_naive/Makefile | 23 + .../cpp_openmp_naive/VolCalibOrig.cpp | 349 ++++++++++++++ .../cpp_openmp_naive/instantiate | 16 + .../cpp_openmp_naive/instantiate_data | 7 + .../implementations/cpp_openmp_naive/run | 3 + .../implementations/haskell_lh/VolCalib.hs | 444 ++++++++++++++++++ .../implementations/haskell_lh/instantiate | 8 + .../haskell_lh/instantiate_data | 7 + .../implementations/haskell_lh/run | 6 + 9 files changed, 863 insertions(+) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run create mode 100644 benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs create mode 100755 benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate create mode 100755 benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data create mode 100755 benchmarks/CalibVolDiff/implementations/haskell_lh/run diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile new file mode 100644 index 0000000..447ba3c --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile @@ -0,0 +1,23 @@ +include setup.mk + +ifndef ($(HAVE_GPU)) +include platform.mk +endif + +SOURCES_CPP =VolCalibOrig.cpp +HELPERS =../includeC/ParseInput.h +OBJECTS =VolCalibOrig.o +EXECUTABLE =VolCalib + +.cpp.o: $(SOURCES_CPP) $(HELPERS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< + +# The GPU version is in: ../VectAll and ../VectOuters. This folder is CPU only! + +cpu: $(EXECUTABLE) +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp new file mode 100644 index 0000000..f907517 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp @@ -0,0 +1,349 @@ +#include +#include + +typedef double REAL; +#define WORKGROUP_SIZE 512 + +#include "Util.h" +#include "ParseInput.h" + +using namespace std; + +struct PrivGlobs { + + // grid + vector myX; + vector myY; + vector myTimeline; + unsigned myXindex; + unsigned myYindex; + + // variable + vector > myResult; + + // coeffs + vector > myMuX; + vector > myVarX; + vector > myMuY; + vector > myVarY; + + // operators + vector > myDx; + vector > myDxx; + + vector > myDy; + vector > myDyy; +} __attribute__ ((aligned (128))); + + + + + +/***********************************/ + +void updateParams(const unsigned g, const double alpha, const double beta, const double nu, PrivGlobs& globs) +{ + for(unsigned i=0;i(s0/dx); + + for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) +{ + const unsigned n = x.size(); + + Dx.resize(n); + Dxx.resize(n); + + for(unsigned i=0;i& a, + const vector& b, + const vector& c, + const vector& r, + const int n, + vector& u, + vector& uu) +{ + int i, offset; + REAL beta; + + u[0] = r[0]; + uu[0] = b[0]; + + for(i=1; i=0; i--) { + u[i] = (u[i] - c[i]*u[i+1]) / uu[i]; + } +} + + +void +rollback( const unsigned g, PrivGlobs& globs ) { + unsigned numX = globs.myX.size(), + numY = globs.myY.size(); + + unsigned numZ = max(numX,numY); + + int k, l; + unsigned i, j; + + int kl, ku, ll, lu; + + double dtInv = 1.0/(globs.myTimeline[g+1]-globs.myTimeline[g]); + + vector > u(numY,vector(numX)), v(numX,vector(numY)); + vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); + + // explicit x + for(i=0;i=0;--i) + { + updateParams(i,alpha,beta,nu,globs); + rollback(i, globs); + } + + return globs.myResult[globs.myXindex][globs.myYindex]; +} + +double* run_CPUkernel( + const unsigned int& outer, + const unsigned int& numX, + const unsigned int& numY, + const unsigned int& numT, + const double& s0, + const double& t, + const double& alpha, + const double& nu, + const double& beta, + const vector& strikes, + vector& res +) { +#pragma omp parallel for default(shared) schedule(static) if(outer>4) + for( unsigned i = 0; i < outer; ++ i ) { + res[i] = value( s0, strikes[i], t, alpha, nu, beta, + numX, numY, numT ); + } +} + + +int main() +{ + unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; + const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; + + cout<<"\n// Running Original (Parallel) Volatility-Calibration Benchmark"< strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); + + for(unsigned i=0;i platform.mk +NCORES=$($HIPERMARK_LIB_DIR/json_get.py $HIPERMARK_PLATFORM num_cores) + +make diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data new file mode 100755 index 0000000..1054784 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +mkdir -p datasets/$HIPERMARK_INPUT_NAME + +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT outer num_x num_y num_t > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run new file mode 100755 index 0000000..8caf40b --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run @@ -0,0 +1,3 @@ +#!/bin/sh +export OMP_NUM_THREADS=$NCORES +cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalib \ No newline at end of file diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs b/benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs new file mode 100644 index 0000000..8068470 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs @@ -0,0 +1,444 @@ +module Main where + +import Control.DeepSeq +import Control.Applicative +import Control.Monad +import Data.Maybe +import System.CPUTime +import System.Environment + +------------------------------------ +--- Requires the installation of --- +--- Parsec package, i.e., --- +--- cabal install parsec --- +------------------------------------ + +import Text.Parsec hiding (optional, (<|>), token) +import Text.Parsec.String + +import Data.Bits +import Data.List +import Prelude + +------------------------------ +--- Parser-related Helpers --- +------------------------------ +signed :: Parser String -> Parser String +signed p = (char '-' >> (('-':) <$> p)) <|> p + +whitespace :: Parser () +whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) + +lexeme :: Parser a -> Parser a +lexeme p = p <* whitespace + +token :: String -> Parser () +token = void . lexeme . string + +readInt :: Parser Int +readInt = lexeme $ read <$> signed (many1 digit) + +readDouble :: Parser Double +readDouble = lexeme $ read <$> signed (s2 <|> s1) + where s1 = do bef <- many1 digit + aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) + return $ bef ++ aft + s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit + +readArray :: Parser a -> Parser [a] +readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") + +--------------------------------------------- +--- Definition of lish-homomorphic reduce --- +--- requires a binary associative op --- +--------------------------------------------- + +reduce :: (a -> a -> a) -> a -> [a] -> a +reduce bop ne lst = foldl bop ne lst + +--------------------------------------------- +--------------------------------------------- + +initGrid :: Double -> Double -> Double -> Double + -> Int -> Int -> Int + -> ( Int, Int, [Double], [Double], [Double], + [[Double]], [[Double]], [[Double]], [[Double]] ) +initGrid s0 alpha nu t num_x num_y num_t = + let logAlpha = log alpha + myTimeline = map (\i -> t * (fromIntegral i) / ((fromIntegral num_t) - 1.0)) [0..num_t-1] + stdX = 20.0 * alpha * s0 * (sqrt t) + stdY = 10.0 * nu * (sqrt t) + (dx, dy) = (stdX / fromIntegral num_x, stdY / fromIntegral num_y) + (myXindex, myYindex) = (truncate (s0 / dx), num_y `div` 2) + myX = map (\i -> (fromIntegral i) * dx - (fromIntegral myXindex) * dx + s0 ) [0..num_x-1] + myY = map (\i -> (fromIntegral i) * dy - (fromIntegral myYindex) * dy + logAlpha) [0..num_y-1] + xXy = replicate num_x (replicate num_y 0.0) + (myMuX, myVarX, myMuY, myVarY) = (xXy, xXy, xXy, xXy) + in (myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY) + +--------------------------------------------- +--------------------------------------------- + +--------------------------------------------- +--------------------------------------------- + +initOperator :: [Double] + -> ( [(Double,Double,Double)], [(Double,Double,Double)] ) +initOperator x = + let n = length x + mid_x = zip3 x (tail x) (tail (tail x)) + + dxu = (x !! 1) - (x !! 0) + dxl = 0.0 + dxlow = (0.0, -1.0 / dxu, 1.0 / dxu) + dxxlow = (0.0, 0.0, 0.0) + + --- Implements a parallel loop such as: --- + --- doall i = 2, N-1, 1 --- + --- (a,b,c) = f(x[i-1], x[i], x[i+1]) --- + --- res[i-1] = (a,b,c) --- + dxmid = map (\(xim1, xi, xip1) -> + let (dxl, dxu) = (xi - xim1, xip1 - xi) + dxlpxu = dxl + dxu + in ( (-dxu/dxl ) / dxlpxu, + ( dxu/dxl - dxl/dxu) / dxlpxu, + ( dxl/dxu ) / dxlpxu + ) + ) mid_x + dxxmid = map (\(xim1, xi, xip1) -> + let (dxl, dxu) = (xi - xim1, xip1 - xi) + dxlpxu = dxl + dxu + in ( ( 2.0/dxl ) / dxlpxu, + -2.0*(1.0/dxl+1.0/dxu) / dxlpxu, + ( 2.0/dxu ) / dxlpxu + ) + ) mid_x + dxll = (x !! (n-1)) - (x !! (n-2)) + dxul = 0.0 + dxhigh = [(-1.0 / dxll, 1.0 / dxll, 0.0)] + dxxhigh= [(0.0, 0.0, 0.0)] + in ( dxlow : (dxmid++dxhigh), dxxlow : (dxxmid++dxxhigh) ) + +----------------------------------------------- +--- A tail-recursive function modeling a --- +--- do loop that goes from i = 0 to bound-1 --- +----------------------------------------------- + +doLoop :: Int -> Int + -> ( [Double], [(Double,Double,Double)], [(Double,Double,Double)], + [Double], [(Double,Double,Double)], [(Double,Double,Double)], + [Double], Double, Double, Double ) + -> ([[Double]], [[Double]], [[Double]], [[Double]], [[Double]]) + -> ([[Double]], [[Double]], [[Double]], [[Double]], [[Double]]) +doLoop i bound loop_ros loop_variants = + if i == bound + then loop_variants + else let (myResult, myMuX, myVarX, myMuY, myVarY) = loop_variants + + ( myX, myDx, myDxx, myY, myDy, myDyy, + myTimeline, alpha, beta, nu ) = loop_ros + + j = (bound-1-i) + + (myMuX', myVarX', myMuY', myVarY') = + updateParams myX myY myTimeline j alpha beta nu + + + + myResult'= rollback j myX myY myTimeline myResult + myMuX' myDx myDxx myVarX' + myMuY' myDy myDyy myVarY' + + loop_variants' = (myResult', myMuX', myVarX', myMuY', myVarY') + + in -- Hack to avoid space leak + myResult' `deepseq` myMuX' `deepseq` myVarX' `deepseq` myMuY' `deepseq` myVarY' `deepseq` + doLoop (i+1) bound loop_ros loop_variants' + +--------------------------------------------- +--------------------------------------------- + +updateParams :: [Double] -> [Double] -> [Double] -> Int -> Double -> Double -> Double + -> ( [[Double]], [[Double]], [[Double]], [[Double]] ) +updateParams myX myY myTimeline g alpha beta nu = + unzip4 $ map (\ xi -> unzip4 $ + map (\ yj -> let b = beta * log(xi) + yj + c = 0.5 * nu * nu * (myTimeline !! g) + in ( 0.0, exp (2.0 * (b - c) ), 0.0, nu * nu ) + ) myY + ) myX +--------------------------------------------- +--- Helpers for the rollback function --- +--- ToDo: make them nice!!! --- +--------------------------------------------- + +-- explicitX = explicitXY dt_inv 0.5 (transpose my_result) (transpose myMuX) (transpose myVarX) myDx myDxx +-- explicitY = explicitXY 0.0 1.0 my_result myMuY myVarY myDy myDyy +explicitXY :: Double -> Double + -> [[Double]] -> [[Double]] -> [[Double]] + -> [ (Double,Double,Double) ] + -> [ (Double,Double,Double) ] + -> [[Double]] +explicitXY dt_inv fact my_result myMuY myVarY myDy myDyy = + map (\ tup_i -> + let (res_row, myMuY_row, myVarY_row) = tup_i + res_row3 = zip3 (0.0:res_row) res_row ((tail res_row) ++ [0.0]) + + in map (\ ((myDy_i, myDyy_i, myMuY_ij, myVarY_ij),(r_jm1, r_j, r_jp1)) -> + let ((dy0, dy1, dy2), (dyy0, dyy1, dyy2)) = (myDy_i, myDyy_i) + res0 = dt_inv * r_j + res1 = fact * (myMuY_ij*dy0 + 0.5*myVarY_ij*dyy0) * r_jm1 + res2 = fact * (myMuY_ij*dy2 + 0.5*myVarY_ij*dyy2) * r_jp1 + res3 = fact * (myMuY_ij*dy1 + 0.5*myVarY_ij*dyy1) * r_j + in res0 + res1 + res2 + res3 + + ) (zip (zip4 myDy myDyy myMuY_row myVarY_row) res_row3) + + ) (zip3 my_result myMuY myVarY) + +------------------------------------------ +--- loop-like definition for explicitX --- +--- inneficient due to list traversal --- +--- to find every index. --- +--- Same is possible for explicitY0 --- +------------------------------------------ +explicitX0 :: Int -> Int -> Double -> [[Double]] -> [[Double]] + -> [ (Double,Double,Double) ] -> [ (Double,Double,Double) ] -> [[Double]] + -> [[Double]] +explicitX0 num_x num_y dt_inv my_result + myMuX myDx myDxx myVarX = + map (\ j -> + map (\ i -> let res0 = dt_inv * ((my_result !! i) !! j) -- my_result[i,j] + ((dx0, dx1, dx2), (dxx0, dxx1, dxx2)) = (myDx !! i, myDxx !! i) + + myMuX_ij = ( myMuX !! i) !! j -- myMuX[i,j] + myVarX_ij = (myVarX !! i) !! j -- myVarX[i,j] + + res1 = if i == 0 then 0.0 + else 0.5 * (myMuX_ij*dx0 + 0.5*myVarX_ij*dxx0) * + ((my_result !! (i-1)) !! j) -- my_result[i-1, j] + res2 = if i == num_x - 1 then 0.0 + else 0.5 * (myMuX_ij*dx2 + 0.5*myVarX_ij*dxx2) * + ((my_result !! (i+1)) !! j) -- my_result[i+1,j] + + res3 = 0.5 * (myMuX_ij*dx1 + 0.5*myVarX_ij*dxx1) * + ((my_result !! i) !! j) -- my_result[i ,j] + + in res0 + res1 + res2 + res3 + + + ) [0..num_x-1] + + ) [0..num_y-1] + +tridag :: [Double] -> [Double] -> [Double] -> [Double] + -> ( [Double], [Double] ) +tridag a b c r = + let u0 = head r + uu0 = head b + + -- scanl's binary operator is NOT associative + uu = scanl (\ uuim1 (ai, bi, cim1) -> + let beta = ai / uuim1 + in bi - beta*cim1 + ) uu0 (zip3 (tail a) (tail b) c) + + -- scanl's binary operator is NOT associative + u = scanl (\ uim1 (ai, ri, uuim1) -> + let beta = ai / uuim1 + in ri - beta*uim1 + ) u0 (zip3 (tail a) (tail r) uu) + + ur = reverse u + uur = reverse uu + ur0'= (head ur) / (head uur) + ur' = scanl (\ uip1 (uri, uuri, cri) -> + (uri - cri*uip1) / uuri + ) ur0' (zip3 (tail ur) (tail uur) (tail $ reverse c)) + in (reverse ur', uu) + + +tridagPar :: [Double] -> [Double] -> [Double] -> [Double] + -> ( [Double], [Double] ) +tridagPar a b c r = + let -- u0 = head r + -- uu0 = head b + u0 = head b + uu0 = head r + + -- creating the 2x2 matrices + mats = map (\(ai,bi,cim1)-> (bi, -ai*cim1, 1.0, 0.0)) (zip3 (tail a) (tail b) c) + -- scan with 2x2 matrix multiplication + scanmat = scanl (\(x1,y1,z1,w1) (x2,y2,z2,w2) -> + let dv = 1.0/(x1*x2) + in ( (x1*x2+y1*z2)*dv, + (x1*y2+y1*w2)*dv, + (z1*x2+w1*z2)*dv, + (z1*y2+w1*w2)*dv ) + ) (1.0, 0.0, 0.0, 1.0) mats + + -- compute the first recurrence result + uu = map (\(x,y,z,w) -> (x*u0 + y) / (z*u0 + w) ) scanmat + + -- compute the second recurrence + pairs = map (\(ai,ri,uuim1)->(ri, -ai/uuim1)) (zip3 (tail a) (tail r) uu) + + scanpairs = scanl (\ (x1,y1) (x2,y2) -> (x2+y2*x1, y1*y2) ) (0.0,1.0) pairs + + u = map (\(x,y) -> x + u0*y) scanpairs + + -- backwards recurrence + ur = reverse u + uur = reverse uu + ur0'= (head ur) / (head uur) + + pairsr = map (\(uri, uuri, cri)->(uri/uuri, -cri/uuri)) (zip3 (tail ur) (tail uur) (tail $ reverse c)) + scanpairsr = scanl (\ (x1,y1) (x2,y2) -> (x2+y2*x1, y1*y2) ) (0.0,1.0) pairsr + ur' = map (\(x,y) -> x + ur0'*y) scanpairsr + + in (reverse ur', uu) + +--------------------------------------------- +--- rollback: the brain of the program --- +--------------------------------------------- + +rollback :: Int -> [Double] -> [Double] -> [Double] -> [[Double]] + -> [[Double]] -> [(Double,Double,Double)] -> [(Double,Double,Double)] -> [[Double]] + -> [[Double]] -> [(Double,Double,Double)] -> [(Double,Double,Double)] -> [[Double]] + -> [[Double]] + +rollback g myX myY myTimeline myResult + myMuX myDx myDxx myVarX + myMuY myDy myDyy myVarY = + + let (numX, numY) = (length myX, length myY) + numZ = max numX numY + dtInv = 1.0 / ( (myTimeline !! (g+1)) - (myTimeline !! g) ) + + u0= explicitXY dtInv 0.5 (transpose myResult) (transpose myMuX) (transpose myVarX) myDx myDxx + v0= explicitXY 0.0 1.0 myResult myMuY myVarY myDy myDyy + + u1= map (\ (us, vs) -> zipWith (+) us vs ) + (zip u0 (transpose v0)) + + u2= map (\ t -> let (uj, myDx, myDxx, myMuX, myVarX) = t + (a,b,c) = unzip3 $ + map (\ tt -> let (myDx, myDxx, myMuX, myVarX) = tt + (dx0, dx1, dx2 ) = myDx + (dxx0, dxx1, dxx2) = myDxx + in ( -0.5*(myMuX*dx0 + 0.5*myVarX*dxx0), + dtInv - 0.5*(myMuX*dx1 + 0.5*myVarX*dxx1), + -0.5*(myMuX*dx2+0.5*myVarX*dxx2) ) ) + (zip4 myDx myDxx myMuX myVarX) + + (uj', yy) = tridag a b c uj -- tridagPar a b c uj + in uj' ) + (zip5 u1 (replicate numY myDx) (replicate numY myDxx) (transpose myMuX) (transpose myVarX)) + + in map (\ t -> let (ui, vi, myDy, myDyy, myMuY, myVarY) = t + (a,b,c) = unzip3 $ + map (\ tt -> let (myDy, myDyy, myMuY, myVarY) = tt + (dy0, dy1, dy2 ) = myDy + (dyy0, dyy1, dyy2) = myDyy + in ( -0.5*(myMuY*dy0+0.5*myVarY*dyy0), + dtInv - 0.5*(myMuY*dy1+0.5*myVarY*dyy1), + -0.5*(myMuY*dy2+0.5*myVarY*dyy2) ) ) + (zip4 myDy myDyy myMuY myVarY) + + y = map (\ (u,v) -> dtInv * u - 0.5 * v) (zip ui vi) + + (ri, yy) = tridag a b c y -- tridagPar a b c y + in ri ) + (zip6 (transpose u2) v0 (replicate numX myDy) (replicate numX myDyy) myMuY myVarY) + +--------------------------------------------- +--------------------------------------------- + +------------------------------------------------- +--- Cosmin ToDo: make MyX & MyY & myTimeline --- +--- vectors instead of lists --- +------------------------------------------------- + +value :: (Double, Double, Double, Double, Double) + -> (Int, Int, Int, Int) -> Double + -> Double +value params it_spaces strike = + let (outer, num_x, num_y, num_t) = it_spaces + (s0, t, alpha, nu, beta) = params + + (myXindex, myYindex, myX, myY, myTimeline, myMuX, myVarX, myMuY, myVarY) = + initGrid s0 alpha nu t num_x num_y num_t + (myDx, myDxx) = initOperator myX + (myDy, myDyy) = initOperator myY + + my_result_ini = map (\ xi -> replicate num_y (max (xi - strike) 0.0 )) myX + + loop_variants = (my_result_ini, myMuX, myVarX, myMuY, myVarY) + loop_ros = (myX, myDx, myDxx, myY, myDy, myDyy, myTimeline, alpha, beta, nu) + + (my_result,_,_,_,_) = doLoop 0 (num_t-1) loop_ros loop_variants + + in (my_result !! myXindex) !! myYindex -- my_result[myXindex, myYindex] + +------------------------------------------------ +--- Main Entry Point: volatility calibration --- +------------------------------------------------ +compute :: (Int, Int, Int, Int) + -> (Double, Double, Double, Double, Double) + -> [Double] +compute it_spaces params = + let (s0, t, alpha, nu, beta) = params + (outer, num_x, num_y, num_t) = it_spaces + strikes = map (\i -> 0.001 * (fromIntegral i)) [0..outer-1] + res = map (value params it_spaces) strikes + in res + +---------------------------------------------- +--- Formatting the Output of the Benchmark --- +---------------------------------------------- +validate :: [Double] -> [Double] -> (Int,Int,Int,Int) -> [String] +validate res_ref res info= + let errs = map abs $ zipWith (-) res_ref res + err = reduce max 0.0 errs + (outer, num_x, num_y, num_t) = info + in ["// Generic Pricing Haskell Benchmark (List-Homomorphism Style):", + "// OUTER: " ++ show outer ++ ", NUM_X: " ++ show num_x ++ + ", NUM_Y: " ++ show num_y ++ ", NUM_T: " ++ show num_t, + ( if err <= 0.00001 -- 0.0005 + then "1\t\t// VALID Result," + else "0\t\t// INVALID Result," ), + "0\t\t// Runtime in microseconds,", + "1\t\t// CPU Threads,", + show res ++ "\t// Volatility Calibration Result."] + + +----------------------------------------- +--- Entry point for Generic Pricing --- +--- The only place where using Monads,--- +--- e.g., parsing Dataset from StdIn --- +----------------------------------------- +main :: IO () +main = do s <- getContents + case parse run "input" s of + Left e -> error $ show e + Right m -> do (v,runtime) <- m + result <- getEnv "HIPERMARK_RESULT" + writeFile result $ show v + runtime_file <- getEnv "HIPERMARK_RUNTIME" + writeFile runtime_file $ show runtime + where run = do whitespace + outer <- readInt + num_x <- readInt + num_y <- readInt + num_t <- readInt + + let params = (0.03, 5.0, 0.2, 0.6, 0.5) --(s0, t, alpha, nu, beta) + + return $ do + start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + let v = compute (outer, num_x, num_y, num_t) params + end <- v `deepseq` getCPUTime + return (v, (end - start) `div` 1000000000) + +-- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs +-- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate new file mode 100755 index 0000000..6a0342d --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e # Die on error. + +cp $HIPERMARK_IMPLEMENTATION/*hs . +cp $HIPERMARK_IMPLEMENTATION/run . + +ghc -Wall -O2 -msse2 -rtsopts VolCalib.hs -o VolCalib diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data new file mode 100755 index 0000000..2a92a4b --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e #Die on error + +mkdir -p datasets/$HIPERMARK_INPUT_NAME + +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT outer num_x num_y num_t > datasets/$HIPERMARK_INPUT_NAME/input.data \ No newline at end of file diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/run b/benchmarks/CalibVolDiff/implementations/haskell_lh/run new file mode 100755 index 0000000..bada098 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/haskell_lh/run @@ -0,0 +1,6 @@ +#!/bin/sh + +set -e + +./VolCalib +RTS -K128m -RTS < ./datasets/$HIPERMARK_INPUT_NAME/input.data +#cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalib +RTS -K128m -RTS From 6ba3b663d1a4e28ae3fe63aae4ae84edb2c3746a Mon Sep 17 00:00:00 2001 From: Thor Date: Mon, 10 Aug 2015 18:55:18 +0200 Subject: [PATCH 035/122] finpar OptionPricing cpp_openmp now works with hipermark --- .../cpp_opencl/ContractDefs/LargeContract.cl | 1167 ---- .../cpp_opencl/ContractDefs/MediumContract.cl | 72 - .../cpp_opencl/ContractDefs/SmallContract.cl | 44 - .../implementations/cpp_opencl/GenPricing.cpp | 186 - .../cpp_opencl/GenericPricingPrivOpt.cl | 377 -- .../cpp_opencl/GenericPricingVectOpt.cl | 588 -- .../GenericPricingVectUncoalesced.cl | 493 -- .../implementations/cpp_opencl/Makefile | 41 - .../implementations/cpp_opencl/StructGPU.h | 611 -- .../implementations/cpp_opencl/instantiate | 27 - .../implementations/cpp_openmp/GenPricing.cpp | 4 +- .../implementations/cpp_openmp/instantiate | 23 +- .../cpp_openmp/instantiate_data | 15 +- .../cpp_sequential/Contracts.h | 1267 ---- .../cpp_sequential/GenPricing.cpp | 152 - .../implementations/cpp_sequential/Makefile | 38 - .../cpp_sequential/SobolGaussBB.h | 239 - .../cpp_sequential/instantiate | 25 - .../implementations/futhark/GenericPricing | Bin 36816 -> 0 bytes .../implementations/futhark/GenericPricing.c | 5323 ----------------- .../futhark/GenericPricing.fut | 443 -- .../implementations/futhark/instantiate | 9 - .../OptionPricing/implementations/futhark/run | 5 - .../implementations/haskell_lh/GenPricing.hs | 520 -- .../implementations/haskell_lh/Payoff3Cond.hs | 1105 ---- .../implementations/haskell_lh/instantiate | 13 - .../implementations/haskell_lh/run | 5 - 27 files changed, 16 insertions(+), 12776 deletions(-) delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/Makefile delete mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h delete mode 100755 benchmarks/OptionPricing/implementations/cpp_opencl/instantiate delete mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/Contracts.h delete mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp delete mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/Makefile delete mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/SobolGaussBB.h delete mode 100755 benchmarks/OptionPricing/implementations/cpp_sequential/instantiate delete mode 100755 benchmarks/OptionPricing/implementations/futhark/GenericPricing delete mode 100644 benchmarks/OptionPricing/implementations/futhark/GenericPricing.c delete mode 100644 benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut delete mode 100755 benchmarks/OptionPricing/implementations/futhark/instantiate delete mode 100755 benchmarks/OptionPricing/implementations/futhark/run delete mode 100644 benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs delete mode 100644 benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs delete mode 100755 benchmarks/OptionPricing/implementations/haskell_lh/instantiate delete mode 100755 benchmarks/OptionPricing/implementations/haskell_lh/run diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl deleted file mode 100644 index 7651cb2..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl +++ /dev/null @@ -1,1167 +0,0 @@ -#include "Constants.h" - -#ifdef VECT_KERNEL - #define underlyings(i,j) \ - (inst_traj[(i*num_under + j)<notify_cash_flow(model, 0, 100., 0 /*2013-01-27, 1980-01-01, EUR*/); - trajectory_inner( num_cash_flows, model_num, 0, 100., md_discts, vhat ); - - if (((underlyings(366,0) < 3758.05) && x3309)) goto L40; - if (((underlyings(366,2) < 1200.) && x3309)) goto L40; - if (((underlyings(366,1) < 11840.) && x3309)) goto L40; - - //model->notify_cash_flow(model, 0, 1000., 1 /*2013-01-27, 2013-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 1, 1000., md_discts, vhat ); return; - -L40: - //model->notify_cash_flow(model, 0, (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))), 1 /*2013-01-27, 2013-01-27, EUR*/); - amount = (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))); - trajectory_inner( num_cash_flows, model_num, 1, amount, md_discts, vhat ); - - return; -} - diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl deleted file mode 100644 index 450343b..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl +++ /dev/null @@ -1,72 +0,0 @@ -#include "Constants.h" - -#ifdef VECT_KERNEL - #define underlyings(i,j) \ - (inst_traj[(i*num_under + j)<notify_cash_flow(model, 0, 1000., 4 /*2017-02-03, 2017-01-27, EUR*/); - trajectory_inner( num_cash_flows, model_num, 4, 1000., md_discts, vhat ); - - if ((1. <= x50)) goto L25; - if ((0.75 < x50)) return; - - //model->notify_cash_flow(model, 0, (-(1000. * (1. - x50))), 4 /*2017-02-03, 2017-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 4, (-(1000. * (1. - x50))), md_discts, vhat ); return; -L25: - //model->notify_cash_flow(model, 0, 750., 4 /*2017-02-03, 2017-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 4, 750., md_discts, vhat ); return; -L24: - //model->notify_cash_flow(model, 0, 1600., 3 /*2016-02-03, 2016-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 3, 1600., md_discts, vhat ); return; -L23: - //model->notify_cash_flow(model, 0, 1450., 2 /*2015-02-03, 2015-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 2, 1450., md_discts, vhat ); return; -L22: - //model->notify_cash_flow(model, 0, 1300., 1 /*2014-02-03, 2014-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 1, 1300., md_discts, vhat ); return; -L21: - //model->notify_cash_flow(model, 0, 1150., 0 /*2013-02-01, 2013-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 0, 1150., md_discts, vhat ); return; -} - diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl deleted file mode 100644 index ec83f9a..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl +++ /dev/null @@ -1,44 +0,0 @@ -#include "Constants.h" - -#ifdef VECT_KERNEL - #define underlyings(i,j) \ - (inst_traj[(i*num_under + j)< - -/*****************************************************/ -/*****************************************************/ -/*****************************************************/ - -double* -run_GPUkernel ( - LoopROScalars & ro_scal, - SobolArrays & sob_arrs, - ModelArrays & md_arrs, - BrowBridgeArrays& bb_arrs, - int & num_cores, - size_t & elapsed_usec - - -) { - cl_context cxGPUContext; // OpenCL context - cl_command_queue cqCommandQueue[16]; // OpenCL command que - cl_uint nDevice; // OpenCL device count - cl_device_id* cdDevices; // OpenCL device list - cl_program cpProgram; // OpenCL program - cl_kernel ckGenPricing = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; // Error code var - - size_t globalWorkSize[1]; // 1D var for Total # of work items - size_t localWorkSize [1]; // 1D var for # of work items in the work group, e.g., { 128 } - size_t global_arr_sz; - - REAL* glb_vhat = NULL; - - - double* vhat_fin = (double*)malloc(ro_scal.num_models*sizeof(double)); - for( int i = 0; i < ro_scal.num_models; i++ ) vhat_fin[i] = 0.0; - - GPU_KERNEL kernel_type = priv_or_vect_kernel( ro_scal ); -#ifdef _OPTIMIZATION_MEM_COALES_ON - const char* kernel_name = (kernel_type == PRIV) ? - "GenericPricingPrivOpt" : // .cl - "GenericPricingVectOpt" ; // .cl -#else - const char* kernel_name = "GenericPricingVectUncoalesced"; -#endif - - { // build the OpenCL program - const char* preamble = makeGPUprogPreamble( ro_scal, kernel_type ); - char compile_opts[128]; - sprintf( compile_opts, "-D lgWARP=%d -D TILE=%d", lgWARP, TILE ); - build_for_GPU( cxGPUContext, cqCommandQueue, nDevice, - cdDevices, cpProgram, GPU_DEV_ID, - compile_opts, preamble, kernel_name ); - } - // we do not measure the just-in-time compilation time! - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - { - num_cores = discriminate_cost_model(ro_scal, cdDevices[GPU_DEV_ID], kernel_type); - computeSobolFixIndex(sob_arrs, ro_scal.chunk); - - globalWorkSize[0] = getWorkSize( ro_scal.num_gpuits, ro_scal.chunk, ro_scal.BLOCK ); - localWorkSize [0] = ro_scal.BLOCK; - } - - oclLoopArrays ocl_arrs; - if(kernel_type == PRIV) { // CALL THE PRIVATE KERNEL - glb_vhat = oclAllocArrays_PrivKernel( - ocl_arrs, cxGPUContext, cqCommandQueue[GPU_DEV_ID], - ciErr1, ro_scal, sob_arrs, bb_arrs, md_arrs - ); - - runGPU_PRIV ( - ro_scal, glb_vhat, ocl_arrs, cqCommandQueue[GPU_DEV_ID], cpProgram, - globalWorkSize, localWorkSize - ); - - reduceVHAT_CPU( ro_scal, glb_vhat, vhat_fin ); - - } else { // VECT VERSION! - - glb_vhat = oclAllocArrays_VectKernel( - ocl_arrs, cxGPUContext, cqCommandQueue[GPU_DEV_ID], - ciErr1, ro_scal, sob_arrs, bb_arrs, md_arrs - ); - - UINT cur_iter = 0, sob_ini_count = ro_scal.sobol_count_ini; - - for(UINT cur_iter = 0; cur_iter < ro_scal.num_mcits; cur_iter+=ro_scal.num_gpuits) { - if(cur_iter + ro_scal.num_gpuits > ro_scal.num_mcits) { - ro_scal.num_gpuits = ro_scal.num_mcits - cur_iter; - globalWorkSize[0] = getWorkSize( ro_scal.num_gpuits,ro_scal.chunk,ro_scal.BLOCK); - } - if(cur_iter != 0) { - size_t cur_size = sizeof(LoopROScalars); - cl_int ciErr2; - ro_scal.sobol_count_ini = cur_iter + sob_ini_count; - clReleaseMemObject(ocl_arrs.ro_scals); - ocl_arrs.ro_scals = clCreateBuffer( - cxGPUContext, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 - ); - ciErr2 = clEnqueueWriteBuffer(cqCommandQueue[GPU_DEV_ID], ocl_arrs.ro_scals, CL_TRUE, 0, - cur_size, &ro_scal, 0, NULL, NULL); - oclCheckError(ciErr2, CL_SUCCESS); - } - - runGPU_VECT ( - ro_scal, glb_vhat, ocl_arrs, cqCommandQueue[GPU_DEV_ID], cpProgram, - globalWorkSize, localWorkSize - ); - - reduceVHAT_CPU( ro_scal, glb_vhat, vhat_fin ); - } - - ro_scal.sobol_count_ini = sob_ini_count; - } - - for(int ii = 0; ii Debug.txt diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl deleted file mode 100644 index 354a8ad..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl +++ /dev/null @@ -1,377 +0,0 @@ -/***************************************************/ -/*** Contract Definitions Are Linked at Run time ***/ -/*** & The RO-Scalar Data-Structure is included, ***/ -/** for e.g., ContractDefs/SmallContract.cl ***/ -/***************************************************/ - -#define TYPE REAL -#define FLAG uchar -#include "Utilities.cl" - -/********************************************/ -/********** SOBOL NUMER GENERATOR ***********/ -/********************************************/ - -void mlfi_genmatrix_uniformGPUind ( - UINT seq_count, - __constant LoopROScalars* ro_scal, - __constant int* sobol_v_dir, - int* sobol_last_num_vec, - REAL* md_zd -) { - UINT j, k, gs, gv_k = 0; - - seq_count += 1; - gs = seq_count >> 1; - gs = seq_count ^ gs; - - UINT sob_dim = ro_scal->num_under * ro_scal->num_dates; - - for( j = 0; j < sob_dim; j++ ) - sobol_last_num_vec[j] = 0; - for( k = 0; k < ro_scal->sobol_bits; ++k ) { - if(gs & 1) { - __constant int* dir_vect - = sobol_v_dir + k*sob_dim; - for( j=0; j < sob_dim; j++ ) { - // xor term g_k * v_k to direction i - sobol_last_num_vec[j] ^= dir_vect[j]; - } - } - gs = gs >> 1; - } - for( j = 0; j < sob_dim; j++ ) { - md_zd[j] = sobol_last_num_vec[j] * ro_scal->sob_norm_fact; - } -} - -inline void mlfi_genmatrix_uniformGPUrecOpt( - UINT f_ind, - __constant LoopROScalars* ro_scal, - __constant int* sobol_v_dir, - int* sobol_last_num_vec, - REAL* md_zd -) { - UINT j; - UINT sob_dim = ro_scal->num_under * ro_scal->num_dates; - f_ind *= sob_dim; - for(j=0; j < sob_dim; j++) { - sobol_last_num_vec[j] ^= sobol_v_dir[ f_ind + j ]; //f_ind * sob_dim - md_zd[j] = sobol_last_num_vec[j] * ro_scal->sob_norm_fact; - } -} - - -inline void mlfi_genmatrix_uniformGPUrec( - UINT seq_count, - __constant LoopROScalars* ro_scal, - __constant int* sobol_v_dir, - int* sobol_last_num_vec, - REAL* md_zd -) { - UINT ell, j; - - UINT c = seq_count; - ell = 0; - while(c & 1) { - ell++; - c >>= 1; - } - UINT sob_dim = ro_scal->num_under * ro_scal->num_dates; - for(j=0; j < sob_dim; j++) { - - sobol_last_num_vec[j] ^= sobol_v_dir[ell*sob_dim + j]; - md_zd[j] = sobol_last_num_vec[j] * ro_scal->sob_norm_fact; //sobol_last_den_inv; - } -} - - -/********************************************/ -/********** GAUSSIAN DISTRIBUTION ***********/ -/********************************************/ - -#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ - (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ - (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) - -inline REAL small_case(REAL q) { - REAL x = 0.180625 - q * q; - return q * rat_eval( - 3.387132872796366608, - 133.14166789178437745, - 1971.5909503065514427, - 13731.693765509461125, - 45921.953931549871457, - 67265.770927008700853, - 33430.575583588128105, - 2509.0809287301226727, - - 1.0, - 42.313330701600911252, - 687.1870074920579083, - 5394.1960214247511077, - 21213.794301586595867, - 39307.89580009271061, - 28729.085735721942674, - 5226.495278852854561); -} - -inline REAL intermediate(REAL r) { - REAL x = r - 1.6; - return rat_eval( - 1.42343711074968357734, - 4.6303378461565452959, - 5.7694972214606914055, - 3.64784832476320460504, - 1.27045825245236838258, - 0.24178072517745061177, - 0.0227238449892691845833, - 7.7454501427834140764e-4, - - 1.0, - 2.05319162663775882187, - 1.6763848301838038494, - 0.68976733498510000455, - 0.14810397642748007459, - 0.0151986665636164571966, - 5.475938084995344946e-4, - 1.05075007164441684324e-9); -} - -inline REAL tail(REAL r) { - REAL x = r - 5.0; - return rat_eval( - 6.6579046435011037772, - 5.4637849111641143699, - 1.7848265399172913358, - 0.29656057182850489123, - 0.026532189526576123093, - 0.0012426609473880784386, - 2.71155556874348757815e-5, - 2.01033439929228813265e-7, - - 1.0, - 0.59983220655588793769, - 0.13692988092273580531, - 0.0148753612908506148525, - 7.868691311456132591e-4, - 1.8463183175100546818e-5, - 1.4215117583164458887e-7, - 2.04426310338993978564e-15); -} - -inline void mlfi_ugaussian_Pinv_vector(REAL* p, UINT N, UINT logBLOCK) { - UINT i, UB = N; - - for ( i=0; i < UB; i++ ) { - REAL dp = p[i] - 0.5; - if (fabs(dp) <= 0.425) { - p[i] = small_case(dp); - } else { - REAL pp = (dp < 0.0) ? dp + 0.5 : (0.5 - dp); - REAL r = sqrt (- log(pp)); - REAL x = (r <= 5.0) ? intermediate(r) : tail(r); - p[i] = (dp < 0.0) ? (0.0 - x) : x; - } - } -} - - -/********************************************/ -/************* BROWNIAN BRIDGE **************/ -/********************************************/ -inline void mlfi_brownianbridge_wiener_pathNoTransGPU( - __constant LoopROScalars* ro_scal, - __constant int* bb_inds, - __constant REAL* bb_data, - REAL* md_zd, - __local REAL* md_z, - UINT block_size -) { - - UINT n, m, md_dim = ro_scal->num_under * block_size, nb_path_dates = ro_scal->num_dates; - __constant int *bb_li, *bb_bi, *bb_ri; - __constant REAL *bb_rw, *bb_lw, *bb_sd; - - bb_bi = bb_inds; - bb_li = bb_inds + nb_path_dates; - bb_ri = bb_inds + (nb_path_dates<<1); - - bb_sd = bb_data; - bb_lw = bb_data + nb_path_dates; - bb_rw = bb_data + (nb_path_dates<<1); - - for (n=0, m=0; m < md_dim; n++, m+=block_size) { - UINT i; - - md_z [ (bb_bi[0]-1) * md_dim + m ] = bb_sd[0] * md_zd[n]; - - for(i=1; i < nb_path_dates; i++) { - int j = bb_li[i] - 1; - int k = bb_ri[i] - 1; - int l = bb_bi[i] - 1; - - REAL wk = md_z [k*md_dim+m]; - REAL zi = md_zd[i*ro_scal->num_under+n]; - - md_z[l*md_dim+m] = (j == -1) ? - bb_rw[i] * wk + bb_sd[i] * zi : - bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * md_z[j*md_dim+m]; - } - } -} - - - -__kernel void payoffGPU( - __constant LoopROScalars* ro_scal, // RO SCALARS - __constant int* sobol_v_dir, // RO SOBOL - __constant UCHAR* fix_index, - // RO Brownian Bridge - __constant int* bb_ia, - __constant REAL* bb_coefs, - // RO MODELS DATA - __constant REAL* model_coefs, - // WO (GLOBAL) VHAT - __global REAL* model_vhat, - // LOCAL ARRAYS - __local REAL* md_z, - //__local REAL* inst_trajWF, - __local REAL* vhat_local -) { - - UINT k, block_size = get_local_size(0); - const UINT ct_init = 0; //ro_scal->sobol_count_ini; - - int sobol_last_num_vec[15];//UINT[ro_scal->sobol_dim]; - REAL md_zd [15]; //[ro_scal->sobol_dim]; - - { // each local array is ajusted w.r.t. the local offset! - UINT localID = get_local_id(0); - md_z = md_z + localID; - //inst_trajWF = inst_trajWF + localID; - vhat_local = vhat_local + localID; - } - - // initialize vhat_local to 0 - for( k = 0; k < ro_scal->num_models*block_size; k+=block_size) { - vhat_local[k] = 0.0; - } - - // ready to go to the main loop - UINT lb = (get_global_id (0) << ro_scal->log_chunk); - UINT ub = min(lb + ro_scal->chunk, ro_scal->num_gpuits); - - - for( k = lb; k < ub; k++ ) { - - // 1. random number generation phase -#ifndef _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR - mlfi_genmatrix_uniformGPUind ( - ct_init+k, ro_scal, - sobol_v_dir, sobol_last_num_vec, md_zd - ); -#else - if( k > lb && k < ub-1) { - mlfi_genmatrix_uniformGPUrecOpt ( - fix_index[k-lb], ro_scal, sobol_v_dir, sobol_last_num_vec, md_zd - ); - } else if (k==lb) { - mlfi_genmatrix_uniformGPUind ( - ct_init+k, ro_scal, - sobol_v_dir, sobol_last_num_vec, md_zd - ); - } else { - mlfi_genmatrix_uniformGPUrec ( - ct_init+k, ro_scal, sobol_v_dir, sobol_last_num_vec, md_zd - ); - } -#endif - - - // 2. generate uniform distribution - mlfi_ugaussian_Pinv_vector(md_zd, ro_scal->num_under*ro_scal->num_dates, ro_scal->logBLOCK); - - // 3. brownian bridge refinement - mlfi_brownianbridge_wiener_pathNoTransGPU( - ro_scal, bb_ia, bb_coefs, md_zd, md_z, block_size - ); - - { // 4. expand md_zd - UINT i; - UINT LB = ro_scal->num_under * block_size; - UINT UB = (ro_scal->num_under * ro_scal->num_dates - 1) * block_size; - for ( i = UB; i >= LB; i -= block_size ) { - md_z[i] -= md_z[i - LB]; - } - } - - { // 5. compute trajectory - UINT m, i, j, q, l; - UINT num_under = ro_scal->num_under; - UINT num_dates = ro_scal->num_dates; - REAL* trajWF = md_zd; - - __constant REAL *md_c, *md_vols, *md_drifts, *md_starts, *md_discts, *md_detvals; - { - UINT num_mods = ro_scal->num_models; - UINT dim_paths = num_under*num_dates; - UINT offset = 0; - md_c = model_coefs + offset; offset += num_mods * num_under * num_under; - md_vols = model_coefs + offset; offset += num_mods * dim_paths; - md_drifts = model_coefs + offset; offset += num_mods * dim_paths; - md_starts = model_coefs + offset; offset += num_mods * num_under; - md_discts = model_coefs + offset; offset += num_mods * ro_scal->num_cash_flows; - md_detvals= model_coefs + offset; - } - - for (m = 0; m < ro_scal->num_models; m++) { - - for (j = 0; j < num_under; j++) { - REAL accum = md_starts[j]; - for( i = 0; i < num_dates; i ++) { - REAL temp = 0.0; - q = num_under*i + j; - - for (l = 0; l <= j; l++) - temp += md_c[num_under * j + l] * md_z[(q - j + l)*block_size]; //md_z[(q - j + l) << logBLOCK]; - - temp = exp(temp * md_vols[q] + md_drifts[q]); - accum *= temp; - trajWF[q] = accum; - } - } - - // 6. reduce each instance/model locally on the multiprocessor - payoffFunction( m, num_under, - ro_scal->num_cash_flows, - ro_scal->num_det_pricers, - md_discts, - md_detvals, - trajWF, - vhat_local - ); - - if ( m+1 < ro_scal->num_models ) { - UINT dim_paths = num_under*num_dates; - md_c += num_under * num_under; md_vols += dim_paths; - md_drifts += dim_paths; md_starts += num_under; - md_discts += ro_scal->num_cash_flows; md_detvals += ro_scal->num_det_pricers; - } - } - } // end 5. compute trajectory - - } // END for( k ) - - barrier(CLK_LOCAL_MEM_FENCE); - - segm_scan_reg_block ( vhat_local - get_local_id(0), block_size * ro_scal->num_models, block_size ); - if( get_local_id(0) == 0) { - UINT glob_size = get_global_size(0)/block_size; - for ( k = 0; k < ro_scal->num_models; k++ ) { - model_vhat[ k * glob_size + get_group_id(0) ] = - vhat_local[ (k + 1)*block_size - 1 ]; - } - } -} - diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl deleted file mode 100644 index 9049b87..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl +++ /dev/null @@ -1,588 +0,0 @@ -/************************************/ -/************* MACROS ***************/ -/************************************/ - -#define TYPE REAL -#define FLAG uchar -#include "Utilities.cl" - -#define DUMMY 1 - -/********************************************/ -/********** SOBOL NUMER GENERATOR ***********/ -/********************************************/ - -#ifdef _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR - -__kernel void mlfi_genmatrix_uniform2 ( - __constant LoopROScalars* ro_scal, - __constant UCHAR* sobol_fix_ind, - __global int* sobol_v_dir, - __global REAL* md_zd -) { - UINT i, j, k; - UINT seq_count = ( get_global_id (0) << ro_scal->log_chunk ); - UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; - -#if(DUMMY==0) - uchar rmb_size = 0; - uchar rmb[32]; -#endif - - md_zd = md_zd + - ( ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) )*sobol_dim + - (get_global_id(0) & (WARP-1)) ); - __global REAL* md_zd_tmp = md_zd; - - UINT UB = (seq_count + (1 << ro_scal->log_chunk) < ro_scal->num_gpuits) ? - seq_count + (1 << ro_scal->log_chunk) : ro_scal->num_gpuits ; - UB = (UB > seq_count) ? UB - seq_count : 0; - - if( UB > 0 ) { - UINT gs; -#if(DUMMY==0) - // Compute gs == the Gray code rep of seq_count - gs = seq_count+1 + ro_scal->sobol_count_ini; - gs = gs ^ (gs>>1); - - // Compute the position of the 1 bits - for( k = 0; k < ro_scal->sobol_bits; ++k ) { - if(gs & 1) { - rmb[rmb_size] = (uchar)k; - rmb_size ++; - } - gs = gs >> 1; - } -#endif - // Compute the random number under the INDEPENDENT formulas - for( i = 0, j=0; j < sobol_dim; j++, i += WARP ) { - UINT accum = 0; - md_zd_tmp = md_zd; - - // FIRST ITER COMPUTED INDEPENDENTLY! -#if(DUMMY==0) - for(k=0; ksobol_bits + rmb[k] ]; - } -#else - gs = seq_count+1 + ro_scal->sobol_count_ini; - gs = gs ^ (gs>>1); - for(k=0; ksobol_bits; k++) { - if(gs & 1) { - accum ^= sobol_v_dir[ j*ro_scal->sobol_bits + k ]; - } - gs = gs >> 1; - } -#endif - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; -#if 1 - // THE REST OF CHUNK-1 ITERATIONS COMPUTED UNDER RECURRENT FORMULA - for( k = 1; k < UB-1; k++ ) { - accum = accum ^ sobol_v_dir[ j*ro_scal->sobol_bits + sobol_fix_ind[k] ]; - - md_zd_tmp += (sobol_dim << lgWARP); - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; - } - - gs = (seq_count + UB - 1 + ro_scal->sobol_count_ini) >> ro_scal->log_chunk; - UINT ell = ro_scal->log_chunk; - while(gs & 1) { - ell++; - gs >>= 1; - } - accum = accum ^ sobol_v_dir[j*ro_scal->sobol_bits + ell]; - md_zd_tmp += (sobol_dim << lgWARP); - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; -#else - for( k = seq_count+1 + ro_scal->sobol_count_ini; k < UB + ro_scal->sobol_count_ini; k++ ) { - gs = k; - UINT ell = 0; - while(gs & 1) { - ell++; - gs >>= 1; - } - - accum = accum ^ sobol_v_dir[j*ro_scal->sobol_bits + ell]; - - md_zd_tmp += (sobol_dim << lgWARP); - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; - } -#endif - } - } // end IF (seq_count < UB) - -} - -#else -/*********************************/ -/*** Independent formula Only ****/ -/*********************************/ - -__kernel void mlfi_genmatrix_uniform2 ( - __constant LoopROScalars* ro_scal, - __constant UCHAR* sobol_fix_ind, - __global int* sobol_v_dir, - __global REAL* md_zd -) { - UINT i, j, k, m; - UINT seq_count = ( get_global_id (0) << ro_scal->log_chunk ); - UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; - - uchar rmb_size = (uchar)0; - uchar rmb[32]; - - md_zd = md_zd + - ( ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) )*sobol_dim + - (get_global_id(0) & (WARP-1)) ); - __global REAL* md_zd_tmp = md_zd; - - UINT UB = (seq_count + (1 << ro_scal->log_chunk) < ro_scal->num_gpuits) ? - seq_count + (1 << ro_scal->log_chunk) : ro_scal->num_gpuits ; - UB = (UB > seq_count) ? UB - seq_count : 0; - - //if( UB > 0 ) - for(m=0; msobol_count_ini; - gs = gs ^ (gs>>1); - - // Compute the position of the 1 bits - for( k = 0; k < ro_scal->sobol_bits; ++k ) { - if(gs & 1) { - rmb[rmb_size] = (uchar)k; - rmb_size ++; - } - gs = gs >> 1; - } - - // Compute the random number under the INDEPENDENT formulas - for( i = 0, j=0; j < sobol_dim; j++, i += WARP ) { - UINT accum = 0; - - for(k=0; ksobol_bits + rmb[k] ]; - } - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; - } - - md_zd_tmp += (sobol_dim << lgWARP); - } // end IF (seq_count < UB) - -} - -#endif - - -/********************************************/ -/********** INV GAUSSIAN DISTRIB ************/ -/********************************************/ - - -#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ - (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ - (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) - -inline REAL small_case(REAL q) { - REAL x = 0.180625 - q * q; - return q * rat_eval( - 3.387132872796366608, - 133.14166789178437745, - 1971.5909503065514427, - 13731.693765509461125, - 45921.953931549871457, - 67265.770927008700853, - 33430.575583588128105, - 2509.0809287301226727, - - 1.0, - 42.313330701600911252, - 687.1870074920579083, - 5394.1960214247511077, - 21213.794301586595867, - 39307.89580009271061, - 28729.085735721942674, - 5226.495278852854561); -} - -inline REAL intermediate(REAL r) { - REAL x = r - 1.6; - return rat_eval( - 1.42343711074968357734, - 4.6303378461565452959, - 5.7694972214606914055, - 3.64784832476320460504, - 1.27045825245236838258, - 0.24178072517745061177, - 0.0227238449892691845833, - 7.7454501427834140764e-4, - - 1.0, - 2.05319162663775882187, - 1.6763848301838038494, - 0.68976733498510000455, - 0.14810397642748007459, - 0.0151986665636164571966, - 5.475938084995344946e-4, - 1.05075007164441684324e-9); -} - -inline REAL tail(REAL r) { - REAL x = r - 5.0; - return rat_eval( - 6.6579046435011037772, - 5.4637849111641143699, - 1.7848265399172913358, - 0.29656057182850489123, - 0.026532189526576123093, - 0.0012426609473880784386, - 2.71155556874348757815e-5, - 2.01033439929228813265e-7, - - 1.0, - 0.59983220655588793769, - 0.13692988092273580531, - 0.0148753612908506148525, - 7.868691311456132591e-4, - 1.8463183175100546818e-5, - 1.4215117583164458887e-7, - 2.04426310338993978564e-15); -} - -__kernel void mlfi_ugaussian_Pinv_vector1( - __constant LoopROScalars* ro_scal, __global REAL* p -) { - UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; - UINT id = get_global_id(0), i, UB; - p += ( (id >> lgWARP) << (ro_scal->log_chunk + lgWARP) )*sobol_dim + ( id & (WARP-1) ); - - id = get_global_id(0) << ro_scal->log_chunk; - - UB = min(id + (1<log_chunk), ro_scal->num_gpuits); - UB = (UB > id) ? UB - id : 0; - UB *= sobol_dim; - - for( id=0, i=0; id < UB; i+=WARP, id++) { - REAL dp = p[i] - 0.5; - if (fabs(dp) <= 0.425) { - p[i] = small_case(dp); - } else { - REAL pp = (dp < 0.0) ? dp + 0.5 : (0.5 - dp); - REAL r = sqrt (- log(pp)); - REAL x = (r <= 5.0) ? intermediate(r) : tail(r); - p[i] = (dp < 0.0) ? (0.0 - x) : x; - } - } -} - -/********************************************/ -/************* BROWNIAN BRIDGE **************/ -/********************************************/ - -__kernel void mlfi_brownianbridge_wiener_path1( - __constant LoopROScalars* ro_scal, - __constant int* bb_inds, - __constant REAL* bb_data, - __global REAL* md_zd, - __global REAL* md_z -) { - __constant int *bb_li, *bb_bi, *bb_ri; - __constant REAL *bb_rw, *bb_lw, *bb_sd; - - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - UINT m, i, md_dim = ro_scal->num_under << lgWARP, nb_path_dates = ro_scal->num_dates; - UINT sobol_dim = ro_scal->num_under * nb_path_dates; - - UINT UB = ( (cur_it + (1<log_chunk) ) < ro_scal->num_gpuits) ? - ( cur_it + (1<log_chunk) ) : ro_scal->num_gpuits; - - bb_bi = bb_inds; - bb_li = bb_inds + nb_path_dates; - bb_ri = bb_inds + (nb_path_dates<<1); - - bb_sd = bb_data; - bb_lw = bb_data + nb_path_dates; - bb_rw = bb_data + (nb_path_dates<<1); - - { - UINT tmp = ( (get_global_id(0) >> lgWARP) << (ro_scal->log_chunk + lgWARP) )*sobol_dim + ( get_global_id(0) & (WARP-1) ); - md_zd = md_zd + tmp; - md_z = md_z + tmp; - } - - for( ; cur_it < UB; cur_it++ ) { - for (m=0; m < md_dim; m+=WARP) { - md_z[ (bb_bi[0]-1) * md_dim + m ] = bb_sd[0] * md_zd[m]; - - for(i=1; i < nb_path_dates; i++) { - int j = bb_li[i] - 1; - int k = bb_ri[i] - 1; - int l = bb_bi[i] - 1; - - REAL wk = md_z [k*md_dim+m]; - REAL zi = md_zd[i*md_dim+m]; - - md_z[l*md_dim+m] = (j == -1) ? - bb_rw[i] * wk + bb_sd[i] * zi : - bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * md_z[j*md_dim+m]; - } - - } - md_z += (sobol_dim << lgWARP); - md_zd += (sobol_dim << lgWARP); - } -} - -/**************************************************/ -/************* TRAJECTORY COMPUTATION *************/ -/**************************************************/ - -void trajectory_contract( - UINT model_num, - __constant LoopROScalars* ro_scal, - __constant REAL* pc_coefs, - __global REAL* inst_traj, - __global REAL* vhat -); - -__kernel void mlfi_comp_traj1( - __constant LoopROScalars* ro_scal, // RO SCALARS - // RO MD INSTANCE DATA - __constant REAL* model_coefs, - // LOCAL SPACE 2 * ro_scal->num_under PER THREAD! - __local REAL* buff, - // RO (GLOBAL) MD_Z - __global REAL* md_z, - // WO (GLOBAL) traj - __global REAL* trajWF -) { - UINT offset; - UINT dim = ro_scal->num_under; - UINT dim_sq = dim*dim; - UINT dim_paths = dim*ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - - UINT UB = ( cur_it+(1<log_chunk) < ro_scal->num_gpuits) ? - cur_it+(1<log_chunk) : ro_scal->num_gpuits ; - { - offset = ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) ); - md_z = md_z + offset*dim_paths + (get_global_id(0) & (WARP-1)); - trajWF = trajWF + offset*dim_paths*ro_scal->num_models + (get_global_id(0) & (WARP-1)); - - offset = get_local_id (0); - offset = (offset >> lgWARP)*(TILE << lgWARP) + (offset & (WARP-1)); // ro_scal->TILE_FACT - buff += offset; - - offset = dim_paths<= LB; i -= WARP ) { - md_z[i] -= md_z[i - LB]; - } - - } - - __constant REAL *md_c, *md_vols, *md_drifts, *md_starts, *md_discts, *md_detvals; - { - UINT num_mods = ro_scal->num_models; - UINT offset = 0; - md_c = model_coefs + offset; offset += num_mods * dim_sq; - md_vols = model_coefs + offset; offset += num_mods * dim_paths; - md_drifts = model_coefs + offset; offset += num_mods * dim_paths; - md_starts = model_coefs + offset; - } - for (m = 0; m < ro_scal->num_models; m++) { - // cache in local space md_starts - for (j = 0; j < dim; j++) { - buff[(dim+j) << lgWARP] = md_starts[ j ]; - } - - for (i = 0; i < ro_scal->num_dates; i++) { - ind = (dim*i) << lgWARP; - - // cache in local space md_z! - for ( j = 0; j<(dim<num_models ) { - md_c += dim_sq; md_vols += dim_paths; - md_drifts += dim_paths; md_starts += dim; - } - - trajWF += offset; - } // end for m - - md_z += offset; - - } // end for cur_it -} - - -__kernel void mlfi_comp_traj_unopt( - __constant LoopROScalars* ro_scal, // RO SCALARS - // RO MD INSTANCE DATA - __constant REAL* model_coefs, - // RO (GLOBAL) MD_Z - __global REAL* md_z, - // WO (GLOBAL) traj - __global REAL* trajWF -) { - UINT offset; - UINT dim = ro_scal->num_under; - UINT dim_sq = dim*dim; - UINT dim_paths = dim*ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - - UINT UB = ( cur_it+(1<log_chunk) < ro_scal->num_gpuits ) ? - cur_it+(1<log_chunk) : ro_scal->num_gpuits ; - { - offset = ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) ); - md_z = md_z + offset*dim_paths + (get_global_id(0) & (WARP-1)); - trajWF = trajWF + offset*dim_paths*ro_scal->num_models + (get_global_id(0) & (WARP-1)); - - offset = dim_paths<= LB; i -= WARP ) { - md_z[i] -= md_z[i - LB]; - } - } - - __constant REAL *md_c, *md_vols, *md_drifts, *md_starts, *md_discts, *md_detvals; - { - UINT num_mods = ro_scal->num_models; - UINT offset = 0; - md_c = model_coefs + offset; offset += num_mods * dim_sq; - md_vols = model_coefs + offset; offset += num_mods * dim_paths; - md_drifts = model_coefs + offset; offset += num_mods * dim_paths; - md_starts = model_coefs + offset; - } - - for (m = 0; m < ro_scal->num_models; m++) { - for (i = 0; i < ro_scal->num_dates; i++) { - UINT ind = dim*i; - for (j = 0; j < dim; j++) { - REAL temp = 0.0; - - for (l = 0; l <= j; l++) { - temp += md_c[dim * j + l] * md_z[ (ind + l) << lgWARP ]; - } - temp = exp(temp * md_vols[ind + j] + md_drifts[ind + j]); - - trajWF[(ind+j) << lgWARP] = (i > 0) ? trajWF[(ind + j - dim) << lgWARP] * temp : - md_starts[ j ] * temp ; - } - } - - if ( m+1 < ro_scal->num_models ) { - md_c += dim_sq; md_vols += dim_paths; - md_drifts += dim_paths; md_starts += dim; - } - - trajWF += offset; - } // end for m - - md_z += offset; - - } // end for cur_it -} - -__kernel void mlfi_reduction_step1( - __constant LoopROScalars* ro_scal, // RO SCALARS - // RO MD INSTANCE DATA - __constant REAL* model_coefs, - // RO (GLOBAL) traj - __global REAL* inst_trajWF, - // WF (GLOBAL) traj - __global REAL* model_vhat, - __local REAL* vhat_local -) { - UINT j; - uint block_size = get_local_size(0); - int sobol_dim = ro_scal->num_under * ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - - UINT UB = ( cur_it + (1<log_chunk) < ro_scal->num_gpuits) ? - cur_it + (1<log_chunk) : ro_scal->num_gpuits ; - - { // adjust the start index - UINT id = get_global_id (0); - inst_trajWF += (id & (WARP-1)) + ( (id >> lgWARP) << (ro_scal->log_chunk+lgWARP) ) * - sobol_dim * ro_scal->num_models; - vhat_local += get_local_id(0); - } - - // initialize vhat_local to 0 - for( j = 0; j < ro_scal->num_models*block_size; j += block_size ) { - vhat_local[j] = 0.0; - } - - __constant REAL *md_discts; - __constant REAL *md_detvals; - { // compute from model_coefs - int offset; - offset = ro_scal->num_under * ( ro_scal->num_under + 1) + 2 * sobol_dim; - offset *= ro_scal->num_models; - md_discts = model_coefs + offset; - md_detvals = md_discts + ro_scal->num_models * ro_scal->num_cash_flows; - } - - for( ; cur_it < UB; cur_it++ ) { - for (j = 0; j < ro_scal->num_models; j++) { - - payoffFunction( j, ro_scal->num_under, - ro_scal->num_cash_flows, - ro_scal->num_det_pricers, - md_discts + j*ro_scal->num_cash_flows, - md_detvals+ j*ro_scal->num_det_pricers, - inst_trajWF, - vhat_local - ); - - inst_trajWF += (sobol_dim << lgWARP); - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - { - segm_scan_reg_block ( vhat_local - get_local_id(0), block_size * ro_scal->num_models, block_size ); - if( get_local_id(0) == 0 ) { - UINT glob_size = get_global_size(0)/block_size; - for ( j = 0; j < ro_scal->num_models; j ++ ) { - model_vhat[ j * glob_size + get_group_id(0) ] = - vhat_local[ (j + 1) * block_size - 1 ]; - } - } - } -} - diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl deleted file mode 100644 index 550102c..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl +++ /dev/null @@ -1,493 +0,0 @@ -/************************************/ -/************* MACROS ***************/ -/************************************/ - -#define TYPE REAL -#define FLAG uchar -#include "../../include/Utilities.cl" - -#define DUMMY 1 - -/************************************/ -/************* MACROS ***************/ -/************************************/ -//#include "Constants.h" -// -//#define underlyings(i,j) \ -// (inst_traj[(i*ro_scal->md_dim + j)]) -// -//#define DUMMY 1 - -/********************************************/ -/********** SOBOL NUMER GENERATOR ***********/ -/********************************************/ - -// TO DO: if we want to overlap kernels, then, since we reuse md_zd for traj_wf multiply also with *ro_scal->num_models - - - -__kernel void mlfi_genmatrix_uniform2 ( - __constant LoopROScalars* ro_scal, - __constant UCHAR* sobol_fix_ind, - __global int* sobol_v_dir, - __global REAL* md_zd -) { - UINT i, j, k; - UINT seq_count = ( get_global_id (0) << ro_scal->log_chunk ); - UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; - - md_zd = md_zd + (get_global_id (0) << ro_scal->log_chunk)*sobol_dim; - __global REAL* md_zd_tmp = md_zd; - - //UINT UB = min(seq_count + (1 << ro_scal->log_chunk), ro_scal->num_gpuits); - UINT UB = (seq_count + (1 << ro_scal->log_chunk) < ro_scal->num_gpuits) ? - seq_count + (1 << ro_scal->log_chunk) : ro_scal->num_gpuits ; - UB = (UB > seq_count) ? UB - seq_count : 0; - - //seq_count += ro_scal->sobol_count_ini; - - if( UB > 0 ) { - UINT gs; - // Compute the random number under the INDEPENDENT formulas - for( i = 0, j=0; j < sobol_dim; j++, i ++ ) { - UINT accum = 0; - md_zd_tmp = md_zd; - - // FIRST ITER COMPUTED INDEPENDENTLY! - gs = seq_count+1 + ro_scal->sobol_count_ini; - gs = gs ^ (gs>>1); - for(k=0; ksobol_bits; k++) { - if(gs & 1) { - accum ^= sobol_v_dir[ j*ro_scal->sobol_bits + k ]; - } - gs = gs >> 1; - } - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; - - // THE REST OF CHUNK-1 ITERATIONS COMPUTED UNDER RECURRENT FORMULA - for( k = 1; k < UB-1; k++ ) { - accum = accum ^ sobol_v_dir[ j*ro_scal->sobol_bits + sobol_fix_ind[k] ]; - - md_zd_tmp += sobol_dim; - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; - } - - // last one - gs = (seq_count + UB - 1 + ro_scal->sobol_count_ini) >> ro_scal->log_chunk; - UINT ell = ro_scal->log_chunk; - while(gs & 1) { - ell++; - gs >>= 1; - } - accum = accum ^ sobol_v_dir[j*ro_scal->sobol_bits + ell]; - md_zd_tmp += sobol_dim; - md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; - } - } // end IF (seq_count < UB) - -} - - - -/********************************************/ -/********** INV GAUSSIAN DISTRIB ************/ -/********************************************/ - - -#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ - (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ - (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) - -inline REAL small_case(REAL q) { - REAL x = 0.180625 - q * q; - return q * rat_eval( - 3.387132872796366608, - 133.14166789178437745, - 1971.5909503065514427, - 13731.693765509461125, - 45921.953931549871457, - 67265.770927008700853, - 33430.575583588128105, - 2509.0809287301226727, - - 1.0, - 42.313330701600911252, - 687.1870074920579083, - 5394.1960214247511077, - 21213.794301586595867, - 39307.89580009271061, - 28729.085735721942674, - 5226.495278852854561); -} - -inline REAL intermediate(REAL r) { - REAL x = r - 1.6; - return rat_eval( - 1.42343711074968357734, - 4.6303378461565452959, - 5.7694972214606914055, - 3.64784832476320460504, - 1.27045825245236838258, - 0.24178072517745061177, - 0.0227238449892691845833, - 7.7454501427834140764e-4, - - 1.0, - 2.05319162663775882187, - 1.6763848301838038494, - 0.68976733498510000455, - 0.14810397642748007459, - 0.0151986665636164571966, - 5.475938084995344946e-4, - 1.05075007164441684324e-9); -} - -inline REAL tail(REAL r) { - REAL x = r - 5.0; - return rat_eval( - 6.6579046435011037772, - 5.4637849111641143699, - 1.7848265399172913358, - 0.29656057182850489123, - 0.026532189526576123093, - 0.0012426609473880784386, - 2.71155556874348757815e-5, - 2.01033439929228813265e-7, - - 1.0, - 0.59983220655588793769, - 0.13692988092273580531, - 0.0148753612908506148525, - 7.868691311456132591e-4, - 1.8463183175100546818e-5, - 1.4215117583164458887e-7, - 2.04426310338993978564e-15); -} - - -__kernel void mlfi_ugaussian_Pinv_vector1( // UNTILED VERSION - __constant LoopROScalars* ro_scal, __global REAL* p - //__global REAL* p , __constant LoopROScalars* ro_scal, __local REAL* tmp_p -) { - UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; - UINT i, UB, id = get_global_id(0) << ro_scal->log_chunk; - p += id * sobol_dim; - - UB = min(id + (1<log_chunk), ro_scal->num_gpuits); - UB = (UB > id) ? UB - id : 0; - UB *= sobol_dim; - - for( i=0; i < UB; i++ ) { - REAL dp = p[i] - 0.5; - if (fabs(dp) <= 0.425) { - p[i] = small_case(dp); - } else { - REAL pp = (dp < 0.0) ? p[i] : (1.0 - p[i]); - REAL r = sqrt (- log(pp)); - REAL x = (r <= 5.0) ? intermediate(r) : tail(r); - p[i] = (dp < 0.0) ? (0.0 - x) : x; - } - } -} - -/********************************************/ -/************* BROWNIAN BRIDGE **************/ -/********************************************/ - -__kernel void mlfi_brownianbridge_wiener_path1( - __constant LoopROScalars* ro_scal, - __constant int* bb_inds, - __constant REAL* bb_data, - __global REAL* md_zd, - __global REAL* md_z -) { - __constant int *bb_li, *bb_bi, *bb_ri; - __constant REAL *bb_rw, *bb_lw, *bb_sd; - - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - UINT m, i, md_dim = ro_scal->num_under, nb_path_dates = ro_scal->num_dates; - UINT sobol_dim = ro_scal->num_under * nb_path_dates; - - UINT UB = ( (cur_it + (1<log_chunk) ) < ro_scal->num_gpuits) ? - ( cur_it + (1<log_chunk) ) : ro_scal->num_gpuits; - -// if ( ro_scal->bb_l != ro_scal->md_nb_path_dates || ro_scal->bb_l <= 0) return; - - bb_bi = bb_inds; - bb_li = bb_inds + nb_path_dates; - bb_ri = bb_inds + (nb_path_dates<<1); - - bb_sd = bb_data; - bb_lw = bb_data + nb_path_dates; - bb_rw = bb_data + (nb_path_dates<<1); - - { - UINT tmp = cur_it*sobol_dim; - md_zd = md_zd + tmp; - md_z = md_z + tmp; - } - - for( ; cur_it < UB; cur_it++ ) { - for (m=0; m < md_dim; m++) { - md_z[ (bb_bi[0]-1) * md_dim + m ] = bb_sd[0] * md_zd[m]; - - for(i=1; i < nb_path_dates; i++) { - int j = bb_li[i] - 1; - int k = bb_ri[i] - 1; - int l = bb_bi[i] - 1; - - REAL wk = md_z [k*md_dim+m]; - REAL zi = md_zd[i*md_dim+m]; - - md_z[l*md_dim+m] = (j == -1) ? - bb_rw[i] * wk + bb_sd[i] * zi : - bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * md_z[j*md_dim+m]; - } - - } - md_z += sobol_dim; - md_zd += sobol_dim; - } -} - -/**************************************************/ -/************* TRAJECTORY COMPUTATION *************/ -/**************************************************/ - -void trajectory_contract( - UINT model_num, - __constant LoopROScalars* ro_scal, - __constant REAL* pc_coefs, - __global REAL* inst_traj, - __global REAL* vhat -); - - -__kernel void mlfi_comp_traj1( - __constant LoopROScalars* ro_scal, // RO SCALARS - // RO MD INSTANCE DATA - __constant REAL* model_coefs, - // RO MODEL ATTRIBUTES -// __constant REAL* pc_coefs, -// __local REAL* buff, - // RO (GLOBAL) MD_Z - __global REAL* md_z, - // WO (GLOBAL) traj - __global REAL* trajWF -) { - UINT dim = ro_scal->num_under; - UINT dim_sq = dim*dim; - UINT dim_paths = dim*ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - - UINT UB = (cur_it+(1<log_chunk) < ro_scal->num_gpuits) ? cur_it + (1<log_chunk) : ro_scal->num_gpuits; - - trajWF += cur_it*dim_paths*ro_scal->num_models; - md_z += cur_it*dim_paths; - - for( ; cur_it < UB; cur_it++ ) { // ... - UINT m, i, j, l; - - { // 4. expand md_zd -- does not affect execution time - UINT LB = dim; - for( i = (dim_paths - 1); i >= LB; i -- ) { - md_z[i] -= md_z[i - LB]; - } - } - - __constant REAL *c, *vols, *drift, *trajRO; - { - UINT num_mods = ro_scal->num_models; - UINT offset = 0; - c = model_coefs + offset; offset += num_mods * dim_sq; - vols = model_coefs + offset; offset += num_mods * dim_paths; - drift = model_coefs + offset; offset += num_mods * dim_paths; - trajRO = model_coefs + offset; - } - - - for (m = 0; m < ro_scal->num_models; m++) { - - - -// __constant REAL* c = inst_coefs + ( ro_scal->inst_c_beg + m*dim_sq ); -// __constant REAL* vols = inst_coefs + ( ro_scal->inst_vols_beg + m*dim_paths ); -// __constant REAL* drift = inst_coefs + ( ro_scal->inst_drifts_beg + m*dim_paths ); -// __constant REAL* trajRO= inst_coefs + ( ro_scal->inst_trajRO_beg + m*dim ); - - for (i = 0; i < ro_scal->num_dates; i++) { - UINT ind = dim*i; - for (j = 0; j < dim; j++) { - REAL temp = 0.0; - - for (l = 0; l <= j; l++) { - temp += c[dim * j + l] * md_z[ (ind + l) ]; - } - temp = exp(temp * vols[ind + j] + drift[ind + j]); - - trajWF[(ind+j)] = (i > 0) ? trajWF[(ind + j - dim)] * temp : trajRO[ j ] * temp ; - } - } - - if ( m+1 < ro_scal->num_models ) { - c += dim_sq; vols += dim_paths; - drift += dim_paths; trajRO += dim; - } - - trajWF += dim_paths; - } // end for m - - md_z += dim_paths; - - } // end for cur_it -} - - - - -__kernel void mlfi_reduction_step1( - __constant LoopROScalars* ro_scal, // RO SCALARS - // RO MD INSTANCE DATA - __constant REAL* inst_coefs, - // RO MODEL ATTRIBUTES -// __constant REAL* pc_coefs, - // RO (GLOBAL) traj - __global REAL* inst_trajWF, - // WF (GLOBAL) traj - __global REAL* model_vhat, - __local REAL* vhat_local -) { - UINT j; - uint block_size = get_local_size(0); - int sobol_dim = ro_scal->num_under * ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; - - //UINT UB = min(cur_it + (1<log_chunk), ro_scal->num_gpuits); - UINT UB = ( cur_it + (1<log_chunk) < ro_scal->num_gpuits) ? - cur_it + (1<log_chunk) : ro_scal->num_gpuits ; - - { // adjust the start index - UINT id = get_global_id (0); -// vhat += ( (id >> lgWARP) << lgWARP )*ro_scal->num_contracts*ro_scal->num_models + (id & (WARP-1)); - inst_trajWF += cur_it*sobol_dim*ro_scal->num_models; - vhat_local += get_local_id(0); - } - - // initialize vhat_local to 0 - for( j = 0; j < ro_scal->num_models*block_size; j += block_size ) { - vhat_local[j] = 0.0; - } - -#if 0 - { // init vhat - UINT step_outer = ro_scal->num_contracts<num_models*step_outer; i+=step_outer) { - for( j = 0; j < step_outer; j+=WARP) { - vhat[j+i] = 0.0; - } - } - } -#endif - - __constant REAL *md_discts; - __constant REAL *md_detvals; - { // compute from model_coefs - int offset; - offset = ro_scal->num_under * ( ro_scal->num_under + 1) + 2 * sobol_dim; - offset *= ro_scal->num_models; - md_discts = inst_coefs + offset; - md_detvals = md_discts + ro_scal->num_models * ro_scal->num_cash_flows; - } - - for( ; cur_it < UB; cur_it++ ) { - //__global REAL* vhat_loc = vhat; - for (j = 0; j < ro_scal->num_models; j++) { - - payoffFunction( j, ro_scal->num_under, - ro_scal->num_cash_flows, - ro_scal->num_det_pricers, - md_discts + j*ro_scal->num_cash_flows, - md_detvals+ j*ro_scal->num_det_pricers, - inst_trajWF, - vhat_local - ); - - //inst_trajWF += (sobol_dim << lgWARP); - - inst_trajWF += sobol_dim; - //vhat_loc += (ro_scal->num_contracts << lgWARP); - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - { - segm_scan_reg_block ( vhat_local - get_local_id(0), block_size * ro_scal->num_models, block_size ); - if( get_local_id(0) == 0 ) { - UINT glob_size = get_global_size(0)/block_size; - for ( j = 0; j < ro_scal->num_models; j ++ ) { - model_vhat[ j * glob_size + get_group_id(0) ] = - vhat_local[ (j + 1) * block_size - 1 ]; - } - } - } - - -#if 0 - for( ; cur_it < UB; cur_it++ ) { - __global REAL* vhat_loc = vhat; - for (j = 0; j < ro_scal->num_models; j++) { - trajectory_contract( j, ro_scal, pc_coefs, inst_trajWF, vhat_loc ); - inst_trajWF += ro_scal->sobol_dim; - vhat_loc += (ro_scal->num_contracts << lgWARP); - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - if( get_local_id(0) == 0) { -#if 1 - UINT step_inner = ro_scal->num_contracts << lgWARP; - UINT step_outer = step_inner * ro_scal->num_models; - UINT BD = (step_outer >> lgWARP) * ro_scal->BLOCK; - UINT i, k; - for( i = 0; i < BD; i += step_outer ) { - for( j = 0; j < step_outer; j += step_inner ) { - for( k = j; k < j+step_inner; k += WARP ) { - for( cur_it = k+(i==0? 1 : 0); cur_it < k+WARP; cur_it++ ) { - vhat[k] += vhat[i+cur_it]; - } - } - } - } -#else - UINT step_j = ro_scal->num_contracts<num_models*step_j; - for (j = 0; j < BD_j; j+=step_j) { // for all instances - for(cur_it=0; cur_it < step_j; cur_it+=WARP) { // for all contracts - UINT i; - for(i=1; inum_cash_flows+date_index]; - //pc_coefs[ro_scal->pc_discounts_beg + model_num*ro_scal->num_cash_flows+date_index]; -} -*/ diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile deleted file mode 100644 index c1c5d4c..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -include setup.mk - -ifndef ($(HAVE_GPU)) -include platform.mk -endif - -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ - -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ - -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ - -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) - -SOURCES_CPP =GenPricing.cpp -HELPERS =StructGPU.h Constants.h Optimizations.h ParseInput.h -OBJECTS =GenPricing.o -EXECUTABLE =GenPricing - - -ifeq ($(HAVE_GPU),1) -#g++ -I. -I/usr/local/cuda/include -O3 NordeaVect.cpp -lOpenCL -default: gpu -else -# cannot build this one... but proceed (return 0) -no-gpu: - @echo "$(HAVE_GPU) \n*** No GPU configured, cannot build `pwd` ***\n" -endif - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -gpu: $(OBJECTS) $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) - -# The CPU version is in: ../Orig_COpenMP. This folder is GPU only! -cpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) - -clean: - rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt - @# clean nVidia compiler cache - rm -rf $(HOME)/.nv/ComputeCache/* - diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h b/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h deleted file mode 100644 index 146abf5..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h +++ /dev/null @@ -1,611 +0,0 @@ -#ifndef GPU_HELPERS -#define GPU_HELPERS - -#include "Optimizations.h" -#include "SDK_stub.h" - -#if (_OPTIMIZATION_USE_FLOATS) - #define TILE GPU_TILE -#else - #define TILE GPU_TILE/2 -#endif - -/****************************/ -/*** GPU-Allocated Arrays ***/ -/****************************/ -struct oclLoopArrays { - - /* RO scalars */ - cl_mem ro_scals; - - /* sobol direction vector; RO */ - cl_mem sobol_dirvcts; // UINT[sobol_bit_count][num_under*num_dates]; - cl_mem sobol_fix_ind; // UCHAR[chunk-1] - - /* Brownian Bridge data RO */ - cl_mem bb_inds; // UINT[3][num_dates] - cl_mem bb_data; // REAL[3][num_dates] - - /* MD instance data; RO */ - cl_mem md_c; // Includes all arrays bellow: -// cl_mem md_c // RO; REAL[num_models][num_under^2] -// cl_mem md_vols; // RO; REAL[num_models][num_under*num_dates] -// cl_mem md_drifts; // RO; REAL[num_models][num_under*num_dates] -// cl_mem md_starts; // RO; REAL[num_models][num_under] -// cl_mem md_discts; // REAL[num_models][num_cash_flows ] -// cl_mem md_detvals; // REAL[num_models][num_det_pricers] - - /* FOR VECTORIZED VERSION */ - cl_mem md_zd; // RW: REAL[num_gpuits]x[num_under*num_dates] - cl_mem md_z; // RW: REAL[num_gpuits]x[num_models]x[num_under*num_dates] - - /* global array to be reduced on CPU; WO */ - cl_mem model_vhat; // WO; ~ [num_models]x[num_contracts]x[num_iter/(chunk*BLOCK)] - - /*** local tiled space ***/ - cl_mem local_space; - - void cleanupPRIV() { - clReleaseMemObject(ro_scals); - clReleaseMemObject(sobol_dirvcts); - clReleaseMemObject(sobol_fix_ind); - clReleaseMemObject(bb_inds); - clReleaseMemObject(bb_data); - clReleaseMemObject(md_c); - clReleaseMemObject(model_vhat); - } - void cleanupVECT() { - cleanupPRIV(); - clReleaseMemObject(md_z ); - clReleaseMemObject(md_zd); - } -}; - -/*********************************/ -/*** Math-Utility Functions ***/ -/*********************************/ - -UINT logNextPow2(UINT n) { - UINT ret = 1; - UINT logret = 0; - while(n>ret) { - ret = ret << 1; - logret += 1; - } - return logret; -} - -UINT prevMultipleOf(UINT n, UINT mul) { - if(n % mul == 0) return n; - UINT res = 0; - while(res <= n) res += mul; - return res - mul; -} - -/*********************************/ -/*** GPU-Glue Helper Functions ***/ -/*********************************/ - -enum GPU_KERNEL { PRIV, VECT }; - -GPU_KERNEL -priv_or_vect_kernel(const LoopROScalars& ro_scal) { -#if (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 1) - return VECT; -#elif (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 2) - return PRIV; -#else - UINT threshold = 16; - bool is_priv = (ro_scal.num_under*ro_scal.num_dates+ro_scal.num_models <= threshold); - fprintf(stderr, "\nCOST MODEL THRESHOLD: %u, PRIV_KERNEL: %d\n", threshold, (int)is_priv); - return (is_priv) ? PRIV : VECT; -#endif -} - -const char* -makeGPUprogPreamble( - const LoopROScalars& ro_scal, - const GPU_KERNEL & kernel_type -) { - const char* preamble = (ro_scal.contract == 1 && kernel_type == VECT) ? - "#define VECT_KERNEL\n#include \"ContractDefs/SmallContract.cl\"\n\n" : - (ro_scal.contract == 1 && kernel_type == PRIV) ? - "#include \"ContractDefs/SmallContract.cl\"\n\n" : - (ro_scal.contract == 2 && kernel_type == VECT) ? - "#define VECT_KERNEL\n#include \"ContractDefs/MediumContract.cl\"\n\n" : - (ro_scal.contract == 2 && kernel_type == PRIV) ? - "#include \"ContractDefs/MediumContract.cl\"\n\n" : - (ro_scal.contract == 3 && kernel_type == VECT) ? - "#define VECT_KERNEL\n#include \"ContractDefs/LargeContract.cl\"\n\n" : - (ro_scal.contract == 3 && kernel_type == PRIV) ? - "#include \"ContractDefs/LargeContract.cl\"\n\n" : NULL; - assert(preamble && "Invalid Contract Number (should be 1, 2 or 3) OR Invalid kernel type (PRIV or VECT)\n"); - return preamble; -} - - -UINT -getWorkSize(const UINT& num_iter, const UINT& chunk, const UINT& block) { - UINT tmp_rem = num_iter % chunk; - UINT res = (tmp_rem == 0) ? - (num_iter / chunk) : - ((num_iter / chunk) + 1) ; - - if(res % block == 0) return res; - - res = (res / block) * block + block; - return res; -} - -int -discriminate_cost_model( LoopROScalars& ro_scal, cl_device_id device, const GPU_KERNEL kernel) { - bool is_priv = (kernel == PRIV); - UINT THRESHOLD; - cl_uint tot_cuda_cores = 0; - - UINT size_vct = ro_scal.num_under * ro_scal.num_dates; - - ro_scal.logBLOCK = 7; - ro_scal.BLOCK = 1 << ro_scal.logBLOCK; - - // If not-enough GPU resources => sequentialize - // the loop into big chunks that execute on GPU. - if(!is_priv) { - // get device memory size info - cl_ulong glob_mem_size; - clGetDeviceInfo(device,CL_DEVICE_GLOBAL_MEM_SIZE,sizeof(glob_mem_size),&glob_mem_size,NULL); - { // check global mem matches the user-declared one - const size_t USER_MEM = ((size_t)GPU_GLB_MEM) << 30; - const size_t ub = static_cast( USER_MEM * 101.0 / 100.0 ); - const size_t lb = static_cast( USER_MEM * 99.0 / 100.0 ); - if ( !(glob_mem_size >= lb && glob_mem_size <= ub) ) { - fprintf(stderr, "WARNING! Querried GPU global memory %lu DIFFERS from what user declared: [%ld,%ld]!\n", - glob_mem_size, lb, ub); - glob_mem_size = static_cast(USER_MEM); - fprintf(stderr, "Using user-declared size for global memory: %lu\n", glob_mem_size); - } - } - - // check if there is enough memory - UINT perit_mem_size = size_vct*( ro_scal.num_models + 1 ) + ro_scal.num_models; - perit_mem_size *= sizeof(REAL); - - UINT max_mc_iter_num = ( (glob_mem_size * 3)/4 ) / perit_mem_size; - - UINT BLOCK = ro_scal.BLOCK; - if(max_mc_iter_num % BLOCK != 0) - max_mc_iter_num = (max_mc_iter_num / BLOCK)*BLOCK + BLOCK; - - max_mc_iter_num = prevMultipleOf(max_mc_iter_num, ro_scal.chunk); - - ro_scal.num_gpuits = MIN(max_mc_iter_num, ro_scal.num_mcits); - -// fprintf(stderr, "# of total iters: %u, # of gpu iters: %u, chunk: %u\n", -// ro_scal.num_mcits, ro_scal.num_gpuits, ro_scal.chunk ); - } else { - ro_scal.num_gpuits = ro_scal.num_mcits; - } - - { - cl_uint compute_units; - clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, - sizeof(compute_units), &compute_units, NULL); - cl_uint comp_capabil_major, comp_capabil_minor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, - sizeof(cl_uint), &comp_capabil_major, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, - sizeof(cl_uint), &comp_capabil_minor, NULL); - tot_cuda_cores = compute_units * - ConvertSMVer2CoresCopy(comp_capabil_major, comp_capabil_minor); - - if( tot_cuda_cores != GPU_CORES ) { - fprintf(stderr, "WARNING! Querried GPU number of cores %u DIFFERS from what user declared: %d!\n", - tot_cuda_cores, GPU_CORES ); - tot_cuda_cores = GPU_CORES; - fprintf(stderr, "Using user-declared GPU number of cores: %u\n", tot_cuda_cores); - } - - UINT div = (1 << logNextPow2(tot_cuda_cores)) * 64; - ro_scal.log_chunk = logNextPow2(ro_scal.num_gpuits / div ); // was div*2 - ro_scal.log_chunk = MIN(ro_scal.log_chunk, logMAX_CHUNK); - if(ro_scal.log_chunk <= 3) ro_scal.log_chunk++; - } - - ro_scal.chunk = 1 << ro_scal.log_chunk; - -// fprintf(stderr, "\n\nCOST MODEL COMPUTED: MC_ITERS: %u, MC_TOT_ITERS: %u, CHUNK: %u, BLOCK: %u\n\n", -// ro_scal.num_gpuits, ro_scal.num_mcits, ro_scal.chunk, ro_scal.BLOCK); - - return tot_cuda_cores; -} - -/*********************************/ -/*** Allocating GPU Buffers & ***/ -/***running the Private Kernels***/ -/*********************************/ - -REAL* -oclAllocArrays_PrivKernel ( - oclLoopArrays& ocl_arrs, - cl_context cxGPUContext, - cl_command_queue& cqCommandQueue, - cl_int& ciErr, - const LoopROScalars& ro_scals, - const SobolArrays & sob_arrs, - const BrowBridgeArrays& bb_arrs, - const ModelArrays & md_arrs -) { - cl_int ciErr2; - size_t cur_size; - REAL* glb_vhat = NULL; - - { // 1. RO scalars - cur_size = sizeof(LoopROScalars); - ocl_arrs.ro_scals = clCreateBuffer( - cxGPUContext, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 - ); - - ciErr = ciErr2; - ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, - cur_size, &ro_scals, 0, NULL, NULL); - } - - { // 2. Sobol RO Arrays - const SobolArrays& cpu_arrs = sob_arrs; - - cur_size = (UINT) ro_scals.num_under * ro_scals.num_dates * - ro_scals.sobol_bits * sizeof(UINT); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(sobol_dirvcts); - - cur_size+= ro_scals.chunk * sizeof(UCHAR); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(sobol_fix_ind); - } - - { // 3. BROWNIAN BRIDGE RO indirect arrays and data arrays - const BrowBridgeArrays& cpu_arrs = bb_arrs; - - cur_size = 3*ro_scals.num_dates*sizeof(UINT); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(bb_inds); - - cur_size = 3*ro_scals.num_dates*sizeof(REAL); - CREATE_AND_ENQUEUE_RO_CL_BUFFER(bb_data); - } - - { // 4. Various RO Model Data Arrays - const ModelArrays& cpu_arrs = md_arrs; - - cur_size = ro_scals.num_under * ( ro_scals.num_under + 2*ro_scals.num_dates + 1); - cur_size += ro_scals.num_cash_flows + ro_scals.num_det_pricers; - cur_size *= ro_scals.num_models * sizeof(REAL); - - CREATE_AND_ENQUEUE_RO_CL_BUFFER(md_c); - } - - { // 5. Finally, the WO Partial Result - //red_sz = getGlobalRedArrSize( ro_scal->mc_iter_num, ro_scal->CHUNK*ro_scal->BLOCK ); - cur_size = getWorkSize(ro_scals.num_gpuits, ro_scals.chunk, ro_scals.BLOCK) / ro_scals.BLOCK; - cur_size *= ro_scals.num_models * sizeof(REAL); - - glb_vhat = (REAL*)malloc(cur_size); - ocl_arrs.model_vhat = clCreateBuffer( - cxGPUContext, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, - cur_size, glb_vhat, &ciErr2 - ); - ciErr |= ciErr2; - } - - // 2. the rest: priv_arr->sobol_last_num_vec/md_zd/inst_trajWF - // are implemented as __local (private) hence do not require - // global memory allocation. - - oclCheckError(ciErr, CL_SUCCESS); - - return glb_vhat; -} - - -void -runGPU_PRIV( - const LoopROScalars& ro_scals, - REAL* glb_vhat, - oclLoopArrays& dev_arr, - cl_command_queue& cqCommandQueue, - cl_program& cpProgram, - size_t* globalWorkSize, - size_t* localWorkSize -) { - cl_kernel ckGenPricing = NULL; // OpenCL kernel - cl_int ciErr1, ciErr2; - - size_t counter = 0, priv_sz = 0; // ro_scals - const int PRIV_MULT = sizeof(REAL)*ro_scals.BLOCK; - - ckGenPricing = clCreateKernel(cpProgram, "payoffGPU", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - // 1. RO SCALARS struct - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.ro_scals ); - - // 2. RO SOBOL ARR // - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.sobol_dirvcts); - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.sobol_fix_ind); - - // 3. RO BROWNIAN BRIDGE // - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.bb_inds); - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.bb_data); - - // 4. RO MD INSTANCE DATA // - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.md_c); - - // 5. GLOBAL WO Array // - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.model_vhat ); - - // 6. LOCAL (PRIVATE ARRAYS) MD_Z - priv_sz = PRIV_MULT*ro_scals.num_under*ro_scals.num_dates; - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, priv_sz, NULL); - - // 7. LOCAL (PRIVATE ARRAY) VHAT - priv_sz = PRIV_MULT * ro_scals.num_models; - ciErr1 |= clSetKernelArg(ckGenPricing, counter++, priv_sz, NULL); // model_vhat (the private one) - - oclCheckError(ciErr1, CL_SUCCESS); - - // 8. ENQUEUE KERNEL!!! // - ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckGenPricing, 1, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL); - oclCheckError(ciErr1, CL_SUCCESS); - - // 9. FINALLY, WRITE BACK!!! // - priv_sz = (globalWorkSize[0]/ro_scals.BLOCK)*ro_scals.num_models*sizeof(REAL); - - ciErr1 |= clEnqueueReadBuffer(cqCommandQueue, dev_arr.model_vhat, CL_TRUE, 0, - priv_sz, glb_vhat, 0, NULL, NULL); - oclCheckError(ciErr1, CL_SUCCESS); - - clReleaseKernel(ckGenPricing); -} - - -void reduceVHAT_CPU(const LoopROScalars& ro_scals, REAL* vhat, double* cpu_vhat ) { - // final reduction on CPU!!! - UINT SZ = getWorkSize(ro_scals.num_gpuits, ro_scals.chunk, ro_scals.BLOCK) / ro_scals.BLOCK; - - for(int ii = 0; ii 4" ); - UINT priv_sz = TILE * ro_scals.BLOCK * sizeof(REAL); - ciErr1 |= clSetKernelArg(ckGenPricing_traj, counter++, priv_sz, NULL); // local_space! - } -#endif - - ciErr1 |= clSetKernelArg(ckGenPricing_traj, counter++, sizeof(cl_mem), (void*)&dev_arr.md_z ); - ciErr1 |= clSetKernelArg(ckGenPricing_traj, counter++, sizeof(cl_mem), (void*)&dev_arr.md_zd); - - ciErr1 |= clEnqueueNDRangeKernel( cqCommandQueue, ckGenPricing_traj, 1, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - - - oclCheckError(ciErr1, CL_SUCCESS); - } - - { // final reduction! - //shrLog("Call Compute Reduction kernel on GPU...\n\n"); - counter = 0; - ckGenPricing_finred = clCreateKernel(cpProgram, "mlfi_reduction_step1", &ciErr1); - oclCheckError(ciErr1, CL_SUCCESS); - - ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.ro_scals ); - ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.md_c ); - - ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.md_zd ); - ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.model_vhat ); - - assert( (ro_scals.num_models <= TILE) && "Illegal dataset: num_models > 8" ); - UINT priv_sz = TILE * ro_scals.BLOCK * sizeof(REAL); - ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, priv_sz, NULL); // local_space! - - ciErr1 |= clEnqueueNDRangeKernel( cqCommandQueue, ckGenPricing_finred, 1, NULL, - globalWorkSize, localWorkSize, 0, NULL, NULL ); - oclCheckError(ciErr1, CL_SUCCESS); - - ciErr1 |= clEnqueueReadBuffer( cqCommandQueue, dev_arr.model_vhat, CL_TRUE, 0, - globalWorkSize[0] * ro_scals.num_models * sizeof(REAL), - glb_vhat, 0, NULL, NULL); - oclCheckError(ciErr1, CL_SUCCESS); - } - - clReleaseKernel(ckGenPricing_sobol ); - clReleaseKernel(ckGenPricing_invg ); - clReleaseKernel(ckGenPricing_brown ); - clReleaseKernel(ckGenPricing_traj ); - clReleaseKernel(ckGenPricing_finred); -} - -#endif // GPU_HELPERS - diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/instantiate b/benchmarks/OptionPricing/implementations/cpp_opencl/instantiate deleted file mode 100755 index 914300f..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/instantiate +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -e - -cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/include/ParserC.h . -cp $FINPAR_LIB_DIR/include/Util.h . -cp $FINPAR_LIB_DIR/include/SDK_stub.h . -cp $FINPAR_LIB_DIR/include/Utilities.cl . -cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . -cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . -cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . -cp -r $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/*cl $FINPAR_IMPLEMENTATION/Makefile $FINPAR_IMPLEMENTATION/ContractDefs . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run < input.data +#$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data $HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk -NCORES=$($HIPERMARK_LIB_DIR/json_get.py $HIPERMARK_PLATFORM num_cores) +#NCORES=$($HIPERMARK_LIB_DIR/json_get.py $HIPERMARK_PLATFORM num_cores) -cat > run < run < $DATASET_NAME +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/Contracts.h b/benchmarks/OptionPricing/implementations/cpp_sequential/Contracts.h deleted file mode 100644 index 9058c84..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/Contracts.h +++ /dev/null @@ -1,1267 +0,0 @@ -#ifndef CONTRACTS_CODE -#define CONTRACTS_CODE - -#define underlyings(i,j) \ - (inst_traj[i*num_under + j]) - -inline -void trajectory_inner( - const UINT& num_cash_flows, - const UINT& model_ind, // the model index - const UINT& disct_index,// index of the discount - const REAL& amount, // update with amount - const REAL* md_discts, // [model_num][num_cash_flow] discounts - double* vhat // [model_num] Accumulated per-model price -) { -#if 0 - UINT prod = ro_scal->num_contracts * ro_scal->inst_num; - UINT index = model_num*ro_scal->num_contracts + contract_number; - index += cur_iter*prod; -#endif - UINT ind = disct_index + model_ind*num_cash_flows; - vhat[model_ind] += (amount * md_discts[ind]); - - //printf("Updating vhat with: %f %f \n", amount, md_discts[ind] ); - - //instance *inst = (instance*) model->model_data; - //inst->vhat[contract_number] += amount * inst->discounts[date_index]; -} - -inline -void trajectory_contract1( // SIMPLE - const UINT& model_num, // the index of the current model - const UINT& num_under, // the number of underlyings - const UINT& num_cash_flows, - const UINT& num_pricers,// the number of deterministic procers - const REAL* md_discts, // [num_models][num_cash_flows] discounts - const REAL* md_detvals, // [num_models, num_det_pricers] pricers - const REAL* inst_traj, // [num_dates, num_under] current trajectory - double* vhat // [model_num] Accumulated per-model price - -) { - REAL amount = ((underlyings(0,0)) - 4000.0) * md_detvals[model_num*num_pricers]; - amount = fmax(0.0, amount); - trajectory_inner( num_cash_flows, model_num, 0, amount, md_discts, vhat ); -} - -inline -void trajectory_contract2( // WORST OFF - const UINT& model_num, // the index of the current model - const UINT& num_under, // the number of underlyings - const UINT& num_cash_flows, - const UINT& num_pricers,// the number of deterministic procers - const REAL* md_discts, // [num_models][num_cash_flows] discounts - const REAL* md_detvals, // [num_models, num_det_pricers] pricers - const REAL* inst_traj, // [num_dates, num_under] current trajectory - double* vhat // [model_num] Accumulated per-model price -) { - double x50; - - if ((1. <= fmin((underlyings(0,1) / 11840.), fmin((underlyings(0,2) / 1200.), (underlyings(0,0) / 3758.05))))) goto L21; - if ((1. <= fmin((underlyings(1,1) / 11840.), fmin((underlyings(1,2) / 1200.), (underlyings(1,0) / 3758.05))))) goto L22; - if ((1. <= fmin((underlyings(2,1) / 11840.), fmin((underlyings(2,2) / 1200.), (underlyings(2,0) / 3758.05))))) goto L23; - if ((1. <= fmin((underlyings(3,1) / 11840.), fmin((underlyings(3,2) / 1200.), (underlyings(3,0) / 3758.05))))) goto L24; - x50=fmin((underlyings(4,1) / 11840.), fmin((underlyings(4,2) / 1200.), (underlyings(4,0) / 3758.05))); - - //model->notify_cash_flow(model, 0, 1000., 4 /*2017-02-03, 2017-01-27, EUR*/); - trajectory_inner( num_cash_flows, model_num, 4, 1000., md_discts, vhat ); - - if ((1. <= x50)) goto L25; - if ((0.75 < x50)) return; - - //model->notify_cash_flow(model, 0, (-(1000. * (1. - x50))), 4 /*2017-02-03, 2017-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 4, (-(1000. * (1. - x50))), md_discts, vhat ); return; -L25: - //model->notify_cash_flow(model, 0, 750., 4 /*2017-02-03, 2017-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 4, 750., md_discts, vhat ); return; -L24: - //model->notify_cash_flow(model, 0, 1600., 3 /*2016-02-03, 2016-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 3, 1600., md_discts, vhat ); return; -L23: - //model->notify_cash_flow(model, 0, 1450., 2 /*2015-02-03, 2015-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 2, 1450., md_discts, vhat ); return; -L22: - //model->notify_cash_flow(model, 0, 1300., 1 /*2014-02-03, 2014-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 1, 1300., md_discts, vhat ); return; -L21: - //model->notify_cash_flow(model, 0, 1150., 0 /*2013-02-01, 2013-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 0, 1150., md_discts, vhat ); return; -} - - - - -// LENGTHY CONTRACT - -inline -void trajectory_contract3( // BARRIER - const UINT& model_num, // the index of the current model - const UINT& num_under, // the number of underlyings - const UINT& num_cash_flows, - const UINT& num_pricers,// the number of deterministic procers - const REAL* md_discts, // [num_models][num_scash_flow] discounts - const REAL* md_detvals, // [num_models, num_det_pricers] pricers - const REAL* inst_traj, // [num_dates, num_under] current trajectory - double* vhat // [model_num] Accumulated per-model price -) { - //assert(model_num==0 && "NUM MODELS > 1"); - UINT x3309; - - if ((underlyings(0,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(0,2) <= 840.)) goto L50; - if ((underlyings(0,1) <= 8288.)) goto L50; - if ((underlyings(1,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(1,2) <= 840.)) goto L50; - if ((underlyings(1,1) <= 8288.)) goto L50; - if ((underlyings(2,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(2,2) <= 840.)) goto L50; - if ((underlyings(2,1) <= 8288.)) goto L50; - if ((underlyings(3,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(3,2) <= 840.)) goto L50; - if ((underlyings(3,1) <= 8288.)) goto L50; - if ((underlyings(4,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(4,2) <= 840.)) goto L50; - if ((underlyings(4,1) <= 8288.)) goto L50; - if ((underlyings(5,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(5,2) <= 840.)) goto L50; - if ((underlyings(5,1) <= 8288.)) goto L50; - if ((underlyings(6,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(6,2) <= 840.)) goto L50; - if ((underlyings(6,1) <= 8288.)) goto L50; - if ((underlyings(7,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(7,2) <= 840.)) goto L50; - if ((underlyings(7,1) <= 8288.)) goto L50; - if ((underlyings(8,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(8,2) <= 840.)) goto L50; - if ((underlyings(8,1) <= 8288.)) goto L50; - if ((underlyings(9,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(9,2) <= 840.)) goto L50; - if ((underlyings(9,1) <= 8288.)) goto L50; - if ((underlyings(10,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(10,2) <= 840.)) goto L50; - if ((underlyings(10,1) <= 8288.)) goto L50; - if ((underlyings(11,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(11,2) <= 840.)) goto L50; - if ((underlyings(11,1) <= 8288.)) goto L50; - if ((underlyings(12,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(12,2) <= 840.)) goto L50; - if ((underlyings(12,1) <= 8288.)) goto L50; - if ((underlyings(13,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(13,2) <= 840.)) goto L50; - if ((underlyings(13,1) <= 8288.)) goto L50; - if ((underlyings(14,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(14,2) <= 840.)) goto L50; - if ((underlyings(14,1) <= 8288.)) goto L50; - if ((underlyings(15,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(15,2) <= 840.)) goto L50; - if ((underlyings(15,1) <= 8288.)) goto L50; - if ((underlyings(16,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(16,2) <= 840.)) goto L50; - if ((underlyings(16,1) <= 8288.)) goto L50; - if ((underlyings(17,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(17,2) <= 840.)) goto L50; - if ((underlyings(17,1) <= 8288.)) goto L50; - if ((underlyings(18,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(18,2) <= 840.)) goto L50; - if ((underlyings(18,1) <= 8288.)) goto L50; - if ((underlyings(19,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(19,2) <= 840.)) goto L50; - if ((underlyings(19,1) <= 8288.)) goto L50; - if ((underlyings(20,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(20,2) <= 840.)) goto L50; - if ((underlyings(20,1) <= 8288.)) goto L50; - if ((underlyings(21,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(21,2) <= 840.)) goto L50; - if ((underlyings(21,1) <= 8288.)) goto L50; - if ((underlyings(22,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(22,2) <= 840.)) goto L50; - if ((underlyings(22,1) <= 8288.)) goto L50; - if ((underlyings(23,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(23,2) <= 840.)) goto L50; - if ((underlyings(23,1) <= 8288.)) goto L50; - if ((underlyings(24,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(24,2) <= 840.)) goto L50; - if ((underlyings(24,1) <= 8288.)) goto L50; - if ((underlyings(25,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(25,2) <= 840.)) goto L50; - if ((underlyings(25,1) <= 8288.)) goto L50; - if ((underlyings(26,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(26,2) <= 840.)) goto L50; - if ((underlyings(26,1) <= 8288.)) goto L50; - if ((underlyings(27,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(27,2) <= 840.)) goto L50; - if ((underlyings(27,1) <= 8288.)) goto L50; - if ((underlyings(28,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(28,2) <= 840.)) goto L50; - if ((underlyings(28,1) <= 8288.)) goto L50; - if ((underlyings(29,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(29,2) <= 840.)) goto L50; - if ((underlyings(29,1) <= 8288.)) goto L50; - if ((underlyings(30,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(30,2) <= 840.)) goto L50; - if ((underlyings(30,1) <= 8288.)) goto L50; - if ((underlyings(31,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(31,2) <= 840.)) goto L50; - if ((underlyings(31,1) <= 8288.)) goto L50; - if ((underlyings(32,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(32,2) <= 840.)) goto L50; - if ((underlyings(32,1) <= 8288.)) goto L50; - if ((underlyings(33,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(33,2) <= 840.)) goto L50; - if ((underlyings(33,1) <= 8288.)) goto L50; - if ((underlyings(34,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(34,2) <= 840.)) goto L50; - if ((underlyings(34,1) <= 8288.)) goto L50; - if ((underlyings(35,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(35,2) <= 840.)) goto L50; - if ((underlyings(35,1) <= 8288.)) goto L50; - if ((underlyings(36,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(36,2) <= 840.)) goto L50; - if ((underlyings(36,1) <= 8288.)) goto L50; - if ((underlyings(37,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(37,2) <= 840.)) goto L50; - if ((underlyings(37,1) <= 8288.)) goto L50; - if ((underlyings(38,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(38,2) <= 840.)) goto L50; - if ((underlyings(38,1) <= 8288.)) goto L50; - if ((underlyings(39,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(39,2) <= 840.)) goto L50; - if ((underlyings(39,1) <= 8288.)) goto L50; - if ((underlyings(40,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(40,2) <= 840.)) goto L50; - if ((underlyings(40,1) <= 8288.)) goto L50; - if ((underlyings(41,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(41,2) <= 840.)) goto L50; - if ((underlyings(41,1) <= 8288.)) goto L50; - if ((underlyings(42,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(42,2) <= 840.)) goto L50; - if ((underlyings(42,1) <= 8288.)) goto L50; - if ((underlyings(43,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(43,2) <= 840.)) goto L50; - if ((underlyings(43,1) <= 8288.)) goto L50; - if ((underlyings(44,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(44,2) <= 840.)) goto L50; - if ((underlyings(44,1) <= 8288.)) goto L50; - if ((underlyings(45,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(45,2) <= 840.)) goto L50; - if ((underlyings(45,1) <= 8288.)) goto L50; - if ((underlyings(46,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(46,2) <= 840.)) goto L50; - if ((underlyings(46,1) <= 8288.)) goto L50; - if ((underlyings(47,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(47,2) <= 840.)) goto L50; - if ((underlyings(47,1) <= 8288.)) goto L50; - if ((underlyings(48,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(48,2) <= 840.)) goto L50; - if ((underlyings(48,1) <= 8288.)) goto L50; - if ((underlyings(49,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(49,2) <= 840.)) goto L50; - if ((underlyings(49,1) <= 8288.)) goto L50; - if ((underlyings(50,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(50,2) <= 840.)) goto L50; - if ((underlyings(50,1) <= 8288.)) goto L50; - if ((underlyings(51,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(51,2) <= 840.)) goto L50; - if ((underlyings(51,1) <= 8288.)) goto L50; - if ((underlyings(52,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(52,2) <= 840.)) goto L50; - if ((underlyings(52,1) <= 8288.)) goto L50; - if ((underlyings(53,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(53,2) <= 840.)) goto L50; - if ((underlyings(53,1) <= 8288.)) goto L50; - if ((underlyings(54,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(54,2) <= 840.)) goto L50; - if ((underlyings(54,1) <= 8288.)) goto L50; - if ((underlyings(55,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(55,2) <= 840.)) goto L50; - if ((underlyings(55,1) <= 8288.)) goto L50; - if ((underlyings(56,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(56,2) <= 840.)) goto L50; - if ((underlyings(56,1) <= 8288.)) goto L50; - if ((underlyings(57,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(57,2) <= 840.)) goto L50; - if ((underlyings(57,1) <= 8288.)) goto L50; - if ((underlyings(58,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(58,2) <= 840.)) goto L50; - if ((underlyings(58,1) <= 8288.)) goto L50; - if ((underlyings(59,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(59,2) <= 840.)) goto L50; - if ((underlyings(59,1) <= 8288.)) goto L50; - if ((underlyings(60,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(60,2) <= 840.)) goto L50; - if ((underlyings(60,1) <= 8288.)) goto L50; - if ((underlyings(61,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(61,2) <= 840.)) goto L50; - if ((underlyings(61,1) <= 8288.)) goto L50; - if ((underlyings(62,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(62,2) <= 840.)) goto L50; - if ((underlyings(62,1) <= 8288.)) goto L50; - if ((underlyings(63,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(63,2) <= 840.)) goto L50; - if ((underlyings(63,1) <= 8288.)) goto L50; - if ((underlyings(64,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(64,2) <= 840.)) goto L50; - if ((underlyings(64,1) <= 8288.)) goto L50; - if ((underlyings(65,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(65,2) <= 840.)) goto L50; - if ((underlyings(65,1) <= 8288.)) goto L50; - if ((underlyings(66,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(66,2) <= 840.)) goto L50; - if ((underlyings(66,1) <= 8288.)) goto L50; - if ((underlyings(67,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(67,2) <= 840.)) goto L50; - if ((underlyings(67,1) <= 8288.)) goto L50; - if ((underlyings(68,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(68,2) <= 840.)) goto L50; - if ((underlyings(68,1) <= 8288.)) goto L50; - if ((underlyings(69,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(69,2) <= 840.)) goto L50; - if ((underlyings(69,1) <= 8288.)) goto L50; - if ((underlyings(70,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(70,2) <= 840.)) goto L50; - if ((underlyings(70,1) <= 8288.)) goto L50; - if ((underlyings(71,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(71,2) <= 840.)) goto L50; - if ((underlyings(71,1) <= 8288.)) goto L50; - if ((underlyings(72,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(72,2) <= 840.)) goto L50; - if ((underlyings(72,1) <= 8288.)) goto L50; - if ((underlyings(73,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(73,2) <= 840.)) goto L50; - if ((underlyings(73,1) <= 8288.)) goto L50; - if ((underlyings(74,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(74,2) <= 840.)) goto L50; - if ((underlyings(74,1) <= 8288.)) goto L50; - if ((underlyings(75,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(75,2) <= 840.)) goto L50; - if ((underlyings(75,1) <= 8288.)) goto L50; - if ((underlyings(76,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(76,2) <= 840.)) goto L50; - if ((underlyings(76,1) <= 8288.)) goto L50; - if ((underlyings(77,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(77,2) <= 840.)) goto L50; - if ((underlyings(77,1) <= 8288.)) goto L50; - if ((underlyings(78,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(78,2) <= 840.)) goto L50; - if ((underlyings(78,1) <= 8288.)) goto L50; - if ((underlyings(79,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(79,2) <= 840.)) goto L50; - if ((underlyings(79,1) <= 8288.)) goto L50; - if ((underlyings(80,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(80,2) <= 840.)) goto L50; - if ((underlyings(80,1) <= 8288.)) goto L50; - if ((underlyings(81,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(81,2) <= 840.)) goto L50; - if ((underlyings(81,1) <= 8288.)) goto L50; - if ((underlyings(82,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(82,2) <= 840.)) goto L50; - if ((underlyings(82,1) <= 8288.)) goto L50; - if ((underlyings(83,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(83,2) <= 840.)) goto L50; - if ((underlyings(83,1) <= 8288.)) goto L50; - if ((underlyings(84,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(84,2) <= 840.)) goto L50; - if ((underlyings(84,1) <= 8288.)) goto L50; - if ((underlyings(85,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(85,2) <= 840.)) goto L50; - if ((underlyings(85,1) <= 8288.)) goto L50; - if ((underlyings(86,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(86,2) <= 840.)) goto L50; - if ((underlyings(86,1) <= 8288.)) goto L50; - if ((underlyings(87,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(87,2) <= 840.)) goto L50; - if ((underlyings(87,1) <= 8288.)) goto L50; - if ((underlyings(88,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(88,2) <= 840.)) goto L50; - if ((underlyings(88,1) <= 8288.)) goto L50; - if ((underlyings(89,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(89,2) <= 840.)) goto L50; - if ((underlyings(89,1) <= 8288.)) goto L50; - if ((underlyings(90,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(90,2) <= 840.)) goto L50; - if ((underlyings(90,1) <= 8288.)) goto L50; - if ((underlyings(91,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(91,2) <= 840.)) goto L50; - if ((underlyings(91,1) <= 8288.)) goto L50; - if ((underlyings(92,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(92,2) <= 840.)) goto L50; - if ((underlyings(92,1) <= 8288.)) goto L50; - if ((underlyings(93,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(93,2) <= 840.)) goto L50; - if ((underlyings(93,1) <= 8288.)) goto L50; - if ((underlyings(94,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(94,2) <= 840.)) goto L50; - if ((underlyings(94,1) <= 8288.)) goto L50; - if ((underlyings(95,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(95,2) <= 840.)) goto L50; - if ((underlyings(95,1) <= 8288.)) goto L50; - if ((underlyings(96,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(96,2) <= 840.)) goto L50; - if ((underlyings(96,1) <= 8288.)) goto L50; - if ((underlyings(97,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(97,2) <= 840.)) goto L50; - if ((underlyings(97,1) <= 8288.)) goto L50; - if ((underlyings(98,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(98,2) <= 840.)) goto L50; - if ((underlyings(98,1) <= 8288.)) goto L50; - if ((underlyings(99,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(99,2) <= 840.)) goto L50; - if ((underlyings(99,1) <= 8288.)) goto L50; - if ((underlyings(100,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(100,2) <= 840.)) goto L50; - if ((underlyings(100,1) <= 8288.)) goto L50; - if ((underlyings(101,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(101,2) <= 840.)) goto L50; - if ((underlyings(101,1) <= 8288.)) goto L50; - if ((underlyings(102,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(102,2) <= 840.)) goto L50; - if ((underlyings(102,1) <= 8288.)) goto L50; - if ((underlyings(103,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(103,2) <= 840.)) goto L50; - if ((underlyings(103,1) <= 8288.)) goto L50; - if ((underlyings(104,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(104,2) <= 840.)) goto L50; - if ((underlyings(104,1) <= 8288.)) goto L50; - if ((underlyings(105,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(105,2) <= 840.)) goto L50; - if ((underlyings(105,1) <= 8288.)) goto L50; - if ((underlyings(106,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(106,2) <= 840.)) goto L50; - if ((underlyings(106,1) <= 8288.)) goto L50; - if ((underlyings(107,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(107,2) <= 840.)) goto L50; - if ((underlyings(107,1) <= 8288.)) goto L50; - if ((underlyings(108,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(108,2) <= 840.)) goto L50; - if ((underlyings(108,1) <= 8288.)) goto L50; - if ((underlyings(109,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(109,2) <= 840.)) goto L50; - if ((underlyings(109,1) <= 8288.)) goto L50; - if ((underlyings(110,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(110,2) <= 840.)) goto L50; - if ((underlyings(110,1) <= 8288.)) goto L50; - if ((underlyings(111,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(111,2) <= 840.)) goto L50; - if ((underlyings(111,1) <= 8288.)) goto L50; - if ((underlyings(112,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(112,2) <= 840.)) goto L50; - if ((underlyings(112,1) <= 8288.)) goto L50; - if ((underlyings(113,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(113,2) <= 840.)) goto L50; - if ((underlyings(113,1) <= 8288.)) goto L50; - if ((underlyings(114,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(114,2) <= 840.)) goto L50; - if ((underlyings(114,1) <= 8288.)) goto L50; - if ((underlyings(115,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(115,2) <= 840.)) goto L50; - if ((underlyings(115,1) <= 8288.)) goto L50; - if ((underlyings(116,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(116,2) <= 840.)) goto L50; - if ((underlyings(116,1) <= 8288.)) goto L50; - if ((underlyings(117,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(117,2) <= 840.)) goto L50; - if ((underlyings(117,1) <= 8288.)) goto L50; - if ((underlyings(118,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(118,2) <= 840.)) goto L50; - if ((underlyings(118,1) <= 8288.)) goto L50; - if ((underlyings(119,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(119,2) <= 840.)) goto L50; - if ((underlyings(119,1) <= 8288.)) goto L50; - if ((underlyings(120,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(120,2) <= 840.)) goto L50; - if ((underlyings(120,1) <= 8288.)) goto L50; - if ((underlyings(121,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(121,2) <= 840.)) goto L50; - if ((underlyings(121,1) <= 8288.)) goto L50; - if ((underlyings(122,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(122,2) <= 840.)) goto L50; - if ((underlyings(122,1) <= 8288.)) goto L50; - if ((underlyings(123,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(123,2) <= 840.)) goto L50; - if ((underlyings(123,1) <= 8288.)) goto L50; - if ((underlyings(124,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(124,2) <= 840.)) goto L50; - if ((underlyings(124,1) <= 8288.)) goto L50; - if ((underlyings(125,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(125,2) <= 840.)) goto L50; - if ((underlyings(125,1) <= 8288.)) goto L50; - if ((underlyings(126,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(126,2) <= 840.)) goto L50; - if ((underlyings(126,1) <= 8288.)) goto L50; - if ((underlyings(127,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(127,2) <= 840.)) goto L50; - if ((underlyings(127,1) <= 8288.)) goto L50; - if ((underlyings(128,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(128,2) <= 840.)) goto L50; - if ((underlyings(128,1) <= 8288.)) goto L50; - if ((underlyings(129,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(129,2) <= 840.)) goto L50; - if ((underlyings(129,1) <= 8288.)) goto L50; - if ((underlyings(130,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(130,2) <= 840.)) goto L50; - if ((underlyings(130,1) <= 8288.)) goto L50; - if ((underlyings(131,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(131,2) <= 840.)) goto L50; - if ((underlyings(131,1) <= 8288.)) goto L50; - if ((underlyings(132,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(132,2) <= 840.)) goto L50; - if ((underlyings(132,1) <= 8288.)) goto L50; - if ((underlyings(133,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(133,2) <= 840.)) goto L50; - if ((underlyings(133,1) <= 8288.)) goto L50; - if ((underlyings(134,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(134,2) <= 840.)) goto L50; - if ((underlyings(134,1) <= 8288.)) goto L50; - if ((underlyings(135,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(135,2) <= 840.)) goto L50; - if ((underlyings(135,1) <= 8288.)) goto L50; - if ((underlyings(136,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(136,2) <= 840.)) goto L50; - if ((underlyings(136,1) <= 8288.)) goto L50; - if ((underlyings(137,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(137,2) <= 840.)) goto L50; - if ((underlyings(137,1) <= 8288.)) goto L50; - if ((underlyings(138,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(138,2) <= 840.)) goto L50; - if ((underlyings(138,1) <= 8288.)) goto L50; - if ((underlyings(139,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(139,2) <= 840.)) goto L50; - if ((underlyings(139,1) <= 8288.)) goto L50; - if ((underlyings(140,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(140,2) <= 840.)) goto L50; - if ((underlyings(140,1) <= 8288.)) goto L50; - if ((underlyings(141,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(141,2) <= 840.)) goto L50; - if ((underlyings(141,1) <= 8288.)) goto L50; - if ((underlyings(142,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(142,2) <= 840.)) goto L50; - if ((underlyings(142,1) <= 8288.)) goto L50; - if ((underlyings(143,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(143,2) <= 840.)) goto L50; - if ((underlyings(143,1) <= 8288.)) goto L50; - if ((underlyings(144,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(144,2) <= 840.)) goto L50; - if ((underlyings(144,1) <= 8288.)) goto L50; - if ((underlyings(145,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(145,2) <= 840.)) goto L50; - if ((underlyings(145,1) <= 8288.)) goto L50; - if ((underlyings(146,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(146,2) <= 840.)) goto L50; - if ((underlyings(146,1) <= 8288.)) goto L50; - if ((underlyings(147,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(147,2) <= 840.)) goto L50; - if ((underlyings(147,1) <= 8288.)) goto L50; - if ((underlyings(148,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(148,2) <= 840.)) goto L50; - if ((underlyings(148,1) <= 8288.)) goto L50; - if ((underlyings(149,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(149,2) <= 840.)) goto L50; - if ((underlyings(149,1) <= 8288.)) goto L50; - if ((underlyings(150,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(150,2) <= 840.)) goto L50; - if ((underlyings(150,1) <= 8288.)) goto L50; - if ((underlyings(151,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(151,2) <= 840.)) goto L50; - if ((underlyings(151,1) <= 8288.)) goto L50; - if ((underlyings(152,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(152,2) <= 840.)) goto L50; - if ((underlyings(152,1) <= 8288.)) goto L50; - if ((underlyings(153,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(153,2) <= 840.)) goto L50; - if ((underlyings(153,1) <= 8288.)) goto L50; - if ((underlyings(154,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(154,2) <= 840.)) goto L50; - if ((underlyings(154,1) <= 8288.)) goto L50; - if ((underlyings(155,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(155,2) <= 840.)) goto L50; - if ((underlyings(155,1) <= 8288.)) goto L50; - if ((underlyings(156,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(156,2) <= 840.)) goto L50; - if ((underlyings(156,1) <= 8288.)) goto L50; - if ((underlyings(157,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(157,2) <= 840.)) goto L50; - if ((underlyings(157,1) <= 8288.)) goto L50; - if ((underlyings(158,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(158,2) <= 840.)) goto L50; - if ((underlyings(158,1) <= 8288.)) goto L50; - if ((underlyings(159,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(159,2) <= 840.)) goto L50; - if ((underlyings(159,1) <= 8288.)) goto L50; - if ((underlyings(160,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(160,2) <= 840.)) goto L50; - if ((underlyings(160,1) <= 8288.)) goto L50; - if ((underlyings(161,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(161,2) <= 840.)) goto L50; - if ((underlyings(161,1) <= 8288.)) goto L50; - if ((underlyings(162,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(162,2) <= 840.)) goto L50; - if ((underlyings(162,1) <= 8288.)) goto L50; - if ((underlyings(163,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(163,2) <= 840.)) goto L50; - if ((underlyings(163,1) <= 8288.)) goto L50; - if ((underlyings(164,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(164,2) <= 840.)) goto L50; - if ((underlyings(164,1) <= 8288.)) goto L50; - if ((underlyings(165,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(165,2) <= 840.)) goto L50; - if ((underlyings(165,1) <= 8288.)) goto L50; - if ((underlyings(166,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(166,2) <= 840.)) goto L50; - if ((underlyings(166,1) <= 8288.)) goto L50; - if ((underlyings(167,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(167,2) <= 840.)) goto L50; - if ((underlyings(167,1) <= 8288.)) goto L50; - if ((underlyings(168,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(168,2) <= 840.)) goto L50; - if ((underlyings(168,1) <= 8288.)) goto L50; - if ((underlyings(169,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(169,2) <= 840.)) goto L50; - if ((underlyings(169,1) <= 8288.)) goto L50; - if ((underlyings(170,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(170,2) <= 840.)) goto L50; - if ((underlyings(170,1) <= 8288.)) goto L50; - if ((underlyings(171,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(171,2) <= 840.)) goto L50; - if ((underlyings(171,1) <= 8288.)) goto L50; - if ((underlyings(172,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(172,2) <= 840.)) goto L50; - if ((underlyings(172,1) <= 8288.)) goto L50; - if ((underlyings(173,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(173,2) <= 840.)) goto L50; - if ((underlyings(173,1) <= 8288.)) goto L50; - if ((underlyings(174,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(174,2) <= 840.)) goto L50; - if ((underlyings(174,1) <= 8288.)) goto L50; - if ((underlyings(175,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(175,2) <= 840.)) goto L50; - if ((underlyings(175,1) <= 8288.)) goto L50; - if ((underlyings(176,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(176,2) <= 840.)) goto L50; - if ((underlyings(176,1) <= 8288.)) goto L50; - if ((underlyings(177,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(177,2) <= 840.)) goto L50; - if ((underlyings(177,1) <= 8288.)) goto L50; - if ((underlyings(178,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(178,2) <= 840.)) goto L50; - if ((underlyings(178,1) <= 8288.)) goto L50; - if ((underlyings(179,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(179,2) <= 840.)) goto L50; - if ((underlyings(179,1) <= 8288.)) goto L50; - if ((underlyings(180,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(180,2) <= 840.)) goto L50; - if ((underlyings(180,1) <= 8288.)) goto L50; - if ((underlyings(181,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(181,2) <= 840.)) goto L50; - if ((underlyings(181,1) <= 8288.)) goto L50; - if ((underlyings(182,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(182,2) <= 840.)) goto L50; - if ((underlyings(182,1) <= 8288.)) goto L50; - if ((underlyings(183,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(183,2) <= 840.)) goto L50; - if ((underlyings(183,1) <= 8288.)) goto L50; - if ((underlyings(184,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(184,2) <= 840.)) goto L50; - if ((underlyings(184,1) <= 8288.)) goto L50; - if ((underlyings(185,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(185,2) <= 840.)) goto L50; - if ((underlyings(185,1) <= 8288.)) goto L50; - if ((underlyings(186,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(186,2) <= 840.)) goto L50; - if ((underlyings(186,1) <= 8288.)) goto L50; - if ((underlyings(187,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(187,2) <= 840.)) goto L50; - if ((underlyings(187,1) <= 8288.)) goto L50; - if ((underlyings(188,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(188,2) <= 840.)) goto L50; - if ((underlyings(188,1) <= 8288.)) goto L50; - if ((underlyings(189,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(189,2) <= 840.)) goto L50; - if ((underlyings(189,1) <= 8288.)) goto L50; - if ((underlyings(190,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(190,2) <= 840.)) goto L50; - if ((underlyings(190,1) <= 8288.)) goto L50; - if ((underlyings(191,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(191,2) <= 840.)) goto L50; - if ((underlyings(191,1) <= 8288.)) goto L50; - if ((underlyings(192,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(192,2) <= 840.)) goto L50; - if ((underlyings(192,1) <= 8288.)) goto L50; - if ((underlyings(193,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(193,2) <= 840.)) goto L50; - if ((underlyings(193,1) <= 8288.)) goto L50; - if ((underlyings(194,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(194,2) <= 840.)) goto L50; - if ((underlyings(194,1) <= 8288.)) goto L50; - if ((underlyings(195,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(195,2) <= 840.)) goto L50; - if ((underlyings(195,1) <= 8288.)) goto L50; - if ((underlyings(196,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(196,2) <= 840.)) goto L50; - if ((underlyings(196,1) <= 8288.)) goto L50; - if ((underlyings(197,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(197,2) <= 840.)) goto L50; - if ((underlyings(197,1) <= 8288.)) goto L50; - if ((underlyings(198,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(198,2) <= 840.)) goto L50; - if ((underlyings(198,1) <= 8288.)) goto L50; - if ((underlyings(199,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(199,2) <= 840.)) goto L50; - if ((underlyings(199,1) <= 8288.)) goto L50; - if ((underlyings(200,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(200,2) <= 840.)) goto L50; - if ((underlyings(200,1) <= 8288.)) goto L50; - if ((underlyings(201,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(201,2) <= 840.)) goto L50; - if ((underlyings(201,1) <= 8288.)) goto L50; - if ((underlyings(202,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(202,2) <= 840.)) goto L50; - if ((underlyings(202,1) <= 8288.)) goto L50; - if ((underlyings(203,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(203,2) <= 840.)) goto L50; - if ((underlyings(203,1) <= 8288.)) goto L50; - if ((underlyings(204,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(204,2) <= 840.)) goto L50; - if ((underlyings(204,1) <= 8288.)) goto L50; - if ((underlyings(205,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(205,2) <= 840.)) goto L50; - if ((underlyings(205,1) <= 8288.)) goto L50; - if ((underlyings(206,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(206,2) <= 840.)) goto L50; - if ((underlyings(206,1) <= 8288.)) goto L50; - if ((underlyings(207,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(207,2) <= 840.)) goto L50; - if ((underlyings(207,1) <= 8288.)) goto L50; - if ((underlyings(208,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(208,2) <= 840.)) goto L50; - if ((underlyings(208,1) <= 8288.)) goto L50; - if ((underlyings(209,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(209,2) <= 840.)) goto L50; - if ((underlyings(209,1) <= 8288.)) goto L50; - if ((underlyings(210,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(210,2) <= 840.)) goto L50; - if ((underlyings(210,1) <= 8288.)) goto L50; - if ((underlyings(211,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(211,2) <= 840.)) goto L50; - if ((underlyings(211,1) <= 8288.)) goto L50; - if ((underlyings(212,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(212,2) <= 840.)) goto L50; - if ((underlyings(212,1) <= 8288.)) goto L50; - if ((underlyings(213,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(213,2) <= 840.)) goto L50; - if ((underlyings(213,1) <= 8288.)) goto L50; - if ((underlyings(214,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(214,2) <= 840.)) goto L50; - if ((underlyings(214,1) <= 8288.)) goto L50; - if ((underlyings(215,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(215,2) <= 840.)) goto L50; - if ((underlyings(215,1) <= 8288.)) goto L50; - if ((underlyings(216,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(216,2) <= 840.)) goto L50; - if ((underlyings(216,1) <= 8288.)) goto L50; - if ((underlyings(217,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(217,2) <= 840.)) goto L50; - if ((underlyings(217,1) <= 8288.)) goto L50; - if ((underlyings(218,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(218,2) <= 840.)) goto L50; - if ((underlyings(218,1) <= 8288.)) goto L50; - if ((underlyings(219,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(219,2) <= 840.)) goto L50; - if ((underlyings(219,1) <= 8288.)) goto L50; - if ((underlyings(220,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(220,2) <= 840.)) goto L50; - if ((underlyings(220,1) <= 8288.)) goto L50; - if ((underlyings(221,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(221,2) <= 840.)) goto L50; - if ((underlyings(221,1) <= 8288.)) goto L50; - if ((underlyings(222,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(222,2) <= 840.)) goto L50; - if ((underlyings(222,1) <= 8288.)) goto L50; - if ((underlyings(223,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(223,2) <= 840.)) goto L50; - if ((underlyings(223,1) <= 8288.)) goto L50; - if ((underlyings(224,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(224,2) <= 840.)) goto L50; - if ((underlyings(224,1) <= 8288.)) goto L50; - if ((underlyings(225,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(225,2) <= 840.)) goto L50; - if ((underlyings(225,1) <= 8288.)) goto L50; - if ((underlyings(226,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(226,2) <= 840.)) goto L50; - if ((underlyings(226,1) <= 8288.)) goto L50; - if ((underlyings(227,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(227,2) <= 840.)) goto L50; - if ((underlyings(227,1) <= 8288.)) goto L50; - if ((underlyings(228,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(228,2) <= 840.)) goto L50; - if ((underlyings(228,1) <= 8288.)) goto L50; - if ((underlyings(229,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(229,2) <= 840.)) goto L50; - if ((underlyings(229,1) <= 8288.)) goto L50; - if ((underlyings(230,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(230,2) <= 840.)) goto L50; - if ((underlyings(230,1) <= 8288.)) goto L50; - if ((underlyings(231,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(231,2) <= 840.)) goto L50; - if ((underlyings(231,1) <= 8288.)) goto L50; - if ((underlyings(232,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(232,2) <= 840.)) goto L50; - if ((underlyings(232,1) <= 8288.)) goto L50; - if ((underlyings(233,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(233,2) <= 840.)) goto L50; - if ((underlyings(233,1) <= 8288.)) goto L50; - if ((underlyings(234,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(234,2) <= 840.)) goto L50; - if ((underlyings(234,1) <= 8288.)) goto L50; - if ((underlyings(235,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(235,2) <= 840.)) goto L50; - if ((underlyings(235,1) <= 8288.)) goto L50; - if ((underlyings(236,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(236,2) <= 840.)) goto L50; - if ((underlyings(236,1) <= 8288.)) goto L50; - if ((underlyings(237,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(237,2) <= 840.)) goto L50; - if ((underlyings(237,1) <= 8288.)) goto L50; - if ((underlyings(238,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(238,2) <= 840.)) goto L50; - if ((underlyings(238,1) <= 8288.)) goto L50; - if ((underlyings(239,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(239,2) <= 840.)) goto L50; - if ((underlyings(239,1) <= 8288.)) goto L50; - if ((underlyings(240,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(240,2) <= 840.)) goto L50; - if ((underlyings(240,1) <= 8288.)) goto L50; - if ((underlyings(241,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(241,2) <= 840.)) goto L50; - if ((underlyings(241,1) <= 8288.)) goto L50; - if ((underlyings(242,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(242,2) <= 840.)) goto L50; - if ((underlyings(242,1) <= 8288.)) goto L50; - if ((underlyings(243,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(243,2) <= 840.)) goto L50; - if ((underlyings(243,1) <= 8288.)) goto L50; - if ((underlyings(244,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(244,2) <= 840.)) goto L50; - if ((underlyings(244,1) <= 8288.)) goto L50; - if ((underlyings(245,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(245,2) <= 840.)) goto L50; - if ((underlyings(245,1) <= 8288.)) goto L50; - if ((underlyings(246,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(246,2) <= 840.)) goto L50; - if ((underlyings(246,1) <= 8288.)) goto L50; - if ((underlyings(247,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(247,2) <= 840.)) goto L50; - if ((underlyings(247,1) <= 8288.)) goto L50; - if ((underlyings(248,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(248,2) <= 840.)) goto L50; - if ((underlyings(248,1) <= 8288.)) goto L50; - if ((underlyings(249,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(249,2) <= 840.)) goto L50; - if ((underlyings(249,1) <= 8288.)) goto L50; - if ((underlyings(250,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(250,2) <= 840.)) goto L50; - if ((underlyings(250,1) <= 8288.)) goto L50; - if ((underlyings(251,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(251,2) <= 840.)) goto L50; - if ((underlyings(251,1) <= 8288.)) goto L50; - if ((underlyings(252,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(252,2) <= 840.)) goto L50; - if ((underlyings(252,1) <= 8288.)) goto L50; - if ((underlyings(253,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(253,2) <= 840.)) goto L50; - if ((underlyings(253,1) <= 8288.)) goto L50; - if ((underlyings(254,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(254,2) <= 840.)) goto L50; - if ((underlyings(254,1) <= 8288.)) goto L50; - if ((underlyings(255,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(255,2) <= 840.)) goto L50; - if ((underlyings(255,1) <= 8288.)) goto L50; - if ((underlyings(256,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(256,2) <= 840.)) goto L50; - if ((underlyings(256,1) <= 8288.)) goto L50; - if ((underlyings(257,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(257,2) <= 840.)) goto L50; - if ((underlyings(257,1) <= 8288.)) goto L50; - if ((underlyings(258,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(258,2) <= 840.)) goto L50; - if ((underlyings(258,1) <= 8288.)) goto L50; - if ((underlyings(259,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(259,2) <= 840.)) goto L50; - if ((underlyings(259,1) <= 8288.)) goto L50; - if ((underlyings(260,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(260,2) <= 840.)) goto L50; - if ((underlyings(260,1) <= 8288.)) goto L50; - if ((underlyings(261,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(261,2) <= 840.)) goto L50; - if ((underlyings(261,1) <= 8288.)) goto L50; - if ((underlyings(262,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(262,2) <= 840.)) goto L50; - if ((underlyings(262,1) <= 8288.)) goto L50; - if ((underlyings(263,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(263,2) <= 840.)) goto L50; - if ((underlyings(263,1) <= 8288.)) goto L50; - if ((underlyings(264,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(264,2) <= 840.)) goto L50; - if ((underlyings(264,1) <= 8288.)) goto L50; - if ((underlyings(265,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(265,2) <= 840.)) goto L50; - if ((underlyings(265,1) <= 8288.)) goto L50; - if ((underlyings(266,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(266,2) <= 840.)) goto L50; - if ((underlyings(266,1) <= 8288.)) goto L50; - if ((underlyings(267,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(267,2) <= 840.)) goto L50; - if ((underlyings(267,1) <= 8288.)) goto L50; - if ((underlyings(268,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(268,2) <= 840.)) goto L50; - if ((underlyings(268,1) <= 8288.)) goto L50; - if ((underlyings(269,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(269,2) <= 840.)) goto L50; - if ((underlyings(269,1) <= 8288.)) goto L50; - if ((underlyings(270,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(270,2) <= 840.)) goto L50; - if ((underlyings(270,1) <= 8288.)) goto L50; - if ((underlyings(271,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(271,2) <= 840.)) goto L50; - if ((underlyings(271,1) <= 8288.)) goto L50; - if ((underlyings(272,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(272,2) <= 840.)) goto L50; - if ((underlyings(272,1) <= 8288.)) goto L50; - if ((underlyings(273,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(273,2) <= 840.)) goto L50; - if ((underlyings(273,1) <= 8288.)) goto L50; - if ((underlyings(274,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(274,2) <= 840.)) goto L50; - if ((underlyings(274,1) <= 8288.)) goto L50; - if ((underlyings(275,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(275,2) <= 840.)) goto L50; - if ((underlyings(275,1) <= 8288.)) goto L50; - if ((underlyings(276,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(276,2) <= 840.)) goto L50; - if ((underlyings(276,1) <= 8288.)) goto L50; - if ((underlyings(277,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(277,2) <= 840.)) goto L50; - if ((underlyings(277,1) <= 8288.)) goto L50; - if ((underlyings(278,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(278,2) <= 840.)) goto L50; - if ((underlyings(278,1) <= 8288.)) goto L50; - if ((underlyings(279,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(279,2) <= 840.)) goto L50; - if ((underlyings(279,1) <= 8288.)) goto L50; - if ((underlyings(280,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(280,2) <= 840.)) goto L50; - if ((underlyings(280,1) <= 8288.)) goto L50; - if ((underlyings(281,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(281,2) <= 840.)) goto L50; - if ((underlyings(281,1) <= 8288.)) goto L50; - if ((underlyings(282,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(282,2) <= 840.)) goto L50; - if ((underlyings(282,1) <= 8288.)) goto L50; - if ((underlyings(283,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(283,2) <= 840.)) goto L50; - if ((underlyings(283,1) <= 8288.)) goto L50; - if ((underlyings(284,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(284,2) <= 840.)) goto L50; - if ((underlyings(284,1) <= 8288.)) goto L50; - if ((underlyings(285,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(285,2) <= 840.)) goto L50; - if ((underlyings(285,1) <= 8288.)) goto L50; - if ((underlyings(286,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(286,2) <= 840.)) goto L50; - if ((underlyings(286,1) <= 8288.)) goto L50; - if ((underlyings(287,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(287,2) <= 840.)) goto L50; - if ((underlyings(287,1) <= 8288.)) goto L50; - if ((underlyings(288,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(288,2) <= 840.)) goto L50; - if ((underlyings(288,1) <= 8288.)) goto L50; - if ((underlyings(289,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(289,2) <= 840.)) goto L50; - if ((underlyings(289,1) <= 8288.)) goto L50; - if ((underlyings(290,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(290,2) <= 840.)) goto L50; - if ((underlyings(290,1) <= 8288.)) goto L50; - if ((underlyings(291,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(291,2) <= 840.)) goto L50; - if ((underlyings(291,1) <= 8288.)) goto L50; - if ((underlyings(292,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(292,2) <= 840.)) goto L50; - if ((underlyings(292,1) <= 8288.)) goto L50; - if ((underlyings(293,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(293,2) <= 840.)) goto L50; - if ((underlyings(293,1) <= 8288.)) goto L50; - if ((underlyings(294,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(294,2) <= 840.)) goto L50; - if ((underlyings(294,1) <= 8288.)) goto L50; - if ((underlyings(295,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(295,2) <= 840.)) goto L50; - if ((underlyings(295,1) <= 8288.)) goto L50; - if ((underlyings(296,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(296,2) <= 840.)) goto L50; - if ((underlyings(296,1) <= 8288.)) goto L50; - if ((underlyings(297,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(297,2) <= 840.)) goto L50; - if ((underlyings(297,1) <= 8288.)) goto L50; - if ((underlyings(298,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(298,2) <= 840.)) goto L50; - if ((underlyings(298,1) <= 8288.)) goto L50; - if ((underlyings(299,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(299,2) <= 840.)) goto L50; - if ((underlyings(299,1) <= 8288.)) goto L50; - if ((underlyings(300,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(300,2) <= 840.)) goto L50; - if ((underlyings(300,1) <= 8288.)) goto L50; - if ((underlyings(301,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(301,2) <= 840.)) goto L50; - if ((underlyings(301,1) <= 8288.)) goto L50; - if ((underlyings(302,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(302,2) <= 840.)) goto L50; - if ((underlyings(302,1) <= 8288.)) goto L50; - if ((underlyings(303,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(303,2) <= 840.)) goto L50; - if ((underlyings(303,1) <= 8288.)) goto L50; - if ((underlyings(304,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(304,2) <= 840.)) goto L50; - if ((underlyings(304,1) <= 8288.)) goto L50; - if ((underlyings(305,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(305,2) <= 840.)) goto L50; - if ((underlyings(305,1) <= 8288.)) goto L50; - if ((underlyings(306,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(306,2) <= 840.)) goto L50; - if ((underlyings(306,1) <= 8288.)) goto L50; - if ((underlyings(307,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(307,2) <= 840.)) goto L50; - if ((underlyings(307,1) <= 8288.)) goto L50; - if ((underlyings(308,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(308,2) <= 840.)) goto L50; - if ((underlyings(308,1) <= 8288.)) goto L50; - if ((underlyings(309,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(309,2) <= 840.)) goto L50; - if ((underlyings(309,1) <= 8288.)) goto L50; - if ((underlyings(310,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(310,2) <= 840.)) goto L50; - if ((underlyings(310,1) <= 8288.)) goto L50; - if ((underlyings(311,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(311,2) <= 840.)) goto L50; - if ((underlyings(311,1) <= 8288.)) goto L50; - if ((underlyings(312,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(312,2) <= 840.)) goto L50; - if ((underlyings(312,1) <= 8288.)) goto L50; - if ((underlyings(313,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(313,2) <= 840.)) goto L50; - if ((underlyings(313,1) <= 8288.)) goto L50; - if ((underlyings(314,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(314,2) <= 840.)) goto L50; - if ((underlyings(314,1) <= 8288.)) goto L50; - if ((underlyings(315,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(315,2) <= 840.)) goto L50; - if ((underlyings(315,1) <= 8288.)) goto L50; - if ((underlyings(316,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(316,2) <= 840.)) goto L50; - if ((underlyings(316,1) <= 8288.)) goto L50; - if ((underlyings(317,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(317,2) <= 840.)) goto L50; - if ((underlyings(317,1) <= 8288.)) goto L50; - if ((underlyings(318,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(318,2) <= 840.)) goto L50; - if ((underlyings(318,1) <= 8288.)) goto L50; - if ((underlyings(319,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(319,2) <= 840.)) goto L50; - if ((underlyings(319,1) <= 8288.)) goto L50; - if ((underlyings(320,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(320,2) <= 840.)) goto L50; - if ((underlyings(320,1) <= 8288.)) goto L50; - if ((underlyings(321,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(321,2) <= 840.)) goto L50; - if ((underlyings(321,1) <= 8288.)) goto L50; - if ((underlyings(322,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(322,2) <= 840.)) goto L50; - if ((underlyings(322,1) <= 8288.)) goto L50; - if ((underlyings(323,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(323,2) <= 840.)) goto L50; - if ((underlyings(323,1) <= 8288.)) goto L50; - if ((underlyings(324,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(324,2) <= 840.)) goto L50; - if ((underlyings(324,1) <= 8288.)) goto L50; - if ((underlyings(325,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(325,2) <= 840.)) goto L50; - if ((underlyings(325,1) <= 8288.)) goto L50; - if ((underlyings(326,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(326,2) <= 840.)) goto L50; - if ((underlyings(326,1) <= 8288.)) goto L50; - if ((underlyings(327,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(327,2) <= 840.)) goto L50; - if ((underlyings(327,1) <= 8288.)) goto L50; - if ((underlyings(328,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(328,2) <= 840.)) goto L50; - if ((underlyings(328,1) <= 8288.)) goto L50; - if ((underlyings(329,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(329,2) <= 840.)) goto L50; - if ((underlyings(329,1) <= 8288.)) goto L50; - if ((underlyings(330,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(330,2) <= 840.)) goto L50; - if ((underlyings(330,1) <= 8288.)) goto L50; - if ((underlyings(331,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(331,2) <= 840.)) goto L50; - if ((underlyings(331,1) <= 8288.)) goto L50; - if ((underlyings(332,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(332,2) <= 840.)) goto L50; - if ((underlyings(332,1) <= 8288.)) goto L50; - if ((underlyings(333,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(333,2) <= 840.)) goto L50; - if ((underlyings(333,1) <= 8288.)) goto L50; - if ((underlyings(334,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(334,2) <= 840.)) goto L50; - if ((underlyings(334,1) <= 8288.)) goto L50; - if ((underlyings(335,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(335,2) <= 840.)) goto L50; - if ((underlyings(335,1) <= 8288.)) goto L50; - if ((underlyings(336,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(336,2) <= 840.)) goto L50; - if ((underlyings(336,1) <= 8288.)) goto L50; - if ((underlyings(337,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(337,2) <= 840.)) goto L50; - if ((underlyings(337,1) <= 8288.)) goto L50; - if ((underlyings(338,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(338,2) <= 840.)) goto L50; - if ((underlyings(338,1) <= 8288.)) goto L50; - if ((underlyings(339,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(339,2) <= 840.)) goto L50; - if ((underlyings(339,1) <= 8288.)) goto L50; - if ((underlyings(340,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(340,2) <= 840.)) goto L50; - if ((underlyings(340,1) <= 8288.)) goto L50; - if ((underlyings(341,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(341,2) <= 840.)) goto L50; - if ((underlyings(341,1) <= 8288.)) goto L50; - if ((underlyings(342,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(342,2) <= 840.)) goto L50; - if ((underlyings(342,1) <= 8288.)) goto L50; - if ((underlyings(343,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(343,2) <= 840.)) goto L50; - if ((underlyings(343,1) <= 8288.)) goto L50; - if ((underlyings(344,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(344,2) <= 840.)) goto L50; - if ((underlyings(344,1) <= 8288.)) goto L50; - if ((underlyings(345,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(345,2) <= 840.)) goto L50; - if ((underlyings(345,1) <= 8288.)) goto L50; - if ((underlyings(346,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(346,2) <= 840.)) goto L50; - if ((underlyings(346,1) <= 8288.)) goto L50; - if ((underlyings(347,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(347,2) <= 840.)) goto L50; - if ((underlyings(347,1) <= 8288.)) goto L50; - if ((underlyings(348,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(348,2) <= 840.)) goto L50; - if ((underlyings(348,1) <= 8288.)) goto L50; - if ((underlyings(349,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(349,2) <= 840.)) goto L50; - if ((underlyings(349,1) <= 8288.)) goto L50; - if ((underlyings(350,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(350,2) <= 840.)) goto L50; - if ((underlyings(350,1) <= 8288.)) goto L50; - if ((underlyings(351,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(351,2) <= 840.)) goto L50; - if ((underlyings(351,1) <= 8288.)) goto L50; - if ((underlyings(352,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(352,2) <= 840.)) goto L50; - if ((underlyings(352,1) <= 8288.)) goto L50; - if ((underlyings(353,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(353,2) <= 840.)) goto L50; - if ((underlyings(353,1) <= 8288.)) goto L50; - if ((underlyings(354,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(354,2) <= 840.)) goto L50; - if ((underlyings(354,1) <= 8288.)) goto L50; - if ((underlyings(355,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(355,2) <= 840.)) goto L50; - if ((underlyings(355,1) <= 8288.)) goto L50; - if ((underlyings(356,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(356,2) <= 840.)) goto L50; - if ((underlyings(356,1) <= 8288.)) goto L50; - if ((underlyings(357,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(357,2) <= 840.)) goto L50; - if ((underlyings(357,1) <= 8288.)) goto L50; - if ((underlyings(358,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(358,2) <= 840.)) goto L50; - if ((underlyings(358,1) <= 8288.)) goto L50; - if ((underlyings(359,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(359,2) <= 840.)) goto L50; - if ((underlyings(359,1) <= 8288.)) goto L50; - if ((underlyings(360,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(360,2) <= 840.)) goto L50; - if ((underlyings(360,1) <= 8288.)) goto L50; - if ((underlyings(361,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(361,2) <= 840.)) goto L50; - if ((underlyings(361,1) <= 8288.)) goto L50; - if ((underlyings(362,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(362,2) <= 840.)) goto L50; - if ((underlyings(362,1) <= 8288.)) goto L50; - if ((underlyings(363,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(363,2) <= 840.)) goto L50; - if ((underlyings(363,1) <= 8288.)) goto L50; - if ((underlyings(364,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(364,2) <= 840.)) goto L50; - if ((underlyings(364,1) <= 8288.)) goto L50; - if ((underlyings(365,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(365,2) <= 840.)) goto L50; - if ((underlyings(365,1) <= 8288.)) goto L50; - if ((underlyings(366,0) <= 2630.6349999999998)) goto L50; - if ((underlyings(366,2) <= 840.)) goto L50; - x3309=(underlyings(366,1) <= 8288.); - goto L48; - -L50: - x3309=1; - -L48: - //model->notify_cash_flow(model, 0, 100., 0 /*2013-01-27, 1980-01-01, EUR*/); - trajectory_inner( num_cash_flows, model_num, 0, 100., md_discts, vhat ); - - if (((underlyings(366,0) < 3758.05) && x3309)) goto L40; - if (((underlyings(366,2) < 1200.) && x3309)) goto L40; - if (((underlyings(366,1) < 11840.) && x3309)) goto L40; - - //model->notify_cash_flow(model, 0, 1000., 1 /*2013-01-27, 2013-01-27, EUR*/); return; - trajectory_inner( num_cash_flows, model_num, 1, 1000., md_discts, vhat ); return; - -L40: - //model->notify_cash_flow(model, 0, (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))), 1 /*2013-01-27, 2013-01-27, EUR*/); - const REAL amount = (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))); - trajectory_inner( num_cash_flows, model_num, 1, amount, md_discts, vhat ); - - return; -} - -#define CONTRACT_NUM 2 - -inline -void aggregDiscountedPayoff( - const UINT& model_num, // the index of the current model - const UINT& contr_num, - const UINT& num_under, // the number of underlyings - const UINT& num_cash_flows, - const UINT& num_pricers,// the number of deterministic procers - const REAL* md_discts, // [num_models][num_scash_flow] discounts - const REAL* md_detvals, // [num_models, num_det_pricers] pricers - const REAL* inst_traj, // [num_dates, num_under] current trajectory - double* vhat // [model_num] Accumulated per-model price -) { - if (contr_num == 1) { -//#if (CONTRACT_NUM == 1) - trajectory_contract1(model_num, num_under, num_cash_flows, num_pricers, md_discts, md_detvals, inst_traj, vhat); - } else if (contr_num == 2) { -//#elif (CONTRACT_NUM == 2) - trajectory_contract2(model_num, num_under, num_cash_flows, num_pricers, md_discts, md_detvals, inst_traj, vhat); - } else if (contr_num == 3) { -//#elif (CONTRACT_NUM == 3) - trajectory_contract3(model_num, num_under, num_cash_flows, num_pricers, md_discts, md_detvals, inst_traj, vhat); - } else { -//#else - trajectory_contract1(model_num, num_under, num_cash_flows, num_pricers, md_discts, md_detvals, inst_traj, vhat); - } -//#endif - -} - -#endif //CONTRACTS_CODE - diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp deleted file mode 100644 index ab03cc8..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// This is the original implementation. - -#define FAST_BB - -#include "ParseInput.h" -#include "SobolGaussBB.h" -#include "Contracts.h" - -double* run_CPUkernel( const LoopROScalars & scals, - const SobolArrays & sob_arrs, - const ModelArrays & md_arrs, - const BrowBridgeArrays& bb_arrs -) { - const UINT sob_dim = scals.num_under * scals.num_dates; - const UINT num_under_sq = scals.num_under * scals.num_under; - const int* sob_matT = sob_arrs.sobol_dirvcts; - - // allocate for Ps threads - const UINT Sd = do_padding( sob_dim ); - UINT* sob_vct = static_cast( malloc( Sd * sizeof(UINT)) ); - REAL* md_vct = static_cast( malloc( Sd * sizeof(REAL)) ); - REAL* trj_vct = static_cast( malloc( Sd * sizeof(REAL)) ); - - const UINT Sv = do_padding( scals.num_models ); - double* vhat = static_cast( malloc( Sv * sizeof(double)) ); - - // init the prices to 0 - for(int i = 0; i < scals.num_models; i ++) { - vhat[ i ] = 0.0; - } - - // Sobol number 0 is a vector of 0s. - for(int i = 0; i < sob_dim; i++) { - sob_vct[i] = 0; - } - - for( int i = 0; i < scals.num_mcits; i ++ ) { - - // Sobol strength-reduced (recurrence) formula. - sobolRec( sob_dim, scals.sobol_bits, sob_matT, i+1, sob_vct ); - - // transform the normal [0,1) to gaussian distribution [-inf, +inf] - uGaussian( scals.sob_norm_fact, sob_dim, sob_vct, md_vct ); - - // correlate the dates on each path using a Brownian Bridge - brownianBridge( scals.num_under, scals.num_dates, - bb_arrs.bb_inds, bb_arrs.bb_data, - md_vct, trj_vct ); - -#ifdef FAST_BB - REAL* traj = md_vct; -#else - REAL* traj = trj_vct; //md_vct; -#endif - - // compute trajectory - for ( int m = 0; m < scals.num_models; m ++ ) { - REAL* md_c = md_arrs.md_c + ( m * num_under_sq ); - REAL* md_vols = md_arrs.md_vols + ( m * sob_dim ); - REAL* md_drifts = md_arrs.md_drifts + ( m * sob_dim ); - REAL* md_starts = md_arrs.md_starts + ( m * scals.num_under ); - - for( int i = 0; i < scals.num_dates; i ++ ) { - for( int j = 0; j < scals.num_under; j ++ ) { - REAL temp = 0.0; - int k = i*scals.num_under + j; - - for ( int l = 0; l <= j; l ++ ) { -#ifdef FAST_BB - REAL md_val = trj_vct[i*scals.num_under + l]; -#else - REAL md_val = md_vct [i*scals.num_under + l]; -#endif - temp += md_c[j*scals.num_under + l] * md_val; - } - - temp = exp( temp*md_vols[k] + md_drifts[k] ); - - traj[k] = (k < scals.num_under) ? - md_starts[ k ] * temp : - traj[k - scals.num_under] * temp ; - } - } - - aggregDiscountedPayoff( m, scals.contract, - scals.num_under, - scals.num_cash_flows, - scals.num_det_pricers, - md_arrs.md_discts, - md_arrs.md_detvals, - traj, vhat ); - } - } - - - for(int i = 0; i < scals.num_models; i ++) { - vhat[i] = vhat[i] / scals.num_mcits; - } - - // clean-up! - free(sob_vct); - free( md_vct); - free(trj_vct); - - return vhat; -} - - -int main() { - LoopROScalars scals; - SobolArrays sob_arrs; - ModelArrays md_arrs; - BrowBridgeArrays bb_arrs; - - fprintf(stdout, "\n// Generic Pricing, Original Sequential Benchmark:\n"); - - readDataSet(scals, sob_arrs, md_arrs, bb_arrs); - - fprintf(stdout, "// Contract: %d, MC Its#: %d, #Underlyings: %d, #Path Dates: %d, chunk: %d\n\n", - scals.contract, scals.num_mcits, scals.num_under, scals.num_dates, scals.chunk ); - - double* prices; - unsigned long int elapsed_usec; - { // run kernel - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - computeSobolFixIndex( sob_arrs, scals.chunk ); - { // do work and cleanup - prices = run_CPUkernel( scals, sob_arrs, md_arrs, bb_arrs ); - } - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; - { - FILE* runtime = fopen("runtime.txt", "w"); - FILE* result = fopen("result.json", "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); - fclose(runtime); - write_1Darr(result, prices, scals.num_models); - fclose(result); - } - - md_arrs .cleanup(); - bb_arrs .cleanup(); - sob_arrs.cleanup(); - } - - return 0; -} - diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile deleted file mode 100644 index e71d099..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -include setup.mk - -ifndef ($(HAVE_GPU)) -include platform.mk -endif - -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) - -SOURCES_CPP =GenPricing.cpp -HELPERS =Contracts.h SobolGaussBB.h ../includeC/Constants.h ../includeC/Optimizations.h ../includeC/ParseInput.h -# XXX what about the boilerplate in ../includeC ??? -OBJECTS =GenPricing.o -EXECUTABLE =GenPricing - -default: cpu - -# TODO need redesign, probably use different executable names (or -# standardisation of "gpu" targets across all benchmarks) - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -cpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) - diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/SobolGaussBB.h b/benchmarks/OptionPricing/implementations/cpp_sequential/SobolGaussBB.h deleted file mode 100644 index d6ae829..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/SobolGaussBB.h +++ /dev/null @@ -1,239 +0,0 @@ -#ifndef SOBOL_GAUSS -#define SOBOL_GAUSS - -/** - * Computes the x's Sobol quasirandom vector - * of size `sob_dim' in result `res' - * using the Sobol-independent formula, - * which does not depend on the previous - * Sobol vector. - */ -inline static -void sobolInd( const int& sobol_dim, // size of the quasi-random vector - const int& bit_count, // number of bits of Sobol numbers - const int* dir_matrix, // [bit_count, sobol_dim]: Sobol's - // direction vectors - const UINT& x, // x'th sobol number - UINT* res // result (quasi-random vector) -) { - UINT gs, y = x + 1; - gs = (y >> 1); - gs = (y ^ gs); - - for( int i = 0; i < sobol_dim; i ++ ) { - res[i] = 0; - } - for( int k = 0; k < bit_count; k ++ ) { - const int* dir_row = dir_matrix + k*sobol_dim; - if( gs & 1 ) { - for( int i = 0; i < sobol_dim; i++ ) { - res[i] ^= dir_row[i]; - } - } - gs = gs >> 1; - } -} - -/** - * Computes the x's Sobol quasirandom vector - * of size `sob_dim' in result `res' - * using the Sobol-reccurent formula, - * which depends on the previous Sobol - * vector (stored in `res'). - */ -inline static -void sobolRec( const int& sobol_dim, // size of the quasi-random vector - const int& bit_count, // number of bits of Sobol numbers - const int* dir_matrix, // [bit_count, sobol_dim]: Sobol's - // direction vectors - const UINT& x, // x'th sobol number - UINT* res // in-out param-result -) { - UINT y = 0; - UINT c = x; - while(c & 1) { - y++; - c >>= 1; - } - //assert( (y < bit_count) && "In sobolRec ell > bit_count!!!"); - - for( int i = 0; i < sobol_dim; i ++ ) { - res[i] ^= dir_matrix[y*sobol_dim + i]; - //md_zd[i] = res[i] * ro_scal->sobol_last_den_inv; - } -} - -inline static void -sobolRecOpt( const int& sobol_dim, // size of the quasi-random vector - const int& bit_count, // number of bits of Sobol numbers - const int* dir_matrix, // [bit_count, sobol_dim]: Sobol's - // direction vectors - const UINT& f_ind, // lookup-table index - UINT* res // in-out param-result -) { - const UINT f_ind_dim = f_ind * sobol_dim; - for( int i = 0; i < sobol_dim; i ++ ) - res[i] ^= dir_matrix[ f_ind_dim + i]; -} - - -/******************************************************/ -/*** Normal-to-Gaussian Distribution Transformation ***/ -/******************************************************/ - -#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ - (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ - (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) - -inline static REAL small_case(const REAL& q) { - REAL x = 0.180625 - q * q; - return q * rat_eval( - 3.387132872796366608, - 133.14166789178437745, - 1971.5909503065514427, - 13731.693765509461125, - 45921.953931549871457, - 67265.770927008700853, - 33430.575583588128105, - 2509.0809287301226727, - - 1.0, - 42.313330701600911252, - 687.1870074920579083, - 5394.1960214247511077, - 21213.794301586595867, - 39307.89580009271061, - 28729.085735721942674, - 5226.495278852854561); -} - -inline static REAL intermediate(const REAL& r) { - REAL x = r - 1.6; - return rat_eval( - 1.42343711074968357734, - 4.6303378461565452959, - 5.7694972214606914055, - 3.64784832476320460504, - 1.27045825245236838258, - 0.24178072517745061177, - 0.0227238449892691845833, - 7.7454501427834140764e-4, - - 1.0, - 2.05319162663775882187, - 1.6763848301838038494, - 0.68976733498510000455, - 0.14810397642748007459, - 0.0151986665636164571966, - 5.475938084995344946e-4, - 1.05075007164441684324e-9); -} - -inline static REAL tail(const REAL& r) { - REAL x = r - 5.0; - return rat_eval( - 6.6579046435011037772, - 5.4637849111641143699, - 1.7848265399172913358, - 0.29656057182850489123, - 0.026532189526576123093, - 0.0012426609473880784386, - 2.71155556874348757815e-5, - 2.01033439929228813265e-7, - - 1.0, - 0.59983220655588793769, - 0.13692988092273580531, - 0.0148753612908506148525, - 7.868691311456132591e-4, - 1.8463183175100546818e-5, - 1.4215117583164458887e-7, - 2.04426310338993978564e-15); -} - -/** - * Transforms the Sobol quasi-random (int) vector `sov_vct' - * to a gaussian distribution, uniformely distributed in [-inf, +inf]. - */ -inline -void uGaussian( const REAL& fract, // 2 ^ sobol_bits - const UINT& dim, // size of the Sobol quasi-random vector - const UINT* sob_vct, // [dim] Sobol quasi-random (int) vector - REAL* gauss_vct // result -) { - for ( int i = 0; i < dim; i ++ ) { - // sobol int number -> sobol real number in [0,1) - REAL sob_real = static_cast(sob_vct[i]) * fract; - - // sobol real number [0,1) -> gaussian number in (-inf, +inf) - REAL dp = sob_real - 0.5; - if ( fabs(dp) <= 0.425 ) { - gauss_vct[i]= small_case(dp); - } else { - REAL pp = (dp < 0.0) ? (0.5 + dp) : (0.5 - dp); - REAL r = sqrt (- log(pp)); - REAL x = (r <= 5.0) ? intermediate(r) : tail(r); - gauss_vct[i]= (dp < 0.0) ? (0.0 - x) : x; - } - } -} - -/******************************************************/ -/*** Brownian Bridge: Correlate each path's dates ***/ -/******************************************************/ - -/** - * Brownian Bridge entry point. - */ -inline -void brownianBridge( - const UINT& num_under, - const UINT& num_dates, - const int* bb_inds, // [3, num_dates] Brownian Bridge's indirect indexing - const REAL* bb_data, // [3, num_dates] Brownian Bridge's data - REAL* md_zd, // [num_dates, num_under] the gaussian vector - // also holds the result! - REAL* res // [num_dates, num_under] temporary array -) { - const int * bb_bi = bb_inds; - const int * bb_li = bb_inds + num_dates; - const int * bb_ri = bb_inds + 2*num_dates; - const REAL* bb_sd = bb_data; - const REAL* bb_lw = bb_data + num_dates; - const REAL* bb_rw = bb_data + 2*num_dates; - - for ( int m = 0; m < num_under; m ++ ) { - res[ (bb_bi[0]-1) * num_under + m ] = bb_sd[0] * md_zd[m]; - - for( int i = 1; i < num_dates; i ++) { - int j = bb_li[i] - 1; - int k = bb_ri[i] - 1; - int l = bb_bi[i] - 1; - - double wk = res [k*num_under + m]; - double zi = md_zd[i*num_under + m]; - - res[l*num_under + m] = (j == -1) ? - bb_rw[i] * wk + bb_sd[i] * zi : - bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * res[j*num_under + m]; - } - } - - const UINT S = num_under * num_dates; -#ifdef FAST_BB - for ( int i = S - 1; i >= num_under; i -- ) { - res[i] -= res[i - num_under]; - } -#else - for( int i = 0; i < S; i ++ ) { - if (i < num_under) - md_zd[i] = res[i]; - else md_zd[i] = res[i] - res[i - num_under]; - } -#endif - - -} - -#endif //SOBOL_GAUSS - diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/instantiate b/benchmarks/OptionPricing/implementations/cpp_sequential/instantiate deleted file mode 100755 index b6df103..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/instantiate +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -set -e - -cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/include/ParserC.h . -cp $FINPAR_LIB_DIR/include/Util.h . -cp $FINPAR_BENCHMARK_LIB_DIR/Constants.h . -cp $FINPAR_BENCHMARK_LIB_DIR/Optimizations.h . -cp $FINPAR_BENCHMARK_LIB_DIR/ParseInput.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/*h $FINPAR_IMPLEMENTATION/Makefile . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run <`sG16DYJJRzkBA8If%ElHUHl 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 diff --git a/benchmarks/OptionPricing/implementations/futhark/GenericPricing.c b/benchmarks/OptionPricing/implementations/futhark/GenericPricing.c deleted file mode 100644 index 729fdb7..0000000 --- a/benchmarks/OptionPricing/implementations/futhark/GenericPricing.c +++ /dev/null @@ -1,5323 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -struct tuple_int_mem_int { - int elem_0; - unsigned char* elem_1; - int elem_2; -}; -static struct tuple_int_mem_int futhark_main(int dir_vs_mem_size_27, - int all_md_c_mem_size_71, - int all_md_vols_mem_size_255, - int all_md_drifts_mem_size_345, - int all_md_st_mem_size_354, - int all_md_detvals_mem_size_360, - int all_md_disc_mem_size_363, - int bb_inds_mem_size_369, - int bb_data_mem_size_376, - unsigned char* dir_vs_mem_40, - unsigned char* all_md_c_mem_84, - unsigned char* all_md_vols_mem_268, - unsigned char* all_md_drifts_mem_350, - unsigned char* all_md_st_mem_359, - unsigned char* all_md_detvals_mem_361, - unsigned char* all_md_disc_mem_368, - unsigned char* bb_inds_mem_371, - unsigned char* bb_data_mem_381, - int size_14, int size_18, - int size_19, int size_20, - int size_21, int size_22, - int size_86, int size_89, - int size_90, int size_91, - int size_92, int size_93, - int size_94, int size_95, - int size_111, int size_112, - int size_113, int size_114, - int size_115, int size_116, - int size_117, - int contract_number_118, - int num_mc_it_119, - int num_dates_120, int num_und_121, - int num_models_122, - int num_bits_123); -float futhark_toFloat32(int x) -{ - return x; -} -int futhark_trunc32(float x) -{ - return x; -} -float futhark_log32(float x) -{ - return log(x); -} -float futhark_sqrt32(float x) -{ - return sqrt(x); -} -float futhark_exp32(float x) -{ - return exp(x); -} -double futhark_toFloat64(int x) -{ - return x; -} -int futhark_trunc64(double x) -{ - return x; -} -double futhark_log64(double x) -{ - return log(x); -} -double futhark_sqrt64(double x) -{ - return sqrt(x); -} -double futhark_exp64(double x) -{ - return exp(x); -} -int timeval_subtract(struct timeval* result, struct timeval* t2, - struct timeval* t1) -{ - unsigned int resolution = 1000000; - long diff = t2->tv_usec + resolution * t2->tv_sec - (t1->tv_usec + - resolution * - t1->tv_sec); - - result->tv_sec = diff / resolution; - result->tv_usec = diff % resolution; - return diff < 0; -} -struct array_reader { - char* elems; - int64_t n_elems_space; - int64_t elem_size; - int64_t n_elems_used; - int64_t* shape; - int(* elem_reader)(void*); -}; -int peekc() - -{ - int c = getchar(); - - ungetc(c, stdin); - return c; -} -void skipspaces() - -{ - int c = getchar(); - - if (isspace(c)) { - skipspaces(); - } else if (c == '/') { - // Skip to end of line. - for (; c != '\n' && c != EOF; c = getchar()) - ; - // Next line may have more spaces. - skipspaces(); - } else if (c != EOF) { - ungetc(c, stdin); - } -} -int read_elem(struct array_reader* reader) -{ - int ret; - - if (reader->n_elems_used == reader->n_elems_space) { - reader->n_elems_space *= 2; - reader->elems = realloc(reader->elems, reader->n_elems_space * - reader->elem_size); - } - ret = reader->elem_reader(reader->elems + reader->n_elems_used * - reader->elem_size); - if (ret == 0) { - reader->n_elems_used++; - } - return ret; -} -int read_array_elems(struct array_reader* reader, int dims) -{ - int c; - int ret; - int first = 1; - char* knows_dimsize = calloc(dims, sizeof(char)); - int cur_dim = dims - 1; - int64_t* elems_read_in_dim = calloc(dims, sizeof(int64_t)); - - while (1) { - skipspaces(); - c = getchar(); - if (c == ']') { - if (knows_dimsize[cur_dim]) { - if (reader->shape[cur_dim] != elems_read_in_dim[cur_dim]) { - ret = 1; - break; - } - } else { - knows_dimsize[cur_dim] = 1; - reader->shape[cur_dim] = elems_read_in_dim[cur_dim]; - } - if (cur_dim == 0) { - ret = 0; - break; - } else { - cur_dim--; - elems_read_in_dim[cur_dim]++; - } - } else if (c == ',') { - skipspaces(); - c = getchar(); - if (c == '[') { - if (cur_dim == dims - 1) { - ret = 1; - break; - } - first = 1; - cur_dim++; - elems_read_in_dim[cur_dim] = 0; - } else if (cur_dim == dims - 1) { - ungetc(c, stdin); - ret = read_elem(reader); - if (ret != 0) { - break; - } - elems_read_in_dim[cur_dim]++; - } else { - ret = 1; - break; - } - } else if (c == EOF) { - ret = 1; - break; - } else if (first) { - if (c == '[') { - if (cur_dim == dims - 1) { - ret = 1; - break; - } - cur_dim++; - elems_read_in_dim[cur_dim] = 0; - } else { - ungetc(c, stdin); - ret = read_elem(reader); - if (ret != 0) { - break; - } - elems_read_in_dim[cur_dim]++; - first = 0; - } - } else { - ret = 1; - break; - } - } - free(knows_dimsize); - free(elems_read_in_dim); - return ret; -} -int read_array(int64_t elem_size, int(* elem_reader)(void*), void** data, - int64_t* shape, int64_t dims) -{ - int ret; - struct array_reader reader; - int64_t read_dims = 0; - - while (1) { - int c; - - skipspaces(); - c = getchar(); - if (c == '[') { - read_dims++; - } else { - if (c != EOF) { - ungetc(c, stdin); - } - break; - } - } - if (read_dims != dims) { - return 1; - } - reader.shape = shape; - reader.n_elems_used = 0; - reader.elem_size = elem_size; - reader.n_elems_space = 16; - reader.elems = calloc(elem_size, reader.n_elems_space); - reader.elem_reader = elem_reader; - ret = read_array_elems(&reader, dims); - *data = reader.elems; - return ret; -} -int read_int(void* dest) -{ - skipspaces(); - if (scanf("%d", (int*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_char(void* dest) -{ - skipspaces(); - if (scanf("%c", (char*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_double(void* dest) -{ - skipspaces(); - if (scanf("%lf", (double*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_float(void* dest) -{ - skipspaces(); - if (scanf("%f", (float*) dest) == 1) { - return 0; - } else { - return 1; - } -} -int read_bool(void* dest) -{ - char b[4]; - - skipspaces(); - if (scanf("%4c", b) == 1) { - if (strncmp(b, "True", 4) == 0) { - *(int*) dest = 1; - return 0; - } else if (strncmp(b, "Fals", 4) == 0 && getchar() == 'e') { - *(int*) dest = 0; - return 0; - } else { - return 1; - } - } else { - return 1; - } -} -static struct tuple_int_mem_int futhark_main(int dir_vs_mem_size_27, - int all_md_c_mem_size_71, - int all_md_vols_mem_size_255, - int all_md_drifts_mem_size_345, - int all_md_st_mem_size_354, - int all_md_detvals_mem_size_360, - int all_md_disc_mem_size_363, - int bb_inds_mem_size_369, - int bb_data_mem_size_376, - unsigned char* dir_vs_mem_40, - unsigned char* all_md_c_mem_84, - unsigned char* all_md_vols_mem_268, - unsigned char* all_md_drifts_mem_350, - unsigned char* all_md_st_mem_359, - unsigned char* all_md_detvals_mem_361, - unsigned char* all_md_disc_mem_368, - unsigned char* bb_inds_mem_371, - unsigned char* bb_data_mem_381, - int size_14, int size_18, - int size_19, int size_20, - int size_21, int size_22, - int size_86, int size_89, - int size_90, int size_91, - int size_92, int size_93, - int size_94, int size_95, - int size_111, int size_112, - int size_113, int size_114, - int size_115, int size_116, - int size_117, - int contract_number_118, - int num_mc_it_119, - int num_dates_120, int num_und_121, - int num_models_122, - int num_bits_123) -{ - int out_memsize_24; - unsigned char* out_mem_23; - int out_arrsize_26; - char y_133; - - y_133 = 0 < size_19; - - int bounds_check_134; - - if (!y_133) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_133", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:253:16-253:24"); - abort(); - } - - char y_135; - - y_135 = 0 < size_22; - - int bounds_check_136; - - if (!y_135) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_135", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:254:19-254:30"); - abort(); - } - - char y_138; - - y_138 = 0 < size_90; - - int bounds_check_139; - - if (!y_138) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_138", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:255:21-255:34"); - abort(); - } - - char y_141; - - y_141 = 0 < size_93; - - int bounds_check_142; - - if (!y_141) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_141", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:256:17-256:26"); - abort(); - } - - char y_144; - - y_144 = 0 < size_95; - - int bounds_check_145; - - if (!y_144) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_144", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:257:22-257:36"); - abort(); - } - - char y_146; - - y_146 = 0 < size_112; - - int bounds_check_147; - - if (!y_146) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_146", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:258:19-258:30"); - abort(); - } - - char cond_149; - - cond_149 = num_mc_it_119 == 0; - - double y_150; - - y_150 = futhark_toFloat64(num_bits_123); - - double res_151; - - res_151 = powl(2.0, y_150); - - int bytes_385; - - bytes_385 = 4 * num_bits_123; - - unsigned char* mem_387; - - mem_387 = malloc(bytes_385); - for (int i_39 = 0; i_39 < num_bits_123; i_39++) { - *(int*) &mem_387[i_39 * 1 * 4 + 0] = i_39; - } - - char cond_153; - - cond_153 = num_und_121 == 0; - - int size_154; - - if (cond_153) { - size_154 = 0; - } else { - size_154 = num_dates_120; - } - - int size_155; - - if (cond_149) { - size_155 = 0; - } else { - size_155 = size_154; - } - - int y_156; - - y_156 = num_dates_120 * num_und_121; - - char assert_arg_157; - - assert_arg_157 = size_14 == y_156; - - int shape_ok_158; - - if (!assert_arg_157) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_157", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:190:20-190:27"); - abort(); - } - - char y_159; - - y_159 = 0 < size_114; - - int bounds_check_160; - - if (!y_159) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_159", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:147:14-147:21"); - abort(); - } - - char y_161; - - y_161 = 1 < size_114; - - int bounds_check_162; - - if (!y_161) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_161", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:148:14-148:21"); - abort(); - } - - char y_163; - - y_163 = 2 < size_114; - - int bounds_check_164; - - if (!y_163) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_163", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:149:14-149:21"); - abort(); - } - - char y_165; - - y_165 = 0 < size_116; - - int bounds_check_166; - - if (!y_165) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_165", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:150:14-150:21"); - abort(); - } - - char y_167; - - y_167 = 1 < size_116; - - int bounds_check_168; - - if (!y_167) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_167", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:151:14-151:21"); - abort(); - } - - char y_169; - - y_169 = 2 < size_116; - - int bounds_check_170; - - if (!y_169) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_169", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:152:14-152:21"); - abort(); - } - - int bytes_399; - - bytes_399 = 8 * num_dates_120; - - unsigned char* mem_404; - - mem_404 = malloc(bytes_399); - for (int i_56 = 0; i_56 < num_dates_120; i_56++) { - *(double*) &mem_404[i_56 * 1 * 8 + 0] = 0.0; - } - - char y_172; - - y_172 = 0 < size_115; - - int bounds_check_173; - - if (!y_172) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_172", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:156:16-156:18"); - abort(); - } - - int x_174; - - x_174 = *(int*) &bb_inds_mem_371[(0 * size_115 + 0 * 1) * 4 + 0]; - - int idx_175; - - idx_175 = x_174 - 1; - - char y_176; - - y_176 = 0 < size_117; - - int bounds_check_177; - - if (!y_176) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_176", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:156:28-156:30"); - abort(); - } - - double x_178; - - x_178 = *(double*) &bb_data_mem_381[(0 * size_117 + 0 * 1) * 8 + 0]; - - char y_179; - - y_179 = 0 < num_dates_120; - - int bounds_check_180; - - if (!y_179) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_179", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:156:36-156:41"); - abort(); - } - - char x_181; - - x_181 = 0 <= idx_175; - - char y_182; - - y_182 = idx_175 < num_dates_120; - - char assert_arg_183; - - assert_arg_183 = x_181 && y_182; - - int bounds_check_184; - - if (!assert_arg_183) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_183", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:156:5-156:8"); - abort(); - } - - int bound_185; - - bound_185 = num_dates_120 - 1; - - char assert_arg_186; - - assert_arg_186 = size_155 == num_dates_120; - - int shape_cert_187; - - if (!assert_arg_186) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_186", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:261:27-261:41"); - abort(); - } - - char cond_188; - - cond_188 = size_155 == 0; - - int size_189; - - if (cond_188) { - size_189 = 0; - } else { - size_189 = size_92; - } - - int size_190; - - if (cond_149) { - size_190 = 0; - } else { - size_190 = size_189; - } - - char zip_cmp_192; - - zip_cmp_192 = size_155 == size_86; - - int zip_assert_193; - - if (!zip_cmp_192) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_192", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:218:38-218:41"); - abort(); - } - - char zip_cmp_195; - - zip_cmp_195 = size_155 == size_91; - - int zip_assert_196; - - if (!zip_cmp_195) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_195", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:218:38-218:41"); - abort(); - } - - char zip_cmp_198; - - zip_cmp_198 = num_und_121 == size_89; - - int zip_assert_199; - - if (!zip_cmp_198) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_198", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:214:33-214:36"); - abort(); - } - - char zip_cmp_200; - - zip_cmp_200 = size_92 == num_und_121; - - int zip_assert_201; - - if (!zip_cmp_200) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_200", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:214:13-214:16"); - abort(); - } - - char assert_arg_202; - - assert_arg_202 = size_92 == size_94; - - int shape_cert_203; - - if (!assert_arg_202) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_202", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:220:9-220:13"); - abort(); - } - - char assert_arg_205; - - assert_arg_205 = size_190 == size_92; - - int shape_cert_206; - - if (!assert_arg_205) { - fprintf(stderr, "Assertion %s at %s failed.\n", "assert_arg_205", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:262:27-262:39"); - abort(); - } - - char cond_207; - - cond_207 = contract_number_118 == 1; - - char cond_208; - - cond_208 = contract_number_118 == 2; - - char cond_209; - - cond_209 = contract_number_118 == 3; - - char y_210; - - y_210 = 0 < size_111; - - char y_211; - - y_211 = 0 < size_155; - - char y_212; - - y_212 = 0 < size_190; - - char y_213; - - y_213 = 0 < size_113; - - char zip_cmp_214; - - zip_cmp_214 = size_190 == 3; - - char y_215; - - y_215 = 1 < size_155; - - char y_216; - - y_216 = 2 < size_155; - - char y_217; - - y_217 = 3 < size_155; - - char y_218; - - y_218 = 4 < size_155; - - char y_219; - - y_219 = 1 < size_113; - - char y_220; - - y_220 = 2 < size_113; - - char y_221; - - y_221 = 3 < size_113; - - char y_222; - - y_222 = 4 < size_113; - - char y_223; - - y_223 = 1 < size_190; - - char y_224; - - y_224 = 2 < size_190; - - char y_281; - - y_281 = 366 < size_155; - - int x_282; - - x_282 = 366 * size_190; - - int i_283; - - i_283 = x_282 / size_92 - (x_282 % size_92 != 0 && x_282 % size_92 < 0 != - size_92 < 0 ? 1 : 0); - - int y_284; - - y_284 = i_283 * size_92; - - int i_remnant_288; - - i_remnant_288 = x_282 - y_284; - - int flat_index_289; - - flat_index_289 = x_282 + 2; - - int i_291; - - i_291 = flat_index_289 / size_92 - (flat_index_289 % size_92 != 0 && - flat_index_289 % size_92 < 0 != - size_92 < 0 ? 1 : 0); - - int y_295; - - y_295 = i_291 * size_92; - - int i_remnant_296; - - i_remnant_296 = flat_index_289 - y_295; - - int flat_index_297; - - flat_index_297 = x_282 + 1; - - int i_298; - - i_298 = flat_index_297 / size_92 - (flat_index_297 % size_92 != 0 && - flat_index_297 % size_92 < 0 != - size_92 < 0 ? 1 : 0); - - int y_299; - - y_299 = i_298 * size_92; - - int i_remnant_300; - - i_remnant_300 = flat_index_297 - y_299; - - int new_slice_size_286; - - new_slice_size_286 = num_und_121 * size_18; - - unsigned char* mem_406; - - mem_406 = malloc(bytes_385); - - unsigned char* mem_418; - - mem_418 = malloc(bytes_385); - - int x_424; - - x_424 = 8 * num_und_121; - - int bytes_423; - - bytes_423 = x_424 * num_dates_120; - - unsigned char* mem_425; - - mem_425 = malloc(bytes_423); - - unsigned char* mem_433; - - mem_433 = malloc(bytes_399); - - unsigned char* mem_483; - - mem_483 = malloc(bytes_399); - - int x_524; - - x_524 = 8 * size_155; - - int bytes_523; - - bytes_523 = x_524 * size_92; - - unsigned char* mem_525; - - mem_525 = malloc(bytes_523); - - int x_535; - - x_535 = 8 * size_92; - - int bytes_534; - - bytes_534 = x_535 * size_155; - - unsigned char* mem_536; - - mem_536 = malloc(bytes_534); - - unsigned char* mem_540; - - mem_540 = malloc(x_524); - - unsigned char* mem_552; - - mem_552 = malloc(24); - - unsigned char* mem_554; - - mem_554 = malloc(bytes_385); - - unsigned char* mem_560; - - mem_560 = malloc(bytes_385); - - unsigned char* mem_563; - - mem_563 = malloc(bytes_423); - - unsigned char* mem_567; - - mem_567 = malloc(bytes_399); - - unsigned char* mem_573; - - mem_573 = malloc(bytes_399); - - unsigned char* mem_596; - - mem_596 = malloc(bytes_523); - - unsigned char* mem_607; - - mem_607 = malloc(bytes_534); - - unsigned char* mem_611; - - mem_611 = malloc(x_524); - - unsigned char* mem_623; - - mem_623 = malloc(x_524); - - int bytes_626; - - bytes_626 = 8 * size_190; - - unsigned char* mem_627; - - mem_627 = malloc(bytes_626); - - unsigned char* mem_640; - - mem_640 = malloc(bytes_385); - - unsigned char* mem_649; - - mem_649 = malloc(bytes_385); - - unsigned char* mem_652; - - mem_652 = malloc(bytes_423); - - unsigned char* mem_656; - - mem_656 = malloc(bytes_399); - - unsigned char* mem_662; - - mem_662 = malloc(bytes_399); - - unsigned char* mem_722; - - mem_722 = malloc(bytes_523); - - unsigned char* mem_771; - - mem_771 = malloc(bytes_534); - - unsigned char* mem_777; - - mem_777 = malloc(x_524); - - double res_2307; - - if (cond_207) { - int bounds_check_301; - - if (!y_210) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_210", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:284:16-284:26"); - abort(); - } - - double res_326; - - res_326 = *(double*) &all_md_detvals_mem_361[(0 * size_111 + 0 * 1) * - 8 + 0]; - - int bounds_check_329; - - if (!y_211) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_211", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:285:17-285:20"); - abort(); - } - - int bounds_check_330; - - if (!y_212) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_212", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:285:17-285:20"); - abort(); - } - - int bounds_check_331; - - if (!y_213) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_213", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_332; - - y_332 = *(double*) &all_md_disc_mem_368[(0 * size_113 + 0 * 1) * 8 + 0]; - - double res_989; - double acc_48; - - acc_48 = 0.0; - for (int i_47 = 0; i_47 < num_mc_it_119; i_47++) { - int res_388; - - res_388 = i_47 + 1; - - int x_389; - - x_389 = res_388 >> 1; - - int res_390; - - res_390 = x_389 ^ res_388; - for (int i_0 = 0; i_0 < num_bits_123; i_0++) { - int res_392; - - res_392 = 1 << i_0; - - int x_393; - - x_393 = res_390 & res_392; - - char res_394; - - res_394 = x_393 == res_392; - - int partition_equivalence_class_395; - - if (res_394) { - partition_equivalence_class_395 = 0; - } else { - partition_equivalence_class_395 = 1; - } - *(int*) &mem_406[i_0 * 1 * 4 + 0] = - partition_equivalence_class_395; - } - - int filter_size_397; - - filter_size_397 = 0; - - int eqclass_104; - - for (int i_103 = 0; i_103 < num_bits_123; i_103++) { - eqclass_104 = *(int*) &mem_406[i_103 * 1 * 4 + 0]; - if (eqclass_104 == 0) { - filter_size_397 = filter_size_397 + 1; - } else { } - } - - int partition_offset_109; - - partition_offset_109 = 0; - - int partition_cur_offset_110; - - for (int i_103 = 0; i_103 < num_bits_123; i_103++) { - eqclass_104 = *(int*) &mem_406[i_103 * 1 * 4 + 0]; - if (eqclass_104 == 0) { - partition_cur_offset_110 = partition_offset_109; - *(int*) &mem_418[partition_cur_offset_110 * 1 * 4 + 0] = - *(int*) &mem_387[i_103 * 1 * 4 + 0]; - partition_offset_109 = partition_offset_109 + 1; - } else { } - } - for (int i_11 = 0; i_11 < num_und_121; i_11++) { - int y_290; - - y_290 = i_11 * size_18; - for (int i_7 = 0; i_7 < num_dates_120; i_7++) { - int x_287; - - x_287 = i_7 * new_slice_size_286; - - int x_292; - - x_292 = x_287 + y_290; - - int res_443; - int acc_5; - - acc_5 = 0; - for (int i_4 = 0; i_4 < filter_size_397; i_4++) { - int not_curried_438; - - not_curried_438 = *(int*) &mem_418[i_4 * 1 * 4 + 0]; - - char y_439; - - y_439 = not_curried_438 < size_18; - - int bounds_check_440; - - if (!y_439) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_439", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:6:35-6:38"); - abort(); - } - - int flat_index_294; - - flat_index_294 = x_292 + not_curried_438; - - int i_302; - - i_302 = flat_index_294 / size_18 - (flat_index_294 % - size_18 != 0 && - flat_index_294 % - size_18 < 0 != - size_18 < - 0 ? 1 : 0); - - int y_303; - - y_303 = i_302 * size_18; - - int i_remnant_304; - - i_remnant_304 = flat_index_294 - y_303; - - int res_441; - - res_441 = *(int*) &dir_vs_mem_40[(i_302 * size_18 + - i_remnant_304 * 1) * - 4 + 0]; - - int res_442; - - res_442 = acc_5 ^ res_441; - - int acc_tmp_226; - - acc_tmp_226 = res_442; - acc_5 = acc_tmp_226; - } - res_443 = acc_5; - - double x_444; - - x_444 = futhark_toFloat64(res_443); - - double res_445; - - res_445 = x_444 / res_151; - - double res_446; - - res_446 = res_445 - 0.5; - - char x_447; - - x_447 = res_446 < 0.0; - - double x_448; - - x_448 = 0.0 - res_446; - - char y_449; - - y_449 = x_448 <= 0.425; - - char x_450; - - x_450 = x_447 && y_449; - - char x_451; - - x_451 = 0.0 <= res_446; - - char y_452; - - y_452 = res_446 <= 0.425; - - char y_453; - - y_453 = x_451 && y_452; - - char cond_454; - - cond_454 = x_450 || y_453; - - double res_455; - - res_455 = res_446 + 0.5; - - double res_456; - - res_456 = 0.5 - res_446; - - double res_457; - - if (x_447) { - res_457 = res_455; - } else { - res_457 = res_456; - } - - double y_458; - - y_458 = res_446 * res_446; - - double arg_459; - - arg_459 = 0.180625 - y_458; - - double x_460; - - x_460 = arg_459 * 2509.0809287301227; - - double y_461; - - y_461 = x_460 + 33430.57558358813; - - double x_462; - - x_462 = arg_459 * y_461; - - double y_463; - - y_463 = x_462 + 67265.7709270087; - - double x_464; - - x_464 = arg_459 * y_463; - - double y_465; - - y_465 = x_464 + 45921.95393154987; - - double x_466; - - x_466 = arg_459 * y_465; - - double y_467; - - y_467 = x_466 + 13731.69376550946; - - double x_468; - - x_468 = arg_459 * y_467; - - double y_469; - - y_469 = x_468 + 1971.5909503065513; - - double x_470; - - x_470 = arg_459 * y_469; - - double y_471; - - y_471 = x_470 + 133.14166789178438; - - double x_472; - - x_472 = arg_459 * y_471; - - double x_473; - - x_473 = x_472 + 3.3871328727963665; - - double x_474; - - x_474 = arg_459 * 5226.495278852854; - - double y_475; - - y_475 = x_474 + 28729.085735721943; - - double x_476; - - x_476 = arg_459 * y_475; - - double y_496; - - y_496 = x_476 + 39307.89580009271; - - double x_497; - - x_497 = arg_459 * y_496; - - double y_498; - - y_498 = x_497 + 21213.794301586597; - - double x_499; - - x_499 = arg_459 * y_498; - - double y_500; - - y_500 = x_499 + 5394.196021424751; - - double x_501; - - x_501 = arg_459 * y_500; - - double y_502; - - y_502 = x_501 + 687.1870074920579; - - double x_503; - - x_503 = arg_459 * y_502; - - double y_504; - - y_504 = x_503 + 42.31333070160091; - - double x_505; - - x_505 = arg_459 * y_504; - - double y_506; - - y_506 = x_505 + 1.0; - - double res_715; - - if (cond_454) { - double res_507; - - res_507 = x_473 / y_506; - - double res_508; - - res_508 = res_446 * res_507; - res_715 = res_508; - } else { - double negate_arg_509; - - negate_arg_509 = futhark_log64(res_457); - - double arg_510; - - arg_510 = -negate_arg_509; - - double res_511; - - res_511 = futhark_sqrt64(arg_510); - - char cond_512; - - cond_512 = res_511 <= 5.0; - - double arg_513; - - arg_513 = res_511 - 1.6; - - double x_514; - - x_514 = arg_513 * 7.745450142783414e-4; - - double y_515; - - y_515 = x_514 + 2.2723844989269184e-2; - - double x_516; - - x_516 = arg_513 * y_515; - - double y_517; - - y_517 = x_516 + 0.2417807251774506; - - double x_518; - - x_518 = arg_513 * y_517; - - double y_575; - - y_575 = x_518 + 1.2704582524523684; - - double x_576; - - x_576 = arg_513 * y_575; - - double y_577; - - y_577 = x_576 + 3.6478483247632045; - - double x_578; - - x_578 = arg_513 * y_577; - - double y_579; - - y_579 = x_578 + 5.769497221460691; - - double x_580; - - x_580 = arg_513 * y_579; - - double y_581; - - y_581 = x_580 + 4.630337846156546; - - double x_582; - - x_582 = arg_513 * y_581; - - double x_583; - - x_583 = x_582 + 1.4234371107496835; - - double x_633; - - x_633 = arg_513 * 1.0507500716444169e-9; - - double y_636; - - y_636 = x_633 + 5.475938084995345e-4; - - double x_637; - - x_637 = arg_513 * y_636; - - double y_638; - - y_638 = x_637 + 1.5198666563616457e-2; - - double x_639; - - x_639 = arg_513 * y_638; - - double y_642; - - y_642 = x_639 + 0.14810397642748008; - - double x_645; - - x_645 = arg_513 * y_642; - - double y_647; - - y_647 = x_645 + 0.6897673349851; - - double x_675; - - x_675 = arg_513 * y_647; - - double y_676; - - y_676 = x_675 + 1.6763848301838038; - - double x_677; - - x_677 = arg_513 * y_676; - - double y_678; - - y_678 = x_677 + 2.053191626637759; - - double x_679; - - x_679 = arg_513 * y_678; - - double y_680; - - y_680 = x_679 + 1.0; - - double arg_681; - - arg_681 = res_511 - 5.0; - - double x_682; - - x_682 = arg_681 * 2.0103343992922881e-7; - - double y_683; - - y_683 = x_682 + 2.7115555687434876e-5; - - double x_684; - - x_684 = arg_681 * y_683; - - double y_685; - - y_685 = x_684 + 1.2426609473880784e-3; - - double x_686; - - x_686 = arg_681 * y_685; - - double y_687; - - y_687 = x_686 + 2.6532189526576124e-2; - - double x_688; - - x_688 = arg_681 * y_687; - - double y_689; - - y_689 = x_688 + 0.29656057182850487; - - double x_690; - - x_690 = arg_681 * y_689; - - double y_691; - - y_691 = x_690 + 1.7848265399172913; - - double x_692; - - x_692 = arg_681 * y_691; - - double y_693; - - y_693 = x_692 + 5.463784911164114; - - double x_694; - - x_694 = arg_681 * y_693; - - double x_695; - - x_695 = x_694 + 6.657904643501103; - - double x_696; - - x_696 = arg_681 * 2.0442631033899398e-5; - - double y_697; - - y_697 = x_696 + 1.421511758316446e-7; - - double x_698; - - x_698 = arg_681 * y_697; - - double y_699; - - y_699 = x_698 + 1.8463183175100548e-5; - - double x_700; - - x_700 = arg_681 * y_699; - - double y_701; - - y_701 = x_700 + 7.868691311456133e-4; - - double x_702; - - x_702 = arg_681 * y_701; - - double y_703; - - y_703 = x_702 + 1.4875361290850615e-2; - - double x_704; - - x_704 = arg_681 * y_703; - - double y_705; - - y_705 = x_704 + 0.1369298809227358; - - double x_706; - - x_706 = arg_681 * y_705; - - double y_707; - - y_707 = x_706 + 0.599832206555888; - - double x_708; - - x_708 = arg_681 * y_707; - - double y_709; - - y_709 = x_708 + 1.0; - - double res_712; - - if (cond_512) { - double res_710; - - res_710 = x_583 / y_680; - res_712 = res_710; - } else { - double res_711; - - res_711 = x_695 / y_709; - res_712 = res_711; - } - - double res_713; - - res_713 = 0.0 - res_712; - - double res_714; - - if (x_447) { - res_714 = res_713; - } else { - res_714 = res_712; - } - res_715 = res_714; - } - *(double*) &mem_433[i_7 * 1 * 8 + 0] = res_715; - } - memmove(mem_483 + 0, mem_404 + 0, num_dates_120 * - sizeof(double)); - - double y_719; - - y_719 = *(double*) &mem_433[0 * 1 * 8 + 0]; - - double lw_val_720; - - lw_val_720 = x_178 * y_719; - *(double*) &mem_483[idx_175 * 1 * 8 + 0] = lw_val_720; - for (int i_251 = 0; i_251 < num_dates_120; i_251++) { - *(double*) &mem_425[8 * (i_11 * num_dates_120) + 8 * - i_251] = *(double*) &mem_483[8 * i_251]; - } - for (int i_723 = 0; i_723 < bound_185; i_723++) { - int i_724; - - i_724 = i_723 + 1; - - char y_725; - - y_725 = i_724 < size_115; - - int bounds_check_727; - - if (!y_725) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_725", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:160:22-160:24"); - abort(); - } - - int x_728; - - x_728 = *(int*) &bb_inds_mem_371[(1 * size_115 + i_724 * - 1) * 4 + 0]; - - int res_729; - - res_729 = x_728 - 1; - - int x_730; - - x_730 = *(int*) &bb_inds_mem_371[(2 * size_115 + i_724 * - 1) * 4 + 0]; - - int res_731; - - res_731 = x_730 - 1; - - int x_736; - - x_736 = *(int*) &bb_inds_mem_371[(0 * size_115 + i_724 * - 1) * 4 + 0]; - - int res_737; - - res_737 = x_736 - 1; - - char x_738; - - x_738 = 0 <= res_731; - - char y_739; - - y_739 = res_731 < num_dates_120; - - char assert_arg_740; - - assert_arg_740 = x_738 && y_739; - - int bounds_check_741; - - if (!assert_arg_740) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_740", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:164:22-164:27"); - abort(); - } - - double res_742; - - res_742 = *(double*) &mem_425[(i_11 * num_dates_120 + - res_731 * 1) * 8 + 0]; - - double res_743; - - res_743 = *(double*) &mem_433[i_724 * 1 * 8 + 0]; - - char y_744; - - y_744 = i_724 < size_117; - - int bounds_check_745; - - if (!y_744) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_744", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:166:22-166:24"); - abort(); - } - - double x_746; - - x_746 = *(double*) &bb_data_mem_381[(2 * size_117 + i_724 * - 1) * 8 + 0]; - - double x_747; - - x_747 = x_746 * res_742; - - double x_748; - - x_748 = *(double*) &bb_data_mem_381[(0 * size_117 + i_724 * - 1) * 8 + 0]; - - double y_749; - - y_749 = x_748 * res_743; - - double res_750; - - res_750 = x_747 + y_749; - - int x_751; - - x_751 = res_729 + 1; - - char cond_752; - - cond_752 = x_751 == 0; - - char x_753; - - x_753 = 0 <= res_729; - - char y_754; - - y_754 = res_729 < num_dates_120; - - char assert_arg_755; - - assert_arg_755 = x_753 && y_754; - - double lw_val_761; - - if (cond_752) { - lw_val_761 = res_750; - } else { - double x_756; - - x_756 = *(double*) &bb_data_mem_381[(1 * size_117 + - i_724 * 1) * 8 + - 0]; - - int bounds_check_757; - - if (!assert_arg_755) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_755", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:170:51-170:56"); - abort(); - } - - double y_758; - - y_758 = *(double*) &mem_425[(i_11 * num_dates_120 + - res_729 * 1) * 8 + 0]; - - double y_759; - - y_759 = x_756 * y_758; - - double res_760; - - res_760 = res_750 + y_759; - lw_val_761 = res_760; - } - - char x_762; - - x_762 = 0 <= res_737; - - char y_763; - - y_763 = res_737 < num_dates_120; - - char assert_arg_764; - - assert_arg_764 = x_762 && y_763; - - int bounds_check_768; - - if (!assert_arg_764) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_764", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:168:13-168:16"); - abort(); - } - *(double*) &mem_425[(i_11 * num_dates_120 + res_737 * 1) * - 8 + 0] = lw_val_761; - } - for (int ii_778 = 0; ii_778 < bound_185; ii_778++) { - int y_779; - - y_779 = ii_778 + 1; - - int res_780; - - res_780 = num_dates_120 - y_779; - - double x_781; - - x_781 = *(double*) &mem_425[(i_11 * num_dates_120 + - res_780 * 1) * 8 + 0]; - - int i_782; - - i_782 = res_780 - 1; - - double y_783; - - y_783 = *(double*) &mem_425[(i_11 * num_dates_120 + i_782 * - 1) * 8 + 0]; - - double lw_val_784; - - lw_val_784 = x_781 - y_783; - *(double*) &mem_425[(i_11 * num_dates_120 + res_780 * 1) * - 8 + 0] = lw_val_784; - } - } - for (int i_29 = 0; i_29 < size_155; i_29++) { - int x_308; - - x_308 = i_29 * size_92; - - int x_317; - - x_317 = i_29 * size_89; - - int x_143; - - x_143 = i_29 * num_und_121; - for (int i_25 = 0; i_25 < size_92; i_25++) { - int flat_index_310; - - flat_index_310 = x_308 + i_25; - - int i_311; - - i_311 = flat_index_310 / size_92 - (flat_index_310 % - size_92 != 0 && - flat_index_310 % - size_92 < 0 != size_92 < - 0 ? 1 : 0); - - int y_312; - - y_312 = i_311 * size_92; - - int i_remnant_313; - - i_remnant_313 = flat_index_310 - y_312; - - double x_942; - - x_942 = *(double*) &all_md_drifts_mem_350[(0 * (size_91 * - size_92) + - i_311 * size_92 + - i_remnant_313 * - 1) * 8 + 0]; - - int flat_index_319; - - flat_index_319 = x_317 + i_25; - - int i_320; - - i_320 = flat_index_319 / size_89 - (flat_index_319 % - size_89 != 0 && - flat_index_319 % - size_89 < 0 != size_89 < - 0 ? 1 : 0); - - int y_321; - - y_321 = i_320 * size_89; - - int i_remnant_322; - - i_remnant_322 = flat_index_319 - y_321; - - double y_943; - - y_943 = *(double*) &all_md_vols_mem_268[(0 * (size_86 * - size_89) + - i_320 * size_89 + - i_remnant_322 * - 1) * 8 + 0]; - - int arg_944; - - arg_944 = i_25 + 1; - - char y_948; - - y_948 = i_25 < size_20; - - int bounds_check_949; - - if (!y_948) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_948", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:205:58-205:62"); - abort(); - } - - char split_index_cnd_951; - - split_index_cnd_951 = arg_944 <= size_21; - - int split_index_assert_952; - - if (!split_index_cnd_951) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "split_index_cnd_951", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:201:56-201:61"); - abort(); - } - - double res_965; - double acc_17; - - acc_17 = 0.0; - for (int i_16 = 0; i_16 < arg_944; i_16++) { - int flat_index_194; - - flat_index_194 = x_143 + i_16; - - int i_197; - - i_197 = flat_index_194 / num_und_121 - (flat_index_194 % - num_und_121 != - 0 && - flat_index_194 % - num_und_121 < - 0 != - num_und_121 < - 0 ? 1 : 0); - - int y_204; - - y_204 = i_197 * num_und_121; - - int i_remnant_225; - - i_remnant_225 = flat_index_194 - y_204; - - double x_961; - - x_961 = *(double*) &mem_425[(i_remnant_225 * - num_dates_120 + i_197 * - 1) * 8 + 0]; - - double x_962; - - x_962 = *(double*) &all_md_c_mem_84[(0 * (size_20 * - size_21) + - i_25 * size_21 + - i_16 * 1) * 8 + 0]; - - double res_963; - - res_963 = x_961 * x_962; - - double res_964; - - res_964 = acc_17 + res_963; - - double acc_tmp_293; - - acc_tmp_293 = res_964; - acc_17 = acc_tmp_293; - } - res_965 = acc_17; - - double res_966; - - res_966 = res_965 * y_943; - - double res_967; - - res_967 = x_942 + res_966; - *(double*) &mem_525[(i_29 * size_92 + i_25 * 1) * 8 + 0] = - res_967; - } - } - for (int i_43 = 0; i_43 < size_92; i_43++) { - double x_973; - - x_973 = *(double*) &all_md_st_mem_359[(0 * size_94 + i_43 * 1) * - 8 + 0]; - for (int i_33 = 0; i_33 < size_155; i_33++) { - double not_curried_974; - - not_curried_974 = *(double*) &mem_525[(i_33 * size_92 + - i_43 * 1) * 8 + 0]; - - double curried_fun_result_975; - - curried_fun_result_975 = futhark_exp64(not_curried_974); - *(double*) &mem_540[i_33 * 1 * 8 + 0] = - curried_fun_result_975; - } - - double acc_38; - - acc_38 = x_973; - for (int i_37 = 0; i_37 < size_155; i_37++) { - double y_978; - - y_978 = *(double*) &mem_540[i_37 * 1 * 8 + 0]; - - double res_979; - - res_979 = acc_38 * y_978; - *(double*) &mem_536[(i_43 * size_155 + i_37 * 1) * 8 + 0] = - res_979; - - double row_42; - - row_42 = *(double*) &mem_536[(i_43 * size_155 + i_37 * 1) * - 8 + 0]; - - double acc_tmp_314; - - acc_tmp_314 = row_42; - acc_38 = acc_tmp_314; - } - } - - double x_982; - - x_982 = *(double*) &mem_536[(0 * size_155 + 0 * 1) * 8 + 0]; - - double x_983; - - x_983 = x_982 - 4000.0; - - double res_984; - - res_984 = x_983 * res_326; - - char cond_985; - - cond_985 = res_984 < 0.0; - - double res_986; - - if (cond_985) { - res_986 = 0.0; - } else { - res_986 = res_984; - } - - double res_987; - - res_987 = res_986 * y_332; - - double res_988; - - res_988 = acc_48 + res_987; - - double acc_tmp_70; - - acc_tmp_70 = res_988; - acc_48 = acc_tmp_70; - } - res_989 = acc_48; - res_2307 = res_989; - } else { - double res_2306; - - if (cond_208) { - *(double*) &mem_552[0 * 1 * 8 + 0] = 2.6609544843735446e-4; - *(double*) &mem_552[1 * 1 * 8 + 0] = 8.445945945945946e-5; - *(double*) &mem_552[2 * 1 * 8 + 0] = 8.333333333333334e-4; - - int zip_assert_991; - - if (!zip_cmp_214) { - fprintf(stderr, "Assertion %s at %s failed.\n", "zip_cmp_214", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:292:56-292:59"); - abort(); - } - - int bounds_check_993; - - if (!y_212) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_212", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:329:62-329:65"); - abort(); - } - - int bounds_check_994; - - if (!y_211) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_211", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:294:20-294:24"); - abort(); - } - - double res_1845; - double acc_232; - - acc_232 = 0.0; - for (int i_231 = 0; i_231 < num_mc_it_119; i_231++) { - int res_1000; - - res_1000 = i_231 + 1; - - int x_1001; - - x_1001 = res_1000 >> 1; - - int res_1002; - - res_1002 = x_1001 ^ res_1000; - for (int i_50 = 0; i_50 < num_bits_123; i_50++) { - int res_1004; - - res_1004 = 1 << i_50; - - int x_1005; - - x_1005 = res_1002 & res_1004; - - char res_1006; - - res_1006 = x_1005 == res_1004; - - int partition_equivalence_class_1007; - - if (res_1006) { - partition_equivalence_class_1007 = 0; - } else { - partition_equivalence_class_1007 = 1; - } - *(int*) &mem_554[i_50 * 1 * 4 + 0] = - partition_equivalence_class_1007; - } - - int filter_size_1009; - - filter_size_1009 = 0; - - int eqclass_341; - - for (int i_336 = 0; i_336 < num_bits_123; i_336++) { - eqclass_341 = *(int*) &mem_554[i_336 * 1 * 4 + 0]; - if (eqclass_341 == 0) { - filter_size_1009 = filter_size_1009 + 1; - } else { } - } - - int partition_offset_370; - - partition_offset_370 = 0; - - int partition_cur_offset_372; - - for (int i_336 = 0; i_336 < num_bits_123; i_336++) { - eqclass_341 = *(int*) &mem_554[i_336 * 1 * 4 + 0]; - if (eqclass_341 == 0) { - partition_cur_offset_372 = partition_offset_370; - *(int*) &mem_560[partition_cur_offset_372 * 1 * 4 + 0] = - *(int*) &mem_387[i_336 * 1 * 4 + 0]; - partition_offset_370 = partition_offset_370 + 1; - } else { } - } - for (int i_61 = 0; i_61 < num_und_121; i_61++) { - int y_334; - - y_334 = i_61 * size_18; - for (int i_57 = 0; i_57 < num_dates_120; i_57++) { - int x_333; - - x_333 = i_57 * new_slice_size_286; - - int x_335; - - x_335 = x_333 + y_334; - - int res_1055; - int acc_55; - - acc_55 = 0; - for (int i_54 = 0; i_54 < filter_size_1009; i_54++) { - int not_curried_1050; - - not_curried_1050 = *(int*) &mem_560[i_54 * 1 * 4 + - 0]; - - char y_1051; - - y_1051 = not_curried_1050 < size_18; - - int bounds_check_1052; - - if (!y_1051) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_1051", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:6:35-6:38"); - abort(); - } - - int flat_index_337; - - flat_index_337 = x_335 + not_curried_1050; - - int i_338; - - i_338 = flat_index_337 / size_18 - (flat_index_337 % - size_18 != 0 && - flat_index_337 % - size_18 < 0 != - size_18 < - 0 ? 1 : 0); - - int y_339; - - y_339 = i_338 * size_18; - - int i_remnant_340; - - i_remnant_340 = flat_index_337 - y_339; - - int res_1053; - - res_1053 = *(int*) &dir_vs_mem_40[(i_338 * size_18 + - i_remnant_340 * - 1) * 4 + 0]; - - int res_1054; - - res_1054 = acc_55 ^ res_1053; - - int acc_tmp_413; - - acc_tmp_413 = res_1054; - acc_55 = acc_tmp_413; - } - res_1055 = acc_55; - - double x_1056; - - x_1056 = futhark_toFloat64(res_1055); - - double res_1057; - - res_1057 = x_1056 / res_151; - - double res_1058; - - res_1058 = res_1057 - 0.5; - - char x_1059; - - x_1059 = res_1058 < 0.0; - - double x_1060; - - x_1060 = 0.0 - res_1058; - - char y_1061; - - y_1061 = x_1060 <= 0.425; - - char x_1062; - - x_1062 = x_1059 && y_1061; - - char x_1063; - - x_1063 = 0.0 <= res_1058; - - char y_1064; - - y_1064 = res_1058 <= 0.425; - - char y_1065; - - y_1065 = x_1063 && y_1064; - - char cond_1066; - - cond_1066 = x_1062 || y_1065; - - double res_1067; - - res_1067 = res_1058 + 0.5; - - double res_1068; - - res_1068 = 0.5 - res_1058; - - double res_1069; - - if (x_1059) { - res_1069 = res_1067; - } else { - res_1069 = res_1068; - } - - double y_1070; - - y_1070 = res_1058 * res_1058; - - double arg_1071; - - arg_1071 = 0.180625 - y_1070; - - double x_1072; - - x_1072 = arg_1071 * 2509.0809287301227; - - double y_1073; - - y_1073 = x_1072 + 33430.57558358813; - - double x_1074; - - x_1074 = arg_1071 * y_1073; - - double y_1075; - - y_1075 = x_1074 + 67265.7709270087; - - double x_1076; - - x_1076 = arg_1071 * y_1075; - - double y_1077; - - y_1077 = x_1076 + 45921.95393154987; - - double x_1079; - - x_1079 = arg_1071 * y_1077; - - double y_1081; - - y_1081 = x_1079 + 13731.69376550946; - - double x_1082; - - x_1082 = arg_1071 * y_1081; - - double y_1083; - - y_1083 = x_1082 + 1971.5909503065513; - - double x_1084; - - x_1084 = arg_1071 * y_1083; - - double y_1085; - - y_1085 = x_1084 + 133.14166789178438; - - double x_1086; - - x_1086 = arg_1071 * y_1085; - - double x_1087; - - x_1087 = x_1086 + 3.3871328727963665; - - double x_1088; - - x_1088 = arg_1071 * 5226.495278852854; - - double y_1089; - - y_1089 = x_1088 + 28729.085735721943; - - double x_1090; - - x_1090 = arg_1071 * y_1089; - - double y_1096; - - y_1096 = x_1090 + 39307.89580009271; - - double x_1097; - - x_1097 = arg_1071 * y_1096; - - double y_1098; - - y_1098 = x_1097 + 21213.794301586597; - - double x_1099; - - x_1099 = arg_1071 * y_1098; - - double y_1100; - - y_1100 = x_1099 + 5394.196021424751; - - double x_1101; - - x_1101 = arg_1071 * y_1100; - - double y_1102; - - y_1102 = x_1101 + 687.1870074920579; - - double x_1103; - - x_1103 = arg_1071 * y_1102; - - double y_1104; - - y_1104 = x_1103 + 42.31333070160091; - - double x_1105; - - x_1105 = arg_1071 * y_1104; - - double y_1106; - - y_1106 = x_1105 + 1.0; - - double res_1596; - - if (cond_1066) { - double res_1107; - - res_1107 = x_1087 / y_1106; - - double res_1108; - - res_1108 = res_1058 * res_1107; - res_1596 = res_1108; - } else { - double negate_arg_1185; - - negate_arg_1185 = futhark_log64(res_1069); - - double arg_1186; - - arg_1186 = -negate_arg_1185; - - double res_1187; - - res_1187 = futhark_sqrt64(arg_1186); - - char cond_1188; - - cond_1188 = res_1187 <= 5.0; - - double arg_1189; - - arg_1189 = res_1187 - 1.6; - - double x_1216; - - x_1216 = arg_1189 * 7.745450142783414e-4; - - double y_1225; - - y_1225 = x_1216 + 2.2723844989269184e-2; - - double x_1229; - - x_1229 = arg_1189 * y_1225; - - double y_1230; - - y_1230 = x_1229 + 0.2417807251774506; - - double x_1231; - - x_1231 = arg_1189 * y_1230; - - double y_1245; - - y_1245 = x_1231 + 1.2704582524523684; - - double x_1371; - - x_1371 = arg_1189 * y_1245; - - double y_1376; - - y_1376 = x_1371 + 3.6478483247632045; - - double x_1380; - - x_1380 = arg_1189 * y_1376; - - double y_1381; - - y_1381 = x_1380 + 5.769497221460691; - - double x_1382; - - x_1382 = arg_1189 * y_1381; - - double y_1413; - - y_1413 = x_1382 + 4.630337846156546; - - double x_1540; - - x_1540 = arg_1189 * y_1413; - - double x_1545; - - x_1545 = x_1540 + 1.4234371107496835; - - double x_1546; - - x_1546 = arg_1189 * 1.0507500716444169e-9; - - double y_1547; - - y_1547 = x_1546 + 5.475938084995345e-4; - - double x_1548; - - x_1548 = arg_1189 * y_1547; - - double y_1549; - - y_1549 = x_1548 + 1.5198666563616457e-2; - - double x_1550; - - x_1550 = arg_1189 * y_1549; - - double y_1551; - - y_1551 = x_1550 + 0.14810397642748008; - - double x_1552; - - x_1552 = arg_1189 * y_1551; - - double y_1553; - - y_1553 = x_1552 + 0.6897673349851; - - double x_1554; - - x_1554 = arg_1189 * y_1553; - - double y_1555; - - y_1555 = x_1554 + 1.6763848301838038; - - double x_1556; - - x_1556 = arg_1189 * y_1555; - - double y_1557; - - y_1557 = x_1556 + 2.053191626637759; - - double x_1558; - - x_1558 = arg_1189 * y_1557; - - double y_1559; - - y_1559 = x_1558 + 1.0; - - double arg_1560; - - arg_1560 = res_1187 - 5.0; - - double x_1561; - - x_1561 = arg_1560 * 2.0103343992922881e-7; - - double y_1562; - - y_1562 = x_1561 + 2.7115555687434876e-5; - - double x_1563; - - x_1563 = arg_1560 * y_1562; - - double y_1564; - - y_1564 = x_1563 + 1.2426609473880784e-3; - - double x_1565; - - x_1565 = arg_1560 * y_1564; - - double y_1568; - - y_1568 = x_1565 + 2.6532189526576124e-2; - - double x_1569; - - x_1569 = arg_1560 * y_1568; - - double y_1570; - - y_1570 = x_1569 + 0.29656057182850487; - - double x_1571; - - x_1571 = arg_1560 * y_1570; - - double y_1572; - - y_1572 = x_1571 + 1.7848265399172913; - - double x_1573; - - x_1573 = arg_1560 * y_1572; - - double y_1574; - - y_1574 = x_1573 + 5.463784911164114; - - double x_1575; - - x_1575 = arg_1560 * y_1574; - - double x_1576; - - x_1576 = x_1575 + 6.657904643501103; - - double x_1577; - - x_1577 = arg_1560 * 2.0442631033899398e-5; - - double y_1578; - - y_1578 = x_1577 + 1.421511758316446e-7; - - double x_1579; - - x_1579 = arg_1560 * y_1578; - - double y_1580; - - y_1580 = x_1579 + 1.8463183175100548e-5; - - double x_1581; - - x_1581 = arg_1560 * y_1580; - - double y_1582; - - y_1582 = x_1581 + 7.868691311456133e-4; - - double x_1583; - - x_1583 = arg_1560 * y_1582; - - double y_1584; - - y_1584 = x_1583 + 1.4875361290850615e-2; - - double x_1585; - - x_1585 = arg_1560 * y_1584; - - double y_1586; - - y_1586 = x_1585 + 0.1369298809227358; - - double x_1587; - - x_1587 = arg_1560 * y_1586; - - double y_1588; - - y_1588 = x_1587 + 0.599832206555888; - - double x_1589; - - x_1589 = arg_1560 * y_1588; - - double y_1590; - - y_1590 = x_1589 + 1.0; - - double res_1593; - - if (cond_1188) { - double res_1591; - - res_1591 = x_1545 / y_1559; - res_1593 = res_1591; - } else { - double res_1592; - - res_1592 = x_1576 / y_1590; - res_1593 = res_1592; - } - - double res_1594; - - res_1594 = 0.0 - res_1593; - - double res_1595; - - if (x_1059) { - res_1595 = res_1594; - } else { - res_1595 = res_1593; - } - res_1596 = res_1595; - } - *(double*) &mem_567[i_57 * 1 * 8 + 0] = res_1596; - } - memmove(mem_573 + 0, mem_404 + 0, num_dates_120 * - sizeof(double)); - - double y_1600; - - y_1600 = *(double*) &mem_567[0 * 1 * 8 + 0]; - - double lw_val_1601; - - lw_val_1601 = x_178 * y_1600; - *(double*) &mem_573[idx_175 * 1 * 8 + 0] = lw_val_1601; - for (int i_414 = 0; i_414 < num_dates_120; i_414++) { - *(double*) &mem_563[8 * (i_61 * num_dates_120) + 8 * - i_414] = *(double*) &mem_573[8 * - i_414]; - } - for (int i_1604 = 0; i_1604 < bound_185; i_1604++) { - int i_1605; - - i_1605 = i_1604 + 1; - - char y_1606; - - y_1606 = i_1605 < size_115; - - int bounds_check_1607; - - if (!y_1606) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_1606", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:160:22-160:24"); - abort(); - } - - int x_1608; - - x_1608 = *(int*) &bb_inds_mem_371[(1 * size_115 + - i_1605 * 1) * 4 + 0]; - - int res_1609; - - res_1609 = x_1608 - 1; - - int x_1610; - - x_1610 = *(int*) &bb_inds_mem_371[(2 * size_115 + - i_1605 * 1) * 4 + 0]; - - int res_1611; - - res_1611 = x_1610 - 1; - - int x_1612; - - x_1612 = *(int*) &bb_inds_mem_371[(0 * size_115 + - i_1605 * 1) * 4 + 0]; - - int res_1613; - - res_1613 = x_1612 - 1; - - char x_1614; - - x_1614 = 0 <= res_1611; - - char y_1615; - - y_1615 = res_1611 < num_dates_120; - - char assert_arg_1616; - - assert_arg_1616 = x_1614 && y_1615; - - int bounds_check_1617; - - if (!assert_arg_1616) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_1616", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:164:22-164:27"); - abort(); - } - - double res_1618; - - res_1618 = *(double*) &mem_563[(i_61 * num_dates_120 + - res_1611 * 1) * 8 + 0]; - - double res_1619; - - res_1619 = *(double*) &mem_567[i_1605 * 1 * 8 + 0]; - - char y_1620; - - y_1620 = i_1605 < size_117; - - int bounds_check_1621; - - if (!y_1620) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_1620", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:166:22-166:24"); - abort(); - } - - double x_1622; - - x_1622 = *(double*) &bb_data_mem_381[(2 * size_117 + - i_1605 * 1) * 8 + - 0]; - - double x_1623; - - x_1623 = x_1622 * res_1618; - - double x_1624; - - x_1624 = *(double*) &bb_data_mem_381[(0 * size_117 + - i_1605 * 1) * 8 + - 0]; - - double y_1625; - - y_1625 = x_1624 * res_1619; - - double res_1626; - - res_1626 = x_1623 + y_1625; - - int x_1627; - - x_1627 = res_1609 + 1; - - char cond_1628; - - cond_1628 = x_1627 == 0; - - char x_1629; - - x_1629 = 0 <= res_1609; - - char y_1630; - - y_1630 = res_1609 < num_dates_120; - - char assert_arg_1631; - - assert_arg_1631 = x_1629 && y_1630; - - double lw_val_1637; - - if (cond_1628) { - lw_val_1637 = res_1626; - } else { - double x_1632; - - x_1632 = *(double*) &bb_data_mem_381[(1 * size_117 + - i_1605 * 1) * - 8 + 0]; - - int bounds_check_1633; - - if (!assert_arg_1631) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_1631", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:170:51-170:56"); - abort(); - } - - double y_1634; - - y_1634 = *(double*) &mem_563[(i_61 * num_dates_120 + - res_1609 * 1) * 8 + - 0]; - - double y_1635; - - y_1635 = x_1632 * y_1634; - - double res_1636; - - res_1636 = res_1626 + y_1635; - lw_val_1637 = res_1636; - } - - char x_1638; - - x_1638 = 0 <= res_1613; - - char y_1639; - - y_1639 = res_1613 < num_dates_120; - - char assert_arg_1640; - - assert_arg_1640 = x_1638 && y_1639; - - int bounds_check_1641; - - if (!assert_arg_1640) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_1640", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:168:13-168:16"); - abort(); - } - *(double*) &mem_563[(i_61 * num_dates_120 + res_1613 * - 1) * 8 + 0] = lw_val_1637; - } - for (int ii_1645 = 0; ii_1645 < bound_185; ii_1645++) { - int y_1646; - - y_1646 = ii_1645 + 1; - - int res_1647; - - res_1647 = num_dates_120 - y_1646; - - double x_1648; - - x_1648 = *(double*) &mem_563[(i_61 * num_dates_120 + - res_1647 * 1) * 8 + 0]; - - int i_1649; - - i_1649 = res_1647 - 1; - - double y_1650; - - y_1650 = *(double*) &mem_563[(i_61 * num_dates_120 + - i_1649 * 1) * 8 + 0]; - - double lw_val_1651; - - lw_val_1651 = x_1648 - y_1650; - *(double*) &mem_563[(i_61 * num_dates_120 + res_1647 * - 1) * 8 + 0] = lw_val_1651; - } - } - for (int i_73 = 0; i_73 < size_155; i_73++) { - int x_344; - - x_344 = i_73 * size_92; - - int x_353; - - x_353 = i_73 * size_89; - - int x_325; - - x_325 = i_73 * num_und_121; - for (int i_69 = 0; i_69 < size_92; i_69++) { - int flat_index_346; - - flat_index_346 = x_344 + i_69; - - int i_347; - - i_347 = flat_index_346 / size_92 - (flat_index_346 % - size_92 != 0 && - flat_index_346 % - size_92 < 0 != - size_92 < - 0 ? 1 : 0); - - int y_348; - - y_348 = i_347 * size_92; - - int i_remnant_349; - - i_remnant_349 = flat_index_346 - y_348; - - double x_1688; - - x_1688 = *(double*) &all_md_drifts_mem_350[(0 * - (size_91 * - size_92) + - i_347 * - size_92 + - i_remnant_349 * - 1) * 8 + 0]; - - int flat_index_355; - - flat_index_355 = x_353 + i_69; - - int i_356; - - i_356 = flat_index_355 / size_89 - (flat_index_355 % - size_89 != 0 && - flat_index_355 % - size_89 < 0 != - size_89 < - 0 ? 1 : 0); - - int y_357; - - y_357 = i_356 * size_89; - - int i_remnant_358; - - i_remnant_358 = flat_index_355 - y_357; - - double y_1690; - - y_1690 = *(double*) &all_md_vols_mem_268[(0 * (size_86 * - size_89) + - i_356 * - size_89 + - i_remnant_358 * - 1) * 8 + 0]; - - int arg_1691; - - arg_1691 = i_69 + 1; - - char y_1695; - - y_1695 = i_69 < size_20; - - int bounds_check_1696; - - if (!y_1695) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_1695", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:205:58-205:62"); - abort(); - } - - char split_index_cnd_1698; - - split_index_cnd_1698 = arg_1691 <= size_21; - - int split_index_assert_1699; - - if (!split_index_cnd_1698) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "split_index_cnd_1698", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:201:56-201:61"); - abort(); - } - - double res_1711; - double acc_66; - - acc_66 = 0.0; - for (int i_65 = 0; i_65 < arg_1691; i_65++) { - double x_1707; - - x_1707 = *(double*) &all_md_c_mem_84[(0 * (size_20 * - size_21) + - i_69 * - size_21 + - i_65 * 1) * - 8 + 0]; - - int flat_index_342; - - flat_index_342 = x_325 + i_65; - - int i_343; - - i_343 = flat_index_342 / num_und_121 - - (flat_index_342 % num_und_121 != 0 && - flat_index_342 % num_und_121 < 0 != - num_und_121 < 0 ? 1 : 0); - - int y_351; - - y_351 = i_343 * num_und_121; - - int i_remnant_352; - - i_remnant_352 = flat_index_342 - y_351; - - double x_1708; - - x_1708 = *(double*) &mem_563[(i_remnant_352 * - num_dates_120 + - i_343 * 1) * 8 + 0]; - - double res_1709; - - res_1709 = x_1708 * x_1707; - - double res_1710; - - res_1710 = acc_66 + res_1709; - - double acc_tmp_429; - - acc_tmp_429 = res_1710; - acc_66 = acc_tmp_429; - } - res_1711 = acc_66; - - double res_1712; - - res_1712 = res_1711 * y_1690; - - double res_1713; - - res_1713 = x_1688 + res_1712; - *(double*) &mem_596[(i_73 * size_92 + i_69 * 1) * 8 + - 0] = res_1713; - } - } - for (int i_88 = 0; i_88 < size_92; i_88++) { - double x_1719; - - x_1719 = *(double*) &all_md_st_mem_359[(0 * size_94 + i_88 * - 1) * 8 + 0]; - for (int i_77 = 0; i_77 < size_155; i_77++) { - double not_curried_1720; - - not_curried_1720 = *(double*) &mem_596[(i_77 * size_92 + - i_88 * 1) * 8 + - 0]; - - double curried_fun_result_1721; - - curried_fun_result_1721 = - futhark_exp64(not_curried_1720); - *(double*) &mem_611[i_77 * 1 * 8 + 0] = - curried_fun_result_1721; - } - - double acc_82; - - acc_82 = x_1719; - for (int i_81 = 0; i_81 < size_155; i_81++) { - double y_1724; - - y_1724 = *(double*) &mem_611[i_81 * 1 * 8 + 0]; - - double res_1725; - - res_1725 = acc_82 * y_1724; - *(double*) &mem_607[(i_88 * size_155 + i_81 * 1) * 8 + - 0] = res_1725; - - double row_87; - - row_87 = *(double*) &mem_607[(i_88 * size_155 + i_81 * - 1) * 8 + 0]; - - double acc_tmp_436; - - acc_tmp_436 = row_87; - acc_82 = acc_tmp_436; - } - } - for (int i_227 = 0; i_227 < size_155; i_227++) { - int x_362; - - x_362 = i_227 * size_190; - for (int i_99 = 0; i_99 < size_190; i_99++) { - int flat_index_364; - - flat_index_364 = x_362 + i_99; - - int i_365; - - i_365 = flat_index_364 / size_92 - (flat_index_364 % - size_92 != 0 && - flat_index_364 % - size_92 < 0 != - size_92 < - 0 ? 1 : 0); - - int y_366; - - y_366 = i_365 * size_92; - - int i_remnant_367; - - i_remnant_367 = flat_index_364 - y_366; - - double x_1731; - - x_1731 = *(double*) &mem_607[(i_remnant_367 * size_155 + - i_365 * 1) * 8 + 0]; - - double y_1732; - - y_1732 = *(double*) &mem_552[i_99 * 1 * 8 + 0]; - - double res_1733; - - res_1733 = x_1731 * y_1732; - *(double*) &mem_627[i_99 * 1 * 8 + 0] = res_1733; - } - - double reduce_ne_1735; - - reduce_ne_1735 = *(double*) &mem_627[0 * 1 * 8 + 0]; - - double res_1751; - double acc_108; - - acc_108 = reduce_ne_1735; - for (int i_107 = 0; i_107 < size_190; i_107++) { - double y_1745; - - y_1745 = *(double*) &mem_552[i_107 * 1 * 8 + 0]; - - int flat_index_382; - - flat_index_382 = x_362 + i_107; - - int i_383; - - i_383 = flat_index_382 / size_92 - (flat_index_382 % - size_92 != 0 && - flat_index_382 % - size_92 < 0 != - size_92 < - 0 ? 1 : 0); - - int y_386; - - y_386 = i_383 * size_92; - - int i_remnant_391; - - i_remnant_391 = flat_index_382 - y_386; - - double x_1746; - - x_1746 = *(double*) &mem_607[(i_remnant_391 * size_155 + - i_383 * 1) * 8 + 0]; - - double res_1747; - - res_1747 = x_1746 * y_1745; - - char cond_1749; - - cond_1749 = acc_108 < res_1747; - - double res_1750; - - if (cond_1749) { - res_1750 = acc_108; - } else { - res_1750 = res_1747; - } - - double acc_tmp_484; - - acc_tmp_484 = res_1750; - acc_108 = acc_tmp_484; - } - res_1751 = acc_108; - *(double*) &mem_623[i_227 * 1 * 8 + 0] = res_1751; - } - - double y_1758; - - y_1758 = *(double*) &mem_623[0 * 1 * 8 + 0]; - - char cond_1759; - - cond_1759 = 1.0 <= y_1758; - - double res_1843; - - if (cond_1759) { - int bounds_check_1760; - - if (!y_213) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_213", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1761; - - y_1761 = *(double*) &all_md_disc_mem_368[(0 * size_113 + 0 * - 1) * 8 + 0]; - - double res_1762; - - res_1762 = 1150.0 * y_1761; - res_1843 = res_1762; - } else { - int bounds_check_1763; - - if (!y_215) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_215", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:295:25-295:29"); - abort(); - } - - double y_1764; - - y_1764 = *(double*) &mem_623[1 * 1 * 8 + 0]; - - char cond_1765; - - cond_1765 = 1.0 <= y_1764; - - double res_1842; - - if (cond_1765) { - int bounds_check_1766; - - if (!y_219) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_219", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1767; - - y_1767 = *(double*) &all_md_disc_mem_368[(0 * size_113 + - 1 * 1) * 8 + - 0]; - - double res_1768; - - res_1768 = 1300.0 * y_1767; - res_1842 = res_1768; - } else { - int bounds_check_1769; - - if (!y_216) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_216", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:296:30-296:34"); - abort(); - } - - double y_1770; - - y_1770 = *(double*) &mem_623[2 * 1 * 8 + 0]; - - char cond_1771; - - cond_1771 = 1.0 <= y_1770; - - double res_1840; - - if (cond_1771) { - int bounds_check_1772; - - if (!y_220) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_220", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1773; - - y_1773 = *(double*) &all_md_disc_mem_368[(0 * - size_113 + - 2 * 1) * - 8 + 0]; - - double res_1790; - - res_1790 = 1450.0 * y_1773; - res_1840 = res_1790; - } else { - int bounds_check_1791; - - if (!y_217) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_217", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:297:35-297:39"); - abort(); - } - - double y_1792; - - y_1792 = *(double*) &mem_623[3 * 1 * 8 + 0]; - - char cond_1793; - - cond_1793 = 1.0 <= y_1792; - - double res_1827; - - if (cond_1793) { - int bounds_check_1803; - - if (!y_221) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "y_221", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1805; - - y_1805 = *(double*) &all_md_disc_mem_368[(0 * - size_113 + - 3 * - 1) * - 8 + 0]; - - double res_1806; - - res_1806 = 1600.0 * y_1805; - res_1827 = res_1806; - } else { - int bounds_check_1807; - - if (!y_218) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "y_218", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:298:40-298:44"); - abort(); - } - - double y_1808; - - y_1808 = *(double*) &mem_623[4 * 1 * 8 + 0]; - - char cond_1809; - - cond_1809 = 1.0 <= y_1808; - - char cond_1810; - - cond_1810 = 0.75 < y_1808; - - double arg_1812; - - arg_1812 = 1000.0 * y_1808; - - double res_1826; - - if (cond_1809) { - int bounds_check_1814; - - if (!y_222) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "y_222", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1815; - - y_1815 = - *(double*) &all_md_disc_mem_368[(0 * - size_113 + - 4 * - 1) * - 8 + 0]; - - double res_1816; - - res_1816 = 1750.0 * y_1815; - res_1826 = res_1816; - } else { - double res_1825; - - if (cond_1810) { - int bounds_check_1817; - - if (!y_222) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "y_222", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1818; - - y_1818 = - *(double*) &all_md_disc_mem_368[(0 * - size_113 + - 4 * - 1) * - 8 + - 0]; - - double res_1820; - - res_1820 = 1000.0 * y_1818; - res_1825 = res_1820; - } else { - int bounds_check_1822; - - if (!y_222) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "y_222", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1823; - - y_1823 = - *(double*) &all_md_disc_mem_368[(0 * - size_113 + - 4 * - 1) * - 8 + - 0]; - - double res_1824; - - res_1824 = arg_1812 * y_1823; - res_1825 = res_1824; - } - res_1826 = res_1825; - } - res_1827 = res_1826; - } - res_1840 = res_1827; - } - res_1842 = res_1840; - } - res_1843 = res_1842; - } - - double res_1844; - - res_1844 = acc_232 + res_1843; - - double acc_tmp_323; - - acc_tmp_323 = res_1844; - acc_232 = acc_tmp_323; - } - res_1845 = acc_232; - res_2306 = res_1845; - } else { - double res_2305; - - if (cond_209) { - int bounds_check_1846; - - if (!y_212) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_212", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:306:29-306:31"); - abort(); - } - - int bounds_check_1847; - - if (!y_223) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_223", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:307:29-307:31"); - abort(); - } - - int bounds_check_1848; - - if (!y_224) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_224", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:308:29-308:31"); - abort(); - } - - int bounds_check_1859; - - if (!y_281) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_281", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:311:19-311:22"); - abort(); - } - - int bounds_check_1860; - - if (!y_213) { - fprintf(stderr, "Assertion %s at %s failed.\n", "y_213", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_1861; - - y_1861 = *(double*) &all_md_disc_mem_368[(0 * size_113 + 0 * - 1) * 8 + 0]; - - double res_1862; - - res_1862 = 100.0 * y_1861; - - double res_2304; - double acc_279; - - acc_279 = 0.0; - for (int i_278 = 0; i_278 < num_mc_it_119; i_278++) { - int res_1873; - - res_1873 = i_278 + 1; - - int x_1917; - - x_1917 = res_1873 >> 1; - - int res_1925; - - res_1925 = x_1917 ^ res_1873; - for (int i_234 = 0; i_234 < num_bits_123; i_234++) { - int res_1927; - - res_1927 = 1 << i_234; - - int x_1928; - - x_1928 = res_1925 & res_1927; - - char res_1929; - - res_1929 = x_1928 == res_1927; - - int partition_equivalence_class_1930; - - if (res_1929) { - partition_equivalence_class_1930 = 0; - } else { - partition_equivalence_class_1930 = 1; - } - *(int*) &mem_640[i_234 * 1 * 4 + 0] = - partition_equivalence_class_1930; - } - - int filter_size_1932; - - filter_size_1932 = 0; - - int eqclass_492; - - for (int i_491 = 0; i_491 < num_bits_123; i_491++) { - eqclass_492 = *(int*) &mem_640[i_491 * 1 * 4 + 0]; - if (eqclass_492 == 0) { - filter_size_1932 = filter_size_1932 + 1; - } else { } - } - - int partition_offset_493; - - partition_offset_493 = 0; - - int partition_cur_offset_494; - - for (int i_491 = 0; i_491 < num_bits_123; i_491++) { - eqclass_492 = *(int*) &mem_640[i_491 * 1 * 4 + 0]; - if (eqclass_492 == 0) { - partition_cur_offset_494 = partition_offset_493; - *(int*) &mem_649[partition_cur_offset_494 * 1 * 4 + - 0] = *(int*) &mem_387[i_491 * 1 * - 4 + 0]; - partition_offset_493 = partition_offset_493 + 1; - } else { } - } - for (int i_245 = 0; i_245 < num_und_121; i_245++) { - int y_374; - - y_374 = i_245 * size_18; - for (int i_241 = 0; i_241 < num_dates_120; i_241++) { - int x_373; - - x_373 = i_241 * new_slice_size_286; - - int x_375; - - x_375 = x_373 + y_374; - - int res_1978; - int acc_239; - - acc_239 = 0; - for (int i_238 = 0; i_238 < filter_size_1932; - i_238++) { - int not_curried_1973; - - not_curried_1973 = *(int*) &mem_649[i_238 * 1 * - 4 + 0]; - - char y_1974; - - y_1974 = not_curried_1973 < size_18; - - int bounds_check_1975; - - if (!y_1974) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "y_1974", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:6:35-6:38"); - abort(); - } - - int flat_index_377; - - flat_index_377 = x_375 + not_curried_1973; - - int i_378; - - i_378 = flat_index_377 / size_18 - - (flat_index_377 % size_18 != 0 && - flat_index_377 % size_18 < 0 != size_18 < - 0 ? 1 : 0); - - int y_379; - - y_379 = i_378 * size_18; - - int i_remnant_380; - - i_remnant_380 = flat_index_377 - y_379; - - int res_1976; - - res_1976 = *(int*) &dir_vs_mem_40[(i_378 * - size_18 + - i_remnant_380 * - 1) * 4 + 0]; - - int res_1977; - - res_1977 = acc_239 ^ res_1976; - - int acc_tmp_520; - - acc_tmp_520 = res_1977; - acc_239 = acc_tmp_520; - } - res_1978 = acc_239; - - double x_1979; - - x_1979 = futhark_toFloat64(res_1978); - - double res_1980; - - res_1980 = x_1979 / res_151; - - double res_1981; - - res_1981 = res_1980 - 0.5; - - char x_1982; - - x_1982 = res_1981 < 0.0; - - double x_2000; - - x_2000 = 0.0 - res_1981; - - char y_2001; - - y_2001 = x_2000 <= 0.425; - - char x_2002; - - x_2002 = x_1982 && y_2001; - - char x_2003; - - x_2003 = 0.0 <= res_1981; - - char y_2004; - - y_2004 = res_1981 <= 0.425; - - char y_2005; - - y_2005 = x_2003 && y_2004; - - char cond_2006; - - cond_2006 = x_2002 || y_2005; - - double res_2007; - - res_2007 = res_1981 + 0.5; - - double res_2008; - - res_2008 = 0.5 - res_1981; - - double res_2009; - - if (x_1982) { - res_2009 = res_2007; - } else { - res_2009 = res_2008; - } - - double y_2010; - - y_2010 = res_1981 * res_1981; - - double arg_2011; - - arg_2011 = 0.180625 - y_2010; - - double x_2012; - - x_2012 = arg_2011 * 2509.0809287301227; - - double y_2013; - - y_2013 = x_2012 + 33430.57558358813; - - double x_2014; - - x_2014 = arg_2011 * y_2013; - - double y_2015; - - y_2015 = x_2014 + 67265.7709270087; - - double x_2016; - - x_2016 = arg_2011 * y_2015; - - double y_2017; - - y_2017 = x_2016 + 45921.95393154987; - - double x_2019; - - x_2019 = arg_2011 * y_2017; - - double y_2020; - - y_2020 = x_2019 + 13731.69376550946; - - double x_2021; - - x_2021 = arg_2011 * y_2020; - - double y_2022; - - y_2022 = x_2021 + 1971.5909503065513; - - double x_2023; - - x_2023 = arg_2011 * y_2022; - - double y_2034; - - y_2034 = x_2023 + 133.14166789178438; - - double x_2038; - - x_2038 = arg_2011 * y_2034; - - double x_2039; - - x_2039 = x_2038 + 3.3871328727963665; - - double x_2040; - - x_2040 = arg_2011 * 5226.495278852854; - - double y_2041; - - y_2041 = x_2040 + 28729.085735721943; - - double x_2042; - - x_2042 = arg_2011 * y_2041; - - double y_2043; - - y_2043 = x_2042 + 39307.89580009271; - - double x_2044; - - x_2044 = arg_2011 * y_2043; - - double y_2045; - - y_2045 = x_2044 + 21213.794301586597; - - double x_2046; - - x_2046 = arg_2011 * y_2045; - - double y_2047; - - y_2047 = x_2046 + 5394.196021424751; - - double x_2048; - - x_2048 = arg_2011 * y_2047; - - double y_2049; - - y_2049 = x_2048 + 687.1870074920579; - - double x_2050; - - x_2050 = arg_2011 * y_2049; - - double y_2051; - - y_2051 = x_2050 + 42.31333070160091; - - double x_2052; - - x_2052 = arg_2011 * y_2051; - - double y_2053; - - y_2053 = x_2052 + 1.0; - - double res_2123; - - if (cond_2006) { - double res_2054; - - res_2054 = x_2039 / y_2053; - - double res_2055; - - res_2055 = res_1981 * res_2054; - res_2123 = res_2055; - } else { - double negate_arg_2056; - - negate_arg_2056 = futhark_log64(res_2009); - - double arg_2057; - - arg_2057 = -negate_arg_2056; - - double res_2058; - - res_2058 = futhark_sqrt64(arg_2057); - - char cond_2059; - - cond_2059 = res_2058 <= 5.0; - - double arg_2060; - - arg_2060 = res_2058 - 1.6; - - double x_2061; - - x_2061 = arg_2060 * 7.745450142783414e-4; - - double y_2062; - - y_2062 = x_2061 + 2.2723844989269184e-2; - - double x_2063; - - x_2063 = arg_2060 * y_2062; - - double y_2064; - - y_2064 = x_2063 + 0.2417807251774506; - - double x_2065; - - x_2065 = arg_2060 * y_2064; - - double y_2066; - - y_2066 = x_2065 + 1.2704582524523684; - - double x_2067; - - x_2067 = arg_2060 * y_2066; - - double y_2068; - - y_2068 = x_2067 + 3.6478483247632045; - - double x_2069; - - x_2069 = arg_2060 * y_2068; - - double y_2070; - - y_2070 = x_2069 + 5.769497221460691; - - double x_2071; - - x_2071 = arg_2060 * y_2070; - - double y_2072; - - y_2072 = x_2071 + 4.630337846156546; - - double x_2073; - - x_2073 = arg_2060 * y_2072; - - double x_2074; - - x_2074 = x_2073 + 1.4234371107496835; - - double x_2075; - - x_2075 = arg_2060 * 1.0507500716444169e-9; - - double y_2076; - - y_2076 = x_2075 + 5.475938084995345e-4; - - double x_2077; - - x_2077 = arg_2060 * y_2076; - - double y_2078; - - y_2078 = x_2077 + 1.5198666563616457e-2; - - double x_2079; - - x_2079 = arg_2060 * y_2078; - - double y_2080; - - y_2080 = x_2079 + 0.14810397642748008; - - double x_2081; - - x_2081 = arg_2060 * y_2080; - - double y_2082; - - y_2082 = x_2081 + 0.6897673349851; - - double x_2083; - - x_2083 = arg_2060 * y_2082; - - double y_2084; - - y_2084 = x_2083 + 1.6763848301838038; - - double x_2085; - - x_2085 = arg_2060 * y_2084; - - double y_2086; - - y_2086 = x_2085 + 2.053191626637759; - - double x_2087; - - x_2087 = arg_2060 * y_2086; - - double y_2088; - - y_2088 = x_2087 + 1.0; - - double arg_2089; - - arg_2089 = res_2058 - 5.0; - - double x_2090; - - x_2090 = arg_2089 * 2.0103343992922881e-7; - - double y_2091; - - y_2091 = x_2090 + 2.7115555687434876e-5; - - double x_2092; - - x_2092 = arg_2089 * y_2091; - - double y_2093; - - y_2093 = x_2092 + 1.2426609473880784e-3; - - double x_2094; - - x_2094 = arg_2089 * y_2093; - - double y_2095; - - y_2095 = x_2094 + 2.6532189526576124e-2; - - double x_2096; - - x_2096 = arg_2089 * y_2095; - - double y_2097; - - y_2097 = x_2096 + 0.29656057182850487; - - double x_2098; - - x_2098 = arg_2089 * y_2097; - - double y_2099; - - y_2099 = x_2098 + 1.7848265399172913; - - double x_2100; - - x_2100 = arg_2089 * y_2099; - - double y_2101; - - y_2101 = x_2100 + 5.463784911164114; - - double x_2102; - - x_2102 = arg_2089 * y_2101; - - double x_2103; - - x_2103 = x_2102 + 6.657904643501103; - - double x_2104; - - x_2104 = arg_2089 * 2.0442631033899398e-5; - - double y_2105; - - y_2105 = x_2104 + 1.421511758316446e-7; - - double x_2106; - - x_2106 = arg_2089 * y_2105; - - double y_2107; - - y_2107 = x_2106 + 1.8463183175100548e-5; - - double x_2108; - - x_2108 = arg_2089 * y_2107; - - double y_2109; - - y_2109 = x_2108 + 7.868691311456133e-4; - - double x_2110; - - x_2110 = arg_2089 * y_2109; - - double y_2111; - - y_2111 = x_2110 + 1.4875361290850615e-2; - - double x_2112; - - x_2112 = arg_2089 * y_2111; - - double y_2113; - - y_2113 = x_2112 + 0.1369298809227358; - - double x_2114; - - x_2114 = arg_2089 * y_2113; - - double y_2115; - - y_2115 = x_2114 + 0.599832206555888; - - double x_2116; - - x_2116 = arg_2089 * y_2115; - - double y_2117; - - y_2117 = x_2116 + 1.0; - - double res_2120; - - if (cond_2059) { - double res_2118; - - res_2118 = x_2074 / y_2088; - res_2120 = res_2118; - } else { - double res_2119; - - res_2119 = x_2103 / y_2117; - res_2120 = res_2119; - } - - double res_2121; - - res_2121 = 0.0 - res_2120; - - double res_2122; - - if (x_1982) { - res_2122 = res_2121; - } else { - res_2122 = res_2120; - } - res_2123 = res_2122; - } - *(double*) &mem_656[i_241 * 1 * 8 + 0] = res_2123; - } - memmove(mem_662 + 0, mem_404 + 0, num_dates_120 * - sizeof(double)); - - double y_2127; - - y_2127 = *(double*) &mem_656[0 * 1 * 8 + 0]; - - double lw_val_2128; - - lw_val_2128 = x_178 * y_2127; - *(double*) &mem_662[idx_175 * 1 * 8 + 0] = lw_val_2128; - for (int i_521 = 0; i_521 < num_dates_120; i_521++) { - *(double*) &mem_652[8 * (num_dates_120 * i_245) + - 8 * i_521] = - *(double*) &mem_662[8 * i_521]; - } - for (int i_2131 = 0; i_2131 < bound_185; i_2131++) { - int i_2132; - - i_2132 = i_2131 + 1; - - char y_2133; - - y_2133 = i_2132 < size_115; - - int bounds_check_2134; - - if (!y_2133) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_2133", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:160:22-160:24"); - abort(); - } - - int x_2135; - - x_2135 = *(int*) &bb_inds_mem_371[(1 * size_115 + - i_2132 * 1) * 4 + - 0]; - - int res_2136; - - res_2136 = x_2135 - 1; - - int x_2137; - - x_2137 = *(int*) &bb_inds_mem_371[(2 * size_115 + - i_2132 * 1) * 4 + - 0]; - - int res_2138; - - res_2138 = x_2137 - 1; - - int x_2139; - - x_2139 = *(int*) &bb_inds_mem_371[(0 * size_115 + - i_2132 * 1) * 4 + - 0]; - - int res_2140; - - res_2140 = x_2139 - 1; - - char x_2141; - - x_2141 = 0 <= res_2138; - - char y_2142; - - y_2142 = res_2138 < num_dates_120; - - char assert_arg_2143; - - assert_arg_2143 = x_2141 && y_2142; - - int bounds_check_2144; - - if (!assert_arg_2143) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_2143", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:164:22-164:27"); - abort(); - } - - double res_2145; - - res_2145 = *(double*) &mem_652[(i_245 * - num_dates_120 + - res_2138 * 1) * 8 + - 0]; - - double res_2146; - - res_2146 = *(double*) &mem_656[i_2132 * 1 * 8 + 0]; - - char y_2147; - - y_2147 = i_2132 < size_117; - - int bounds_check_2148; - - if (!y_2147) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_2147", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:166:22-166:24"); - abort(); - } - - double x_2149; - - x_2149 = *(double*) &bb_data_mem_381[(2 * size_117 + - i_2132 * 1) * - 8 + 0]; - - double x_2150; - - x_2150 = x_2149 * res_2145; - - double x_2151; - - x_2151 = *(double*) &bb_data_mem_381[(0 * size_117 + - i_2132 * 1) * - 8 + 0]; - - double y_2152; - - y_2152 = x_2151 * res_2146; - - double res_2153; - - res_2153 = x_2150 + y_2152; - - int x_2154; - - x_2154 = res_2136 + 1; - - char cond_2155; - - cond_2155 = x_2154 == 0; - - char x_2156; - - x_2156 = 0 <= res_2136; - - char y_2157; - - y_2157 = res_2136 < num_dates_120; - - char assert_arg_2158; - - assert_arg_2158 = x_2156 && y_2157; - - double lw_val_2164; - - if (cond_2155) { - lw_val_2164 = res_2153; - } else { - double x_2159; - - x_2159 = *(double*) &bb_data_mem_381[(1 * - size_117 + - i_2132 * - 1) * 8 + - 0]; - - int bounds_check_2160; - - if (!assert_arg_2158) { - fprintf(stderr, - "Assertion %s at %s failed.\n", - "assert_arg_2158", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:170:51-170:56"); - abort(); - } - - double y_2161; - - y_2161 = *(double*) &mem_652[(i_245 * - num_dates_120 + - res_2136 * 1) * - 8 + 0]; - - double y_2162; - - y_2162 = x_2159 * y_2161; - - double res_2163; - - res_2163 = res_2153 + y_2162; - lw_val_2164 = res_2163; - } - - char x_2165; - - x_2165 = 0 <= res_2140; - - char y_2166; - - y_2166 = res_2140 < num_dates_120; - - char assert_arg_2167; - - assert_arg_2167 = x_2165 && y_2166; - - int bounds_check_2168; - - if (!assert_arg_2167) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "assert_arg_2167", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:168:13-168:16"); - abort(); - } - *(double*) &mem_652[(i_245 * num_dates_120 + - res_2140 * 1) * 8 + 0] = - lw_val_2164; - } - for (int ii_2172 = 0; ii_2172 < bound_185; ii_2172++) { - int y_2173; - - y_2173 = ii_2172 + 1; - - int res_2174; - - res_2174 = num_dates_120 - y_2173; - - double x_2175; - - x_2175 = *(double*) &mem_652[(i_245 * - num_dates_120 + - res_2174 * 1) * 8 + - 0]; - - int i_2176; - - i_2176 = res_2174 - 1; - - double y_2177; - - y_2177 = *(double*) &mem_652[(i_245 * - num_dates_120 + - i_2176 * 1) * 8 + 0]; - - double lw_val_2178; - - lw_val_2178 = x_2175 - y_2177; - *(double*) &mem_652[(i_245 * num_dates_120 + - res_2174 * 1) * 8 + 0] = - lw_val_2178; - } - } - for (int i_257 = 0; i_257 < size_155; i_257++) { - int x_384; - - x_384 = i_257 * size_92; - - int x_407; - - x_407 = i_257 * size_89; - - int x_417; - - x_417 = i_257 * num_und_121; - for (int i_253 = 0; i_253 < size_92; i_253++) { - int flat_index_400; - - flat_index_400 = x_384 + i_253; - - int i_401; - - i_401 = flat_index_400 / size_92 - (flat_index_400 % - size_92 != 0 && - flat_index_400 % - size_92 < 0 != - size_92 < - 0 ? 1 : 0); - - int y_402; - - y_402 = i_401 * size_92; - - int i_remnant_403; - - i_remnant_403 = flat_index_400 - y_402; - - double x_2217; - - x_2217 = *(double*) &all_md_drifts_mem_350[(0 * - (size_91 * - size_92) + - i_401 * - size_92 + - i_remnant_403 * - 1) * 8 + - 0]; - - int flat_index_409; - - flat_index_409 = x_407 + i_253; - - int i_410; - - i_410 = flat_index_409 / size_89 - (flat_index_409 % - size_89 != 0 && - flat_index_409 % - size_89 < 0 != - size_89 < - 0 ? 1 : 0); - - int y_411; - - y_411 = i_410 * size_89; - - int i_remnant_412; - - i_remnant_412 = flat_index_409 - y_411; - - double y_2219; - - y_2219 = *(double*) &all_md_vols_mem_268[(0 * - (size_86 * - size_89) + - i_410 * - size_89 + - i_remnant_412 * - 1) * 8 + - 0]; - - int arg_2220; - - arg_2220 = i_253 + 1; - - char y_2224; - - y_2224 = i_253 < size_20; - - int bounds_check_2225; - - if (!y_2224) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_2224", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:205:58-205:62"); - abort(); - } - - char split_index_cnd_2227; - - split_index_cnd_2227 = arg_2220 <= size_21; - - int split_index_assert_2228; - - if (!split_index_cnd_2227) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "split_index_cnd_2227", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:201:56-201:61"); - abort(); - } - - double res_2240; - double acc_250; - - acc_250 = 0.0; - for (int i_249 = 0; i_249 < arg_2220; i_249++) { - int flat_index_419; - - flat_index_419 = x_417 + i_249; - - int i_420; - - i_420 = flat_index_419 / num_und_121 - - (flat_index_419 % num_und_121 != 0 && - flat_index_419 % num_und_121 < 0 != - num_und_121 < 0 ? 1 : 0); - - int y_421; - - y_421 = i_420 * num_und_121; - - int i_remnant_422; - - i_remnant_422 = flat_index_419 - y_421; - - double x_2236; - - x_2236 = *(double*) &mem_652[(i_remnant_422 * - num_dates_120 + - i_420 * 1) * 8 + - 0]; - - double x_2237; - - x_2237 = *(double*) &all_md_c_mem_84[(0 * - (size_20 * - size_21) + - i_253 * - size_21 + - i_249 * - 1) * 8 + - 0]; - - double res_2238; - - res_2238 = x_2236 * x_2237; - - double res_2239; - - res_2239 = acc_250 + res_2238; - - double acc_tmp_529; - - acc_tmp_529 = res_2239; - acc_250 = acc_tmp_529; - } - res_2240 = acc_250; - - double res_2241; - - res_2241 = res_2240 * y_2219; - - double res_2242; - - res_2242 = x_2217 + res_2241; - *(double*) &mem_722[(i_257 * size_92 + i_253 * 1) * - 8 + 0] = res_2242; - } - } - for (int i_271 = 0; i_271 < size_92; i_271++) { - double x_2248; - - x_2248 = *(double*) &all_md_st_mem_359[(0 * size_94 + - i_271 * 1) * 8 + - 0]; - for (int i_261 = 0; i_261 < size_155; i_261++) { - double not_curried_2249; - - not_curried_2249 = *(double*) &mem_722[(i_261 * - size_92 + - i_271 * 1) * - 8 + 0]; - - double curried_fun_result_2250; - - curried_fun_result_2250 = - futhark_exp64(not_curried_2249); - *(double*) &mem_777[i_261 * 1 * 8 + 0] = - curried_fun_result_2250; - } - - double acc_266; - - acc_266 = x_2248; - for (int i_265 = 0; i_265 < size_155; i_265++) { - double y_2253; - - y_2253 = *(double*) &mem_777[i_265 * 1 * 8 + 0]; - - double res_2254; - - res_2254 = acc_266 * y_2253; - *(double*) &mem_771[(i_271 * size_155 + i_265 * 1) * - 8 + 0] = res_2254; - - double row_270; - - row_270 = *(double*) &mem_771[(i_271 * size_155 + - i_265 * 1) * 8 + 0]; - - double acc_tmp_532; - - acc_tmp_532 = row_270; - acc_266 = acc_tmp_532; - } - } - - char res_2273; - char acc_276; - - acc_276 = 0; - for (int i_275 = 0; i_275 < size_155; i_275++) { - int x_427; - - x_427 = i_275 * size_190; - - int i_430; - - i_430 = x_427 / size_92 - (x_427 % size_92 != 0 && - x_427 % size_92 < 0 != - size_92 < 0 ? 1 : 0); - - int y_431; - - y_431 = i_430 * size_92; - - int i_remnant_432; - - i_remnant_432 = x_427 - y_431; - - double x_2264; - - x_2264 = *(double*) &mem_771[(i_remnant_432 * size_155 + - i_430 * 1) * 8 + 0]; - - char x_2265; - - x_2265 = x_2264 <= 2630.6349999999998; - - int flat_index_477; - - flat_index_477 = x_427 + 1; - - int i_478; - - i_478 = flat_index_477 / size_92 - (flat_index_477 % - size_92 != 0 && - flat_index_477 % - size_92 < 0 != - size_92 < - 0 ? 1 : 0); - - int y_479; - - y_479 = i_478 * size_92; - - int i_remnant_480; - - i_remnant_480 = flat_index_477 - y_479; - - double x_2266; - - x_2266 = *(double*) &mem_771[(i_remnant_480 * size_155 + - i_478 * 1) * 8 + 0]; - - char y_2267; - - y_2267 = x_2266 <= 8288.0; - - char x_2268; - - x_2268 = x_2265 || y_2267; - - int flat_index_486; - - flat_index_486 = x_427 + 2; - - int i_487; - - i_487 = flat_index_486 / size_92 - (flat_index_486 % - size_92 != 0 && - flat_index_486 % - size_92 < 0 != - size_92 < - 0 ? 1 : 0); - - int y_488; - - y_488 = i_487 * size_92; - - int i_remnant_489; - - i_remnant_489 = flat_index_486 - y_488; - - double x_2269; - - x_2269 = *(double*) &mem_771[(i_remnant_489 * size_155 + - i_487 * 1) * 8 + 0]; - - char y_2270; - - y_2270 = x_2269 <= 840.0; - - char res_2271; - - res_2271 = x_2268 || y_2270; - - char res_2272; - - res_2272 = acc_276 || res_2271; - - char acc_tmp_537; - - acc_tmp_537 = res_2272; - acc_276 = acc_tmp_537; - } - res_2273 = acc_276; - - double x_2274; - - x_2274 = *(double*) &mem_771[(i_remnant_288 * size_155 + - i_283 * 1) * 8 + 0]; - - char x_2275; - - x_2275 = x_2274 < 3758.05; - - double x_2276; - - x_2276 = *(double*) &mem_771[(i_remnant_296 * size_155 + - i_291 * 1) * 8 + 0]; - - char y_2277; - - y_2277 = x_2276 < 1200.0; - - char x_2278; - - x_2278 = x_2275 || y_2277; - - double x_2279; - - x_2279 = *(double*) &mem_771[(i_remnant_300 * size_155 + - i_298 * 1) * 8 + 0]; - - char y_2280; - - y_2280 = x_2279 < 11840.0; - - char y_2281; - - y_2281 = x_2278 || y_2280; - - char res_2282; - - res_2282 = res_2273 && y_2281; - - double x_2283; - - x_2283 = x_2276 / 1200.0; - - double arg_2284; - - arg_2284 = x_2283 - 1.0; - - double x_2285; - - x_2285 = x_2274 / 3758.05; - - double arg_2286; - - arg_2286 = x_2285 - 1.0; - - char cond_2287; - - cond_2287 = arg_2284 < arg_2286; - - double res_2288; - - if (cond_2287) { - res_2288 = arg_2284; - } else { - res_2288 = arg_2286; - } - - double x_2289; - - x_2289 = x_2279 / 11840.0; - - double arg_2290; - - arg_2290 = x_2289 - 1.0; - - char cond_2291; - - cond_2291 = arg_2290 < res_2288; - - double res_2292; - - if (cond_2291) { - res_2292 = arg_2290; - } else { - res_2292 = res_2288; - } - - double y_2293; - - y_2293 = 1.0 + res_2292; - - double res_2294; - - res_2294 = 1000.0 * y_2293; - - double res_2301; - - if (res_2282) { - int bounds_check_2295; - - if (!y_219) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_219", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_2296; - - y_2296 = *(double*) &all_md_disc_mem_368[(0 * size_113 + - 1 * 1) * 8 + - 0]; - - double res_2297; - - res_2297 = res_2294 * y_2296; - res_2301 = res_2297; - } else { - int bounds_check_2298; - - if (!y_219) { - fprintf(stderr, "Assertion %s at %s failed.\n", - "y_219", - "/home/athas/repos/finpar/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut:331:66-331:70"); - abort(); - } - - double y_2299; - - y_2299 = *(double*) &all_md_disc_mem_368[(0 * size_113 + - 1 * 1) * 8 + - 0]; - - double res_2300; - - res_2300 = 1000.0 * y_2299; - res_2301 = res_2300; - } - - double res_2302; - - res_2302 = res_1862 + res_2301; - - double res_2303; - - res_2303 = acc_279 + res_2302; - - double acc_tmp_485; - - acc_tmp_485 = res_2303; - acc_279 = acc_tmp_485; - } - res_2304 = acc_279; - res_2305 = res_2304; - } else { - res_2305 = 0.0; - } - res_2306 = res_2305; - } - res_2307 = res_2306; - } - - double y_2308; - - y_2308 = futhark_toFloat64(num_mc_it_119); - - double arr_elem_2309; - - arr_elem_2309 = res_2307 / y_2308; - - unsigned char* mem_799; - - mem_799 = malloc(8); - *(double*) &mem_799[0 * 1 * 8 + 0] = arr_elem_2309; - out_mem_23 = mem_799; - out_memsize_24 = 8; - out_arrsize_26 = 1; - - struct tuple_int_mem_int retval_0; - - retval_0.elem_0 = out_memsize_24; - retval_0.elem_1 = out_mem_23; - retval_0.elem_2 = out_arrsize_26; - return retval_0; -} -int main(int argc, char** argv) -{ - struct timeval t_start, t_end, t_diff; - unsigned long elapsed_usec; - - { - int out_memsize_24; - unsigned char* out_mem_23; - int out_arrsize_26; - int dir_vs_mem_size_27; - int all_md_c_mem_size_71; - int all_md_vols_mem_size_255; - int all_md_drifts_mem_size_345; - int all_md_st_mem_size_354; - int all_md_detvals_mem_size_360; - int all_md_disc_mem_size_363; - int bb_inds_mem_size_369; - int bb_data_mem_size_376; - unsigned char* dir_vs_mem_40; - unsigned char* all_md_c_mem_84; - unsigned char* all_md_vols_mem_268; - unsigned char* all_md_drifts_mem_350; - unsigned char* all_md_st_mem_359; - unsigned char* all_md_detvals_mem_361; - unsigned char* all_md_disc_mem_368; - unsigned char* bb_inds_mem_371; - unsigned char* bb_data_mem_381; - int size_14; - int size_18; - int size_19; - int size_20; - int size_21; - int size_22; - int size_86; - int size_89; - int size_90; - int size_91; - int size_92; - int size_93; - int size_94; - int size_95; - int size_111; - int size_112; - int size_113; - int size_114; - int size_115; - int size_116; - int size_117; - int contract_number_118; - int num_mc_it_119; - int num_dates_120; - int num_und_121; - int num_models_122; - int num_bits_123; - struct tuple_int_mem_int main_ret_1; - - if (read_int(&contract_number_118) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&num_mc_it_119) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&num_dates_120) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&num_und_121) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&num_models_122) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - if (read_int(&num_bits_123) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "int"); - exit(1); - } - { - int64_t shape[2]; - - if (read_array(sizeof(int), read_int, (void**) &dir_vs_mem_40, - shape, 2) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "[[int]]"); - exit(1); - } - size_14 = shape[0]; - size_18 = shape[1]; - dir_vs_mem_size_27 = sizeof(int) * shape[0] * shape[1]; - } - { - int64_t shape[3]; - - if (read_array(sizeof(double), read_double, - (void**) &all_md_c_mem_84, shape, 3) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[[float64]]]"); - exit(1); - } - size_19 = shape[0]; - size_20 = shape[1]; - size_21 = shape[2]; - all_md_c_mem_size_71 = sizeof(double) * shape[0] * shape[1] * - shape[2]; - } - { - int64_t shape[3]; - - if (read_array(sizeof(double), read_double, - (void**) &all_md_vols_mem_268, shape, 3) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[[float64]]]"); - exit(1); - } - size_22 = shape[0]; - size_86 = shape[1]; - size_89 = shape[2]; - all_md_vols_mem_size_255 = sizeof(double) * shape[0] * shape[1] * - shape[2]; - } - { - int64_t shape[3]; - - if (read_array(sizeof(double), read_double, - (void**) &all_md_drifts_mem_350, shape, 3) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[[float64]]]"); - exit(1); - } - size_90 = shape[0]; - size_91 = shape[1]; - size_92 = shape[2]; - all_md_drifts_mem_size_345 = sizeof(double) * shape[0] * shape[1] * - shape[2]; - } - { - int64_t shape[2]; - - if (read_array(sizeof(double), read_double, - (void**) &all_md_st_mem_359, shape, 2) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[float64]]"); - exit(1); - } - size_93 = shape[0]; - size_94 = shape[1]; - all_md_st_mem_size_354 = sizeof(double) * shape[0] * shape[1]; - } - { - int64_t shape[2]; - - if (read_array(sizeof(double), read_double, - (void**) &all_md_detvals_mem_361, shape, 2) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[float64]]"); - exit(1); - } - size_95 = shape[0]; - size_111 = shape[1]; - all_md_detvals_mem_size_360 = sizeof(double) * shape[0] * shape[1]; - } - { - int64_t shape[2]; - - if (read_array(sizeof(double), read_double, - (void**) &all_md_disc_mem_368, shape, 2) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[float64]]"); - exit(1); - } - size_112 = shape[0]; - size_113 = shape[1]; - all_md_disc_mem_size_363 = sizeof(double) * shape[0] * shape[1]; - } - { - int64_t shape[2]; - - if (read_array(sizeof(int), read_int, (void**) &bb_inds_mem_371, - shape, 2) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", "[[int]]"); - exit(1); - } - size_114 = shape[0]; - size_115 = shape[1]; - bb_inds_mem_size_369 = sizeof(int) * shape[0] * shape[1]; - } - { - int64_t shape[2]; - - if (read_array(sizeof(double), read_double, - (void**) &bb_data_mem_381, shape, 2) != 0) { - fprintf(stderr, "Syntax error when reading %s.\n", - "[[float64]]"); - exit(1); - } - size_116 = shape[0]; - size_117 = shape[1]; - bb_data_mem_size_376 = sizeof(double) * shape[0] * shape[1]; - } - gettimeofday(&t_start, NULL); - main_ret_1 = futhark_main(dir_vs_mem_size_27, all_md_c_mem_size_71, - all_md_vols_mem_size_255, - all_md_drifts_mem_size_345, - all_md_st_mem_size_354, - all_md_detvals_mem_size_360, - all_md_disc_mem_size_363, - bb_inds_mem_size_369, bb_data_mem_size_376, - dir_vs_mem_40, all_md_c_mem_84, - all_md_vols_mem_268, all_md_drifts_mem_350, - all_md_st_mem_359, all_md_detvals_mem_361, - all_md_disc_mem_368, bb_inds_mem_371, - bb_data_mem_381, size_14, size_18, size_19, - size_20, size_21, size_22, size_86, size_89, - size_90, size_91, size_92, size_93, size_94, - size_95, size_111, size_112, size_113, - size_114, size_115, size_116, size_117, - contract_number_118, num_mc_it_119, - num_dates_120, num_und_121, num_models_122, - num_bits_123); - gettimeofday(&t_end, NULL); - out_memsize_24 = main_ret_1.elem_0; - out_mem_23 = main_ret_1.elem_1; - out_arrsize_26 = main_ret_1.elem_2; - { - if (out_arrsize_26 == 0) { - printf("empty(%s)", "float64"); - } else { - int print_i_2; - - putchar('['); - for (print_i_2 = 0; print_i_2 < out_arrsize_26; print_i_2++) { - double* print_elem_3 = (double*) out_mem_23 + print_i_2 * 1; - - printf("%.6f", *print_elem_3); - if (print_i_2 != out_arrsize_26 - 1) { - printf(", "); - } - } - putchar(']'); - } - } - printf("\n"); - } - ; - if (argc == 3 && strcmp(argv[1], "-t") == 0) { - FILE * runtime_file; - runtime_file = fopen(argv[2], "w"); - if (runtime_file == NULL) { - fprintf(stderr, "Cannot open %s: %s\n", argv[2], strerror(errno)); - exit(1); - } - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed_usec = t_diff.tv_sec * 1e6 + t_diff.tv_usec; - fprintf(runtime_file, "%ld\n", elapsed_usec / 1000); - fclose(runtime_file); - } - return 0; -} diff --git a/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut b/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut deleted file mode 100644 index 216abe7..0000000 --- a/benchmarks/OptionPricing/implementations/futhark/GenericPricing.fut +++ /dev/null @@ -1,443 +0,0 @@ -fun int grayCode(int x) = (x >> 1) ^ x - ----------------------------------------- ---- Sobol Generator ----------------------------------------- -fun bool testBit(int n, int ind) = - let t = (1 << ind) in (n & t) == t - ------------------------------------------------------------------ ----- INDEPENDENT FORMULA: ----- filter is redundantly computed inside map. ----- Currently Futhark hoists it outside, but this will ----- not allow fusing the filter with reduce => redomap, ------------------------------------------------------------------ -fun int xorInds(int n, [int,num_bits] dir_vs) = - let reldv_vals = map( fn int (int dv, int i) => - if testBit(grayCode(n),i) - then dv else 0 - , zip(dir_vs,iota(num_bits)) ) in - reduce( ^, 0, reldv_vals ) - -fun [int] sobolIndI ( [[int]] dir_vs, int n ) = - map( xorInds(n), dir_vs ) - -fun [real] sobolIndR( [[int,num_bits]] dir_vs, int n ) = - let divisor = 2.0 pow toFloat (num_bits) in - let arri = sobolIndI( dir_vs, n ) in - map( fn real (int x) => toFloat(x) / divisor, arri ) - --------------------------------- ----- STRENGTH-REDUCED FORMULA --------------------------------- -fun int index_of_least_significant_0(int num_bits, int n) = - let {goon,k} = {True,0} in - loop ({goon,k,n}) = - for i < num_bits do - if(goon) - then if (n & 1) == 1 - then {True, k+1, n>>1} - else {False,k, n } - else {False,k, n } - in k - -fun [int] sobolRecI([[int,num_bits]] sob_dir_vs, [int] prev, int n) = - let bit = index_of_least_significant_0(num_bits,n) in - map (fn int ({[int],int} vct_prev) => - let {vct_row, prev} = vct_prev in - vct_row[bit] ^ prev - , zip(sob_dir_vs,prev)) - -fun [[real]] sobolRecMap( real sob_fact, [[int]] dir_vs, {int,int} lu_bds ) = - let {lb_inc, ub_exc} = lu_bds in - -- the if inside may be particularly ugly for - -- flattening since it introduces control flow! - let contribs = map( fn [int] (int k) => - if (k==0) - then sobolIndI(dir_vs,lb_inc+1) - else recM(dir_vs,k+lb_inc) - , iota(ub_exc-lb_inc) - ) in - let vct_ints = scan( fn [int] ([int] x, [int] y) => zipWith(^, x, y) - , replicate( size(0,dir_vs), 0 ) - , contribs - ) - in map( fn [real] ([int] xs) => - map ( fn real (int x) => - toFloat(x) * sob_fact - , xs) - , vct_ints) - -fun [int] sobolRecI2([[int]] sob_dirs, [int] prev, int i)= - let col = recM(sob_dirs, i) in zipWith(^,prev,col) - -fun [int] recM( [[int,num_bits]] sob_dirs, int i ) = - let bit= index_of_least_significant_0(num_bits,i) in - map( fn int([int] row) => row[bit], sob_dirs ) - --- computes sobol numbers: n,..,n+chunk-1 -fun [[real],chunk] sobolChunk([[int,num_bits],len] dir_vs, int n, int chunk) = - let sob_fact= 1.0 / toFloat(1 << num_bits) in - let sob_beg = sobolIndI(dir_vs, n+1) in - let contrbs = map( fn [int] (int k) => - let sob = k + n in - if(k==0) then sob_beg - else recM(dir_vs, k+n) - , iota(chunk) ) in - let vct_ints= scan( fn [int] ([int] x, [int] y) => - zipWith(^, x, y) - , replicate(len, 0), contrbs ) in - map( fn [real] ([int] xs) => - map ( fn real (int x) => - toFloat(x) * sob_fact - , xs) - , vct_ints) - ----------------------------------------- ---- Inverse Gaussian ----------------------------------------- -fun real polyAppr( real x, - real a0, real a1, real a2, real a3, - real a4, real a5, real a6, real a7, - real b0, real b1, real b2, real b3, - real b4, real b5, real b6, real b7 - ) = - (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0) / - (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) - -fun real smallcase(real q) = - q * polyAppr( 0.180625 - q * q, - - 3.387132872796366608, - 133.14166789178437745, - 1971.5909503065514427, - 13731.693765509461125, - 45921.953931549871457, - 67265.770927008700853, - 33430.575583588128105, - 2509.0809287301226727, - - 1.0, - 42.313330701600911252, - 687.1870074920579083, - 5394.1960214247511077, - 21213.794301586595867, - 39307.89580009271061, - 28729.085735721942674, - 5226.495278852854561 - ) - -fun real intermediate(real r) = - polyAppr( r - 1.6, - - 1.42343711074968357734, - 4.6303378461565452959, - 5.7694972214606914055, - 3.64784832476320460504, - 1.27045825245236838258, - 0.24178072517745061177, - 0.0227238449892691845833, - 7.7454501427834140764e-4, - - 1.0, - 2.05319162663775882187, - 1.6763848301838038494, - 0.68976733498510000455, - 0.14810397642748007459, - 0.0151986665636164571966, - 5.475938084995344946e-4, - 1.05075007164441684324e-9 - ) - -fun real tail(real r) = - polyAppr( r - 5.0, - - 6.6579046435011037772, - 5.4637849111641143699, - 1.7848265399172913358, - 0.29656057182850489123, - 0.026532189526576123093, - 0.0012426609473880784386, - 2.71155556874348757815e-5, - 2.01033439929228813265e-7, - - 1.0, - 0.59983220655588793769, - 0.13692988092273580531, - 0.0148753612908506148525, - 7.868691311456132591e-4, - 1.8463183175100546818e-5, - 1.4215117583164458887e-7, - 2.04426310338993978564e-5 - ) - -fun real ugaussianEl( real p ) = - let dp = p - 0.5 - in --if ( fabs(dp) <= 0.425 ) - if ( ( (dp < 0.0 ) && (0.0 - dp <= 0.425) ) || - ( (0.0 <= dp) && (dp <= 0.425) ) ) - then smallcase(dp) - else let pp = if(dp < 0.0) then dp + 0.5 - else 0.5 - dp in - let r = sqrt( - log(pp) ) in - let x = if(r <= 5.0) then intermediate(r) - else tail(r) in - if(dp < 0.0) then 0.0 - x - else x - --- Transforms a uniform distribution [0,1) --- into a gaussian distribution (-inf, +inf) -fun [real] ugaussian([real] ps) = map(ugaussianEl, ps) - - ---------------------------------- ---- Brownian Bridge ---------------------------------- -fun [real,num_dates] brownianBridgeDates ( - [[int, num_dates],3] bb_inds, - [[real,num_dates],3] bb_data, - [real,num_dates] gauss - ) = - let bi = bb_inds[0] in - let li = bb_inds[1] in - let ri = bb_inds[2] in - let sd = bb_data[0] in - let lw = bb_data[1] in - let rw = bb_data[2] in - - let bbrow = copy(replicate(num_dates, 0.0)) in - let bbrow[ bi[0]-1 ] = sd[0] * gauss[0] in - - loop (bbrow) = - for i < num_dates-1 do -- use i+1 since i in 1 .. num_dates-1 - let j = li[i+1] - 1 in - let k = ri[i+1] - 1 in - let l = bi[i+1] - 1 in - - let wk = bbrow [k ] in - let zi = gauss [i+1] in - let tmp= rw[i+1] * wk + sd[i+1] * zi in - - let bbrow[ l ] = if( j == -1) - then tmp - else tmp + lw[i+1] * bbrow[j] - in bbrow - - -- This can be written as map-reduce, but it - -- needs delayed arrays to be mapped nicely! - in loop (bbrow) = - for ii < num_dates-1 do - let i = num_dates - (ii+1) in - let bbrow[i] = bbrow[i] - bbrow[i-1] - in bbrow - in bbrow - -fun [[real,num_und],num_dates] brownianBridge ( - int num_und, - [[int, num_dates],3] bb_inds, - [[real,num_dates],3] bb_data, - [real] gaussian_arr - ) = - let gauss2d = reshape((num_dates,num_und), gaussian_arr) in - let gauss2dT = transpose(gauss2d) in - transpose( - map( brownianBridgeDates(bb_inds, bb_data), gauss2dT ) - ) - - ---------------------------------- ---- Black-Scholes ---------------------------------- -fun [real] take(int n, [real] a) = let {first, rest} = split((n), a) in first - -fun [[real,num_und],num_dates] -correlateDeltas( [[real,num_und],num_und ] md_c, - [[real,num_und],num_dates] zds -) = - map( fn [real,num_und] ([real,num_und] zi) => - map( fn real (int j) => - let x = zipWith( *, take(j+1,zi), take(j+1,md_c[j]) ) - in reduce( +, 0.0, x ) - , iota(num_und) ) - , zds ) - -fun [real,num_und] combineVs( [real,num_und] n_row, - [real,num_und] vol_row, - [real,num_und] dr_row ) = - map(+, zip(dr_row, map(*, zip(n_row, vol_row ) ))) - -fun [[real,num_und],num_dates] -mkPrices( [real,num_und] md_starts, - [[real,num_und],num_dates] md_vols, - [[real,num_und],num_dates] md_drifts, - [[real,num_und],num_dates] noises -) = - let c_rows = map( combineVs, zip(noises, md_vols, md_drifts) ) in - let e_rows = map( fn [real] ([real] x) => map(exp, x) - , c_rows --map( combineVs, zip(noises, md_vols, md_drifts) ) - ) - in scan( fn [real] ([real] x, [real] y) => zipWith(*, x, y) - , md_starts, e_rows ) - -fun [[real,num_und],num_dates] blackScholes( - [[real,num_und],num_und ] md_c, - [[real,num_und],num_dates] md_vols, - [[real,num_und],num_dates] md_drifts, - [real,num_und] md_starts, - [[real,num_und],num_dates] bb_arr - ) = - let noises = correlateDeltas(md_c, bb_arr) - in mkPrices(md_starts, md_vols, md_drifts, noises) - ----------------------------------------- --- MAIN ----------------------------------------- -fun [real] mainInd( - int contract_number, - int num_mc_it, - [[int,num_bits]] dir_vs_nosz, - [[[real,num_und],num_und ],num_models] md_cs, - [[[real,num_und],num_dates],num_models] md_vols, - [[[real,num_und],num_dates],num_models] md_drifts, - [[real,num_und],num_models] md_sts, - [[real],num_models] md_detvals, - [[real],num_models] md_discts, - [[int, num_dates],3] bb_inds, - [[real,num_dates],3] bb_data -) = - let dir_vs = reshape( (num_dates*num_und, num_bits), dir_vs_nosz ) in - - let sobol_mat = map ( sobolIndR(dir_vs) - , map( fn int (int x) => x + 1, iota(num_mc_it) ) - ) in - - let gauss_mat = map ( ugaussian, sobol_mat ) in - - let bb_mat = map ( brownianBridge( num_und, bb_inds, bb_data ), gauss_mat ) in - - let payoffs = map ( fn [real] ([[real]] bb_row) => - let market_params = zip(md_cs, md_vols, md_drifts, md_sts) in - let bd_row = map (fn [[real]] ({[[real]],[[real]],[[real]],[real]} m) => - let {c,vol,drift,st} = m in - blackScholes(c, vol, drift, st, bb_row) - , market_params) - in - let payoff_params = zip(md_discts, md_detvals, bd_row) in - map (fn real ({[real],[real],[[real]]} p) => - let {disct, detval, bd} = p in - genericPayoff(contract_number, disct, detval, bd) - , payoff_params) - , bb_mat) - in - let payoff = reduce ( fn [real] ([real] x, [real] y) => - zipWith(+, x, y) - , replicate(num_models, 0.0) - , payoffs ) - in map (fn real (real price) => price / toFloat(num_mc_it), payoff) - - - -fun [real] main( - int contract_number, - int num_mc_it, - [[int,num_bits]] dir_vs_nosz, - [[[real,num_und],num_und ],num_models] md_cs, - [[[real,num_und],num_dates],num_models] md_vols, - [[[real,num_und],num_dates],num_models] md_drifts, - [[real,num_und],num_models] md_sts, - [[real],num_models] md_detvals, - [[real],num_models] md_discts, - [[int, num_dates],3] bb_inds, - [[real,num_dates],3] bb_data -) = - let sobvctsz = num_dates*num_und in - let dir_vs = reshape( (sobvctsz,num_bits), dir_vs_nosz ) in - let sobol_mat = streamMapMax ( fn [[real,sobvctsz]] (int chunk, [int] ns) => - sobolChunk(dir_vs, ns[0], chunk) - , iota(num_mc_it) ) in - - let gauss_mat = map ( ugaussian, sobol_mat ) in - - let bb_mat = map ( brownianBridge( num_und, bb_inds, bb_data ), gauss_mat ) in - - let payoffs = map ( fn [real] ([[real]] bb_row) => - let market_params = zip(md_cs, md_vols, md_drifts, md_sts) in - let bd_row = map (fn [[real]] ({[[real]],[[real]],[[real]],[real]} m) => - let {c,vol,drift,st} = m in - blackScholes(c, vol, drift, st, bb_row) - , market_params) - in - let payoff_params = zip(md_discts, md_detvals, bd_row) in - map (fn real ({[real],[real],[[real]]} p) => - let {disct, detval, bd} = p in - genericPayoff(contract_number, disct, detval, bd) - , payoff_params) - , bb_mat) - in - let payoff = reduce( fn [real] ([real] x, [real] y) => - zipWith(+, x, y) - , replicate(num_models, 0.0) - , payoffs ) - in map (fn real (real price) => price / toFloat(num_mc_it), payoff) - - ----------------------------------------- --- PAYOFF FUNCTIONS ----------------------------------------- -fun real genericPayoff(int contract, [real] md_disct, [real] md_detval, [[real]] xss) = - if (contract == 1) then payoff1(md_disct, md_detval, xss) - else if (contract == 2) then payoff2(md_disct, xss) - else if (contract == 3) then payoff3(md_disct, xss) - else 0.0 - -fun real payoff1([real] md_disct, [real] md_detval, [[real]] xss) = --- invariant: xss is a 1x1 matrix - let detval = md_detval[0] in - let amount = ( xss[0,0] - 4000.0 ) * detval in - let amount0= if (0.0 < amount) then amount else 0.0 - in trajInner(amount0, 0, md_disct) - -fun real payoff2 ([real] md_disc, [[real]] xss) = --- invariant: xss is a 5x3 matrix - let {date, amount} = - if (1.0 <= fminPayoff(xss[0])) then {0, 1150.0} - else if (1.0 <= fminPayoff(xss[1])) then {1, 1300.0} - else if (1.0 <= fminPayoff(xss[2])) then {2, 1450.0} - else if (1.0 <= fminPayoff(xss[3])) then {3, 1600.0} - else let x50 = fminPayoff(xss[4]) in - let val = if ( 1.0 <= x50 ) then 1750.0 - else if ( 0.75 < x50 ) then 1000.0 - else x50*1000.0 - in {4, val} - in trajInner(amount, date, md_disc) - -fun real payoff3([real] md_disct, [[real]] xss) = --- invariant: xss is a 367x3 matrix - let conds = map (fn bool ([real] x) => (x[0] <= 2630.6349999999998) || - (x[1] <= 8288.0) || - (x[2] <= 840.0) - , xss) in - let cond = reduce (||, False, conds) in - let price1= trajInner(100.0, 0, md_disct) in - let goto40= cond && - ( (xss[366,0] < 3758.05) || - (xss[366,1] < 11840.0) || - (xss[366,2] < 1200.0 ) ) in - let amount= if goto40 - then 1000.0 * fminPayoff(xss[366]) - else 1000.0 in - let price2 = trajInner(amount, 1, md_disct) in - price1 + price2 - -fun real fminPayoff([real] xs) = --- MIN( zipWith(/, xss, {3758.05, 11840.0, 1200.0}) ) - let {a,b,c} = { xs[0]/3758.05, xs[1]/11840.0, xs[2]/1200.0} in - if a < b then if a < c then a else c - else if b < c then b else c - -fun real MIN([real] arr) = - reduce( fn real (real x, real y) => if(x input.data - -cp $FINPAR_IMPLEMENTATION/run . - -futhark-c $FINPAR_IMPLEMENTATION/GenericPricing.fut -o GenericPricing diff --git a/benchmarks/OptionPricing/implementations/futhark/run b/benchmarks/OptionPricing/implementations/futhark/run deleted file mode 100755 index 9aef238..0000000 --- a/benchmarks/OptionPricing/implementations/futhark/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -./GenericPricing -t runtime.txt < input.data > result.json diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs deleted file mode 100644 index 511e316..0000000 --- a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs +++ /dev/null @@ -1,520 +0,0 @@ -module Main where - -import Control.DeepSeq -import Control.Applicative -import Control.Monad -import Data.Maybe -import System.CPUTime - ------------------------------------- ---- Requires the installation of --- ---- Parsec package, i.e., --- ---- cabal install parsec --- ------------------------------------- - -import Text.Parsec hiding (optional, (<|>), token) -import Text.Parsec.String - -import Data.Bits -import Data.List hiding (tail) -import Prelude hiding (tail) - -import Data.Vector.Unboxed(Vector) -- for gaussian approx -import qualified Data.Vector.Unboxed as V - ------------------------------- ---- Parser-related Helpers --- ------------------------------- -signed :: Parser String -> Parser String -signed p = (char '-' >> (('-':) <$> p)) <|> p - -whitespace :: Parser () -whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) - -lexeme :: Parser a -> Parser a -lexeme p = p <* whitespace - -token :: String -> Parser () -token = void . lexeme . string - -readInt :: Parser Int -readInt = lexeme $ read <$> signed (many1 digit) - -readDouble :: Parser Double -readDouble = lexeme $ read <$> signed (s2 <|> s1) - where s1 = do bef <- many1 digit - aft <- fromMaybe "" <$> - optional ((:) <$> char '.' <*> many1 digit) - exp <- fromMaybe "" <$> - optional ((:) <$> char 'e' <*> signed (many1 digit)) - return $ bef ++ aft ++ exp - s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit - -readArray :: Parser a -> Parser [a] -readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") - ---------------------------------------------- ---- Definition of lish-homomorphic reduce --- ---- requires a binary associative op --- ---------------------------------------------- - -reduce :: (a -> a -> a) -> a -> [a] -> a -reduce bop ne lst = foldl bop ne lst - ---zip5 :: [a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)] ---zip5 [] [] [] [] [] = [] ---zip5 (a:as) (b:bs) (c:cs) (d:ds) (e:es) = --- (a,b,c,d,e) :: (zip5 as bs cs ds es) ---zip5 as bs cs ds es = [] - ---------------------------------------------- ---- Chunking Helpers --- ---------------------------------------------- -chunk :: Int -> [a] -> [[a]] -chunk _ [] = [] -chunk n arr = take n arr : chunk n (drop n arr) - ---------------------------------------------- ---- Sobol Quasi-random vector generation --- ---------------------------------------------- -grayCode :: Int -> Int -grayCode x = (x `shiftR` 1) `xor` x - -xorInds :: Int -> Int -> [Int] -> Int -xorInds bits_num n dir_vs = reduce xor 0 $ map (dir_vs!!) is - where bits = [0..bits_num-1] - is = filter (testBit $ grayCode n) bits - -sobolIndI :: Int -> [[Int]] -> Int -> [Int] -sobolIndI bits_num dir_vs n = - map (xorInds bits_num n) dir_vs - -sobolIndR :: Int -> [[Int]] -> Int -> [Double] -sobolIndR bits_num dir_vs n = - map ((/divisor) . fromIntegral) arri - where arri = sobolIndI bits_num dir_vs n - divisor = 2.0 ** fromIntegral bits_num - - -lsb0 :: (Bits a, Num b, Num a) => a -> b -lsb0 n = lsb0_help 0 n - where lsb0_help ell c | (c .&. 1 == 0) = ell - | otherwise = lsb0_help (ell+1) (c `shiftR` 1) - -sobolRecI :: Int -> [[Int]] -> [Int] -> Int -> [Int] -sobolRecI bits_num sob_dir_vs prev n = zipWith xor prev dir_vs - where dir_vs = map ( !! bit ) sob_dir_vs - bit = lsb0 n -- rmt n - -sobolRecMap :: Double -> Int -> [[Int]] -> (Int,Int) -> [[Double]] -sobolRecMap sob_fact bits_num dir_vs (l, u) = - let a = sobolIndI bits_num dir_vs l - norm = ( * sob_fact ) . fromIntegral - in map (map norm) (scanl (sobolRecI bits_num dir_vs) a [l..u-1]) - - ------------------------------------------- ---- To-Gaussian Distribution Transform.--- ------------------------------------------- -polyAppr :: Double -> Double -> Double -> Double -> Double -> Double - -> Double -> Double -> Double -> Double -> Double -> Double - -> Double -> Double -> Double -> Double -> Double -> Double -polyAppr x a0 a1 a2 a3 a4 a5 a6 a7 b0 b1 b2 b3 b4 b5 b6 b7 = - (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0) / - (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) - - --- same functionality as "polyAppr", but using vectors for constants -approx :: Double -> Vector Double -> Vector Double -> Double -approx x as bs = let reduce xs = V.foldr (\b c -> b + x*c) 0 xs - in reduce as / reduce bs - -smallcase q = q * approx (0.180625 - q*q) small_as small_bs -small_as = V.fromList [ 3.387132872796366608 - , 133.14166789178437745 - , 1971.5909503065514427 - , 13731.693765509461125 - , 45921.953931549871457 - , 67265.770927008700853 - , 33430.575583588128105 - , 2509.0809287301226727 ] -small_bs = V.fromList [ 1.0 - , 42.313330701600911252 - , 687.1870074920579083 - , 5394.1960214247511077 - , 21213.794301586595867 - , 39307.89580009271061 - , 28729.085735721942674 - , 5226.495278852854561 ] - -intermediate q = approx (q-1.6) interm_as interm_bs -interm_as = V.fromList [ 1.42343711074968357734 - , 4.6303378461565452959 - , 5.7694972214606914055 - , 3.64784832476320460504 - , 1.27045825245236838258 - , 0.24178072517745061177 - , 0.0227238449892691845833 - , 7.7454501427834140764e-4] -interm_bs = V.fromList [ 1.0 - , 2.05319162663775882187 - , 1.6763848301838038494 - , 0.68976733498510000455 - , 0.14810397642748007459 - , 0.0151986665636164571966 - , 5.475938084995344946e-4 - , 1.05075007164441684324e-9] - -tail q = approx (q - 5.0) tail_as tail_bs -tail_as = V.fromList [ 6.6579046435011037772 - , 5.4637849111641143699 - , 1.7848265399172913358 - , 0.29656057182850489123 - , 0.026532189526576123093 - , 0.0012426609473880784386 - , 2.71155556874348757815e-5 - , 2.01033439929228813265e-7] -tail_bs = V.fromList [ 1.0 - , 0.59983220655588793769 - , 0.13692988092273580531 - , 0.0148753612908506148525 - , 7.868691311456132591e-4 - , 1.8463183175100546818e-5 - , 1.4215117583164458887e-7 - , 2.04426310338993978564e-15] - -{- -smallcase :: Double -> Double -smallcase q = - q * - polyAppr - ( 0.180625 - q * q) - 3.387132872796366608 - 133.14166789178437745 - 1971.5909503065514427 - 13731.693765509461125 - 45921.953931549871457 - 67265.770927008700853 - 33430.575583588128105 - 2509.0809287301226727 - - 1.0 - 42.313330701600911252 - 687.1870074920579083 - 5394.1960214247511077 - 21213.794301586595867 - 39307.89580009271061 - 28729.085735721942674 - 5226.495278852854561 - -intermediate :: Double -> Double -intermediate r = - polyAppr (r - 1.6) - 1.42343711074968357734 - 4.6303378461565452959 - 5.7694972214606914055 - 3.64784832476320460504 - 1.27045825245236838258 - 0.24178072517745061177 - 0.0227238449892691845833 - 7.7454501427834140764e-4 - - 1.0 - 2.05319162663775882187 - 1.6763848301838038494 - 0.68976733498510000455 - 0.14810397642748007459 - 0.0151986665636164571966 - 5.475938084995344946e-4 - 1.05075007164441684324e-9 - -tail :: Double -> Double -tail r = - polyAppr (r - 5.0) - 6.6579046435011037772 - 5.4637849111641143699 - 1.7848265399172913358 - 0.29656057182850489123 - 0.026532189526576123093 - 0.0012426609473880784386 - 2.71155556874348757815e-5 - 2.01033439929228813265e-7 - - 1.0 - 0.59983220655588793769 - 0.13692988092273580531 - 0.0148753612908506148525 - 7.868691311456132591e-4 - 1.8463183175100546818e-5 - 1.4215117583164458887e-7 - 2.04426310338993978564e-5 --} - -ugaussianEl :: Double -> Double -ugaussianEl p = - if ((dp < 0.0) && (0.0 - dp <= 0.425)) || ((0.0 <= dp) && (dp <= 0.425)) - then smallcase dp - else let pp = if dp < 0.0 then dp + 0.5 else 0.5 - dp - r = sqrt $ -log pp - x = if r <= 5.0 then intermediate r else tail r - in if dp < 0.0 then 0.0 - x else x - where dp = p - 0.5 - -ugaussian :: [Double] -> [Double] -ugaussian = map ugaussianEl - ------------------------------------------- ---- Brownian-Bridge Implementation --- ------------------------------------------- -brownianBridgeDates :: Int -> [[Int]] -> [[Double]] -> [Double] -> [Double] -brownianBridgeDates num_dates bb_inds bb_data gauss = - let bbrow = update (replicate num_dates 0.0) - (bi!!0) (sd!!0 * gauss!!0) - bbrow' = foldl f bbrow $ drop 1 $ - zip3 (zip3 bi li ri) (zip3 sd lw rw) gauss - in zipWith (-) bbrow' (0.0:bbrow') - where [bi,li,ri] = map (map $ subtract 1) bb_inds - [sd,lw,rw] = bb_data - f bbrow ((l,j,k),(x,y,z),zi) = - let wk = bbrow !! k - tmp = z * wk + x * zi - in update bbrow l $ if (j + 1) == 0 - then tmp - else tmp + y * (bbrow!!j) - update a i v = take i a ++ [v] ++ drop (i+1) a - -brownianBridge :: Int -> Int -> [[Int]] -> [[Double]] -> [Double] -> [[Double]] -brownianBridge num_paths num_dates bb_inds bb_data gaussian_arr = - transpose $ map (brownianBridgeDates num_dates bb_inds bb_data) gauss2dT - where gauss2d = chunk num_paths gaussian_arr - gauss2dT = transpose gauss2d - ------------------------------------------- ---- Black-Scholes Implementation --- ------------------------------------------- -fftmp :: Int -> [[Double]] -> [Double] -> [Double] -fftmp num_paths md_c zi = map f [0..num_paths-1] - where f j = reduce (+) 0.0 $ zipWith (*) (take (j+1) zi) (take (j+1) $ md_c!!j) - -correlateDeltas :: Int -> [[Double]] -> [[Double]] -> [[Double]] -correlateDeltas num_paths md_c = map $ fftmp num_paths md_c - -combineVs :: [Double] -> [Double] -> [Double] -> [Double] -combineVs n_row vol_row dr_row = - zipWith (+) dr_row $ zipWith (*) n_row vol_row - -mkPrices :: [Double] -> [[Double]] -> [[Double]] -> [[Double]] -> [[Double]] -mkPrices md_starts md_vols md_drifts noises = - drop 1 $ scanl (zipWith (*)) md_starts e_rows - where e_rows = map (map exp) $ zipWith3 combineVs noises md_vols md_drifts - -blackScholes :: Int -> [[Double]] -> [[Double]] -> [[Double]] - -> [Double] -> [[Double]] -> [[Double]] -blackScholes num_paths md_c md_vols md_drifts md_starts bb_arr = - mkPrices md_starts md_vols md_drifts noises - where noises = correlateDeltas num_paths md_c bb_arr - - ------------------------------------------- ---- Payoff functions --- ------------------------------------------- -payoff :: Int -> [Double] -> [Double] -> [[Double]] -> Double -payoff contract md_disc md_detval xss = - if contract == 1 then payoff1 md_disc md_detval xss - else if contract == 2 then payoff2 md_disc xss - else if contract == 3 then payoff3 md_disc xss - else 0.0 - -payoff1 :: [Double] -> [Double] -> [[Double]] -> Double -payoff1 md_disc md_detvals xss = - let detval = head md_detvals - amount = ( (head (head xss)) - 4000.0 ) * detval - amount'= max 0.0 amount - in trajInner amount' 0 md_disc - -payoff2 :: [Double] -> [[Double]] -> Double -payoff2 md_disc xss - | 1.0 <= mins !! 0 = trajInner 1150.0 0 md_disc - | 1.0 <= mins !! 1 = trajInner 1300.0 1 md_disc - | 1.0 <= mins !! 2 = trajInner 1450.0 2 md_disc - | 1.0 <= mins !! 3 = trajInner 1600.0 3 md_disc - | 1.0 <= mins !! 4 = trajInner 1750.0 4 md_disc - | 0.75 < mins !! 4 = trajInner 1000.0 4 md_disc - | otherwise = trajInner (1000 * (mins!!4)) 4 md_disc - where divs = [ 1.0/3758.05, 1.0/11840.0, 1.0/1200.0 ] - xss_div = map (zipWith (*) divs) xss - mins = map minimum xss_div - - -payoff3 :: [Double] -> [[Double]] -> Double -payoff3 md_disc xss = - let underlyings (i,j) = (xss !! i) !! j - --- Test: (underlyings(n,0) <= 2630.6349999999998) || --- (underlyings(n,2) <= 840.0) || --- (underlyings(n,1) <= 8288.0) --- for any n <- [0..366] - x3309 = any (\ [x,y,z] -> or [ x <= 2630.6349999999998 - , y <= 8288.0 - , z <= 840.0]) - xss - - goto_40 = x3309 && - ( (underlyings(366,0) < 3758.05) || - (underlyings(366,2) < 1200.0 ) || - (underlyings(366,1) < 11840.0) ) - - price1 = trajInner 100.0 0 md_disc - - price2 = if goto_40 - then let m1 = min ((underlyings(366,2) / 1200.0 ) - 1.0) - ((underlyings(366,0) / 3758.05) - 1.0) - m2 = min ((underlyings(366,1) / 11840.0) - 1.0) m1 - amount = (1000.0 * (1.0 + m2 ) ) - in trajInner amount 1 md_disc - else trajInner 1000.0 1 md_disc - in price1 + price2 - - - -trajInner :: Double -> Int -> [Double] -> Double -trajInner amount i disc = amount * disc !! i - --------------------------------------------- --------------------------------------------- --------------------------------------------- - - - -------------------------------------------- ---- Main Entry Point: price computation --- -------------------------------------------- - ---- Using only the (not very efficient) Sobol formula! --- -compute :: Int -> Int -> Int -> Int -> Int -> Int -> [[Int]] - -> [[[Double]]] -> [[[Double]]] -> [[[Double]]] - -> [[Double]] -> [[Double]] -> [[Double]] - -> [[Int]] -> [[Double]] - -> [Double] -compute contract num_mc_it num_dates num_under num_models num_bits - dir_vs md_cs md_vols md_drifts md_starts md_detvals - md_discts bb_inds bb_data = - - let num_det_pricers = length $ head md_detvals - num_cash_flows = length $ head md_discts - - sobol_mat = map (sobolIndR num_bits dir_vs) [1..num_mc_it] - gauss_mat = map ugaussian sobol_mat - bb_mat = map (brownianBridge num_under num_dates bb_inds bb_data) gauss_mat - - md_cvdsmat= zip5 md_cs md_vols md_drifts md_starts (replicate num_models bb_mat) - bs_mats = map (\cvdsmat -> let (c, vol, drift, start, bb_mat) = cvdsmat - in map (blackScholes num_under c vol drift start) bb_mat - ) - md_cvdsmat - - md_discmat= zip3 md_discts md_detvals bs_mats - payoffs = map (\disc_bs -> let (disc, detvals, bsmat) = disc_bs - in map (payoff contract disc detvals) bsmat - ) - md_discmat - - sum_prices= map (\payoff -> reduce (+) 0.0 payoff) payoffs - prices = map (\sp -> sp / fromIntegral num_mc_it) sum_prices - in prices - - ---- Chunking the computation and using sobol-independent formula --- ---- for the first element and the more efficient sobol-recurrent --- --- formula for the rest of elements --- -compute_chunk :: Int -> Int -> Int -> Int -> Int -> Int -> [[Int]] - -> [[[Double]]] -> [[[Double]]] -> [[[Double]]] - -> [[Double]] -> [[Double]] -> [[Double]] - -> [[Int ]] -> [[Double]] -> (Int,Int) - -> [Double] -compute_chunk contract num_mc_it num_dates num_under num_models num_bits - dir_vs md_cs md_vols md_drifts md_starts md_detvals - md_discts bb_inds bb_data (lb,ub) = - let num_det_pricers = length $ head md_detvals - num_cash_flows = length $ head md_discts - - sob_factor = 1.0 / (2.0 ** fromIntegral num_bits) - - sobol_mat = sobolRecMap sob_factor num_bits dir_vs (lb,ub) - gauss_mat = map ugaussian sobol_mat - bb_mat = map (brownianBridge num_under num_dates bb_inds bb_data) gauss_mat - - md_cvdsmat= zip5 md_cs md_vols md_drifts md_starts (replicate num_models bb_mat) - bs_mats = map (\cvdsmat -> let (c, vol, drift, start, bb_mat) = cvdsmat - in map (blackScholes num_under c vol drift start) bb_mat - ) - md_cvdsmat - - md_discmat= zip3 md_discts md_detvals bs_mats - payoffs = map (\disc_bs -> let (disc, detvals, bsmat) = disc_bs - in map (payoff contract disc detvals) bsmat - ) - md_discmat - - sum_prices= map (\payoff -> reduce (+) 0.0 payoff) payoffs - prices = map (\sp -> sp / fromIntegral num_mc_it) sum_prices - in prices - -tiledSkeleton :: Int -> Int -> Int -> ((Int,Int) -> [Double]) -> [Double] -tiledSkeleton sob_dim num_mc_its chunk fun = - let divides = num_mc_its `mod` chunk == 0 - extra = if (divides) then [] else [num_mc_its] - iv = zip [1,chunk+1..] ([chunk, 2*chunk .. num_mc_its] ++ extra ) - in (reduce (zipWith (+)) (replicate sob_dim 0.0) . map fun) iv - ------------------------------------------ ---- Entry point for Generic Pricing --- ---- The only place where using Monads,--- ---- e.g., parsing Dataset from StdIn --- ------------------------------------------ -main :: IO () -main = do s <- getContents - case parse run "input" s of - Left e -> error $ show e - Right m -> do - (v,runtime) <- m - writeFile "result.json" $ show v - writeFile "runtime.txt" $ show runtime - where run = do - whitespace - contract <- readInt - num_mc_it <- readInt - num_dates <- readInt - num_under <- readInt - - num_models<- readInt - num_bits <- readInt - sob_dirvs <- readInt2d - md_cs <- readDouble3d - md_vols <- readDouble3d - md_drifts <- readDouble3d - md_starts <- readDouble2d - md_detvals<- readDouble2d - md_discts <- readDouble2d - bb_inds <- readInt2d - bb_data <- readDouble2d - - let tiled_skel = tiledSkeleton (num_under*num_dates) num_mc_it 128 - - return $ do - start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. - let v = tiled_skel $ - compute_chunk - contract num_mc_it num_dates num_under num_models num_bits - sob_dirvs md_cs md_vols md_drifts md_starts md_detvals - md_discts bb_inds bb_data - end <- v `deepseq` getCPUTime - return (v, (end - start) `div` 1000000000) - - readInt2d = readArray $ readArray readInt - readDouble1d = readArray readDouble - readDouble2d = readArray $ readArray readDouble - readDouble3d = readArray $ readArray $ readArray readDouble - --- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs --- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs b/benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs deleted file mode 100644 index 136a27f..0000000 --- a/benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs +++ /dev/null @@ -1,1105 +0,0 @@ -module Payoff3Cond where - -payoff3Cond :: [[Double]] -> Bool -payoff3Cond xss = - let underlyings (i,j) = (xss !! i) !! j - in (underlyings(0,0) <= 2630.6349999999998) || - (underlyings(0,2) <= 840.0) || - (underlyings(0,1) <= 8288.0) || - (underlyings(1,0) <= 2630.6349999999998) || - (underlyings(1,2) <= 840.0) || - (underlyings(1,1) <= 8288.0) || - (underlyings(2,0) <= 2630.6349999999998) || - (underlyings(2,2) <= 840.0) || - (underlyings(2,1) <= 8288.0) || - (underlyings(3,0) <= 2630.6349999999998) || - (underlyings(3,2) <= 840.0) || - (underlyings(3,1) <= 8288.0) || - (underlyings(4,0) <= 2630.6349999999998) || - (underlyings(4,2) <= 840.0) || - (underlyings(4,1) <= 8288.0) || - (underlyings(5,0) <= 2630.6349999999998) || - (underlyings(5,2) <= 840.0) || - (underlyings(5,1) <= 8288.0) || - (underlyings(6,0) <= 2630.6349999999998) || - (underlyings(6,2) <= 840.0) || - (underlyings(6,1) <= 8288.0) || - (underlyings(7,0) <= 2630.6349999999998) || - (underlyings(7,2) <= 840.0) || - (underlyings(7,1) <= 8288.0) || - (underlyings(8,0) <= 2630.6349999999998) || - (underlyings(8,2) <= 840.0) || - (underlyings(8,1) <= 8288.0) || - (underlyings(9,0) <= 2630.6349999999998) || - (underlyings(9,2) <= 840.0) || - (underlyings(9,1) <= 8288.0) || - (underlyings(10,0) <= 2630.6349999999998) || - (underlyings(10,2) <= 840.0) || - (underlyings(10,1) <= 8288.0) || - (underlyings(11,0) <= 2630.6349999999998) || - (underlyings(11,2) <= 840.0) || - (underlyings(11,1) <= 8288.0) || - (underlyings(12,0) <= 2630.6349999999998) || - (underlyings(12,2) <= 840.0) || - (underlyings(12,1) <= 8288.0) || - (underlyings(13,0) <= 2630.6349999999998) || - (underlyings(13,2) <= 840.0) || - (underlyings(13,1) <= 8288.0) || - (underlyings(14,0) <= 2630.6349999999998) || - (underlyings(14,2) <= 840.0) || - (underlyings(14,1) <= 8288.0) || - (underlyings(15,0) <= 2630.6349999999998) || - (underlyings(15,2) <= 840.0) || - (underlyings(15,1) <= 8288.0) || - (underlyings(16,0) <= 2630.6349999999998) || - (underlyings(16,2) <= 840.0) || - (underlyings(16,1) <= 8288.0) || - (underlyings(17,0) <= 2630.6349999999998) || - (underlyings(17,2) <= 840.0) || - (underlyings(17,1) <= 8288.0) || - (underlyings(18,0) <= 2630.6349999999998) || - (underlyings(18,2) <= 840.0) || - (underlyings(18,1) <= 8288.0) || - (underlyings(19,0) <= 2630.6349999999998) || - (underlyings(19,2) <= 840.0) || - (underlyings(19,1) <= 8288.0) || - (underlyings(20,0) <= 2630.6349999999998) || - (underlyings(20,2) <= 840.0) || - (underlyings(20,1) <= 8288.0) || - (underlyings(21,0) <= 2630.6349999999998) || - (underlyings(21,2) <= 840.0) || - (underlyings(21,1) <= 8288.0) || - (underlyings(22,0) <= 2630.6349999999998) || - (underlyings(22,2) <= 840.0) || - (underlyings(22,1) <= 8288.0) || - (underlyings(23,0) <= 2630.6349999999998) || - (underlyings(23,2) <= 840.0) || - (underlyings(23,1) <= 8288.0) || - (underlyings(24,0) <= 2630.6349999999998) || - (underlyings(24,2) <= 840.0) || - (underlyings(24,1) <= 8288.0) || - (underlyings(25,0) <= 2630.6349999999998) || - (underlyings(25,2) <= 840.0) || - (underlyings(25,1) <= 8288.0) || - (underlyings(26,0) <= 2630.6349999999998) || - (underlyings(26,2) <= 840.0) || - (underlyings(26,1) <= 8288.0) || - (underlyings(27,0) <= 2630.6349999999998) || - (underlyings(27,2) <= 840.0) || - (underlyings(27,1) <= 8288.0) || - (underlyings(28,0) <= 2630.6349999999998) || - (underlyings(28,2) <= 840.0) || - (underlyings(28,1) <= 8288.0) || - (underlyings(29,0) <= 2630.6349999999998) || - (underlyings(29,2) <= 840.0) || - (underlyings(29,1) <= 8288.0) || - (underlyings(30,0) <= 2630.6349999999998) || - (underlyings(30,2) <= 840.0) || - (underlyings(30,1) <= 8288.0) || - (underlyings(31,0) <= 2630.6349999999998) || - (underlyings(31,2) <= 840.0) || - (underlyings(31,1) <= 8288.0) || - (underlyings(32,0) <= 2630.6349999999998) || - (underlyings(32,2) <= 840.0) || - (underlyings(32,1) <= 8288.0) || - (underlyings(33,0) <= 2630.6349999999998) || - (underlyings(33,2) <= 840.0) || - (underlyings(33,1) <= 8288.0) || - (underlyings(34,0) <= 2630.6349999999998) || - (underlyings(34,2) <= 840.0) || - (underlyings(34,1) <= 8288.0) || - (underlyings(35,0) <= 2630.6349999999998) || - (underlyings(35,2) <= 840.0) || - (underlyings(35,1) <= 8288.0) || - (underlyings(36,0) <= 2630.6349999999998) || - (underlyings(36,2) <= 840.0) || - (underlyings(36,1) <= 8288.0) || - (underlyings(37,0) <= 2630.6349999999998) || - (underlyings(37,2) <= 840.0) || - (underlyings(37,1) <= 8288.0) || - (underlyings(38,0) <= 2630.6349999999998) || - (underlyings(38,2) <= 840.0) || - (underlyings(38,1) <= 8288.0) || - (underlyings(39,0) <= 2630.6349999999998) || - (underlyings(39,2) <= 840.0) || - (underlyings(39,1) <= 8288.0) || - (underlyings(40,0) <= 2630.6349999999998) || - (underlyings(40,2) <= 840.0) || - (underlyings(40,1) <= 8288.0) || - (underlyings(41,0) <= 2630.6349999999998) || - (underlyings(41,2) <= 840.0) || - (underlyings(41,1) <= 8288.0) || - (underlyings(42,0) <= 2630.6349999999998) || - (underlyings(42,2) <= 840.0) || - (underlyings(42,1) <= 8288.0) || - (underlyings(43,0) <= 2630.6349999999998) || - (underlyings(43,2) <= 840.0) || - (underlyings(43,1) <= 8288.0) || - (underlyings(44,0) <= 2630.6349999999998) || - (underlyings(44,2) <= 840.0) || - (underlyings(44,1) <= 8288.0) || - (underlyings(45,0) <= 2630.6349999999998) || - (underlyings(45,2) <= 840.0) || - (underlyings(45,1) <= 8288.0) || - (underlyings(46,0) <= 2630.6349999999998) || - (underlyings(46,2) <= 840.0) || - (underlyings(46,1) <= 8288.0) || - (underlyings(47,0) <= 2630.6349999999998) || - (underlyings(47,2) <= 840.0) || - (underlyings(47,1) <= 8288.0) || - (underlyings(48,0) <= 2630.6349999999998) || - (underlyings(48,2) <= 840.0) || - (underlyings(48,1) <= 8288.0) || - (underlyings(49,0) <= 2630.6349999999998) || - (underlyings(49,2) <= 840.0) || - (underlyings(49,1) <= 8288.0) || - (underlyings(50,0) <= 2630.6349999999998) || - (underlyings(50,2) <= 840.0) || - (underlyings(50,1) <= 8288.0) || - (underlyings(51,0) <= 2630.6349999999998) || - (underlyings(51,2) <= 840.0) || - (underlyings(51,1) <= 8288.0) || - (underlyings(52,0) <= 2630.6349999999998) || - (underlyings(52,2) <= 840.0) || - (underlyings(52,1) <= 8288.0) || - (underlyings(53,0) <= 2630.6349999999998) || - (underlyings(53,2) <= 840.0) || - (underlyings(53,1) <= 8288.0) || - (underlyings(54,0) <= 2630.6349999999998) || - (underlyings(54,2) <= 840.0) || - (underlyings(54,1) <= 8288.0) || - (underlyings(55,0) <= 2630.6349999999998) || - (underlyings(55,2) <= 840.0) || - (underlyings(55,1) <= 8288.0) || - (underlyings(56,0) <= 2630.6349999999998) || - (underlyings(56,2) <= 840.0) || - (underlyings(56,1) <= 8288.0) || - (underlyings(57,0) <= 2630.6349999999998) || - (underlyings(57,2) <= 840.0) || - (underlyings(57,1) <= 8288.0) || - (underlyings(58,0) <= 2630.6349999999998) || - (underlyings(58,2) <= 840.0) || - (underlyings(58,1) <= 8288.0) || - (underlyings(59,0) <= 2630.6349999999998) || - (underlyings(59,2) <= 840.0) || - (underlyings(59,1) <= 8288.0) || - (underlyings(60,0) <= 2630.6349999999998) || - (underlyings(60,2) <= 840.0) || - (underlyings(60,1) <= 8288.0) || - (underlyings(61,0) <= 2630.6349999999998) || - (underlyings(61,2) <= 840.0) || - (underlyings(61,1) <= 8288.0) || - (underlyings(62,0) <= 2630.6349999999998) || - (underlyings(62,2) <= 840.0) || - (underlyings(62,1) <= 8288.0) || - (underlyings(63,0) <= 2630.6349999999998) || - (underlyings(63,2) <= 840.0) || - (underlyings(63,1) <= 8288.0) || - (underlyings(64,0) <= 2630.6349999999998) || - (underlyings(64,2) <= 840.0) || - (underlyings(64,1) <= 8288.0) || - (underlyings(65,0) <= 2630.6349999999998) || - (underlyings(65,2) <= 840.0) || - (underlyings(65,1) <= 8288.0) || - (underlyings(66,0) <= 2630.6349999999998) || - (underlyings(66,2) <= 840.0) || - (underlyings(66,1) <= 8288.0) || - (underlyings(67,0) <= 2630.6349999999998) || - (underlyings(67,2) <= 840.0) || - (underlyings(67,1) <= 8288.0) || - (underlyings(68,0) <= 2630.6349999999998) || - (underlyings(68,2) <= 840.0) || - (underlyings(68,1) <= 8288.0) || - (underlyings(69,0) <= 2630.6349999999998) || - (underlyings(69,2) <= 840.0) || - (underlyings(69,1) <= 8288.0) || - (underlyings(70,0) <= 2630.6349999999998) || - (underlyings(70,2) <= 840.0) || - (underlyings(70,1) <= 8288.0) || - (underlyings(71,0) <= 2630.6349999999998) || - (underlyings(71,2) <= 840.0) || - (underlyings(71,1) <= 8288.0) || - (underlyings(72,0) <= 2630.6349999999998) || - (underlyings(72,2) <= 840.0) || - (underlyings(72,1) <= 8288.0) || - (underlyings(73,0) <= 2630.6349999999998) || - (underlyings(73,2) <= 840.0) || - (underlyings(73,1) <= 8288.0) || - (underlyings(74,0) <= 2630.6349999999998) || - (underlyings(74,2) <= 840.0) || - (underlyings(74,1) <= 8288.0) || - (underlyings(75,0) <= 2630.6349999999998) || - (underlyings(75,2) <= 840.0) || - (underlyings(75,1) <= 8288.0) || - (underlyings(76,0) <= 2630.6349999999998) || - (underlyings(76,2) <= 840.0) || - (underlyings(76,1) <= 8288.0) || - (underlyings(77,0) <= 2630.6349999999998) || - (underlyings(77,2) <= 840.0) || - (underlyings(77,1) <= 8288.0) || - (underlyings(78,0) <= 2630.6349999999998) || - (underlyings(78,2) <= 840.0) || - (underlyings(78,1) <= 8288.0) || - (underlyings(79,0) <= 2630.6349999999998) || - (underlyings(79,2) <= 840.0) || - (underlyings(79,1) <= 8288.0) || - (underlyings(80,0) <= 2630.6349999999998) || - (underlyings(80,2) <= 840.0) || - (underlyings(80,1) <= 8288.0) || - (underlyings(81,0) <= 2630.6349999999998) || - (underlyings(81,2) <= 840.0) || - (underlyings(81,1) <= 8288.0) || - (underlyings(82,0) <= 2630.6349999999998) || - (underlyings(82,2) <= 840.0) || - (underlyings(82,1) <= 8288.0) || - (underlyings(83,0) <= 2630.6349999999998) || - (underlyings(83,2) <= 840.0) || - (underlyings(83,1) <= 8288.0) || - (underlyings(84,0) <= 2630.6349999999998) || - (underlyings(84,2) <= 840.0) || - (underlyings(84,1) <= 8288.0) || - (underlyings(85,0) <= 2630.6349999999998) || - (underlyings(85,2) <= 840.0) || - (underlyings(85,1) <= 8288.0) || - (underlyings(86,0) <= 2630.6349999999998) || - (underlyings(86,2) <= 840.0) || - (underlyings(86,1) <= 8288.0) || - (underlyings(87,0) <= 2630.6349999999998) || - (underlyings(87,2) <= 840.0) || - (underlyings(87,1) <= 8288.0) || - (underlyings(88,0) <= 2630.6349999999998) || - (underlyings(88,2) <= 840.0) || - (underlyings(88,1) <= 8288.0) || - (underlyings(89,0) <= 2630.6349999999998) || - (underlyings(89,2) <= 840.0) || - (underlyings(89,1) <= 8288.0) || - (underlyings(90,0) <= 2630.6349999999998) || - (underlyings(90,2) <= 840.0) || - (underlyings(90,1) <= 8288.0) || - (underlyings(91,0) <= 2630.6349999999998) || - (underlyings(91,2) <= 840.0) || - (underlyings(91,1) <= 8288.0) || - (underlyings(92,0) <= 2630.6349999999998) || - (underlyings(92,2) <= 840.0) || - (underlyings(92,1) <= 8288.0) || - (underlyings(93,0) <= 2630.6349999999998) || - (underlyings(93,2) <= 840.0) || - (underlyings(93,1) <= 8288.0) || - (underlyings(94,0) <= 2630.6349999999998) || - (underlyings(94,2) <= 840.0) || - (underlyings(94,1) <= 8288.0) || - (underlyings(95,0) <= 2630.6349999999998) || - (underlyings(95,2) <= 840.0) || - (underlyings(95,1) <= 8288.0) || - (underlyings(96,0) <= 2630.6349999999998) || - (underlyings(96,2) <= 840.0) || - (underlyings(96,1) <= 8288.0) || - (underlyings(97,0) <= 2630.6349999999998) || - (underlyings(97,2) <= 840.0) || - (underlyings(97,1) <= 8288.0) || - (underlyings(98,0) <= 2630.6349999999998) || - (underlyings(98,2) <= 840.0) || - (underlyings(98,1) <= 8288.0) || - (underlyings(99,0) <= 2630.6349999999998) || - (underlyings(99,2) <= 840.0) || - (underlyings(99,1) <= 8288.0) || - (underlyings(100,0) <= 2630.6349999999998) || - (underlyings(100,2) <= 840.0) || - (underlyings(100,1) <= 8288.0) || - (underlyings(101,0) <= 2630.6349999999998) || - (underlyings(101,2) <= 840.0) || - (underlyings(101,1) <= 8288.0) || - (underlyings(102,0) <= 2630.6349999999998) || - (underlyings(102,2) <= 840.0) || - (underlyings(102,1) <= 8288.0) || - (underlyings(103,0) <= 2630.6349999999998) || - (underlyings(103,2) <= 840.0) || - (underlyings(103,1) <= 8288.0) || - (underlyings(104,0) <= 2630.6349999999998) || - (underlyings(104,2) <= 840.0) || - (underlyings(104,1) <= 8288.0) || - (underlyings(105,0) <= 2630.6349999999998) || - (underlyings(105,2) <= 840.0) || - (underlyings(105,1) <= 8288.0) || - (underlyings(106,0) <= 2630.6349999999998) || - (underlyings(106,2) <= 840.0) || - (underlyings(106,1) <= 8288.0) || - (underlyings(107,0) <= 2630.6349999999998) || - (underlyings(107,2) <= 840.0) || - (underlyings(107,1) <= 8288.0) || - (underlyings(108,0) <= 2630.6349999999998) || - (underlyings(108,2) <= 840.0) || - (underlyings(108,1) <= 8288.0) || - (underlyings(109,0) <= 2630.6349999999998) || - (underlyings(109,2) <= 840.0) || - (underlyings(109,1) <= 8288.0) || - (underlyings(110,0) <= 2630.6349999999998) || - (underlyings(110,2) <= 840.0) || - (underlyings(110,1) <= 8288.0) || - (underlyings(111,0) <= 2630.6349999999998) || - (underlyings(111,2) <= 840.0) || - (underlyings(111,1) <= 8288.0) || - (underlyings(112,0) <= 2630.6349999999998) || - (underlyings(112,2) <= 840.0) || - (underlyings(112,1) <= 8288.0) || - (underlyings(113,0) <= 2630.6349999999998) || - (underlyings(113,2) <= 840.0) || - (underlyings(113,1) <= 8288.0) || - (underlyings(114,0) <= 2630.6349999999998) || - (underlyings(114,2) <= 840.0) || - (underlyings(114,1) <= 8288.0) || - (underlyings(115,0) <= 2630.6349999999998) || - (underlyings(115,2) <= 840.0) || - (underlyings(115,1) <= 8288.0) || - (underlyings(116,0) <= 2630.6349999999998) || - (underlyings(116,2) <= 840.0) || - (underlyings(116,1) <= 8288.0) || - (underlyings(117,0) <= 2630.6349999999998) || - (underlyings(117,2) <= 840.0) || - (underlyings(117,1) <= 8288.0) || - (underlyings(118,0) <= 2630.6349999999998) || - (underlyings(118,2) <= 840.0) || - (underlyings(118,1) <= 8288.0) || - (underlyings(119,0) <= 2630.6349999999998) || - (underlyings(119,2) <= 840.0) || - (underlyings(119,1) <= 8288.0) || - (underlyings(120,0) <= 2630.6349999999998) || - (underlyings(120,2) <= 840.0) || - (underlyings(120,1) <= 8288.0) || - (underlyings(121,0) <= 2630.6349999999998) || - (underlyings(121,2) <= 840.0) || - (underlyings(121,1) <= 8288.0) || - (underlyings(122,0) <= 2630.6349999999998) || - (underlyings(122,2) <= 840.0) || - (underlyings(122,1) <= 8288.0) || - (underlyings(123,0) <= 2630.6349999999998) || - (underlyings(123,2) <= 840.0) || - (underlyings(123,1) <= 8288.0) || - (underlyings(124,0) <= 2630.6349999999998) || - (underlyings(124,2) <= 840.0) || - (underlyings(124,1) <= 8288.0) || - (underlyings(125,0) <= 2630.6349999999998) || - (underlyings(125,2) <= 840.0) || - (underlyings(125,1) <= 8288.0) || - (underlyings(126,0) <= 2630.6349999999998) || - (underlyings(126,2) <= 840.0) || - (underlyings(126,1) <= 8288.0) || - (underlyings(127,0) <= 2630.6349999999998) || - (underlyings(127,2) <= 840.0) || - (underlyings(127,1) <= 8288.0) || - (underlyings(128,0) <= 2630.6349999999998) || - (underlyings(128,2) <= 840.0) || - (underlyings(128,1) <= 8288.0) || - (underlyings(129,0) <= 2630.6349999999998) || - (underlyings(129,2) <= 840.0) || - (underlyings(129,1) <= 8288.0) || - (underlyings(130,0) <= 2630.6349999999998) || - (underlyings(130,2) <= 840.0) || - (underlyings(130,1) <= 8288.0) || - (underlyings(131,0) <= 2630.6349999999998) || - (underlyings(131,2) <= 840.0) || - (underlyings(131,1) <= 8288.0) || - (underlyings(132,0) <= 2630.6349999999998) || - (underlyings(132,2) <= 840.0) || - (underlyings(132,1) <= 8288.0) || - (underlyings(133,0) <= 2630.6349999999998) || - (underlyings(133,2) <= 840.0) || - (underlyings(133,1) <= 8288.0) || - (underlyings(134,0) <= 2630.6349999999998) || - (underlyings(134,2) <= 840.0) || - (underlyings(134,1) <= 8288.0) || - (underlyings(135,0) <= 2630.6349999999998) || - (underlyings(135,2) <= 840.0) || - (underlyings(135,1) <= 8288.0) || - (underlyings(136,0) <= 2630.6349999999998) || - (underlyings(136,2) <= 840.0) || - (underlyings(136,1) <= 8288.0) || - (underlyings(137,0) <= 2630.6349999999998) || - (underlyings(137,2) <= 840.0) || - (underlyings(137,1) <= 8288.0) || - (underlyings(138,0) <= 2630.6349999999998) || - (underlyings(138,2) <= 840.0) || - (underlyings(138,1) <= 8288.0) || - (underlyings(139,0) <= 2630.6349999999998) || - (underlyings(139,2) <= 840.0) || - (underlyings(139,1) <= 8288.0) || - (underlyings(140,0) <= 2630.6349999999998) || - (underlyings(140,2) <= 840.0) || - (underlyings(140,1) <= 8288.0) || - (underlyings(141,0) <= 2630.6349999999998) || - (underlyings(141,2) <= 840.0) || - (underlyings(141,1) <= 8288.0) || - (underlyings(142,0) <= 2630.6349999999998) || - (underlyings(142,2) <= 840.0) || - (underlyings(142,1) <= 8288.0) || - (underlyings(143,0) <= 2630.6349999999998) || - (underlyings(143,2) <= 840.0) || - (underlyings(143,1) <= 8288.0) || - (underlyings(144,0) <= 2630.6349999999998) || - (underlyings(144,2) <= 840.0) || - (underlyings(144,1) <= 8288.0) || - (underlyings(145,0) <= 2630.6349999999998) || - (underlyings(145,2) <= 840.0) || - (underlyings(145,1) <= 8288.0) || - (underlyings(146,0) <= 2630.6349999999998) || - (underlyings(146,2) <= 840.0) || - (underlyings(146,1) <= 8288.0) || - (underlyings(147,0) <= 2630.6349999999998) || - (underlyings(147,2) <= 840.0) || - (underlyings(147,1) <= 8288.0) || - (underlyings(148,0) <= 2630.6349999999998) || - (underlyings(148,2) <= 840.0) || - (underlyings(148,1) <= 8288.0) || - (underlyings(149,0) <= 2630.6349999999998) || - (underlyings(149,2) <= 840.0) || - (underlyings(149,1) <= 8288.0) || - (underlyings(150,0) <= 2630.6349999999998) || - (underlyings(150,2) <= 840.0) || - (underlyings(150,1) <= 8288.0) || - (underlyings(151,0) <= 2630.6349999999998) || - (underlyings(151,2) <= 840.0) || - (underlyings(151,1) <= 8288.0) || - (underlyings(152,0) <= 2630.6349999999998) || - (underlyings(152,2) <= 840.0) || - (underlyings(152,1) <= 8288.0) || - (underlyings(153,0) <= 2630.6349999999998) || - (underlyings(153,2) <= 840.0) || - (underlyings(153,1) <= 8288.0) || - (underlyings(154,0) <= 2630.6349999999998) || - (underlyings(154,2) <= 840.0) || - (underlyings(154,1) <= 8288.0) || - (underlyings(155,0) <= 2630.6349999999998) || - (underlyings(155,2) <= 840.0) || - (underlyings(155,1) <= 8288.0) || - (underlyings(156,0) <= 2630.6349999999998) || - (underlyings(156,2) <= 840.0) || - (underlyings(156,1) <= 8288.0) || - (underlyings(157,0) <= 2630.6349999999998) || - (underlyings(157,2) <= 840.0) || - (underlyings(157,1) <= 8288.0) || - (underlyings(158,0) <= 2630.6349999999998) || - (underlyings(158,2) <= 840.0) || - (underlyings(158,1) <= 8288.0) || - (underlyings(159,0) <= 2630.6349999999998) || - (underlyings(159,2) <= 840.0) || - (underlyings(159,1) <= 8288.0) || - (underlyings(160,0) <= 2630.6349999999998) || - (underlyings(160,2) <= 840.0) || - (underlyings(160,1) <= 8288.0) || - (underlyings(161,0) <= 2630.6349999999998) || - (underlyings(161,2) <= 840.0) || - (underlyings(161,1) <= 8288.0) || - (underlyings(162,0) <= 2630.6349999999998) || - (underlyings(162,2) <= 840.0) || - (underlyings(162,1) <= 8288.0) || - (underlyings(163,0) <= 2630.6349999999998) || - (underlyings(163,2) <= 840.0) || - (underlyings(163,1) <= 8288.0) || - (underlyings(164,0) <= 2630.6349999999998) || - (underlyings(164,2) <= 840.0) || - (underlyings(164,1) <= 8288.0) || - (underlyings(165,0) <= 2630.6349999999998) || - (underlyings(165,2) <= 840.0) || - (underlyings(165,1) <= 8288.0) || - (underlyings(166,0) <= 2630.6349999999998) || - (underlyings(166,2) <= 840.0) || - (underlyings(166,1) <= 8288.0) || - (underlyings(167,0) <= 2630.6349999999998) || - (underlyings(167,2) <= 840.0) || - (underlyings(167,1) <= 8288.0) || - (underlyings(168,0) <= 2630.6349999999998) || - (underlyings(168,2) <= 840.0) || - (underlyings(168,1) <= 8288.0) || - (underlyings(169,0) <= 2630.6349999999998) || - (underlyings(169,2) <= 840.0) || - (underlyings(169,1) <= 8288.0) || - (underlyings(170,0) <= 2630.6349999999998) || - (underlyings(170,2) <= 840.0) || - (underlyings(170,1) <= 8288.0) || - (underlyings(171,0) <= 2630.6349999999998) || - (underlyings(171,2) <= 840.0) || - (underlyings(171,1) <= 8288.0) || - (underlyings(172,0) <= 2630.6349999999998) || - (underlyings(172,2) <= 840.0) || - (underlyings(172,1) <= 8288.0) || - (underlyings(173,0) <= 2630.6349999999998) || - (underlyings(173,2) <= 840.0) || - (underlyings(173,1) <= 8288.0) || - (underlyings(174,0) <= 2630.6349999999998) || - (underlyings(174,2) <= 840.0) || - (underlyings(174,1) <= 8288.0) || - (underlyings(175,0) <= 2630.6349999999998) || - (underlyings(175,2) <= 840.0) || - (underlyings(175,1) <= 8288.0) || - (underlyings(176,0) <= 2630.6349999999998) || - (underlyings(176,2) <= 840.0) || - (underlyings(176,1) <= 8288.0) || - (underlyings(177,0) <= 2630.6349999999998) || - (underlyings(177,2) <= 840.0) || - (underlyings(177,1) <= 8288.0) || - (underlyings(178,0) <= 2630.6349999999998) || - (underlyings(178,2) <= 840.0) || - (underlyings(178,1) <= 8288.0) || - (underlyings(179,0) <= 2630.6349999999998) || - (underlyings(179,2) <= 840.0) || - (underlyings(179,1) <= 8288.0) || - (underlyings(180,0) <= 2630.6349999999998) || - (underlyings(180,2) <= 840.0) || - (underlyings(180,1) <= 8288.0) || - (underlyings(181,0) <= 2630.6349999999998) || - (underlyings(181,2) <= 840.0) || - (underlyings(181,1) <= 8288.0) || - (underlyings(182,0) <= 2630.6349999999998) || - (underlyings(182,2) <= 840.0) || - (underlyings(182,1) <= 8288.0) || - (underlyings(183,0) <= 2630.6349999999998) || - (underlyings(183,2) <= 840.0) || - (underlyings(183,1) <= 8288.0) || - (underlyings(184,0) <= 2630.6349999999998) || - (underlyings(184,2) <= 840.0) || - (underlyings(184,1) <= 8288.0) || - (underlyings(185,0) <= 2630.6349999999998) || - (underlyings(185,2) <= 840.0) || - (underlyings(185,1) <= 8288.0) || - (underlyings(186,0) <= 2630.6349999999998) || - (underlyings(186,2) <= 840.0) || - (underlyings(186,1) <= 8288.0) || - (underlyings(187,0) <= 2630.6349999999998) || - (underlyings(187,2) <= 840.0) || - (underlyings(187,1) <= 8288.0) || - (underlyings(188,0) <= 2630.6349999999998) || - (underlyings(188,2) <= 840.0) || - (underlyings(188,1) <= 8288.0) || - (underlyings(189,0) <= 2630.6349999999998) || - (underlyings(189,2) <= 840.0) || - (underlyings(189,1) <= 8288.0) || - (underlyings(190,0) <= 2630.6349999999998) || - (underlyings(190,2) <= 840.0) || - (underlyings(190,1) <= 8288.0) || - (underlyings(191,0) <= 2630.6349999999998) || - (underlyings(191,2) <= 840.0) || - (underlyings(191,1) <= 8288.0) || - (underlyings(192,0) <= 2630.6349999999998) || - (underlyings(192,2) <= 840.0) || - (underlyings(192,1) <= 8288.0) || - (underlyings(193,0) <= 2630.6349999999998) || - (underlyings(193,2) <= 840.0) || - (underlyings(193,1) <= 8288.0) || - (underlyings(194,0) <= 2630.6349999999998) || - (underlyings(194,2) <= 840.0) || - (underlyings(194,1) <= 8288.0) || - (underlyings(195,0) <= 2630.6349999999998) || - (underlyings(195,2) <= 840.0) || - (underlyings(195,1) <= 8288.0) || - (underlyings(196,0) <= 2630.6349999999998) || - (underlyings(196,2) <= 840.0) || - (underlyings(196,1) <= 8288.0) || - (underlyings(197,0) <= 2630.6349999999998) || - (underlyings(197,2) <= 840.0) || - (underlyings(197,1) <= 8288.0) || - (underlyings(198,0) <= 2630.6349999999998) || - (underlyings(198,2) <= 840.0) || - (underlyings(198,1) <= 8288.0) || - (underlyings(199,0) <= 2630.6349999999998) || - (underlyings(199,2) <= 840.0) || - (underlyings(199,1) <= 8288.0) || - (underlyings(200,0) <= 2630.6349999999998) || - (underlyings(200,2) <= 840.0) || - (underlyings(200,1) <= 8288.0) || - (underlyings(201,0) <= 2630.6349999999998) || - (underlyings(201,2) <= 840.0) || - (underlyings(201,1) <= 8288.0) || - (underlyings(202,0) <= 2630.6349999999998) || - (underlyings(202,2) <= 840.0) || - (underlyings(202,1) <= 8288.0) || - (underlyings(203,0) <= 2630.6349999999998) || - (underlyings(203,2) <= 840.0) || - (underlyings(203,1) <= 8288.0) || - (underlyings(204,0) <= 2630.6349999999998) || - (underlyings(204,2) <= 840.0) || - (underlyings(204,1) <= 8288.0) || - (underlyings(205,0) <= 2630.6349999999998) || - (underlyings(205,2) <= 840.0) || - (underlyings(205,1) <= 8288.0) || - (underlyings(206,0) <= 2630.6349999999998) || - (underlyings(206,2) <= 840.0) || - (underlyings(206,1) <= 8288.0) || - (underlyings(207,0) <= 2630.6349999999998) || - (underlyings(207,2) <= 840.0) || - (underlyings(207,1) <= 8288.0) || - (underlyings(208,0) <= 2630.6349999999998) || - (underlyings(208,2) <= 840.0) || - (underlyings(208,1) <= 8288.0) || - (underlyings(209,0) <= 2630.6349999999998) || - (underlyings(209,2) <= 840.0) || - (underlyings(209,1) <= 8288.0) || - (underlyings(210,0) <= 2630.6349999999998) || - (underlyings(210,2) <= 840.0) || - (underlyings(210,1) <= 8288.0) || - (underlyings(211,0) <= 2630.6349999999998) || - (underlyings(211,2) <= 840.0) || - (underlyings(211,1) <= 8288.0) || - (underlyings(212,0) <= 2630.6349999999998) || - (underlyings(212,2) <= 840.0) || - (underlyings(212,1) <= 8288.0) || - (underlyings(213,0) <= 2630.6349999999998) || - (underlyings(213,2) <= 840.0) || - (underlyings(213,1) <= 8288.0) || - (underlyings(214,0) <= 2630.6349999999998) || - (underlyings(214,2) <= 840.0) || - (underlyings(214,1) <= 8288.0) || - (underlyings(215,0) <= 2630.6349999999998) || - (underlyings(215,2) <= 840.0) || - (underlyings(215,1) <= 8288.0) || - (underlyings(216,0) <= 2630.6349999999998) || - (underlyings(216,2) <= 840.0) || - (underlyings(216,1) <= 8288.0) || - (underlyings(217,0) <= 2630.6349999999998) || - (underlyings(217,2) <= 840.0) || - (underlyings(217,1) <= 8288.0) || - (underlyings(218,0) <= 2630.6349999999998) || - (underlyings(218,2) <= 840.0) || - (underlyings(218,1) <= 8288.0) || - (underlyings(219,0) <= 2630.6349999999998) || - (underlyings(219,2) <= 840.0) || - (underlyings(219,1) <= 8288.0) || - (underlyings(220,0) <= 2630.6349999999998) || - (underlyings(220,2) <= 840.0) || - (underlyings(220,1) <= 8288.0) || - (underlyings(221,0) <= 2630.6349999999998) || - (underlyings(221,2) <= 840.0) || - (underlyings(221,1) <= 8288.0) || - (underlyings(222,0) <= 2630.6349999999998) || - (underlyings(222,2) <= 840.0) || - (underlyings(222,1) <= 8288.0) || - (underlyings(223,0) <= 2630.6349999999998) || - (underlyings(223,2) <= 840.0) || - (underlyings(223,1) <= 8288.0) || - (underlyings(224,0) <= 2630.6349999999998) || - (underlyings(224,2) <= 840.0) || - (underlyings(224,1) <= 8288.0) || - (underlyings(225,0) <= 2630.6349999999998) || - (underlyings(225,2) <= 840.0) || - (underlyings(225,1) <= 8288.0) || - (underlyings(226,0) <= 2630.6349999999998) || - (underlyings(226,2) <= 840.0) || - (underlyings(226,1) <= 8288.0) || - (underlyings(227,0) <= 2630.6349999999998) || - (underlyings(227,2) <= 840.0) || - (underlyings(227,1) <= 8288.0) || - (underlyings(228,0) <= 2630.6349999999998) || - (underlyings(228,2) <= 840.0) || - (underlyings(228,1) <= 8288.0) || - (underlyings(229,0) <= 2630.6349999999998) || - (underlyings(229,2) <= 840.0) || - (underlyings(229,1) <= 8288.0) || - (underlyings(230,0) <= 2630.6349999999998) || - (underlyings(230,2) <= 840.0) || - (underlyings(230,1) <= 8288.0) || - (underlyings(231,0) <= 2630.6349999999998) || - (underlyings(231,2) <= 840.0) || - (underlyings(231,1) <= 8288.0) || - (underlyings(232,0) <= 2630.6349999999998) || - (underlyings(232,2) <= 840.0) || - (underlyings(232,1) <= 8288.0) || - (underlyings(233,0) <= 2630.6349999999998) || - (underlyings(233,2) <= 840.0) || - (underlyings(233,1) <= 8288.0) || - (underlyings(234,0) <= 2630.6349999999998) || - (underlyings(234,2) <= 840.0) || - (underlyings(234,1) <= 8288.0) || - (underlyings(235,0) <= 2630.6349999999998) || - (underlyings(235,2) <= 840.0) || - (underlyings(235,1) <= 8288.0) || - (underlyings(236,0) <= 2630.6349999999998) || - (underlyings(236,2) <= 840.0) || - (underlyings(236,1) <= 8288.0) || - (underlyings(237,0) <= 2630.6349999999998) || - (underlyings(237,2) <= 840.0) || - (underlyings(237,1) <= 8288.0) || - (underlyings(238,0) <= 2630.6349999999998) || - (underlyings(238,2) <= 840.0) || - (underlyings(238,1) <= 8288.0) || - (underlyings(239,0) <= 2630.6349999999998) || - (underlyings(239,2) <= 840.0) || - (underlyings(239,1) <= 8288.0) || - (underlyings(240,0) <= 2630.6349999999998) || - (underlyings(240,2) <= 840.0) || - (underlyings(240,1) <= 8288.0) || - (underlyings(241,0) <= 2630.6349999999998) || - (underlyings(241,2) <= 840.0) || - (underlyings(241,1) <= 8288.0) || - (underlyings(242,0) <= 2630.6349999999998) || - (underlyings(242,2) <= 840.0) || - (underlyings(242,1) <= 8288.0) || - (underlyings(243,0) <= 2630.6349999999998) || - (underlyings(243,2) <= 840.0) || - (underlyings(243,1) <= 8288.0) || - (underlyings(244,0) <= 2630.6349999999998) || - (underlyings(244,2) <= 840.0) || - (underlyings(244,1) <= 8288.0) || - (underlyings(245,0) <= 2630.6349999999998) || - (underlyings(245,2) <= 840.0) || - (underlyings(245,1) <= 8288.0) || - (underlyings(246,0) <= 2630.6349999999998) || - (underlyings(246,2) <= 840.0) || - (underlyings(246,1) <= 8288.0) || - (underlyings(247,0) <= 2630.6349999999998) || - (underlyings(247,2) <= 840.0) || - (underlyings(247,1) <= 8288.0) || - (underlyings(248,0) <= 2630.6349999999998) || - (underlyings(248,2) <= 840.0) || - (underlyings(248,1) <= 8288.0) || - (underlyings(249,0) <= 2630.6349999999998) || - (underlyings(249,2) <= 840.0) || - (underlyings(249,1) <= 8288.0) || - (underlyings(250,0) <= 2630.6349999999998) || - (underlyings(250,2) <= 840.0) || - (underlyings(250,1) <= 8288.0) || - (underlyings(251,0) <= 2630.6349999999998) || - (underlyings(251,2) <= 840.0) || - (underlyings(251,1) <= 8288.0) || - (underlyings(252,0) <= 2630.6349999999998) || - (underlyings(252,2) <= 840.0) || - (underlyings(252,1) <= 8288.0) || - (underlyings(253,0) <= 2630.6349999999998) || - (underlyings(253,2) <= 840.0) || - (underlyings(253,1) <= 8288.0) || - (underlyings(254,0) <= 2630.6349999999998) || - (underlyings(254,2) <= 840.0) || - (underlyings(254,1) <= 8288.0) || - (underlyings(255,0) <= 2630.6349999999998) || - (underlyings(255,2) <= 840.0) || - (underlyings(255,1) <= 8288.0) || - (underlyings(256,0) <= 2630.6349999999998) || - (underlyings(256,2) <= 840.0) || - (underlyings(256,1) <= 8288.0) || - (underlyings(257,0) <= 2630.6349999999998) || - (underlyings(257,2) <= 840.0) || - (underlyings(257,1) <= 8288.0) || - (underlyings(258,0) <= 2630.6349999999998) || - (underlyings(258,2) <= 840.0) || - (underlyings(258,1) <= 8288.0) || - (underlyings(259,0) <= 2630.6349999999998) || - (underlyings(259,2) <= 840.0) || - (underlyings(259,1) <= 8288.0) || - (underlyings(260,0) <= 2630.6349999999998) || - (underlyings(260,2) <= 840.0) || - (underlyings(260,1) <= 8288.0) || - (underlyings(261,0) <= 2630.6349999999998) || - (underlyings(261,2) <= 840.0) || - (underlyings(261,1) <= 8288.0) || - (underlyings(262,0) <= 2630.6349999999998) || - (underlyings(262,2) <= 840.0) || - (underlyings(262,1) <= 8288.0) || - (underlyings(263,0) <= 2630.6349999999998) || - (underlyings(263,2) <= 840.0) || - (underlyings(263,1) <= 8288.0) || - (underlyings(264,0) <= 2630.6349999999998) || - (underlyings(264,2) <= 840.0) || - (underlyings(264,1) <= 8288.0) || - (underlyings(265,0) <= 2630.6349999999998) || - (underlyings(265,2) <= 840.0) || - (underlyings(265,1) <= 8288.0) || - (underlyings(266,0) <= 2630.6349999999998) || - (underlyings(266,2) <= 840.0) || - (underlyings(266,1) <= 8288.0) || - (underlyings(267,0) <= 2630.6349999999998) || - (underlyings(267,2) <= 840.0) || - (underlyings(267,1) <= 8288.0) || - (underlyings(268,0) <= 2630.6349999999998) || - (underlyings(268,2) <= 840.0) || - (underlyings(268,1) <= 8288.0) || - (underlyings(269,0) <= 2630.6349999999998) || - (underlyings(269,2) <= 840.0) || - (underlyings(269,1) <= 8288.0) || - (underlyings(270,0) <= 2630.6349999999998) || - (underlyings(270,2) <= 840.0) || - (underlyings(270,1) <= 8288.0) || - (underlyings(271,0) <= 2630.6349999999998) || - (underlyings(271,2) <= 840.0) || - (underlyings(271,1) <= 8288.0) || - (underlyings(272,0) <= 2630.6349999999998) || - (underlyings(272,2) <= 840.0) || - (underlyings(272,1) <= 8288.0) || - (underlyings(273,0) <= 2630.6349999999998) || - (underlyings(273,2) <= 840.0) || - (underlyings(273,1) <= 8288.0) || - (underlyings(274,0) <= 2630.6349999999998) || - (underlyings(274,2) <= 840.0) || - (underlyings(274,1) <= 8288.0) || - (underlyings(275,0) <= 2630.6349999999998) || - (underlyings(275,2) <= 840.0) || - (underlyings(275,1) <= 8288.0) || - (underlyings(276,0) <= 2630.6349999999998) || - (underlyings(276,2) <= 840.0) || - (underlyings(276,1) <= 8288.0) || - (underlyings(277,0) <= 2630.6349999999998) || - (underlyings(277,2) <= 840.0) || - (underlyings(277,1) <= 8288.0) || - (underlyings(278,0) <= 2630.6349999999998) || - (underlyings(278,2) <= 840.0) || - (underlyings(278,1) <= 8288.0) || - (underlyings(279,0) <= 2630.6349999999998) || - (underlyings(279,2) <= 840.0) || - (underlyings(279,1) <= 8288.0) || - (underlyings(280,0) <= 2630.6349999999998) || - (underlyings(280,2) <= 840.0) || - (underlyings(280,1) <= 8288.0) || - (underlyings(281,0) <= 2630.6349999999998) || - (underlyings(281,2) <= 840.0) || - (underlyings(281,1) <= 8288.0) || - (underlyings(282,0) <= 2630.6349999999998) || - (underlyings(282,2) <= 840.0) || - (underlyings(282,1) <= 8288.0) || - (underlyings(283,0) <= 2630.6349999999998) || - (underlyings(283,2) <= 840.0) || - (underlyings(283,1) <= 8288.0) || - (underlyings(284,0) <= 2630.6349999999998) || - (underlyings(284,2) <= 840.0) || - (underlyings(284,1) <= 8288.0) || - (underlyings(285,0) <= 2630.6349999999998) || - (underlyings(285,2) <= 840.0) || - (underlyings(285,1) <= 8288.0) || - (underlyings(286,0) <= 2630.6349999999998) || - (underlyings(286,2) <= 840.0) || - (underlyings(286,1) <= 8288.0) || - (underlyings(287,0) <= 2630.6349999999998) || - (underlyings(287,2) <= 840.0) || - (underlyings(287,1) <= 8288.0) || - (underlyings(288,0) <= 2630.6349999999998) || - (underlyings(288,2) <= 840.0) || - (underlyings(288,1) <= 8288.0) || - (underlyings(289,0) <= 2630.6349999999998) || - (underlyings(289,2) <= 840.0) || - (underlyings(289,1) <= 8288.0) || - (underlyings(290,0) <= 2630.6349999999998) || - (underlyings(290,2) <= 840.0) || - (underlyings(290,1) <= 8288.0) || - (underlyings(291,0) <= 2630.6349999999998) || - (underlyings(291,2) <= 840.0) || - (underlyings(291,1) <= 8288.0) || - (underlyings(292,0) <= 2630.6349999999998) || - (underlyings(292,2) <= 840.0) || - (underlyings(292,1) <= 8288.0) || - (underlyings(293,0) <= 2630.6349999999998) || - (underlyings(293,2) <= 840.0) || - (underlyings(293,1) <= 8288.0) || - (underlyings(294,0) <= 2630.6349999999998) || - (underlyings(294,2) <= 840.0) || - (underlyings(294,1) <= 8288.0) || - (underlyings(295,0) <= 2630.6349999999998) || - (underlyings(295,2) <= 840.0) || - (underlyings(295,1) <= 8288.0) || - (underlyings(296,0) <= 2630.6349999999998) || - (underlyings(296,2) <= 840.0) || - (underlyings(296,1) <= 8288.0) || - (underlyings(297,0) <= 2630.6349999999998) || - (underlyings(297,2) <= 840.0) || - (underlyings(297,1) <= 8288.0) || - (underlyings(298,0) <= 2630.6349999999998) || - (underlyings(298,2) <= 840.0) || - (underlyings(298,1) <= 8288.0) || - (underlyings(299,0) <= 2630.6349999999998) || - (underlyings(299,2) <= 840.0) || - (underlyings(299,1) <= 8288.0) || - (underlyings(300,0) <= 2630.6349999999998) || - (underlyings(300,2) <= 840.0) || - (underlyings(300,1) <= 8288.0) || - (underlyings(301,0) <= 2630.6349999999998) || - (underlyings(301,2) <= 840.0) || - (underlyings(301,1) <= 8288.0) || - (underlyings(302,0) <= 2630.6349999999998) || - (underlyings(302,2) <= 840.0) || - (underlyings(302,1) <= 8288.0) || - (underlyings(303,0) <= 2630.6349999999998) || - (underlyings(303,2) <= 840.0) || - (underlyings(303,1) <= 8288.0) || - (underlyings(304,0) <= 2630.6349999999998) || - (underlyings(304,2) <= 840.0) || - (underlyings(304,1) <= 8288.0) || - (underlyings(305,0) <= 2630.6349999999998) || - (underlyings(305,2) <= 840.0) || - (underlyings(305,1) <= 8288.0) || - (underlyings(306,0) <= 2630.6349999999998) || - (underlyings(306,2) <= 840.0) || - (underlyings(306,1) <= 8288.0) || - (underlyings(307,0) <= 2630.6349999999998) || - (underlyings(307,2) <= 840.0) || - (underlyings(307,1) <= 8288.0) || - (underlyings(308,0) <= 2630.6349999999998) || - (underlyings(308,2) <= 840.0) || - (underlyings(308,1) <= 8288.0) || - (underlyings(309,0) <= 2630.6349999999998) || - (underlyings(309,2) <= 840.0) || - (underlyings(309,1) <= 8288.0) || - (underlyings(310,0) <= 2630.6349999999998) || - (underlyings(310,2) <= 840.0) || - (underlyings(310,1) <= 8288.0) || - (underlyings(311,0) <= 2630.6349999999998) || - (underlyings(311,2) <= 840.0) || - (underlyings(311,1) <= 8288.0) || - (underlyings(312,0) <= 2630.6349999999998) || - (underlyings(312,2) <= 840.0) || - (underlyings(312,1) <= 8288.0) || - (underlyings(313,0) <= 2630.6349999999998) || - (underlyings(313,2) <= 840.0) || - (underlyings(313,1) <= 8288.0) || - (underlyings(314,0) <= 2630.6349999999998) || - (underlyings(314,2) <= 840.0) || - (underlyings(314,1) <= 8288.0) || - (underlyings(315,0) <= 2630.6349999999998) || - (underlyings(315,2) <= 840.0) || - (underlyings(315,1) <= 8288.0) || - (underlyings(316,0) <= 2630.6349999999998) || - (underlyings(316,2) <= 840.0) || - (underlyings(316,1) <= 8288.0) || - (underlyings(317,0) <= 2630.6349999999998) || - (underlyings(317,2) <= 840.0) || - (underlyings(317,1) <= 8288.0) || - (underlyings(318,0) <= 2630.6349999999998) || - (underlyings(318,2) <= 840.0) || - (underlyings(318,1) <= 8288.0) || - (underlyings(319,0) <= 2630.6349999999998) || - (underlyings(319,2) <= 840.0) || - (underlyings(319,1) <= 8288.0) || - (underlyings(320,0) <= 2630.6349999999998) || - (underlyings(320,2) <= 840.0) || - (underlyings(320,1) <= 8288.0) || - (underlyings(321,0) <= 2630.6349999999998) || - (underlyings(321,2) <= 840.0) || - (underlyings(321,1) <= 8288.0) || - (underlyings(322,0) <= 2630.6349999999998) || - (underlyings(322,2) <= 840.0) || - (underlyings(322,1) <= 8288.0) || - (underlyings(323,0) <= 2630.6349999999998) || - (underlyings(323,2) <= 840.0) || - (underlyings(323,1) <= 8288.0) || - (underlyings(324,0) <= 2630.6349999999998) || - (underlyings(324,2) <= 840.0) || - (underlyings(324,1) <= 8288.0) || - (underlyings(325,0) <= 2630.6349999999998) || - (underlyings(325,2) <= 840.0) || - (underlyings(325,1) <= 8288.0) || - (underlyings(326,0) <= 2630.6349999999998) || - (underlyings(326,2) <= 840.0) || - (underlyings(326,1) <= 8288.0) || - (underlyings(327,0) <= 2630.6349999999998) || - (underlyings(327,2) <= 840.0) || - (underlyings(327,1) <= 8288.0) || - (underlyings(328,0) <= 2630.6349999999998) || - (underlyings(328,2) <= 840.0) || - (underlyings(328,1) <= 8288.0) || - (underlyings(329,0) <= 2630.6349999999998) || - (underlyings(329,2) <= 840.0) || - (underlyings(329,1) <= 8288.0) || - (underlyings(330,0) <= 2630.6349999999998) || - (underlyings(330,2) <= 840.0) || - (underlyings(330,1) <= 8288.0) || - (underlyings(331,0) <= 2630.6349999999998) || - (underlyings(331,2) <= 840.0) || - (underlyings(331,1) <= 8288.0) || - (underlyings(332,0) <= 2630.6349999999998) || - (underlyings(332,2) <= 840.0) || - (underlyings(332,1) <= 8288.0) || - (underlyings(333,0) <= 2630.6349999999998) || - (underlyings(333,2) <= 840.0) || - (underlyings(333,1) <= 8288.0) || - (underlyings(334,0) <= 2630.6349999999998) || - (underlyings(334,2) <= 840.0) || - (underlyings(334,1) <= 8288.0) || - (underlyings(335,0) <= 2630.6349999999998) || - (underlyings(335,2) <= 840.0) || - (underlyings(335,1) <= 8288.0) || - (underlyings(336,0) <= 2630.6349999999998) || - (underlyings(336,2) <= 840.0) || - (underlyings(336,1) <= 8288.0) || - (underlyings(337,0) <= 2630.6349999999998) || - (underlyings(337,2) <= 840.0) || - (underlyings(337,1) <= 8288.0) || - (underlyings(338,0) <= 2630.6349999999998) || - (underlyings(338,2) <= 840.0) || - (underlyings(338,1) <= 8288.0) || - (underlyings(339,0) <= 2630.6349999999998) || - (underlyings(339,2) <= 840.0) || - (underlyings(339,1) <= 8288.0) || - (underlyings(340,0) <= 2630.6349999999998) || - (underlyings(340,2) <= 840.0) || - (underlyings(340,1) <= 8288.0) || - (underlyings(341,0) <= 2630.6349999999998) || - (underlyings(341,2) <= 840.0) || - (underlyings(341,1) <= 8288.0) || - (underlyings(342,0) <= 2630.6349999999998) || - (underlyings(342,2) <= 840.0) || - (underlyings(342,1) <= 8288.0) || - (underlyings(343,0) <= 2630.6349999999998) || - (underlyings(343,2) <= 840.0) || - (underlyings(343,1) <= 8288.0) || - (underlyings(344,0) <= 2630.6349999999998) || - (underlyings(344,2) <= 840.0) || - (underlyings(344,1) <= 8288.0) || - (underlyings(345,0) <= 2630.6349999999998) || - (underlyings(345,2) <= 840.0) || - (underlyings(345,1) <= 8288.0) || - (underlyings(346,0) <= 2630.6349999999998) || - (underlyings(346,2) <= 840.0) || - (underlyings(346,1) <= 8288.0) || - (underlyings(347,0) <= 2630.6349999999998) || - (underlyings(347,2) <= 840.0) || - (underlyings(347,1) <= 8288.0) || - (underlyings(348,0) <= 2630.6349999999998) || - (underlyings(348,2) <= 840.0) || - (underlyings(348,1) <= 8288.0) || - (underlyings(349,0) <= 2630.6349999999998) || - (underlyings(349,2) <= 840.0) || - (underlyings(349,1) <= 8288.0) || - (underlyings(350,0) <= 2630.6349999999998) || - (underlyings(350,2) <= 840.0) || - (underlyings(350,1) <= 8288.0) || - (underlyings(351,0) <= 2630.6349999999998) || - (underlyings(351,2) <= 840.0) || - (underlyings(351,1) <= 8288.0) || - (underlyings(352,0) <= 2630.6349999999998) || - (underlyings(352,2) <= 840.0) || - (underlyings(352,1) <= 8288.0) || - (underlyings(353,0) <= 2630.6349999999998) || - (underlyings(353,2) <= 840.0) || - (underlyings(353,1) <= 8288.0) || - (underlyings(354,0) <= 2630.6349999999998) || - (underlyings(354,2) <= 840.0) || - (underlyings(354,1) <= 8288.0) || - (underlyings(355,0) <= 2630.6349999999998) || - (underlyings(355,2) <= 840.0) || - (underlyings(355,1) <= 8288.0) || - (underlyings(356,0) <= 2630.6349999999998) || - (underlyings(356,2) <= 840.0) || - (underlyings(356,1) <= 8288.0) || - (underlyings(357,0) <= 2630.6349999999998) || - (underlyings(357,2) <= 840.0) || - (underlyings(357,1) <= 8288.0) || - (underlyings(358,0) <= 2630.6349999999998) || - (underlyings(358,2) <= 840.0) || - (underlyings(358,1) <= 8288.0) || - (underlyings(359,0) <= 2630.6349999999998) || - (underlyings(359,2) <= 840.0) || - (underlyings(359,1) <= 8288.0) || - (underlyings(360,0) <= 2630.6349999999998) || - (underlyings(360,2) <= 840.0) || - (underlyings(360,1) <= 8288.0) || - (underlyings(361,0) <= 2630.6349999999998) || - (underlyings(361,2) <= 840.0) || - (underlyings(361,1) <= 8288.0) || - (underlyings(362,0) <= 2630.6349999999998) || - (underlyings(362,2) <= 840.0) || - (underlyings(362,1) <= 8288.0) || - (underlyings(363,0) <= 2630.6349999999998) || - (underlyings(363,2) <= 840.0) || - (underlyings(363,1) <= 8288.0) || - (underlyings(364,0) <= 2630.6349999999998) || - (underlyings(364,2) <= 840.0) || - (underlyings(364,1) <= 8288.0) || - (underlyings(365,0) <= 2630.6349999999998) || - (underlyings(365,2) <= 840.0) || - (underlyings(365,1) <= 8288.0) || - (underlyings(366,0) <= 2630.6349999999998) || - (underlyings(366,2) <= 840.0) diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/instantiate b/benchmarks/OptionPricing/implementations/haskell_lh/instantiate deleted file mode 100755 index e17fc9a..0000000 --- a/benchmarks/OptionPricing/implementations/haskell_lh/instantiate +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -set -e # Die on error. - -impl_dir=$FINPAR_IMPLEMENTATION -input=$FINPAR_INPUT - -cp $impl_dir/*hs . -cp $impl_dir/run . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data - -ghc -Wall -O2 -msse2 -rtsopts GenPricing.hs -o GenPricing diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/run b/benchmarks/OptionPricing/implementations/haskell_lh/run deleted file mode 100755 index eb51132..0000000 --- a/benchmarks/OptionPricing/implementations/haskell_lh/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -./GenPricing +RTS -K128m -RTS < input.data From 896a231516210619c451807735cbe0b2269f8b08 Mon Sep 17 00:00:00 2001 From: Thor Date: Mon, 10 Aug 2015 18:55:49 +0200 Subject: [PATCH 036/122] finpar OptionPricing cpp_openmp now works with hipermark --- benchmarks/OptionPricing/implementations/cpp_openmp/run | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 benchmarks/OptionPricing/implementations/cpp_openmp/run diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/run b/benchmarks/OptionPricing/implementations/cpp_openmp/run new file mode 100755 index 0000000..22d7e81 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/run @@ -0,0 +1,3 @@ +#!/bin/sh +#export OMP_NUM_THREADS=$NCORES +cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./GenPricing \ No newline at end of file From ee34175aca1229d3d720536df73a168e48001b5a Mon Sep 17 00:00:00 2001 From: Thor Date: Tue, 11 Aug 2015 17:48:19 +0200 Subject: [PATCH 037/122] including script to run hipermark --- hipermark_op | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 hipermark_op diff --git a/hipermark_op b/hipermark_op new file mode 100755 index 0000000..036fb83 --- /dev/null +++ b/hipermark_op @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/OptionPricing/ +echo Running hipermark OptionPricing cpp_openmp small dataset, 20 times. +echo Storing all results in instantiations/ + +rm -rf instantiations/OptionPricing/ +../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_openmp small,medium \ No newline at end of file From 821e9838027325ce6c20d6bbb5338888aba86682 Mon Sep 17 00:00:00 2001 From: Thor Date: Thu, 13 Aug 2015 15:45:55 +0200 Subject: [PATCH 038/122] Finpar now only has two implementations of InterestCalib -- This is done for testing of hipermark. --- .../cpp_opencl_all/FindBestKer.h | 160 ------ .../cpp_opencl_all/GenAlgFlat.h | 349 ------------- .../cpp_opencl_all/GenAlgKers.h | 297 ----------- .../implementations/cpp_opencl_all/MainKer.h | 223 -------- .../implementations/cpp_opencl_all/Makefile | 45 -- .../cpp_opencl_all/SrcCL/BestIndValRedKer.cl | 109 ---- .../cpp_opencl_all/SrcCL/CalibKers.cl | 477 ------------------ .../cpp_opencl_all/SrcCL/Date.cl | 147 ------ .../cpp_opencl_all/SrcCL/ExactYhat.cl | 314 ------------ .../cpp_opencl_all/SrcCL/G2ppUtil.cl | 231 --------- .../cpp_opencl_all/SrcCL/GenAlg.cl | 313 ------------ .../cpp_opencl_all/SrcCL/Reductions.cl | 380 -------------- .../cpp_opencl_all/SwapCalib.cpp | 52 -- .../cpp_opencl_all/UtilGPGPU.h | 285 ----------- .../cpp_opencl_all/instantiate | 24 - .../cpp_openmp_outer/GenAlgFlat.h | 266 ---------- .../implementations/cpp_openmp_outer/Makefile | 40 -- .../cpp_openmp_outer/SwapCalib | Bin 80848 -> 0 bytes .../cpp_openmp_outer/SwapCalib.cpp | 73 --- .../cpp_openmp_outer/UtilCPU.h | 102 ---- .../cpp_openmp_outer/instantiate | 36 -- .../cpp_sequential/EvalGenomeOrig.h | 155 ------ .../implementations/cpp_sequential/G2PPorig.h | 176 ------- .../cpp_sequential/GenAlgFlat.h | 281 ----------- .../implementations/cpp_sequential/Genome.h | 238 --------- .../implementations/cpp_sequential/Makefile | 40 -- .../cpp_sequential/SwapCalib.cpp | 61 --- .../implementations/cpp_sequential/UtilCPU.h | 48 -- .../cpp_sequential/instantiate | 39 -- .../implementations/haskell_lh/Constants.hs | 103 ---- .../implementations/haskell_lh/Date.hs | 155 ------ .../implementations/haskell_lh/EvalGenome.hs | 214 -------- .../implementations/haskell_lh/Genome.hs | 128 ----- .../implementations/haskell_lh/MathMod.hs | 390 -------------- .../implementations/haskell_lh/SwapCalib.hs | 308 ----------- .../implementations/haskell_lh/instantiate | 13 - .../implementations/haskell_lh/run | 5 - 37 files changed, 6277 deletions(-) delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/FindBestKer.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgFlat.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgKers.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/MainKer.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/Makefile delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/BestIndValRedKer.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/CalibKers.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Date.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/ExactYhat.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/G2ppUtil.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/GenAlg.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Reductions.cl delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/SwapCalib.cpp delete mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl_all/UtilGPGPU.h delete mode 100755 benchmarks/InterestCalib/implementations/cpp_opencl_all/instantiate delete mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp_outer/GenAlgFlat.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp_outer/Makefile delete mode 100755 benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib delete mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib.cpp delete mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp_outer/UtilCPU.h delete mode 100755 benchmarks/InterestCalib/implementations/cpp_openmp_outer/instantiate delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/EvalGenomeOrig.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/Makefile delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp delete mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h delete mode 100755 benchmarks/InterestCalib/implementations/cpp_sequential/instantiate delete mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Constants.hs delete mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Date.hs delete mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs delete mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs delete mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs delete mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs delete mode 100755 benchmarks/InterestCalib/implementations/haskell_lh/instantiate delete mode 100755 benchmarks/InterestCalib/implementations/haskell_lh/run diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/FindBestKer.h b/benchmarks/InterestCalib/implementations/cpp_opencl_all/FindBestKer.h deleted file mode 100644 index 084157d..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/FindBestKer.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef FIND_BEST_KERNEL -#define FIND_BEST_KERNEL - -#include "SDK_stub.h" -#include "Constants.h" - -class FindBestKer { - // Assumptions: - // 1. the input array, `arr' has `size(arr) >= N', - // 2. the result arrays, has `size(r_ind)=size(r_val) >= LWG' - // - // Computation is split in two stages: - // - one that compute at most LWG elements (denoting partial reduces) - // - a second one that reduces the resulting LWG elements in one local workgroup. - private: - const size_t LWG; - size_t GWG; - uint UNROLL; - - // inputs, i.e., resources not owned by this kernel! - const cl_mem arr; // of size `N', and `offset' into it! - const uint N; - const uint offset; - - - OclObjects ocl; - - // res_ind and res_val have at least size LWG_FB - const cl_mem res_ind; - const cl_mem res_val; - - - // resources owned by this kernel - cl_kernel ker1; - cl_kernel ker2; - - public: - FindBestKer ( const uint sz, - const uint off, - const cl_mem& a, - const cl_mem& r_ind, - const cl_mem& r_val, - const OclObjects& o, - const int& lwg - ) : N(sz), offset(off), LWG(lwg), - arr(a), res_ind(r_ind), res_val(r_val), ocl(o) - { - UNROLL = mkUnrollFactor(); - GWG = mkGlobalWork (); - ker1 = mkKernel1 (); - ker2 = mkKernel2 (); - - bool sanity = is_pow2(lwg) && lwg <= LWG_FB; - assert( sanity && "In FindBestKer: Workgroup size not a pow of two or too large!" ); - } - - virtual ~FindBestKer() { - clReleaseKernel(ker1); - clReleaseKernel(ker2); - } - - void run ( int& best_ind, REAL& best_val ) { - cl_int ciErr1; - - //printf("Before run kernel 1 (LWG,GWG,UNROLL): (%ld,%ld,%d)\n", LWG, GWG, UNROLL); - - // run the reduction for each local group - ciErr1 = clEnqueueNDRangeKernel ( - ocl.getCommandQueue(), - ker1, 1, NULL, & GWG, & LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - - if( GWG > LWG ) { - // run the reduction for the resulted local group - ciErr1 = clEnqueueNDRangeKernel ( - ocl.getCommandQueue(), - ker2, 1, NULL, & LWG, & LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - } - - { // Finally, read-back the histogram result! - ciErr1 |= clEnqueueReadBuffer ( - ocl.getCommandQueue(), res_val, CL_TRUE, 0, - sizeof(REAL), &best_val, 0, NULL, NULL - ); - ciErr1 |= clEnqueueReadBuffer ( - ocl.getCommandQueue(), res_ind, CL_TRUE, 0, - sizeof(uint), &best_ind, 0, NULL, NULL - ); - } - oclCheckError(ciErr1, CL_SUCCESS); -// printf("After enqueue Best (Ind,Val): (%d,%f)\n\n", best_ind, best_val); - } - - private: - int mkUnrollFactor() { - const int sqLWG = LWG * LWG; - const bool exact1 = (N % sqLWG) == 0; - const int unroll = ( exact1 ) ? ( N / sqLWG ) : ( (N / sqLWG) + 1 ); - return unroll; - } - - int mkGlobalWork() { - const int urolLWG= UNROLL * LWG; - const bool exact2 = (N % urolLWG) == 0; - const int numGWG = ( exact2 ) ? (N / urolLWG) : ( (N / urolLWG) + 1 ); - return numGWG * LWG; - } - - cl_kernel mkKernel1( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl.program, "redbest_ker1", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->arr ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_ind ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_val ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &this->offset ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &this->N ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &this->UNROLL ); - - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkKernel2( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl.program, "redbest_ker2", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - uint newN = GWG / LWG; - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_ind ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_val ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &newN ); - - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - -}; - -#endif // FIND_BEST_KERNEL - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgFlat.h deleted file mode 100644 index 79b0b35..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgFlat.h +++ /dev/null @@ -1,349 +0,0 @@ -#ifndef GEN_ALG_FLAT -#define GEN_ALG_FLAT - -#include "Constants.h" -#include "GenAlgUtil.h" -#include "Candidate.h" - -#include "IrregShape.h" -#include "UtilGPGPU.h" -#include "EvalGenomeInl.h" - -#include "FindBestKer.h" -#include "MainKer.h" -#include "GenAlgKers.h" - -/** - * Printing Swaption / Calibrated Price / Black Price / RMS - * The result is an array REAL[NUM_SWAP_QUOTES, 3] recording - * for each swaption the calibrated price, the black price - * and the percentagewise difference between the two. - */ -REAL* makeSummary(uint winner, CpuArrays& arrs) { - REAL* res = (REAL*) malloc( 3*NUM_SWAP_QUOTES*sizeof(REAL) ); - - REAL rms = 0.0; - - fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); - fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", - arrs.get_a() [winner], arrs.get_b() [winner], arrs.get_sigma ()[winner], - arrs.get_nu()[winner], arrs.get_rho()[winner], arrs.get_logLik()[winner] ); - fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); - - for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { - REAL black_price = arrs.get_quote(winner)[i]; - REAL calib_price = arrs.get_price(winner)[i]; - REAL err_ratio = (calib_price - black_price) / black_price; - - res[3*i + 0] = 10000.0*calib_price; - res[3*i + 1] = 10000.0*black_price; - res[3*i + 2] = 100.0*fabs(err_ratio); - - rms += err_ratio * err_ratio; - - fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", - i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], - res[3*i + 0], res[3*i + 1], res[3*i + 2] ); - } - - rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); - fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); - - return res; -} - - -/** - * Utility function: find the genome with the best likelihood: - * scans the logLik array and fill in the index and likelihood - * of the best genome. - */ -void find_best(const REAL* logLik, int& best_ind, REAL& best_lik) { - bool sanity = true; - - best_lik = -INFINITY; - best_ind = 0; - - // this is in fact a reduction, but POP_SIZE is - // not big enough to warrant a parallel execution. - for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX - REAL val = logLik[i]; - - sanity = !( isnan(val) || isinf(val) ); - assert( sanity && "val is NaN in find_best" ); - - if( val > best_lik ) { best_ind = i; best_lik = val; } - } -} - -void find_best_GPU( - FindBestKer& bestker, OclObjects& ocl_objs, - OclBuffers& ocl_arrs, const REAL* logLik, - int& best_ind, REAL& best_lik -) { - bool sanity = true; - - bestker.run(best_ind, best_lik); - - sanity = ! ( isnan(best_lik) || isinf(best_lik) ); - assert( sanity && "val is NaN in find_best" ); -} - -Move_Type selectMoveType(REAL move_selected) { - Move_Type move_type = NONE; - - REAL prob; - Move_Type type; - UINT k = 0; - do { - prob = mcmc_moves_selection_cumdensfct[k].fst; - type = mcmc_moves_selection_cumdensfct[k].snd; - - if( move_selected <= prob ) { - move_type = type; - } - k ++; - } while ( move_selected > prob && k < CUMDENSFCT_CARD ); - - assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); - - return move_type; -} - -/** - * Main Entry Point for Swaption Calibration - * The (out) arguments are in fact the resulted - * winning genome result & its likelihood. - * The array result has size 3*NUM_SWAP_QUOTES - * and records for each swaption the calibrated - * price, the black price and the percentage - * difference between the two. - */ -REAL* mainKernelGPU(REAL& wg_a, - REAL& wg_b, - REAL& wg_sigma, - REAL& wg_nu, - REAL& wg_rho, - REAL& wg_logLik -) { - uint FLAT_SZ; - short* shape = getIregShapeAdjusted( LWG_EG, FLAT_SZ ); - int * start_inds = getStartInd( FLAT_SZ, shape, NUM_SWAP_QUOTES ); - - CpuArrays cpu_arrs(FLAT_SZ, shape); - REAL *g_a, *g_b, *g_rho, *g_nu, *g_sigma, *logLik, *bf_rat; - { // getting the cpu arrays - g_a = cpu_arrs.get_a (); - g_b = cpu_arrs.get_b (); - g_rho = cpu_arrs.get_rho (); - g_nu = cpu_arrs.get_nu (); - g_sigma = cpu_arrs.get_sigma (); - logLik = cpu_arrs.get_logLik(); - bf_rat = cpu_arrs.get_bf_rat(); - } - - OclObjects ocl_objs; OclBuffers ocl_arrs; - { // Initialization of the GPU resources: - initGPUresources ( cpu_arrs, ocl_objs, ocl_arrs ); - } - - FindBestKer bestker ( POP_SIZE, 10*POP_SIZE, ocl_arrs.genomes, - ocl_arrs.best_ind, ocl_arrs.best_val, ocl_objs, 128 ); - MainKer mainker ( cpu_arrs, ocl_arrs, ocl_objs ); - GenAlgKers genalgker( cpu_arrs, ocl_arrs, ocl_objs ); - - srand ( SEED ); - srand48 ( SEED ); - - // initialized the genomes with random numbers inside - // their acceptable bounds => requires 5*POP_SIZE randoms -#if (GPU_VERSION == 2) - genalgker.run_init( ); -#else - - for( int i = 0; i < POP_SIZE; i++ ) { - REAL r01, tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; - g_a [i ] = tmp; - g_a [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; - g_b [i ] = tmp; - g_b [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; - g_rho [i ] = tmp; - g_rho [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; - g_nu [i ] = tmp; - g_nu [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; - g_sigma [i ] = tmp; - g_sigma [i + POP_SIZE] = tmp; - - bf_rat [i ] = 1.0; - } -#endif - - // Initial evaluation of the genomes! -#if (GPU_VERSION == 2) - mainker.run (); - genalgker.run_cpLik(); - -#elif (GPU_VERSION == 1) - mainker.run(); - for( int i = 0; i < POP_SIZE; i++ ) { - logLik[i] = logLik[i+POP_SIZE]; - } -#else - fprintf(stderr, "This is GPU only, GPU_VERSION should be set to 1 or 2 in KerConsts.h!"); - exit(1); -#endif - - // sequential loop that runs the genetic algorithms - // (takes a population and returns a population) - for( int j = 0; j < MCMC_LOOPS; j++ ) { - - // select which move to perform: BEGIN - // Note: this block can also be a loop (in fixed order) - // over the various move types - REAL move_selected = getRandUnifNorm(); - Move_Type move_type = selectMoveType(move_selected); - -#if ( GPU_VERSION == 2 && WITH_SOBOL == 0 ) - sobol_offset ++; -#endif - - if ( move_type == DIMS_ALL ) { -#if (GPU_VERSION == 2) - genalgker.run_mutate( 33 ); -#else - for( int i = 0; i < POP_SIZE; i++ ) { - mutate_dims_all( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); // default ampl_ratio - } -#endif - - } else if ( move_type == DIMS_ONE ) { - - UINT dim_j = getRandIntNorm(GENOME_DIM); - -#if (GPU_VERSION == 2) - #if (WITH_SOBOL == 0) - sobol_offset++; - #endif - genalgker.run_mutate( dim_j ); -#else - for( int i = 0; i < POP_SIZE; i++ ) { - mutate_dims_one( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i, dim_j ); // default ampl_ratio - } -#endif - } else /* if ( move_type == DEMCMC ) */ { -#if (GPU_VERSION == 2) - genalgker.run_McMcDc( ); -#else - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums - mcmc_DE( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); - } -#endif - } - - // evaluate the proposal -#if (GPU_VERSION == 2 || GPU_VERSION == 1) - mainker.run(); -#else - fprintf(stderr, "This is GPU only, GPU_VERSION should be set to 1 or 2 in KerConsts.h!"); - exit(1); -#endif - - // mcmc_acceptance_rejection(); - // Deciding whether to accept or reject the proposal, - // obtained by mutating/crossover of the individual. -#if (GPU_VERSION == 2) - genalgker.run_accept_cond( ); - genalgker.run_accept_prop( ); -#else - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel - // Metropolis: get a random U[0,1) for each candidate - // rand=N.random.uniform() - REAL rand = getRandUnifNorm(); - - // selection: dimensions considered independent - // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) - REAL acceptance = std::min( 1.0, exp( logLik[i+POP_SIZE] - logLik[i] ) * bf_rat[i] ); - - // if acceptance criterion is met then p->p' else does nothing - if ( rand < acceptance ) accept( i, g_a, g_b, g_rho, g_nu, g_sigma, logLik ); - } -#endif - - // print best candidate for the current iteration: -#if (GPU_VERSION == 2) - if ( (j % 16) == 0 ) { - int best_ind; REAL best_lik; - find_best_GPU( bestker, ocl_objs, ocl_arrs, logLik, best_ind, best_lik ); - fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", - j, best_lik, best_ind ); - } -#else - if ( (j % 16) == 0 ){ - int best_ind; REAL best_lik; - find_best(logLik, best_ind, best_lik); - fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", - j, best_lik, best_ind ); - } -#endif - } - -#if (GPU_VERSION == 2) - { // copy back genomes - uint cur_size = 12 * POP_SIZE * sizeof(REAL); - uint ciErr; - cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); - ciErr = clEnqueueReadBuffer(cmd_queue, ocl_arrs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); - oclCheckError( ciErr, CL_SUCCESS ); - } -#endif - - REAL* result; - { // print best candidate for the current iteration: - int best_ind; REAL best_lik; - find_best(logLik, best_ind, best_lik); - - // recompute the calibrated price and the black price sequentially! - logLik[best_ind] = - eval_genome( g_a[best_ind], g_b[best_ind], g_rho[best_ind], g_nu[best_ind], - g_sigma[best_ind], cpu_arrs.get_quote(best_ind), - cpu_arrs.get_price(best_ind), FLAT_SZ, shape, start_inds ); - - // Finally, make/print the result! - wg_a = cpu_arrs.get_a() [best_ind]; - wg_b = cpu_arrs.get_b() [best_ind]; - wg_sigma = cpu_arrs.get_sigma ()[best_ind]; - wg_nu = cpu_arrs.get_nu() [best_ind]; - wg_rho = cpu_arrs.get_rho() [best_ind]; - wg_logLik = cpu_arrs.get_logLik()[best_ind]; - - result = makeSummary( best_ind, cpu_arrs ); - } - - delete[] start_inds; - - // Releasing the GPU resources: - releaseGPUresources ( ocl_objs, ocl_arrs ); - - // Releasing the CPU resources: - cpu_arrs.releaseResources(); - - return result; -} - -#endif // end ifndef - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgKers.h b/benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgKers.h deleted file mode 100644 index 545297e..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/GenAlgKers.h +++ /dev/null @@ -1,297 +0,0 @@ -#ifndef GEN_ALG_KERNELS -#define GEN_ALG_KERNELS - -#include "SDK_stub.h" -#include "Constants.h" - -class GenAlgKers { - private: - size_t LWG[3]; - size_t GWG[3]; - - const uint lwg; -// uint sobol_offset; - - CpuArrays cpu_arrs; - OclBuffers gpu_buffs; - OclObjects ocl_objs; - - // resources owned by this kernel - cl_kernel init_ker; - cl_kernel cplik_ker; - cl_kernel accnd_ker; - cl_kernel acprp_ker; - cl_kernel mutat_ker; - cl_kernel mcde_ker; - - public: - GenAlgKers( const CpuArrays & arrs, - const OclBuffers& buffs, - const OclObjects& objs - ) : cpu_arrs(arrs), gpu_buffs(buffs), ocl_objs(objs), lwg( mkLWG(POP_SIZE) ) - { - //sobol_offset = 1; - - bool valid = (POP_SIZE >= 32) && (POP_SIZE <= 512); - assert( valid && "Population size NOT in range [32, 512]!" ); - init_ker = mkInitKernel (); - cplik_ker = mkCpLiKernel (); - accnd_ker = mkAcceptCondKernel (); - acprp_ker = mkAcceptPropKernel (); - mutat_ker = mkMutateDimKernel (); - mcde_ker = mkMcMcDcKernel (); - } - - virtual ~GenAlgKers() { - clReleaseKernel( init_ker); - clReleaseKernel(cplik_ker); - clReleaseKernel(accnd_ker); - clReleaseKernel(acprp_ker); - clReleaseKernel(mutat_ker); - clReleaseKernel( mcde_ker); - } - - void run_init( ) { - cl_int ciErr1; - - LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; - GWG[0] = lwg; GWG[1] = 6; GWG[2] = 1; - - // set the index of the next random number! - ciErr1 |= clSetKernelArg( init_ker, 3, sizeof(uint), &sobol_offset ); - oclCheckError(ciErr1, CL_SUCCESS); - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - init_ker, 2, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - oclCheckError(ciErr1, CL_SUCCESS); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - sobol_offset += (5 * POP_SIZE); - } - - void run_cpLik( ) { - cl_int ciErr1; - - LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; - GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - cplik_ker, 1, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - } - - void run_accept_cond( ) { - cl_int ciErr1; - - LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; - GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; - - // set the index of the next random number! - ciErr1 |= clSetKernelArg( accnd_ker, 3, sizeof(uint), &sobol_offset); - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - accnd_ker, 1, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - - sobol_offset += (1 * POP_SIZE); - } - - void run_accept_prop( ) { - cl_int ciErr1; - - LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; - GWG[0] = lwg; GWG[1] = 6; GWG[2] = 1; - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - acprp_ker, 2, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - } - - // IF dim_j > 4 then is a mutate_all! - void run_mutate( const uint dim_j ) { - cl_int ciErr1; - - LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; - GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; - - // set the index of the next random number! - ciErr1 |= clSetKernelArg( mutat_ker, 3, sizeof(uint), &sobol_offset); - ciErr1 |= clSetKernelArg( mutat_ker, 4, sizeof(uint), &dim_j); - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - mutat_ker, 1, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - - sobol_offset += (5 * POP_SIZE); - } - - void run_McMcDc( ) { - cl_int ciErr1; - - LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; - GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; - - // set the index of the next random number! - ciErr1 |= clSetKernelArg( mcde_ker, 3, sizeof(uint), &sobol_offset); - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - mcde_ker, 1, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - - sobol_offset += (8 * POP_SIZE); - } - - - private: - - uint mkLWG( const uint Npop ) { - if( (Npop % WARP) == 0 ) return Npop; - else return (Npop / WARP + 1) * WARP; - } - - cl_kernel mkInitKernel ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "init_genome", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gene_ranges ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkCpLiKernel ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "copyLogLik", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkAcceptCondKernel ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "accept_cond", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accept_cond ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkAcceptPropKernel ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "accept_prop", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accept_cond ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkMutateDimKernel ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - uint dim_j = 7; - - - kernel = clCreateKernel( ocl_objs.program, "mutate_dims", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gene_ranges ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &dim_j ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(REAL), &MOVES_UNIF_AMPL_RATIO ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkMcMcDcKernel ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM); - const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO; - - - kernel = clCreateKernel( ocl_objs.program, "mcmc_DE", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gene_ranges ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(REAL), &gamma_avg ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(REAL), &l_ratio ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } -}; - -#endif diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/MainKer.h b/benchmarks/InterestCalib/implementations/cpp_opencl_all/MainKer.h deleted file mode 100644 index c607f33..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/MainKer.h +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef MAIN_KERNEL -#define MAIN_KERNEL - -#include "SDK_stub.h" -#include "Constants.h" - -class MainKer { - private: - size_t LWG[3]; - size_t GWG[3]; - - CpuArrays cpu_arrs; - OclBuffers gpu_buffs; - OclObjects ocl_objs; - - - // resources owned by this kernel - cl_kernel ker; - cl_kernel ker_red1; - cl_kernel ker_red2; - - public: - MainKer ( const CpuArrays & arrs, - const OclBuffers& buffs, - const OclObjects& objs - ) : cpu_arrs(arrs), gpu_buffs(buffs), ocl_objs(objs) - { -// LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; -// GWG[0] = arrs.SS; GWG[1] = POP_SIZE; GWG[2] = 1; - - ker = mkKernel1 (); - ker_red1 = mkKernel2 (); - ker_red2 = mkKernel3 (); - } - - virtual ~MainKer() { - clReleaseKernel(ker); - clReleaseKernel(ker_red1); - clReleaseKernel(ker_red2); - } - - void run ( ) { - cl_int ciErr1; - - //printf("Before run kernel 1 (LWG,GWG,UNROLL): (%ld,%ld,%d)\n", LWG, GWG, UNROLL); -#if (GPU_VERSION == 1) - copy_in_buffers1(); -#endif - { // run the main, big kernel with local segmented reduction for each local group - LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; - GWG[0] = cpu_arrs.SS; GWG[1] = POP_SIZE; GWG[2] = 1; - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - ker, 3, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - } - - { // run the second segmented reduction kernel - LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; - GWG[0] = cpu_arrs.SS; GWG[1] = NUM_HERMITE; GWG[2] = POP_SIZE; - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - ker_red1, 3, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - } - - { // run the third regular reduction kernel - LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; - GWG[0] = LWG_EG; GWG[1] = POP_SIZE; GWG[2] = 1; - - ciErr1 = clEnqueueNDRangeKernel ( - ocl_objs.getCommandQueue(), - ker_red2, 3, NULL, this->GWG, this->LWG, - 0, NULL, NULL - ); - ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); - oclCheckError(ciErr1, CL_SUCCESS); - } - -#if (GPU_VERSION == 1) -// copy_out_buffers1(); -// copy_out_buffers2(); - copy_out_buffers3(); -#endif - } - - private: - cl_kernel mkKernel1 ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "eval_genome_main", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.shape ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.swap_quotes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.ci_t1cs_scale ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.new_quote_price); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.scalars ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_SWAP_QUOTES ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &cpu_arrs.SS ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkKernel2 ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "eval_genome_red1", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.shape ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gauss_coefs ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gauss_weights ); - - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.ci_t1cs_scale ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.scalars ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accum0 ); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_SWAP_QUOTES ); -// ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &cpu_arrs.SS ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - cl_kernel mkKernel3 ( ) { - cl_kernel kernel; - UINT counter = 0; - cl_int ciErr1; - - kernel = clCreateKernel( ocl_objs.program, "eval_genome_red2", &ciErr1 ); - oclCheckError( ciErr1, CL_SUCCESS ); - - counter = 0; - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.scalars ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accum0 ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.new_quote_price); - - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_SWAP_QUOTES ); - ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_HERMITE ); - oclCheckError( ciErr1, CL_SUCCESS ); - - return kernel; - } - - - void copy_in_buffers1() { - cl_int ciErr; - size_t cur_size; - cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); - - cur_size = 13 * POP_SIZE * sizeof(REAL); - ciErr |= clEnqueueWriteBuffer(cmd_queue, gpu_buffs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); - - oclCheckError(ciErr, CL_SUCCESS); - } - - void copy_out_buffers1() { - cl_int ciErr; - size_t cur_size; - cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); - - cur_size = 4 * cpu_arrs.SS * POP_SIZE * sizeof(REAL); - ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.ci_t1cs_scale, CL_TRUE, 0, cur_size, cpu_arrs.ci_t1cs_scale, 0, NULL, NULL); - - cur_size = NUM_SWAP_QUOTES * POP_SIZE * sizeof(REAL); // need only to write back the quotes (not the prices) - ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.new_quote_price, CL_TRUE, 0, cur_size, cpu_arrs.new_quote_price, 0, NULL, NULL); - - cur_size = 8 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(REAL); - ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.scalars, CL_TRUE, 0, cur_size, cpu_arrs.scalars, 0, NULL, NULL); - } - - void copy_out_buffers2() { - cl_int ciErr; - size_t cur_size; - cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); - - cur_size = NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE * sizeof(REAL); - ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.accum0, CL_TRUE, 0, cur_size, cpu_arrs.accum0, 0, NULL, NULL); - } - - void copy_out_buffers3() { - cl_int ciErr; - size_t cur_size, offset; - cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); - - cur_size = POP_SIZE * sizeof(REAL); - offset = 11 * POP_SIZE * sizeof(REAL); - ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.genomes, CL_TRUE, offset, cur_size, cpu_arrs.get_logLik() + POP_SIZE, 0, NULL, NULL); - -// cur_size = 13 * POP_SIZE * sizeof(REAL); -// ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); - -// cur_size = 2 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(REAL); // need only to write back the quotes (not the prices) -// ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.new_quote_price, CL_TRUE, 0, cur_size, cpu_arrs.new_quote_price, 0, NULL, NULL); - } -}; - -#endif // MAIN_KERNEL - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/Makefile b/benchmarks/InterestCalib/implementations/cpp_opencl_all/Makefile deleted file mode 100644 index 024a527..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -include ../../setup.mk - -ifndef ($(HAVE_GPU)) -include ../../platform.mk -endif - -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ - -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ - -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ - -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) - -SOURCES_CPP =SwapCalib.cpp -HELPERS =../includeC/ParseInput.h -OBJECTS =SwapCalib.o -EXECUTABLE =SwapCalib - - -default: gpu - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -# The GPU version is in: ../CppAndGPU. This folder is CPU only! -gpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) - -cpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) - - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx SrcCL/*.ptx ./Debug.txt - @# clean nVidia compiler cache - rm -rf $(HOME)/.nv/ComputeCache/* - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/BestIndValRedKer.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/BestIndValRedKer.cl deleted file mode 100644 index 5be7b32..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/BestIndValRedKer.cl +++ /dev/null @@ -1,109 +0,0 @@ -/******************************************************/ -/********* FIND_BEST KERNEL and HELPERS ***************/ -/******************************************************/ - -inline REAL2 OP_BEST(REAL2 iv1, REAL2 iv2) { - return ( ( iv1.y > iv2.y ) ? iv1 : iv2 ); -} - -inline REAL2 reduce_best_warp( __local volatile REAL2* sh_data ) { - const uint th_id = get_local_id(0) & (WARP-1); - - if( th_id >= 1 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-1 ] ); - if( th_id >= 2 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-2 ] ); - if( th_id >= 4 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-4 ] ); - if( th_id >= 8 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-8 ] ); -#if (WARP == 32) - if( th_id >= 16 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-16] ); -#endif - return sh_data[th_id]; -} - -inline void reduce_best_local ( __local volatile REAL2* sh_data ) { - // perform scan at warp level - REAL2 res = reduce_best_warp( sh_data + WARP_FST ); - barrier( CLK_LOCAL_MEM_FENCE ); - - // gather per-warp results in the first WARP elements - if ( TH_ID == WARP_LST ) { - sh_data[ WARP_ID ] = res; - } - barrier(CLK_LOCAL_MEM_FENCE); - - if( TH_ID < WARP ) { - reduce_best_warp( sh_data ); - } - barrier(CLK_LOCAL_MEM_FENCE); -} - - -__kernel void -redbest_ker1 ( - __global REAL *arr, - __global uint *res_ind, - __global REAL *res_val, - uint offset, - uint N, - uint U -) { - __local REAL2 locred[ LWG_FB ]; - - arr += offset; - - REAL2 seqbest = (REAL2) ( 0.0, -INFTY ); - - uint i = get_group_id(0) * (U * get_local_size(0)) + get_local_id(0); - - - //uint B = min( i + (U * get_local_size(0)), N ); - uint B = i + (U * get_local_size(0)); - if( B > N ) { B = N; } - - for( ; i < B; i += get_local_size(0) ) { - REAL2 cur = (REAL2) ( (REAL)i, arr[i] ); - seqbest = OP_BEST(seqbest, cur); - } - - locred[ get_local_id(0) ] = seqbest; - barrier(CLK_LOCAL_MEM_FENCE); - - reduce_best_local ( locred ); - - if ( get_local_id(0) == get_local_size(0) - 1 ) { - REAL2 res = locred[WARP-1]; - res_ind[ get_group_id(0) ] = (uint) res.x; - res_val[ get_group_id(0) ] = res.y; - } -} - -/** - * Assumes we have to reduce exactly one local workgroup. - */ -__kernel void -redbest_ker2 ( - __global uint *arr_ind, - __global REAL *arr_val, - uint N -) { - __local REAL2 locred[ LWG_FB ]; - - uint th_id = get_local_id(0); - - if ( th_id >= N ) { - REAL2 tmp = (REAL2) ( 0.0, -INFTY ); - locred[ th_id ] = tmp; - } else { - REAL2 tmp = (REAL2) ( (REAL)arr_ind[th_id], arr_val[th_id] ); - locred[ th_id ] = tmp; - } - - barrier(CLK_LOCAL_MEM_FENCE); - reduce_best_local( locred ); - - if ( th_id == get_local_size(0) - 1 ) { - REAL2 res = locred[ WARP-1 ]; - arr_ind[ 0 ] = (uint) res.x; - arr_val[ 0 ] = res.y; - } -} - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/CalibKers.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/CalibKers.cl deleted file mode 100644 index cd35060..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/CalibKers.cl +++ /dev/null @@ -1,477 +0,0 @@ -// BOP is a generic binary associative operator, -// e.g., +, *, AND, OR -//#define BOP(a,b) ( (a)+(b) ) - - -#include "KerConsts.h" - -#define TH_ID (get_local_id(0)) -#define WARP_ID (TH_ID >> lgWARP) -#define WARP_FST (WARP_ID << lgWARP) -#define WARP_LST (WARP_FST + (WARP-1)) - - -#if WITH_FLOAT - typedef float2 REAL2; - typedef float4 REAL4; -#else - typedef double2 REAL2; - typedef double4 REAL4; -#endif - -inline REAL minR(REAL a, REAL b) { return ( (a <= b) ? a : b ); } -inline REAL maxR(REAL a, REAL b) { return ( (a <= b) ? b : a ); } - -#include "GenAlg.cl" -#include "BestIndValRedKer.cl" - -/******************************************************/ -/********* EVAL_GENOME KERNELS and HELPERS ************/ -/******************************************************/ - -/** Assumes global shape has the following layout: - * 1. flags, i.e., 1 if start of segment, -1 if iddle thread, and 0 otherwise - * 2. iota(n_schedi) - * 3. the swaption index - * 4. the size of the current segment - * Local shape has the following structure: - * 1. flags as uchar, where 1 denote the start of a segment, - * 2. cond as uchar, where 0 denotes thread is active, - * 3. index as short in iota(n_schedi), - * 4. swaption's global index as short - * 5. size fo the current segment as short - */ -inline -bool fillShapeMeta(__global short* shape, - __local short* sh_mem, - uint Nshp -) { - bool iddle = false; - uint loc_ind = TH_ID, glb_ind = get_global_id(0); // ignore global dimension 1 - short tmp = shape[ glb_ind ]; - - { // fill the boolean part! - __local uchar* shape_meta = (__local uchar*) sh_mem; - - shape_meta[ loc_ind ] = ( tmp != 0 ) ? (uchar) 1 : (uchar) 0; - loc_ind += get_local_size(0); - shape_meta[ loc_ind ] = (uchar) 0; - } - - glb_ind += Nshp; - sh_mem[ loc_ind ] = shape[ glb_ind ]; // setting iota(n_schedi) - - loc_ind += get_local_size(0); - glb_ind += Nshp; - sh_mem[ loc_ind ] = shape[ glb_ind ]; // setting the swaption index - - loc_ind += get_local_size(0); - glb_ind += Nshp; - tmp = shape[ glb_ind ]; - if( tmp < 0 ) { iddle = true; tmp = -tmp; } - sh_mem[loc_ind] = tmp; - - barrier(CLK_LOCAL_MEM_FENCE); - return iddle; -} - -inline -short getIotaInd (__local short* shape) { - return shape[ TH_ID + get_local_size(0) ]; -} -inline -short getSwapGlbInd(__local short* shape) { - return shape[ (get_local_size(0) << 1) + TH_ID ]; -} -inline -short getSwapLocInd(__local short* shape) { - short res = getSwapGlbInd(shape) - shape[ get_local_size(0) << 1 ]; - return res; -} -inline -short getSgmSize (__local short* shape ) { - return shape[ (get_local_size(0) << 1) + get_local_size(0) + TH_ID ]; -} - -#include "Date.cl" -#include "G2ppUtil.cl" -#include "Reductions.cl" -#include "ExactYhat.cl" - - -/** - * Two-dimensional kernel: - * 1. the outer dimension is POP_SIZE, - * 2. the inner dimension is Nshp, i.e., an approximation - * (with idde threads) of the flattened parallelism - * of the loop of count `NUM_SWAP_QUOTES'. - */ - -__kernel __attribute__((reqd_work_group_size(LWG_EG, 1, 1))) -void eval_genome_main ( - __global short *glb_shape, - __global REAL *SwaptionQuotes, - __global REAL *genomes, - __global REAL *glb_arrs, // ci ++ t1_cs ++ scale ++ bbi - __global REAL *new_quote_price, // [POP_SIZE * NUM_SWAP_QUOTES * 2] - __global REAL *interm_scalars, // [POP_SIZE * NUM_SWAP_QUOTES * 8] - // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, - // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } - uint Nswap, - uint Npop, - uint Nshp -) { - REAL4 tmp4; - - __local short shape_meta [ (LWG_EG << 2) ]; - __local REAL4 sh_mem4 [ LWG_EG + (LWG_EG >> 1) ]; - - bool iddle = fillShapeMeta( glb_shape, shape_meta, Nshp ); - - REAL swap_freq = 1.0, maturity = 1.0, tmat0 = 1.0; uint n_schedi; - if( !iddle ) { - int ttt = getSwapGlbInd(shape_meta); - swap_freq = SwaptionQuotes[ (ttt<<2) + 1 ]; - maturity = add_years( TODAY, SwaptionQuotes[ (ttt<<2) ] ); - n_schedi = (uint) (12.0 * SwaptionQuotes[ (ttt<<2) + 2 ] / swap_freq); - tmat0 = date_act_365( maturity, TODAY ); - } - - REAL strike, beg_date, end_date; - { // BLACK PRICE COMPUTATION. - __local uchar* flags = (__local uchar*) shape_meta; - - tmp4 = (REAL4) (0.0, MAX_DATE, MIN_DATE, 1.0); - if(!iddle) { - tmp4.w = (REAL) getIotaInd(shape_meta); // i - tmp4.y = add_months( maturity, swap_freq*tmp4.w ); // t0 - tmp4.z = add_months( tmp4.y, swap_freq ); // tn - tmp4.x = zc(tmp4.z) * date_act_365(tmp4.z,tmp4.y); // lvl - } - beg_date = tmp4.y; end_date = tmp4.z; - - sh_mem4[ TH_ID ] = tmp4; - barrier(CLK_LOCAL_MEM_FENCE); - segm_reduce_plusminmax( sh_mem4, flags ); // ToDo 2 - - int last_ind = TH_ID - getIotaInd( shape_meta ); - if(!iddle) last_ind += n_schedi - 1; - tmp4 = sh_mem4[last_ind]; // the reduction result! - barrier(CLK_LOCAL_MEM_FENCE); - - strike = ( zc(tmp4.y) - zc(tmp4.z) ) / tmp4.x; - if( flags[TH_ID] && (!iddle) ) { - // if thread is the start of a segment - // write new_quote to global memory! - int ttt = getSwapGlbInd(shape_meta); - tmp4.y = 0.5 * SwaptionQuotes[ (ttt<<2) + 3 ] * tmat0; - // was get_group_id(1) - new_quote_price[ get_global_id(1)*Nswap + ttt ] = - tmp4.x * strike * ( uGaussian_P(tmp4.y) - uGaussian_P(-tmp4.y) ); - } - } // END BLACK PRICE. - - { // PRICER OF SWAPTION COMPUTATION - - REAL y0, y1, eps, eps_contrib, mux, t4, t1_cs_first; - { - REAL a, b, rho, nu, sigma; - { - uint tmp_ind = get_global_id(1) + Npop; - uint Npop2 = (Npop << 1); - a = genomes[ tmp_ind ]; tmp_ind += Npop2; - b = genomes[ tmp_ind ]; tmp_ind += Npop2; - rho = genomes[ tmp_ind ]; tmp_ind += Npop2; - nu = genomes[ tmp_ind ]; tmp_ind += Npop2; - sigma = genomes[ tmp_ind ]; tmp_ind += Npop2; - } -// - { - REAL v0_mat, v0_end, vt_end, baii, bbii, tmp; - tmp4 = bigv( a, b, rho, nu, sigma, tmat0 ); - v0_mat = tmp4.x; -// - tmp = date_act_365(end_date, TODAY); - tmp4 = bigv( a, b, rho, nu, sigma, tmp ); - v0_end = tmp4.x; -// - tmp = date_act_365(end_date, maturity); - tmp4 = bigv( a, b, rho, nu, sigma, tmp ); - vt_end = tmp4.x; - //baii = tmp4.y; - //bbii = tmp4.z; - tmp4.w = 0.5 * ( vt_end - v0_end + v0_mat ); // expo_aici - tmp4.x = date_act_365( end_date, beg_date ) * strike; // res - } -// - { - //bool is_first = ((__local uchar*)shape_meta)[TH_ID] && (!iddle); - bool is_first = (!iddle) && ( (TH_ID == get_local_size(0)-1) || (((__local uchar*)shape_meta)[TH_ID+1]==1) ); // actually is_last! - REAL muy, rhoxy, sigmax, sigmay, rhoxyc, rhoxycs, zc_mat, tmp1, tmp2; - uint gind = get_global_id(1)*Nswap + getSwapGlbInd(shape_meta), offset = Npop*Nswap; // was get_group_id(1) -// - mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); - if(is_first) interm_scalars[ gind ] = mux; gind += offset; -// - muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); - if(is_first) interm_scalars[ gind ] = muy; gind += offset; -// - tmp1 = sqrt( b_fun(2.0*a, tmat0) ); // sqrt_bfun_a - sigmax = sigma * tmp1; - if(is_first) interm_scalars[ gind ] = sqrt(2.0) * sigmax; gind += offset; -// - tmp2 = sqrt( b_fun(2.0*b, tmat0) ); // sqrt_bfun_b - sigmay = nu * tmp2; - rhoxy = rho * b_fun(a+b, tmat0) / (tmp1 * tmp2); - t4 = (rhoxy * sigmay) / sigmax; -// - rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel - rhoxycs = sqrt( rhoxyc ); // used in reduction kernel - if(is_first) interm_scalars[ gind ] = rhoxy / (sigmax*rhoxycs); gind += offset; - if(is_first) interm_scalars[ gind ] = sigmay * rhoxycs; gind += offset; -// - zc_mat = zc(maturity); - if(is_first) tmp4.x += 1.0; //cii - tmp4.x *= zc(end_date) / zc_mat; // fact_aici - if(is_first) interm_scalars[ gind ] = zc_mat; gind += offset; -// - t1_cs_first = tmp4.z * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*tmp4.z) ); - eps = 0.5 * sigmax; - eps_contrib = sigmay * (rhoxy * eps / sigmax); - y0 = sigmay * KKK * rhoxycs; - y1 = muy - y0; - y0 += muy - ( rhoxyc / b ); - } - } - - { - { // save to global arrays, ci, t1_cs, scale, bbi, and - // store (aici, baii, bbii, log_aici) in tmp4! - uint gind = get_global_id(1) * Nshp + get_global_id(0), offset = Nshp * Npop; - REAL fact_aici = tmp4.x; - - if( !iddle ) glb_arrs[gind] = fact_aici; gind += offset; // ci [i] - if( !iddle ) glb_arrs[gind] = t1_cs_first + tmp4.w; gind += offset; // t1_cs[i] - if( !iddle ) glb_arrs[gind] = - ( tmp4.y + tmp4.z * t4 ); gind += offset; // scale[i] - if( !iddle ) glb_arrs[gind] = tmp4.z; // bbi [i] - - tmp4.x *= exp(tmp4.w); // aici - tmp4.w += log(fact_aici); // log_aici - - sh_mem4[ TH_ID ] = tmp4; - barrier(CLK_LOCAL_MEM_FENCE); - } - - { // finally call `exactYhat', and store `f' and `df' to global memory. - REAL f, g, h, df; - uint gind = getSwapGlbInd(shape_meta); - __local uchar* flags = (__local uchar*)shape_meta; - //uint n_schedi = (iddle) ? 1 : (uint)(12.0 * SwaptionQuotes[ (gind<<2) + 2 ] / swap_freq); - - f = exactYhat( iddle, flags, n_schedi, y0, y1, sh_mem4, mux ); - - if( flags[TH_ID] && (!iddle) ) { // start of segment - uint offset = Npop*Nswap; - gind += get_global_id(1)*Nswap + 6*offset; // was get_group_id(1) - interm_scalars[ gind ] = f; - gind += offset; - } - - y0 += eps_contrib; - y1 += eps_contrib; - mux+= eps; - g = exactYhat( iddle, flags, n_schedi, y0, y1, sh_mem4, mux ); - - y0 -= 2.0*eps_contrib; - y1 -= 2.0*eps_contrib; - mux-= 2.0*eps; - h = exactYhat( iddle, flags, n_schedi, y0, y1, sh_mem4, mux ); - - if( flags[TH_ID] && (!iddle) ) { // start of segment - interm_scalars[ gind ] = 0.5 * ( g - h ) / eps; // i.e., df - } - } - } - } -} - -/********************************************************/ -/*************** Main Reduction kernel 1 ****************/ -/********************************************************/ -/** - * Two-dimensional kernel: - * 1. the outermost dimension is POP_SIZE, - * 2. the middle dimension is Gauss_DIM - * 2. the inner dimension is Nshp, i.e., an approximation - * (with idde threads) of the flattened parallelism - * of the loop of count `NUM_SWAP_QUOTES'. - */ - -__kernel __attribute__((reqd_work_group_size(LWG_EG, 1, 1))) -void eval_genome_red1 ( - __global short *glb_shape, - __constant REAL *gauss_coefs, // [Gauss_DIM] - __constant REAL *gauss_weights, // [Gauss_DIM] - - __global REAL *glb_arrs, // ci ++ t1_cs ++ scale ++ bbi - __global REAL *interm_scalars, // [POP_SIZE * NUM_SWAP_QUOTES * 8] - // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, - // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } - - __global REAL *accum0, // [ POP_SIZE * NUM_SWAP_QUOTES * Gauss_DIM ] - - uint Nswap, - uint Nshp -) { - __local short shape_meta [ LWG_EG << 2 ]; - __local REAL sh_mem [ LWG_EG ]; - - bool iddle; - { - iddle = fillShapeMeta( glb_shape, shape_meta, Nshp ); - } - - REAL x_quad = gauss_coefs [get_global_id(1)]; - - REAL sigmay_rhoxycs, x, h1; - if(!iddle){ - REAL mux, muy, sqrt2sigmax, t2, f, df, yhat_x; // Npop == POP_SIZE = get_global_size(2) - uint gind = get_global_id(2) * Nswap + getSwapGlbInd(shape_meta), offset = get_global_size(2) * Nswap; - - mux = interm_scalars[ gind ]; gind += offset; - muy = interm_scalars[ gind ]; gind += offset; - - // x = sqrt2sigmax * x_quad + mux; - sqrt2sigmax = interm_scalars[ gind ]; gind += offset; // - x = sqrt2sigmax * x_quad + mux; - - t2 = interm_scalars[ gind ]; gind += offset; - - sigmay_rhoxycs = interm_scalars[ gind ]; gind += offset + offset; - f = interm_scalars[ gind ]; gind += offset; - df = interm_scalars[ gind ]; - - yhat_x = f + df*(x - mux); - h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); - } - - if(!iddle){ - uint gind = get_global_id(2) * Nshp + get_global_id(0), offset = Nshp * get_global_size(2); - gind += 3 * offset; - REAL bbi = glb_arrs[gind]; gind -= offset; - REAL h2 = h1 + bbi * sigmay_rhoxycs; - - REAL scale = glb_arrs[gind]; gind -= offset; - REAL t1_cs = glb_arrs[gind]; gind -= offset; - REAL expo_aici = t1_cs + scale*x; - - REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); - - x = glb_arrs[gind] * expo_part; - } - - { // segmented reduce with operator plus the x's - - __local uchar* flags = (__local uchar*) shape_meta; - bool is_last = (!iddle) && ( (TH_ID == get_local_size(0)-1) || ( flags[TH_ID+1] == 1) ); - - sh_mem[TH_ID] = (iddle) ? 0.0 : x; - barrier(CLK_LOCAL_MEM_FENCE); - - segm_reduce_plus( sh_mem, flags ); - - if( is_last ) { - REAL accum = sh_mem[TH_ID]; - REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; - tmp = exp( - 0.5 * tmp * tmp ); - - REAL w_quad = gauss_weights[get_global_id(1)]; - - REAL res = w_quad * tmp * ( uGaussian_P(-h1) - accum ); - - //uint GaussDIM = get_global_size(1); -#if 0 - uint gind = get_global_id(2) * get_global_size(1) * Nswap + - getSwapGlbInd(shape_meta) * get_global_size(1) + get_global_id(1) ; - accum0[gind] = res; -#else - // accum0 is put it in transposed form, i.e., - // accum0[ j * Nswap + ttt ] and is used in - // this way by the next kernel - uint gind = get_global_id(2) * get_global_size(1) * Nswap + - get_global_id(1) * Nswap + getSwapGlbInd(shape_meta); - accum0[gind] = res; -#endif - } - } -} - - - -/********************************************************/ -/*************** Main Reduction kernel 2 ****************/ -/********************************************************/ -inline REAL cauchy_pdf( REAL z, REAL mu, REAL gamma ) { - REAL x = (z-mu) / gamma; - return 1.0 / ( PI * gamma * (1.0+x*x) ); -} -inline REAL logLikelihood_cauchy( REAL y_ref, REAL y ) { - REAL LLHOOD_CAUCHY_OFFS = 5.0; - REAL gamma = ( fabs(y_ref) / 50.0 ) * LLHOOD_CAUCHY_OFFS + 0.01; - REAL pdfs = cauchy_pdf( y, y_ref, gamma ); - pdfs += 1.0e-20; // avoid NaNs - return log(pdfs); -} - -/** - * Two-dimensional kernel: - * 1. the outermost global dimension is POP_SIZE, - * 2. the innermost global dimension is equal to the local - * dimension, i.e., LWG_EG, which is an overapproximation - * of NUM_SWAP_QUOTES. - * Each local groups process exactly NUM_SWAP_QUOTES elements, - * and the rest of the htreads are iddle. - * This is taking a shortcut to implement reduce in a regular fashion. - */ - -__kernel __attribute__((reqd_work_group_size(LWG_EG, 1, 1))) -void eval_genome_red2 ( - __global REAL *genomes, - __global REAL *interm_scalars, // [POP_SIZE * NUM_SWAP_QUOTES * 8] - // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, - // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } - __global REAL *accum0, // [ POP_SIZE * NUM_SWAP_QUOTES * Gauss_DIM ] - __global REAL *new_quote_price, // [POP_SIZE * NUM_SWAP_QUOTES * 2] - - uint Nswap, - uint GaussDIM -) { - __local REAL sh_mem [ LWG_EG ]; - - bool iddle = ( TH_ID >= Nswap ); - - REAL lik = 0.0; - if (!iddle) { - REAL accum = 0.0; - uint gid = get_global_id(1) * GaussDIM * Nswap + get_global_id(0); - for( uint j = 0; j < GaussDIM; j++, gid += Nswap ) { - accum += accum0[ gid ]; - } - - gid = get_global_id(1) * Nswap + TH_ID; - REAL zc_mat = interm_scalars[ gid + (5 * get_global_size(1) * Nswap) ]; - - REAL nprice = zc_mat * ( accum / sqrt( PI ) ); - new_quote_price[ gid + get_global_size(1)*Nswap ] = nprice; - - lik = logLikelihood_cauchy( new_quote_price[gid], nprice ); - } - - sh_mem[ TH_ID ] = lik; - barrier(CLK_LOCAL_MEM_FENCE); - - REAL rms = reduce_reg_plus( sh_mem ); - - if(TH_ID == 0) genomes[ 11*get_global_size(1) + get_global_id(1) ] = rms; -} - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Date.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Date.cl deleted file mode 100644 index 680f5bf..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Date.cl +++ /dev/null @@ -1,147 +0,0 @@ -////////////////////////////////////////////////////// -//// Date: Gregorian calendar -////////////////////////////////////////////////////// -#ifndef GREG_CALEND -#define GREG_CALEND - -#define MINUTES_IN_DAY 1440 // hours_in_day * 60; -#define MINUTES_TO_NOON 720 // (hours_in_day / 2) * 60; - -typedef struct DDD{ - int year; - int month; - int day; - int hour; - int min; -} Date; - -Date mkDate(int y, int mo, int d, int h, int mn) { - Date date; - date.year = y; - date.month = mo; - date.day = d; - date.hour = h; - date.min = mn; - return date; -} - -inline -int MOD(int x, int y) { - return ( x - (x/y)*y ); -} - -inline -int date_of_gregorian( Date date ) { - int ym; - if(date.month == 1 || date.month == 2) { - ym = ( 1461 * ( date.year + 4800 - 1 ) ) / 4 + - ( 367 * ( date.month + 10 ) ) / 12 - - ( 3 * ( ( date.year + 4900 - 1 ) / 100 ) ) / 4; - } else { - ym = ( 1461 * ( date.year + 4800 ) ) / 4 + - ( 367 * ( date.month - 2 ) ) / 12 - - ( 3 * ( ( date.year + 4900 ) / 100 ) ) / 4; - } - - int tmp = ym + date.day - 32075 - 2444238; - - return tmp * MINUTES_IN_DAY + date.hour * 60 + date.min; -} - -inline -Date gregorian_of_date ( int minutes_since_epoch ) { - int jul, l, n, i, j, d, m, y, daytime; - - jul = minutes_since_epoch / MINUTES_IN_DAY; - l = jul + 68569 + 2444238; - n = ( 4 * l ) / 146097; - l = l - ( 146097 * n + 3 ) / 4; - i = ( 4000 * ( l + 1 ) ) / 1461001; - - l = l - ( 1461 * i ) / 4 + 31; - j = ( 80 * l ) / 2447; - d = l - ( 2447 * j ) / 80; - l = j / 11; - - m = j + 2 - ( 12 * l ); - y = 100 * ( n - 49 ) + i + l; - - daytime = MOD( minutes_since_epoch, MINUTES_IN_DAY ); - -// if ( daytime == MINUTES_TO_NOON ) return Date(y,m,d,12,0); -// else return Date(y,m,d, daytime / 60, MOD(daytime, 60)); - - return mkDate(y,m,d, daytime / 60, MOD(daytime, 60)); -} - -inline -bool check_date(int year, int month, int day) { - bool tmp1, tmp2, tmp3; - - tmp1 = ( 1 <= day && 1 <= month && month <= 12 && 1980 <= year && year <= 2299 ); - tmp2 = ( day <= 28 ); - - if ( month == 2 ) { - tmp3 = ( day == 29 && MOD(year, 4) == 0 && ( year == 2000 || (not (MOD(year, 100) == 0)) ) ); - } else if ( month == 4 || month == 6 || month == 9 || month == 11 ) { - tmp3 = ( day <= 30 ); - } else { - tmp3 = ( day <= 31 ); - } - - return tmp1 && (tmp2 || tmp3); -} - -inline -REAL days_between(REAL t1, REAL t2) { - return ( (t1 - t2) / MINUTES_IN_DAY ); -} - -inline -REAL date_act_365(REAL t1, REAL t2) { - return ( days_between(t1, t2) / 365.0 ); -} - -inline -bool leap(int y) { - return ( MOD(y,4) == 0 && ( ( MOD(y,100)!=0 ) || (MOD(y,400)==0) ) ); -} - -inline -int end_of_month( int year, int month ) { - bool leap_year = leap(year); - if ( month == 2 && leap_year ) return 29; - else if ( month == 2 ) return 28; - else if ( month == 4 || month == 6 || month == 9 || month == 11 ) return 30; - else return 31; -} - -inline -REAL add_months ( REAL time, REAL rnbmonths ) { - int nbmonths = convert_int(rnbmonths); //(int) rnbmonths; - Date date = gregorian_of_date( convert_int( time ) ); - - date.month += nbmonths; - date.year += (date.month-1) / 12; - date.month = MOD( date.month-1, 12 ) + 1; - - if ( date.month <= 0 ) { date.year -= 1; date.month += 12; } - - { // date.day = min( date.day, end_of_month(date.year, date.month) ); - int tmp = end_of_month(date.year, date.month); - if(date.day > tmp) date.day = tmp; - } - - date.hour = 12; - date.min = 0; - - return (REAL) ( date_of_gregorian( date ) ); -} - -inline -REAL add_years( REAL date, REAL nbyears ) { - return add_months( date, nbyears * 12.0 ); -} - -#endif // ifndef GREG_CALEND - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/ExactYhat.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/ExactYhat.cl deleted file mode 100644 index d66d7dd..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/ExactYhat.cl +++ /dev/null @@ -1,314 +0,0 @@ -// reduction with + -REAL to_solve( bool iddle, - uint n_schedi, - __local uchar* flags, - __local REAL * sh_mem, - - REAL scale, - REAL bbi, - REAL yhat -) { - REAL accum; - sh_mem[TH_ID] = (iddle) ? 0.0 : scale * exp( - bbi * yhat ); - barrier(CLK_LOCAL_MEM_FENCE); - - segm_reduce_plus( sh_mem, flags ); // ToDo 2 - - int last_ind = TH_ID - getIotaInd( (__local short*)flags ); - if(!iddle) last_ind += n_schedi - 1; - - accum = sh_mem[last_ind]; - barrier(CLK_LOCAL_MEM_FENCE); - - return accum - 1.0; -} - - -/** - * root finding by Brent's method. - */ -//REAL2 tmp2 = rootFinding_Brent(iddle, shape, sh_mem4, scales, uplo.y, uplo.x, 1.0e-4, 1000); -//rootFinding_Brent(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); -inline -REAL2 rootFinding_Brent( bool iddle, - uint n_schedi, - __local uchar* flags, - __local REAL * sh_mem, - REAL bbi, //sh_mem4[TH_ID].z; - REAL scale, - REAL a, //lb, - REAL b, //ub, - REAL tol, - uint iter_max - // (root, fb) : (REAL, REAL) -) { - REAL2 res; - - REAL fa = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, a); - REAL fb = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, b); - - if( (!iddle) && fa*fb >= 0.0 ) { - res.x = 0.0; - res.y = ( a >= 0.0 ) ? INFTY : -INFTY; - iddle = true; - } - - if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } - - REAL c = a, fc = fa; - bool mflag = true; - REAL d = 0.0; - - uchar ok = 0; int i = 0; - do { - { // reduce with && global termination - ok = ( fb == 0.0 || fabs(b-a) < tol || i >= iter_max ); - - if( ok ) { - if( !iddle ) { - res.x = b; - res.y = fb; - } - iddle = true; - } - - flags[TH_ID+get_local_size(0)] = iddle; - barrier(CLK_LOCAL_MEM_FENCE); - ok = reduce_reg_and( flags + get_local_size(0) ); - //barrier(CLK_LOCAL_MEM_FENCE); - } - i ++; - - // the loop's body - if( !ok ) { - REAL s; - if( !iddle ) { - if( fa == fc || fb == fc ) { - s = b - fb * (b - a) / (fb - fa); - } else { - REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); - REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); - REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); - s = s1 + s2 + s3; - } - - bool big_cond = - ( (3.0 * a + b) /4.0 > s || s > b) || - ( mflag && fabs(b-c)/2.0 <= fabs(s-b) ) || - ( !mflag && fabs(c-d)/2.0 <= fabs(s-b) ) || - ( mflag && fabs(b-c) <= fabs(tol) ) || - ( !mflag && fabs(c-d) <= fabs(tol) ) ; - - if ( big_cond ) { - mflag = true; - s = (a + b) / 2.0; - } else { - mflag = false; - } - } - REAL fs = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, s); - - if( !iddle ) { - // d is assigned for the first time here: - // it's not used above because mflag is set - d = c; - c = b; fc = fb; - - if( fa*fs < 0.0 ) { b = s; fb = fs; } - else { a = s; fa = fs; } - - if( fabs(fa) < fabs(fb) ) { - REAL tmp; - tmp = a; a = b; b = tmp; - tmp = fa; fa = fb; fb = tmp; - } - } - } - } while (!ok); - - return res; -} - - -/*********************************************/ -/*********************************************/ - -inline -REAL2 rootBisection( bool iddle, - uint n_schedi, - __local uchar* flags, - __local REAL * sh_mem, - REAL bbi, //sh_mem4[TH_ID].z; - REAL scale, - REAL a, //lb, - REAL b, //ub, - REAL tol, - uint iter_max - // (root, fb) : (REAL, REAL) -) { - REAL2 res; - - REAL fa = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, a); - REAL fb = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, b); - - if( (!iddle) && fa*fb >= 0.0 ) { - res.x = 0.0; - res.y = ( a >= 0.0 ) ? INFTY : -INFTY; - iddle = true; - } - - REAL x = b, fx = fb; - - uchar ok = 0; int i = 0; - do { - { // reduce with && global termination - ok = ( fx == 0.0 || fabs(b-a) < tol || i >= iter_max ); - - if( ok ) { - if( !iddle ) { - res.x = x; - res.y = fx; - } - iddle = true; - } - - flags[TH_ID+get_local_size(0)] = iddle; - barrier(CLK_LOCAL_MEM_FENCE); - ok = reduce_reg_and( flags + get_local_size(0) ); - //barrier(CLK_LOCAL_MEM_FENCE); - } - i ++; - - // the loop's body - if( !ok ) { - REAL s; - - x=(a+b)/2.0; - - REAL fx = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, x); - - if( !iddle ) { - if ( fa*fx > 0.0 ) { a = x; fa = fx; } - else { b = x; } - } - } - } while (!ok); - - return res; -} - - -/********************************************/ -/********************************************/ - - -/** - * Computes Yhat - */ -REAL exactYhat( bool iddle, - __local uchar* flags, - uint n_schedi, - REAL y0, - REAL y1, - __local REAL4* sh_mem4, - REAL x -) { - REAL res = 0.0, scales; - REAL2 uplo; - - { // the first reduction (+,max) - bool is_last; short lind; - __local REAL2* sh_mem2 = (__local REAL2*) (sh_mem4 + LWG_EG); - - if( iddle ) { - uplo = (REAL2) ( 0.0, -INFTY ); - } else { - REAL4 tmp4 = sh_mem4[ TH_ID ]; - REAL baix = tmp4.y * x; - - uplo.x = tmp4.x * exp( -baix ); - uplo.y = ( tmp4.w - baix ) / tmp4.z; - } - scales = uplo.x; - - barrier(CLK_LOCAL_MEM_FENCE); - sh_mem2[ TH_ID ] = uplo; - barrier(CLK_LOCAL_MEM_FENCE); - - segm_reduce_plusmax( sh_mem2, flags ); // ToDo: Fix this please! - - int last_ind = TH_ID - getIotaInd( (__local short*) flags ); - if(!iddle) last_ind += n_schedi - 1; - uplo = sh_mem2[last_ind]; // the reduction result! - barrier(CLK_LOCAL_MEM_FENCE); - } - -// CHECKING uplo - - if ( n_schedi == 1 ) { - res = uplo.y; - iddle = true; - } - - if(!iddle) { // adjust `up' - int lfind = TH_ID - getIotaInd( (__local short*)flags ) + n_schedi - 1; - REAL log_s = log(uplo.x); - REAL tmp = log_s / sh_mem4[ lfind ].z; //bbi[n_schedi-1]; - lfind += 1 - n_schedi; - - if ( tmp <= 0.0 ) { - uplo.x = tmp; - } else { - tmp = log_s / sh_mem4[lfind].z; // bbi[0]; - if ( 0.0 <= tmp ) uplo.x = tmp; - else uplo.x = - INFTY; - } - } - -// const REAL yl = lo - EPS; -// const REAL yu = up + EPS; - if ( (!iddle) && (y1 <= uplo.y - EPS) ) { - // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS - - res = y1 + 1.0; - iddle = true; - } else if ( (!iddle) && (uplo.x + EPS <= y0) ) { - // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) - - res = y0 - 1.0; - iddle = true; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - { - uplo.x = minR( uplo.x + EPS, y1 ); - uplo.y = maxR( uplo.y - EPS, y0 ); - // tmp2 = (root, error); //UINT iter; - -#if 1 - REAL2 tmp2 = rootFinding_Brent( - iddle, n_schedi, flags, (__local REAL*) (sh_mem4+LWG_EG), - sh_mem4[TH_ID].z, scales, uplo.y, uplo.x, 1.0e-4, 1000 - ); -#else - - REAL2 tmp2 = rootBisection( - iddle, n_schedi, flags, (__local REAL*) (sh_mem4+LWG_EG), - sh_mem4[TH_ID].z, scales, uplo.y, uplo.x, 1.0e-4, 1000 - ); - - -#endif - - if( !iddle ) { - res = ( tmp2.y == -INFTY ) ? - y0 - 1.0 : - ( tmp2.y == INFTY ) ? y1 + 1.0 : tmp2.x; - } - } - - return res; -} - - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/G2ppUtil.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/G2ppUtil.cl deleted file mode 100644 index b3544d8..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/G2ppUtil.cl +++ /dev/null @@ -1,231 +0,0 @@ -//////////////////////////////////////////////////////////////////// -///// Trivial (w.r.t. parallelism) Helper Functions for G2PP -//////////////////////////////////////////////////////////////////// - -#ifndef G2PP_UTIL -#define G2PP_UTIL - -//////////////////////////////////// -/// MATH RELATED -//////////////////////////////////// - -//------------------------------------------------------------------------- -// polynomial expansion of the erf() function, with error<=1.5e-7 -// formula 7.1.26 (page 300), Handbook of Mathematical Functions, Abramowitz and Stegun -// http://people.math.sfu.ca/~cbm/aands/frameindex.htm - -inline -REAL erff1( REAL x ) { - REAL poly = 0.0, t, t2; - - t = 1.0 / (1.0 + 0.3275911*x); - poly += 0.254829592 * t; - - t2 = t * t; - poly += (-0.284496736) * t2; - poly += 1.421413741 * t * t2; - - t2 = t2 * t2; - poly += (-1.453152027) * t2; - poly += 1.061405429 * t * t2; - - return ( 1.0 - poly * exp(-(x*x)) ); - -// REAL p = 0.3275911; -// REAL a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741, a4 = -1.453152027, a5 = 1.061405429; -// -// REAL t = 1.0/(1.0+p*x); -// REAL t2 = t * t; -// REAL t3 = t * t2; -// REAL t4 = t2 * t2; -// REAL t5 = t2 * t3; -// return ( 1.0 - (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5) * exp(-(x*x)) ); - -} - -//------------------------------------------------------------------------- -// Cumulative Distribution Function for a standard normal distribution - -inline -REAL uGaussian_P( REAL x ) { - REAL u = x / sqrt(2.0); - REAL e = ( u < 0.0 ) ? -erff1(-u) : erff1(u); - - return ( 0.5 * (1.0 + e) ); -} - -inline -REAL erff_poly_only( REAL x ) { - REAL poly = 0.0, t, t2; - - t = 1.0 / (1.0 + 0.3275911*x); - poly += 0.254829592 * t; - - t2 = t * t; - poly += (-0.284496736) * t2; - poly += 1.421413741 * t * t2; - - t2 = t2 * t2; - poly += (-1.453152027) * t2; - poly += 1.061405429 * t * t2; - - return poly; -} - -inline -REAL uGaussian_P_withExpFactor( REAL x, REAL exp_factor ) { - REAL u = fabs( x / sqrt(2.0) ); - REAL e = erff_poly_only(u); - - REAL res = 0.5 * e * exp(exp_factor-u*u); - - if( x >= 0.0 ) { - res = exp(exp_factor) - res; - } - - return res; -} - -///////////////////////// -//// G2PP Utilities -///////////////////////// - -inline -REAL zc( REAL t ) { - return exp( - R * date_act_365( t, TODAY ) ); -} - -inline -REAL b_fun( REAL z0, REAL tau ) { - return ( 1.0 - exp(-z0*tau) ) / z0; -} - -inline -REAL t_fun( REAL sigma, REAL x0, REAL tau ) { - REAL expxtau = exp( -x0*tau ) ; - REAL exp2xtau = expxtau*expxtau; - - return sigma*sigma/(x0*x0) * ( tau + 2.0/x0*expxtau-1.0/(2.0*x0)*exp2xtau-3.0/(2.0*x0) ); -} - - -/////////////////////////////////////////////////////////////////// -// the first parameter `genome' is the five-genes genome used in -// the genetic algorithms that models the interest rate -// the second parameter is the time -// the result is V in Brigo and Mercurio's book page 148. -// \var(\int_t^T [x(u)+y(u)]du) -/////////////////////////////////////////////////////////////////// -//res = (v, bai, bbi, _) -inline -REAL4 bigv( REAL g_a, - REAL g_b, - REAL g_rho, - REAL g_nu, - REAL g_sig, - REAL tau -) { - REAL4 res4; - - res4.w = g_sig; //(g_sig == 0.0) ? 1.0e-10 : g_sig; // g_sigma - res4.y = b_fun(g_a, tau); - res4.z = b_fun(g_b, tau); - res4.x = t_fun(res4.w, g_a,tau); - res4.x+= t_fun(g_nu, g_b,tau); - res4.x+= 2.0 * g_rho * g_nu * res4.w / (g_a * g_b) * - ( tau - res4.y - res4.z + b_fun(g_a+g_b, tau) ); - - return res4; -} - - -/////////////////////////////////////////////////////////////////// -// the first parameter `genome' is the five-genes genome used in -// the genetic algorithms that models the interest rate -// the other parameter are times: today, maturity, and the -// lower and upper bound of the considered time interval -// -// the result is: x drift term in tmat-forward measure -/////////////////////////////////////////////////////////////////// -inline -REAL bigmx( REAL a, - REAL b, - REAL rho, - REAL nu, - REAL sigma, // ends genome - REAL today, - REAL tmat, - REAL s, - REAL t -) { - REAL ts = date_act_365(t, s) ; - REAL tmatt = date_act_365(tmat, t) ; - - REAL tmat0 = date_act_365(tmat, today); - REAL tmats = date_act_365(tmat, s) ; - REAL t0 = date_act_365(t, today); - REAL s0 = date_act_365(s, today); - - REAL tmp, res = 0.0; - - tmp = (sigma*sigma)/(a*a)+(sigma*rho*nu)/(a*b); - tmp *= ( 1.0 - exp(- a * ts) ); - res += tmp; - - tmp = sigma * sigma / (2.0 * a * a); - tmp *= exp(- a * tmatt) - exp(- a * (tmats + ts)); - res -= tmp; - - tmp = rho * sigma * nu / (b * (a + b)); - tmp *= exp(-b * tmatt) - exp(-b*tmat0 - a*t0 + (a+b)*s0); - res -= tmp; - - return res; -} - - -/////////////////////////////////////////////////////////////////// -// the first parameter `genome' is the five-genes genome used in -// the genetic algorithms that models the interest rate -// the other parameter are times: today, maturity, and the -// lower and upper bound of the considered time interval -// -// the result is: y drift term in tmat-forward measure -/////////////////////////////////////////////////////////////////// -inline -REAL bigmy( REAL a, - REAL b, - REAL rho, - REAL nu, - REAL sigma, // ends genome - REAL today, - REAL tmat, - REAL s, - REAL t -) { - REAL ts = date_act_365(t, s ); - REAL tmatt = date_act_365(tmat, t ); - REAL tmat0 = date_act_365(tmat, today); - REAL tmats = date_act_365(tmat, s ); - REAL t0 = date_act_365(t, today); - REAL s0 = date_act_365(s, today); - - REAL tmp, res = 0.0; - - tmp = nu*nu/(b*b)+sigma*rho*nu/(a*b); - tmp *= 1.0 - exp(-b * ts); - res += tmp; - - tmp = nu * nu / (2.0 * b * b); - tmp *= exp(-b * tmatt) - exp(-b * (tmats + ts)); - res -= tmp; - - tmp = sigma * rho * nu / (a * (a + b)); - tmp *= exp(-a * tmatt) - exp(-a*tmat0 - b*t0 + (a+b)*s0); - res -= tmp; - - return res; -} - -#endif // ifndef G2PP_UTIL - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/GenAlg.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/GenAlg.cl deleted file mode 100644 index 381a92e..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/GenAlg.cl +++ /dev/null @@ -1,313 +0,0 @@ -// Various Kinds of Regular and Segmented Reduction -#ifndef GEN_ALG_KERNELS -#define GEN_ALG_KERNELS - -REAL getSobolNum( uint n, __constant int* SOBOL_DIR_VCT ) { - int n_gray = (n >> 1) ^ n; - int res = 0; - for( int i=0; i < SOBOL_BITS_NUM; i++ ) { - int t = (1 << i); - bool cond = ( (n_gray & t) == t ); - if ( cond ) { - res = res ^ SOBOL_DIR_VCT[i]; - } - } - REAL rres = ((REAL)res) / ( (1< 0.0 ) ? (backward_range / forward_range) : 1.0; - - // assign p' - REAL diff = amplitude * r01 - semiamplitude; - return (REAL2) (gene + diff, bf_fact); -} - -inline -REAL constrain_gene( REAL gene, REAL lb, REAL ub ) { - return maxR( lb, minR( ub, gene ) ); -} - -/*******************************************/ -/********** MUTATE DIMs KERNEL ***********/ -/*******************************************/ - -/** - * One-Dimensional Kernel: - * Dimension is POP_SIZE (LWG = GWG) - */ -__kernel void -mutate_dims ( __global REAL* genomes, //[13, POP_SIZE] - __constant REAL* lub, //[2, 5]. i.e., [lower,upper] gene range - __constant int * SOBOL_DIR_VCT, //[SOBOL_BITS_NUM == 30] - uint sob_offset, - uint dim_j, - REAL amplitude_ratio, // = MOVES_UNIF_AMPL_RATIO - uint Npop // POP_SIZE -) { - uint gid = get_global_id(0); -#if (SOBOL_TRANSP == 1) - uint gidr = gid*5 + sob_offset; -#else - uint gidr = gid + sob_offset; -#endif - uint offset = ( Npop << 1 ); - REAL fb_rat = 1.0; - REAL2 tmp; - - if( gid < Npop ) { - gid += Npop; - for(int i=0; i < 5; i++) { - REAL lb = lub[i], ub = lub[i+5]; - REAL r01 = getSobolNum(gidr, SOBOL_DIR_VCT); - - REAL ampl = (dim_j > 4 || dim_j == i) ? amplitude_ratio : 0.0; - tmp = mutate_helper( genomes[gid-Npop], genomes[gid], - lb, ub, r01, ampl ); - - REAL val = constrain_gene(tmp.x, lb, ub); - genomes[gid] = val; //(i == 2 && val == 0.0) ? EPS0 : val; - - fb_rat *= tmp.y; - gid += offset; -#if (SOBOL_TRANSP == 1) - gidr += 1; -#else - gidr += Npop; -#endif - } - gid += Npop; - genomes[gid] = fb_rat; - } -} - - -/**********************************************/ -/************* Crossover MCMC_DE **************/ -/**********************************************/ - -inline REAL getRandUnifNorm(REAL r) { - return r; -} -//Returns a (pseudo) random integer in [0, ub) -inline uint getRandIntNorm(uint ub, REAL r01) { - return (uint) (r01 * ub); -} - -inline -REAL perturbation( REAL gene, - REAL gene_k, - REAL gene_l, - REAL r01, - REAL lb, - REAL ub, - REAL gamma1, - REAL amplitude_ratio //= MOVES_UNIF_AMPL_RATIO -) { - REAL amplitude = fabs( (ub - lb) * amplitude_ratio ); - REAL semiamplitude = amplitude / 2.0; - REAL perturb = ( amplitude * r01 - semiamplitude ); - return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); -} - -/** - * Crossover - * One-Dimensional of size POP_SIZE = LWG = GWG - */ -__kernel void -mcmc_DE( __global REAL *genomes, - __constant REAL *lub, // [2, 5]. i.e., [lower,upper] gene range - __constant int *SOBOL_DIR_VCT, // [SOBOL_BITS_NUM == 30] - uint sob_offset, - REAL gamma_avg, // 2.38 / sqrt(2.0*GENOME_DIM), - REAL ampl_ratio, // 0.1 * MOVES_UNIF_AMPL_RATIO - uint Npop -) { - REAL r01; - uint gid = get_global_id(0); - -#if (SOBOL_TRANSP == 1) - uint gidr = gid*8 + sob_offset; - uint rinc = 1; -#else - uint gidr = gid + sob_offset; - uint rinc = Npop; -#endif - - uint offset = ( Npop << 1 ); - - if( gid < Npop ) { - uint cand_UB = Npop - 1; - r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); gidr += rinc; - uint k = getRandIntNorm( cand_UB, r01 ); - if ( k == gid ) { - k = cand_UB; - cand_UB -= 1; - } - - r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); gidr += rinc; - uint l = getRandIntNorm( cand_UB, r01 ); - if ( l == gid || l == k ) { - l = cand_UB; - } - - // proposal - // gamma: integrated out from the adviced Multivariate Gaussian with Gaussian target (Braak, 2006) - // random.uniform: is it supposed to be Sobol or such ? Does C++ rand() works? - // gamma = N.random.uniform( gamma_avg-0.5, gamma_avg+0.5 ) - r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); gidr += rinc; - REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm( r01 ); - - for( int j = 0; j < 5; j ++ ) { - REAL lb = lub[j], ub = lub[j+5]; - - r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); - REAL val = perturbation ( genomes[gid], genomes[k], genomes[l], r01, lb, ub, gamma1, ampl_ratio ); - val = constrain_gene( val, lb, ub ); - - genomes[ gid + Npop ] = val; //( j == 2 && val == 0.0 ) ? EPS0 : val; - - gidr += rinc; - gid += offset; - k += offset; - l += offset; - } - - gid += offset; - genomes[gid] = 1.0; // TODO: fix - } -} - - -#endif // GEN_ALG_KERNELS - diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Reductions.cl b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Reductions.cl deleted file mode 100644 index 200c5ef..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SrcCL/Reductions.cl +++ /dev/null @@ -1,380 +0,0 @@ -// Various Kinds of Regular and Segmented Reduction -#ifndef REDUCTION_KERNELS -#define REDUCTION_KERNELS - -/*************************************************/ -/*** Regular Total Reduction With Operator AND ***/ -/*************************************************/ - -inline -uchar reduce_reg_and_warp( - __local volatile uchar* sh_data -) { - const uint th_id = get_local_id(0) & (WARP-1); - - if( th_id >= 1 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-1 ]; - if( th_id >= 2 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-2 ]; - if( th_id >= 4 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-4 ]; - if( th_id >= 8 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-8 ]; -#if (WARP == 32) - if( th_id >= 16) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-16]; -#endif - return sh_data[th_id]; -} - -inline -uchar reduce_reg_and ( __local volatile uchar* sh_data ) { - // perform scan at warp level - uchar res = reduce_reg_and_warp( sh_data + WARP_FST ); - barrier( CLK_LOCAL_MEM_FENCE ); - - // gather per-warp results in the first WARP elements - if ( TH_ID == WARP_LST ) { - sh_data[ WARP_ID ] = res; - } - barrier(CLK_LOCAL_MEM_FENCE); - - if( TH_ID < WARP ) { - reduce_reg_and_warp( sh_data ); - } - barrier(CLK_LOCAL_MEM_FENCE); -#if 0 - if( WARP_ID != 0 ) { - res = res && sh_data[ WARP_ID-1 ]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - sh_data[TH_ID] = res; - - barrier(CLK_LOCAL_MEM_FENCE); - - res = sh_data[ get_local_size(0) - 1 ]; - barrier(CLK_LOCAL_MEM_FENCE); - return res; -#else - res = sh_data[ (get_local_size(0) >> lgWARP) - 1 ]; //sh_data[WARP-1]; - barrier(CLK_LOCAL_MEM_FENCE); - return res; -#endif -} - -/*************************************************/ -/*** Regular Total Reduction With Operator PLUS***/ -/*************************************************/ - -inline -REAL reduce_reg_plus_warp( - __local volatile REAL* sh_data -) { - const uint th_id = get_local_id(0) & (WARP-1); - - if( th_id >= 1 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-1 ]; - if( th_id >= 2 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-2 ]; - if( th_id >= 4 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-4 ]; - if( th_id >= 8 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-8 ]; -#if (WARP == 32) - if( th_id >= 16) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-16]; -#endif - return sh_data[th_id]; -} - -inline -REAL reduce_reg_plus ( __local volatile REAL* sh_data ) { - // perform scan at warp level - REAL res = reduce_reg_plus_warp( sh_data + WARP_FST ); - barrier( CLK_LOCAL_MEM_FENCE ); - - // gather per-warp results in the first WARP elements - if ( TH_ID == WARP_LST ) { - sh_data[ WARP_ID ] = res; - } - barrier(CLK_LOCAL_MEM_FENCE); - - if( TH_ID < WARP ) { - reduce_reg_plus_warp( sh_data ); - } - barrier(CLK_LOCAL_MEM_FENCE); - - if( WARP_ID != 0 ) { - res = res + sh_data[ WARP_ID-1 ]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - sh_data[TH_ID] = res; - barrier(CLK_LOCAL_MEM_FENCE); - -// res = sh_data[ get_local_size(0) - 1 ]; -// barrier(CLK_LOCAL_MEM_FENCE); -// return res; - - return sh_data[ get_local_size(0) - 1 ]; -} - -/*************************************************/ -/*** Irregular, Segmented Reduction With Op. + ***/ -/*************************************************/ - -inline REAL segm_reduce_plus_warp( - __local volatile REAL* ptr, - __local volatile uchar* hd ) { - const uint th_id = TH_ID & (WARP-1); - - if( th_id >= 1 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-1] + ptr[th_id]; - hd [th_id] = hd[th_id - 1] | hd[th_id]; - } - if( th_id >= 2 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-2] + ptr[th_id]; - hd [th_id] = hd[th_id - 2] | hd[th_id]; - } - if( th_id >= 4 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-4] + ptr[th_id]; - hd [th_id] = hd[th_id - 4] | hd[th_id]; - } - if( th_id >= 8 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-8] + ptr[th_id]; - hd [th_id] = hd[th_id - 8] | hd[th_id]; - } -#if (WARP == 32) - if( th_id >= 16 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-16]+ ptr[th_id]; - hd [th_id] = hd[th_id - 16] | hd[th_id]; - } -#endif - return ptr[th_id]; -} - -inline void segm_reduce_plus( - __local volatile REAL *ptr, - __local volatile uchar *hd -) { - // 1a: record whether this warp begins - // with an ``open'' segment. - uchar th_flag = hd[ TH_ID ]; - bool warp_is_open = ( hd[WARP_FST] == 0 ); - barrier(CLK_LOCAL_MEM_FENCE); - - // 1b: intra-warp segmented scan for each warp - REAL val = segm_reduce_plus_warp( ptr + WARP_FST, hd + WARP_FST ); - - // 2a: the last value is the correct partial result - REAL warp_total = ptr[WARP_LST]; - - // 2b: warp_flag is the OR-reduction of the flags - // in a warp, and is computed indirectly from - // the mindex in hd[] - bool warp_flag = hd[WARP_LST]!=0 || !warp_is_open; - bool will_accum= warp_is_open && (hd[TH_ID] == 0); - - barrier(CLK_LOCAL_MEM_FENCE); - - // 2c: the last thread in a warp writes partial results - if( TH_ID == WARP_LST ) { - ptr[WARP_ID] = warp_total; - hd [WARP_ID] = warp_flag; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // 3: one warp scans the per-warp results - if( WARP_ID == 0 ) { - segm_reduce_plus_warp( ptr + WARP_FST, hd + WARP_FST ); - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // 4: accumulate results from step 3: - if ( WARP_ID != 0 && will_accum ) { - val = val + ptr[ WARP_ID-1 ]; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - ptr[TH_ID] = val; - hd [TH_ID] = th_flag; - - barrier(CLK_LOCAL_MEM_FENCE); -} - -/****************************************************/ -/*** Irregular, Segmented Reduce With Op. (+,max) ***/ -/****************************************************/ - -inline REAL2 OP_PLUS_MAX(REAL2 a, REAL2 b) { - return (REAL2) ( a.x + b.x, maxR(a.y, b.y) ); -} - -inline REAL2 segm_reduce_plusmax_warp( - __local volatile REAL2* ptr, - __local volatile uchar* hd ) { - const uint th_id = TH_ID & (WARP-1); - - if( th_id >= 1 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-1], ptr[th_id]); - hd [th_id] = hd[th_id - 1] | hd[th_id]; - } - if( th_id >= 2 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-2], ptr[th_id]); - hd [th_id] = hd[th_id - 2] | hd[th_id]; - } - if( th_id >= 4 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-4], ptr[th_id]); - hd [th_id] = hd[th_id - 4] | hd[th_id]; - } - if( th_id >= 8 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-8], ptr[th_id]); - hd [th_id] = hd[th_id - 8] | hd[th_id]; - } -#if (WARP == 32) - if( th_id >= 16 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-16], ptr[th_id]); - hd [th_id] = hd[th_id - 16] | hd[th_id]; - } -#endif - return ptr[th_id]; -} - -inline void segm_reduce_plusmax( - __local volatile REAL2 *ptr, - __local volatile uchar *hd -) { - // 1a: record whether this warp begins - // with an ``open'' segment. - uchar th_flag = hd[ TH_ID ]; - bool warp_is_open = ( hd[WARP_FST] == 0 ); - barrier(CLK_LOCAL_MEM_FENCE); - - // 1b: intra-warp segmented scan for each warp - REAL2 val = segm_reduce_plusmax_warp( ptr + WARP_FST, hd + WARP_FST ); - - // 2a: the last value is the correct partial result - REAL2 warp_total = ptr[WARP_LST]; - - // 2b: warp_flag is the OR-reduction of the flags - // in a warp, and is computed indirectly from - // the mindex in hd[] - bool warp_flag = hd[WARP_LST]!=0 || !warp_is_open; - bool will_accum= warp_is_open && (hd[TH_ID] == 0); - - barrier(CLK_LOCAL_MEM_FENCE); - - // 2c: the last thread in a warp writes partial results - if( TH_ID == WARP_LST ) { - ptr[WARP_ID] = warp_total; - hd [WARP_ID] = warp_flag; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // 3: one warp scans the per-warp results - if( WARP_ID == 0 ) { - segm_reduce_plusmax_warp( ptr + WARP_FST, hd + WARP_FST ); - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // 4: accumulate results from step 3: - if ( WARP_ID != 0 && will_accum ) { - val = OP_PLUS_MAX( val, ptr[ WARP_ID-1 ] ); - } - - barrier(CLK_LOCAL_MEM_FENCE); - - ptr[TH_ID] = val; - hd [TH_ID] = th_flag; - - barrier(CLK_LOCAL_MEM_FENCE); -} - - -/****************************************************/ -/*** Irregular, Segmented Reduce With Op. (+,max) ***/ -/****************************************************/ - -inline REAL4 OP_PLUS_MIN_MAX( REAL4 a, REAL4 b ) { - return ( REAL4 ) ( a.x + b.x, minR(a.y, b.y), maxR(a.z, b.z), 1.0 ); -} - -inline REAL4 segm_reduce_plusminmax_warp( - __local volatile REAL4* ptr, - __local volatile uchar* hd ) { - const uint th_id = TH_ID & (WARP-1); - - if( th_id >= 1 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-1], ptr[th_id]); - hd [th_id] = hd[th_id - 1] | hd[th_id]; - } - if( th_id >= 2 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-2], ptr[th_id]); - hd [th_id] = hd[th_id - 2] | hd[th_id]; - } - if( th_id >= 4 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-4], ptr[th_id]); - hd [th_id] = hd[th_id - 4] | hd[th_id]; - } - if( th_id >= 8 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-8], ptr[th_id]); - hd [th_id] = hd[th_id - 8] | hd[th_id]; - } -#if (WARP == 32) - if( th_id >= 16 ) { - ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-16], ptr[th_id]); - hd [th_id] = hd[th_id - 16] | hd[th_id]; - } -#endif - return ptr[th_id]; -} - -inline void segm_reduce_plusminmax( - __local volatile REAL4 *ptr, - __local volatile uchar *hd -) { - // 1a: record whether this warp begins - // with an ``open'' segment. - uchar th_flag = hd[ TH_ID ]; - bool warp_is_open = ( hd[WARP_FST] == 0 ); - barrier(CLK_LOCAL_MEM_FENCE); - - // 1b: intra-warp segmented scan for each warp - REAL4 val = segm_reduce_plusminmax_warp( ptr + WARP_FST, hd + WARP_FST ); - - // 2a: the last value is the correct partial result - REAL4 warp_total = ptr[WARP_LST]; - - // 2b: warp_flag is the OR-reduction of the flags - // in a warp, and is computed indirectly from - // the mindex in hd[] - bool warp_flag = hd[WARP_LST]!=0 || !warp_is_open; - bool will_accum= warp_is_open && (hd[TH_ID] == 0); - - barrier(CLK_LOCAL_MEM_FENCE); - - // 2c: the last thread in a warp writes partial results - if( TH_ID == WARP_LST ) { - ptr[WARP_ID] = warp_total; - hd [WARP_ID] = warp_flag; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // 3: one warp scans the per-warp results - if( WARP_ID == 0 ) { - segm_reduce_plusminmax_warp( ptr + WARP_FST, hd + WARP_FST ); - } - - barrier(CLK_LOCAL_MEM_FENCE); - - // 4: accumulate results from step 3: - if ( WARP_ID != 0 && will_accum ) { - val = OP_PLUS_MIN_MAX( val, ptr[ WARP_ID-1 ] ); - } - - barrier(CLK_LOCAL_MEM_FENCE); - - ptr[TH_ID] = val; - hd [TH_ID] = th_flag; - - barrier(CLK_LOCAL_MEM_FENCE); -} - -#endif // REDUCTION_KERNELS diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_opencl_all/SwapCalib.cpp deleted file mode 100644 index 98ab15a..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/SwapCalib.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************/ -/*** Translated to C++ & parallelized ***/ -/*** in OpenCL by Cosmin E. Oancea ***/ -/*** from an original OCaml code ***/ -/*** (sequential) by LexiFi ***/ -/*** and a sequential Python implem ***/ -/*** using a different genetic alg.***/ -/*** by Christian Andreetta ***/ -/****************************************/ - - -#include "Util.h" -#include "Constants.h" -#include "ParseInput.h" -#include "GenAlgFlat.h" - - -int main() -{ - REAL wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, - wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; - REAL* calib_arr = NULL; - - printf("\n// Running GPU-Parallel Swaption-Calibration Benchmark\n"); - - readDataSet( POP_SIZE, MCMC_LOOPS, - NUM_SWAP_QUOTES, SwaptionQuotes, - NUM_HERMITE, HermiteCoeffs, HermiteWeights, - NUM_SOBOL_BITS, SobolDirVct - ); - - unsigned long int elapsed = 0; - { // Main Computational Kernel - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - calib_arr = mainKernelGPU(wg_a, wg_b, wg_sigma, wg_nu, wg_rho, wg_logLik); - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; - } - - { // validation and writeback of the result - bool is_valid = validate( wg_logLik, calib_arr, NUM_SWAP_QUOTES ); - writeStatsAndResult( is_valid, wg_a, wg_b, wg_sigma, wg_nu, wg_rho, - wg_logLik, calib_arr, NUM_SWAP_QUOTES, - true, GPU_CORES, elapsed ); - } - - return 1; -} diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/UtilGPGPU.h b/benchmarks/InterestCalib/implementations/cpp_opencl_all/UtilGPGPU.h deleted file mode 100644 index bb18d8e..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/UtilGPGPU.h +++ /dev/null @@ -1,285 +0,0 @@ -#ifndef GPGPU_UTILITIES -#define GPGPU_UTILITIES - -#include "SDK_stub.h" - -/************************/ -/*** Helper Functions ***/ -/************************/ -bool is_pow2(uint n) { - uint c = 1; - while(c < n) { - c = c << 1; - } - return (c == n); -} - - -struct CpuArrays { - // size of the shape array - const uint SS; - - // shape of the irregular arrays for one genome - short* shape; - - // [13 * POP_SIZE] = - // { a, a_p, b, b_p, rho, rho_p, nu, nu_p, - // sigma, sigma_p, logLik, logLik_p, bf_rat } - REAL* genomes; - - // [ 4 * SS * POP_SIZE ] - REAL* ci_t1cs_scale; - - // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] - REAL* new_quote_price; - - // [ NUM_SWAP_QUOTES*NUM_HERMITE ] - REAL* accum0; - - // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] - // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, - // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } - REAL* scalars; - - REAL gene_ranges[10]; - - CpuArrays (const uint n, short* shp) : SS(n) { - shape = shp; - - genomes = new REAL[ 13 * POP_SIZE ]; - ci_t1cs_scale = new REAL[ 4 * SS * POP_SIZE ]; - scalars = new REAL[ 8 * NUM_SWAP_QUOTES * POP_SIZE ]; - - new_quote_price = new REAL [ 2 * NUM_SWAP_QUOTES * POP_SIZE ]; - accum0 = new REAL [ NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE ]; - - for(int i=0; i<5; i++) { gene_ranges[i] = g_mins[i]; } - for(int i=0; i<5; i++) { gene_ranges[i+5] = g_maxs[i]; } - } - - void releaseResources() { - delete[] shape; - delete[] genomes; - delete[] ci_t1cs_scale; - delete[] scalars; - delete[] new_quote_price; - delete[] accum0; - } - - // genome helpers - REAL* get_a () { return genomes; } - REAL* get_b () { return genomes + POP_SIZE*2; } - REAL* get_rho () { return genomes + POP_SIZE*4; } - REAL* get_nu () { return genomes + POP_SIZE*6; } - REAL* get_sigma () { return genomes + POP_SIZE*8; } - REAL* get_logLik() { return genomes + POP_SIZE*10;} - REAL* get_bf_rat() { return genomes + POP_SIZE*12;} - - // get the shape of the irregular array (for one genome) - short* get_shape (){ return shape; } - - // get the start iterator into arrays ci, t1cs, scale for genome i - REAL* get_ci (int i) { return ci_t1cs_scale + SS*i; } - REAL* get_t1cs (int i) { return ci_t1cs_scale + SS*i + SS*POP_SIZE; } - REAL* get_scale (int i) { return ci_t1cs_scale + SS*i + 2*SS*POP_SIZE; } - REAL* get_bbi (int i) { return ci_t1cs_scale + SS*i + 3*SS*POP_SIZE; } - - // get the start iterator into array-expanded scalars for genome i - REAL* get_mux (int i) { return scalars + i * NUM_SWAP_QUOTES ; } - REAL* get_muy (int i) { return scalars + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_sqsigx(int i) { return scalars + i * NUM_SWAP_QUOTES + 2 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_t2 (int i) { return scalars + i * NUM_SWAP_QUOTES + 3 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_sigrho(int i) { return scalars + i * NUM_SWAP_QUOTES + 4 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_zcmat (int i) { return scalars + i * NUM_SWAP_QUOTES + 5 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_f (int i) { return scalars + i * NUM_SWAP_QUOTES + 6 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_df (int i) { return scalars + i * NUM_SWAP_QUOTES + 7 * NUM_SWAP_QUOTES * POP_SIZE; } - - // get the quotes prices for genome i - REAL* get_quote (int i) { return new_quote_price + i * NUM_SWAP_QUOTES; } - REAL* get_price (int i) { return new_quote_price + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } - - // get the accumulator for the irregular array for genome i - REAL* get_accum (int i) { return accum0 + i * NUM_SWAP_QUOTES * NUM_HERMITE; } -}; - -/**************************************/ -/*** OpenCL related Data Structures ***/ -/**************************************/ -struct OclBuffers { - // Used for BestFit reduction (size LWG_FB) - cl_mem best_ind; - cl_mem best_val; - - cl_mem shape; // [ SS * 4 ] - cl_mem swap_quotes; // [ NUM_SWAP_QUOTES * 4 ] - cl_mem genomes; // [13 * POP_SIZE] - cl_mem ci_t1cs_scale; // [ 4 * SS * POP_SIZE ] - cl_mem new_quote_price; // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] - cl_mem accum0; // [ NUM_SWAP_QUOTES * NUM_HERMITE ] - cl_mem scalars; // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] - - cl_mem gauss_coefs; - cl_mem gauss_weights; - - cl_mem gene_ranges; - cl_mem sobol_dir_vct; - - cl_mem accept_cond; - - - void releaseResources ( ) { - shrLog(stdlog, "Release oclBuffers ... "); - - clReleaseMemObject( best_ind ); - clReleaseMemObject( best_val ); - - clReleaseMemObject( shape ); - clReleaseMemObject( swap_quotes ); - - clReleaseMemObject( genomes ); - clReleaseMemObject( ci_t1cs_scale ); - clReleaseMemObject( new_quote_price ); - clReleaseMemObject( accum0 ); - clReleaseMemObject( scalars ); - - clReleaseMemObject( gauss_coefs ); - clReleaseMemObject( gauss_weights ); - - clReleaseMemObject( gene_ranges ); - clReleaseMemObject( sobol_dir_vct ); - - clReleaseMemObject( accept_cond ); - } -}; - -struct OclObjects { - UINT dev_id; - - cl_command_queue cmdQueue[16]; // OpenCL command queue - cl_context context; // OpenCL context - cl_device_id* devices; // OpenCL device list - cl_program program; // OpenCL program - - cl_command_queue& getCommandQueue() { - return cmdQueue[dev_id]; - } - void releaseResources ( ) { - shrLog(stdlog, "Release OpenCL objects ..."); - clReleaseProgram ( program ); - clReleaseCommandQueue( getCommandQueue() ); - free(devices); - clReleaseContext( context ); - } -}; - - -/******************************************/ -/*** Filling the OpenCL data structures ***/ -/******************************************/ -void compileGPUprog( OclObjects& objs ) { - char compile_option[512]; - -#ifdef MAC - // Build the program with 'mad' Optimization option - char flags[] = "-cl-mad-enable -DMAC "; -#else - char flags[] = ""; -#endif - - //sprintf( compile_option, "-I. -I SrcCL -D TODAY=%10f -D LWG_FB=%d -D INFTY=%f", TODAY, LWG_FB, INFTY ); - sprintf( compile_option, "%s -I. -I SrcCL -I../includeC -D lgWARP=%d -D TODAY=%10f -D LWG_FB=%d -D INFTY=%f -D MAX_DATE=%f -D MIN_DATE=%f -D SOBOL_BITS_NUM=%d", - flags, lgWARP, TODAY, LWG_FB, INFTY, MAX_DATE, MIN_DATE, NUM_SOBOL_BITS ); - - objs.dev_id = 0; - cl_uint nDevice; - build_for_GPU( - objs.context, - objs.cmdQueue, - nDevice, - objs.devices, - objs.program, - objs.dev_id, - compile_option, - "", - "SrcCL/CalibKers" - ); -} - -void makeOclBuffers ( CpuArrays& cpu_arrs, OclObjects& ocl_objs, OclBuffers& ocl_arrs ) { - cl_int ciErr, ciErr2; - size_t cur_size; - cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); - - cur_size = LWG_FB * sizeof(REAL); - ocl_arrs.best_val = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2); ciErr |= ciErr2; - - cur_size = LWG_FB * sizeof(uint); - ocl_arrs.best_ind = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2); ciErr |= ciErr2; - - // for the main kernel(s) - cur_size = 4 * cpu_arrs.SS * sizeof(short); - ocl_arrs.shape = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.shape, CL_TRUE, 0, cur_size, cpu_arrs.shape, 0, NULL, NULL); - - // swaption quotes - cur_size = 4 * NUM_SWAP_QUOTES * sizeof(REAL); - ocl_arrs.swap_quotes = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.swap_quotes, CL_TRUE, 0, cur_size, SwaptionQuotes, 0, NULL, NULL); - - // gene ranges - cur_size = 10 * sizeof(REAL); - ocl_arrs.gene_ranges = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.gene_ranges, CL_TRUE, 0, cur_size, cpu_arrs.gene_ranges, 0, NULL, NULL); - - // sobol direction vector - cur_size = 30 * sizeof(REAL); - ocl_arrs.sobol_dir_vct = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.sobol_dir_vct, CL_TRUE, 0, cur_size, SobolDirVct, 0, NULL, NULL); - - // acceptance condition - cur_size = POP_SIZE * sizeof(unsigned char); - ocl_arrs.accept_cond = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - - // GaussHermite coefficients and weights! - cur_size = NUM_HERMITE * sizeof(REAL); - ocl_arrs.gauss_coefs = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.gauss_coefs, CL_TRUE, 0, cur_size, HermiteCoeffs, 0, NULL, NULL); - ocl_arrs.gauss_weights = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; - ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.gauss_weights, CL_TRUE, 0, cur_size, HermiteWeights, 0, NULL, NULL); - - cur_size = 13 * POP_SIZE * sizeof(REAL); - ocl_arrs.genomes = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; -// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); - - cur_size = 4 * cpu_arrs.SS * POP_SIZE * sizeof(REAL); - ocl_arrs.ci_t1cs_scale = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; -// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.ci_t1cs_scale, CL_TRUE, 0, cur_size, cpu_arrs.ci_t1cs_scale, 0, NULL, NULL); - - cur_size = 2 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(REAL); - ocl_arrs.new_quote_price = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; -// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.new_quote_price, CL_TRUE, 0, cur_size, cpu_arrs.new_quote_price, 0, NULL, NULL); - - cur_size = 8 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(REAL); - ocl_arrs.scalars = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; -// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.scalars, CL_TRUE, 0, cur_size, cpu_arrs.scalars, 0, NULL, NULL); - - cur_size = NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE * sizeof(REAL); - ocl_arrs.accum0 = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; -// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.accum0, CL_TRUE, 0, cur_size, cpu_arrs.accum0, 0, NULL, NULL); - - oclCheckError(ciErr, CL_SUCCESS); -} - -void initGPUresources ( CpuArrays& cpu_arrs, OclObjects& ocl_objs, OclBuffers& ocl_arrs ) { - compileGPUprog ( ocl_objs ); - makeOclBuffers ( cpu_arrs, ocl_objs, ocl_arrs ); -} - -void releaseGPUresources( OclObjects& ocl_objs, OclBuffers& ocl_arrs ) { - fprintf(stderr, "Releasing GPU Resources ... "); - ocl_arrs.releaseResources(); - ocl_objs.releaseResources(); - fprintf(stderr, "OK!\n"); -} - -#endif // GPGPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl_all/instantiate b/benchmarks/InterestCalib/implementations/cpp_opencl_all/instantiate deleted file mode 100755 index 5b32e00..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_opencl_all/instantiate +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -e - -cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/include/ParserC.h . -cp $FINPAR_LIB_DIR/include/Util.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT outer num_x num_y num_t > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run < best_lik ) { best_ind = i; best_lik = val; } - } -} - -Move_Type selectMoveType(REAL move_selected) { - Move_Type move_type = NONE; - - REAL prob; - Move_Type type; - UINT k = 0; - do { - prob = mcmc_moves_selection_cumdensfct[k].fst; - type = mcmc_moves_selection_cumdensfct[k].snd; - - if( move_selected <= prob ) { - move_type = type; - } - k ++; - } while ( move_selected > prob && k < CUMDENSFCT_CARD ); - - assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); - - return move_type; -} - -/** - * Main Entry Point for Swaption Calibration - * The (out) arguments are in fact the resulted - * winning genome result & its likelihood. - * The array result has size 3*NUM_SWAP_QUOTES - * and records for each swaption the calibrated - * price, the black price and the percentage - * difference between the two. - */ -REAL* mainKernelCPU(REAL& wg_a, - REAL& wg_b, - REAL& wg_sigma, - REAL& wg_nu, - REAL& wg_rho, - REAL& wg_logLik -) { - uint FLAT_SZ; - short* shape = getIregShapeAdjusted( LWG_EG, FLAT_SZ ); - int * start_inds = getStartInd( FLAT_SZ, shape, NUM_SWAP_QUOTES ); - - CpuArrays cpu_arrs(FLAT_SZ, shape); - REAL *g_a, *g_b, *g_rho, *g_nu, *g_sigma, *logLik, *bf_rat; - { // getting the cpu arrays - g_a = cpu_arrs.get_a (); - g_b = cpu_arrs.get_b (); - g_rho = cpu_arrs.get_rho (); - g_nu = cpu_arrs.get_nu (); - g_sigma = cpu_arrs.get_sigma (); - logLik = cpu_arrs.get_logLik(); - bf_rat = cpu_arrs.get_bf_rat(); - } - - srand ( SEED ); - srand48 ( SEED ); - - // initialized the genomes with random numbers inside - // their acceptable bounds => requires 5*POP_SIZE randoms - for( int i = 0; i < POP_SIZE; i++ ) { - REAL r01, tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; - g_a [i ] = tmp; - g_a [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; - g_b [i ] = tmp; - g_b [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; - g_rho [i ] = tmp; - g_rho [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; - g_nu [i ] = tmp; - g_nu [i + POP_SIZE] = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; - g_sigma [i ] = tmp; - g_sigma [i + POP_SIZE] = tmp; - - bf_rat [i ] = 1.0; - } - - // Initial evaluation of the genomes! -#pragma omp parallel for default(shared) schedule(dynamic) if(POP_SIZE>3) - for( int i = 0; i < POP_SIZE; i++ ) { - logLik[i] = eval_genome( g_a[i], g_b[i], g_rho[i], g_nu[i], g_sigma[i], - cpu_arrs.get_quote(i), cpu_arrs.get_price(i), - FLAT_SZ, shape, start_inds - ); - } - - // convergence loop that runs the genetic algorithms - // (takes a population and returns a population) - for( int j = 0; j < MCMC_LOOPS; j++ ) { - - // select which move to perform. - // Note: this block can also be a loop (in fixed order) - // over the various move types - REAL move_selected = getRandUnifNorm(); - Move_Type move_type = selectMoveType(move_selected); - - if ( move_type == DIMS_ALL ) { - for( int i = 0; i < POP_SIZE; i++ ) { - mutate_dims_all( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); - } - - } else if ( move_type == DIMS_ONE ) { - - UINT dim_j = getRandIntNorm(GENOME_DIM); - - for( int i = 0; i < POP_SIZE; i++ ) { - mutate_dims_one( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i, dim_j ); - } - } else /* if ( move_type == DEMCMC ) */ { - - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums - mcmc_DE( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); - } - } - - // evaluate the proposal -#pragma omp parallel for default(shared) schedule(dynamic) if(POP_SIZE>3) - for( int i = 0; i < POP_SIZE; i++ ) { - logLik[i+POP_SIZE] = - eval_genome( g_a [i+POP_SIZE], g_b [i+POP_SIZE], g_rho[i+POP_SIZE], - g_nu[i+POP_SIZE], g_sigma[i+POP_SIZE], - cpu_arrs.get_quote(i), cpu_arrs.get_price(i), - FLAT_SZ, shape, start_inds ); - } - - // mcmc_acceptance_rejection(); - // Deciding whether to accept or reject the proposal, - // obtained by mutating/crossover of the individual. - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel - // Metropolis: get a random U[0,1) for each candidate - REAL rand = getRandUnifNorm(); - - // selection: dimensions considered independent - // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) - REAL acceptance = std::min( 1.0, exp( logLik[i+POP_SIZE] - logLik[i] ) * bf_rat[i] ); - - // if acceptance criterion is met then p->p' else does nothing - if ( rand < acceptance ) accept( i, g_a, g_b, g_rho, g_nu, g_sigma, logLik ); - } - - // print best candidate for the current iteration: - if ( (j % 16) == 0 ){ - int best_ind; REAL best_lik; - find_best(logLik, best_ind, best_lik); - fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", - j, best_lik, best_ind ); - } - } - - REAL* result; - { // print best candidate for the current iteration: - int best_ind; REAL best_lik; - find_best(logLik, best_ind, best_lik); - - // recompute the calibrated price and the black price! - logLik[best_ind] = - eval_genome( g_a[best_ind], g_b[best_ind], g_rho[best_ind], g_nu[best_ind], - g_sigma[best_ind], cpu_arrs.get_quote(best_ind), - cpu_arrs.get_price(best_ind), FLAT_SZ, shape, start_inds ); - - // Finally, make/print the result! - wg_a = cpu_arrs.get_a() [best_ind]; - wg_b = cpu_arrs.get_b() [best_ind]; - wg_sigma = cpu_arrs.get_sigma ()[best_ind]; - wg_nu = cpu_arrs.get_nu() [best_ind]; - wg_rho = cpu_arrs.get_rho() [best_ind]; - wg_logLik = cpu_arrs.get_logLik()[best_ind]; - - result = makeSummary( best_ind, cpu_arrs ); - } - - delete[] start_inds; - // Releasing the CPU resources: - cpu_arrs.releaseResources(); - - return result; -} - -#endif // end ifndef - diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/Makefile b/benchmarks/InterestCalib/implementations/cpp_openmp_outer/Makefile deleted file mode 100644 index 8817c4f..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -include setup.mk - -ifndef ($(HAVE_GPU)) -include platform.mk -endif - -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -#-fno-unsafe-math-optimizations -fno-finite-math-only -#-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans - -SOURCES_CPP =SwapCalib.cpp -OBJECTS =SwapCalib.o -EXECUTABLE =SwapCalib - - -default: cpu - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -# The GPU version is in: ../CppAndGPU. This folder is CPU only! -gpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - -cpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) - diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib b/benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib deleted file mode 100755 index 9cc25976a5063b0509d9e19b065e77112a96db87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80848 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 diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib.cpp deleted file mode 100644 index 280d767..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/SwapCalib.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************/ -/*** Translated to C++ & parallelized ***/ -/*** in OpenCL by Cosmin E. Oancea ***/ -/*** from an original OCaml code ***/ -/*** (sequential) by LexiFi ***/ -/*** and a sequential Python implem ***/ -/*** using a different genetic alg.***/ -/*** by Christian Andreetta ***/ -/****************************************/ - -#include "Util.h" -#include "Constants.h" -#include "ParseInput.h" -#include "GenAlgFlat.h" -#include "WriteResult.h" - -int main() -{ - REAL wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, - wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; - REAL* calib_arr = NULL; - - printf("\n// Running Original (CPU Parallel) Swaption-Calibration Benchmark\n"); - - readDataSet( POP_SIZE, MCMC_LOOPS, - NUM_SWAP_QUOTES, SwaptionQuotes, - NUM_HERMITE, HermiteCoeffs, HermiteWeights, - NUM_SOBOL_BITS, SobolDirVct - ); - - unsigned long int elapsed_usec = 0; - { // Main Computational Kernel - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - calib_arr = mainKernelCPU(wg_a, wg_b, wg_sigma, wg_nu, wg_rho, wg_logLik); - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; - } - - { // validation and writeback of the result - FILE* runtime = fopen("runtime.txt", "w"); - FILE* result = fopen("result.json", "w"); - const int Ps = get_CPU_num_threads(); - fprintf(runtime, "%d\n", elapsed_usec / 1000); - fclose(runtime); - - writeResult(result, - wg_a, - wg_b, - wg_sigma, - wg_nu, - wg_rho, - wg_logLik, - calib_arr); - - fclose(result); - } - - return 0; -} - - -#if 0 -void test_all() { - test_dates (); - test_math (); - test_g2ppUtil (); - test_pricer_of_swaption(); -} -#endif diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/UtilCPU.h b/benchmarks/InterestCalib/implementations/cpp_openmp_outer/UtilCPU.h deleted file mode 100644 index 4ed4ec9..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/UtilCPU.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef CPU_UTILITIES -#define CPU_UTILITIES - -/************************/ -/*** Helper Functions ***/ -/************************/ -bool is_pow2(uint n) { - uint c = 1; - while(c < n) { - c = c << 1; - } - return (c == n); -} - - -struct CpuArrays { - // size of the shape array - const uint SS; - - // shape of the irregular arrays for one genome - short* shape; - - // [13 * POP_SIZE] = - // { a, a_p, b, b_p, rho, rho_p, nu, nu_p, - // sigma, sigma_p, logLik, logLik_p, bf_rat } - REAL* genomes; - - // [ 4 * SS * POP_SIZE ] - REAL* ci_t1cs_scale; - - // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] - REAL* new_quote_price; - - // [ NUM_SWAP_QUOTES*NUM_HERMITE ] - REAL* accum0; - - // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] - // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, - // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } - REAL* scalars; - - REAL gene_ranges[10]; - - CpuArrays (const uint n, short* shp) : SS(n) { - shape = shp; - - genomes = new REAL[ 13 * POP_SIZE ]; - ci_t1cs_scale = new REAL[ 4 * SS * POP_SIZE ]; - scalars = new REAL[ 8 * NUM_SWAP_QUOTES * POP_SIZE ]; - - new_quote_price = new REAL [ 2 * NUM_SWAP_QUOTES * POP_SIZE ]; - accum0 = new REAL [ NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE ]; - - for(int i=0; i<5; i++) { gene_ranges[i] = g_mins[i]; } - for(int i=0; i<5; i++) { gene_ranges[i+5] = g_maxs[i]; } - } - - void releaseResources() { - delete[] shape; - delete[] genomes; - delete[] ci_t1cs_scale; - delete[] scalars; - delete[] new_quote_price; - delete[] accum0; - } - - // genome helpers - REAL* get_a () { return genomes; } - REAL* get_b () { return genomes + POP_SIZE*2; } - REAL* get_rho () { return genomes + POP_SIZE*4; } - REAL* get_nu () { return genomes + POP_SIZE*6; } - REAL* get_sigma () { return genomes + POP_SIZE*8; } - REAL* get_logLik() { return genomes + POP_SIZE*10;} - REAL* get_bf_rat() { return genomes + POP_SIZE*12;} - - // get the shape of the irregular array (for one genome) - short* get_shape (){ return shape; } - - // get the start iterator into arrays ci, t1cs, scale for genome i - REAL* get_ci (int i) { return ci_t1cs_scale + SS*i; } - REAL* get_t1cs (int i) { return ci_t1cs_scale + SS*i + SS*POP_SIZE; } - REAL* get_scale (int i) { return ci_t1cs_scale + SS*i + 2*SS*POP_SIZE; } - REAL* get_bbi (int i) { return ci_t1cs_scale + SS*i + 3*SS*POP_SIZE; } - - // get the start iterator into array-expanded scalars for genome i - REAL* get_mux (int i) { return scalars + i * NUM_SWAP_QUOTES ; } - REAL* get_muy (int i) { return scalars + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_sqsigx(int i) { return scalars + i * NUM_SWAP_QUOTES + 2 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_t2 (int i) { return scalars + i * NUM_SWAP_QUOTES + 3 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_sigrho(int i) { return scalars + i * NUM_SWAP_QUOTES + 4 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_zcmat (int i) { return scalars + i * NUM_SWAP_QUOTES + 5 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_f (int i) { return scalars + i * NUM_SWAP_QUOTES + 6 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_df (int i) { return scalars + i * NUM_SWAP_QUOTES + 7 * NUM_SWAP_QUOTES * POP_SIZE; } - - // get the quotes prices for genome i - REAL* get_quote (int i) { return new_quote_price + i * NUM_SWAP_QUOTES; } - REAL* get_price (int i) { return new_quote_price + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } - - // get the accumulator for the irregular array for genome i - REAL* get_accum (int i) { return accum0 + i * NUM_SWAP_QUOTES * NUM_HERMITE; } -}; -#endif // CPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/instantiate b/benchmarks/InterestCalib/implementations/cpp_openmp_outer/instantiate deleted file mode 100755 index 38705e6..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_openmp_outer/instantiate +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -set -e - -cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/include/ParserC.h . -cp $FINPAR_LIB_DIR/include/Util.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/KerConsts.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Date.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/GenAlgUtil.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Candidate.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/IrregShape.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/EvalGenomeInl.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/G2PP.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/G2ppUtil.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/MathModule.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/WriteResult.h . -cp $FINPAR_IMPLEMENTATION/GenAlgFlat.h . -cp $FINPAR_IMPLEMENTATION/UtilCPU.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run <(12.0 * swaption[2] / swap_freq); - const REAL tmat0 = date_act_365( maturity, TODAY ); - - REAL strike; - { // BLACK PRICE computation - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; - - for(UINT i = 0; i < n_schedi; i++) { // reduce o map - // Map computes a1 and a2 (depends on i) - const REAL a1 = add_months( maturity, swap_freq*i ); - const REAL a2 = add_months( a1, swap_freq ); - - // Reduction( lvl: +, t0 : min, tn : max ) - lvl += zc(a2) * date_act_365(a2, a1); - t0 = std::min(t0, a1); - tn = std::max(tn, a2); - } - - strike = ( zc(t0) - zc(tn) ) / lvl; - const REAL d1 = 0.5 * swaption[3] * tmat0; - new_quote = lvl * strike * ( uGaussian_P(d1) - uGaussian_P(-d1) ); - } // END BLACK PRICE - - { // PRICER OF SWAPTION COMPUTATION - REAL v0_mat, dummy1, dummy2; - bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); -// - const REAL mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); - const REAL muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); -// - const REAL zc_mat = zc(maturity); -// - const REAL sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); - const REAL sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); - const REAL rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); - const REAL sigmax = sigma * sqrt_bfun_a; - const REAL sigmay = nu * sqrt_bfun_b; - - const REAL rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel - const REAL rhoxycs = sqrt( rhoxyc ); // used in reduction kernel - const REAL sigmay_rhoxycs = sigmay * rhoxycs; - const REAL t4 = (rhoxy * sigmay) / sigmax; - - for( UINT i = 0; i < n_schedi; i++ ) { - const REAL beg_date = add_months( maturity, swap_freq*i ); //scheduleix[i]; - const REAL end_date = add_months( beg_date, swap_freq ); //scheduleiy[i]; - const REAL res = date_act_365( end_date, beg_date ) * strike; - - const REAL cii = ( i == n_schedi-1 ) ? 1.0 + res : res; - - REAL v0_end, vt_end, baii, bbii, date_tod1, date_tod2; - date_tod1 = date_act_365(end_date, TODAY); - bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); - date_tod2 = date_act_365(end_date, maturity); - bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); - - const REAL expo_aici = 0.5 * (vt_end - v0_end + v0_mat); - const REAL fact_aici = cii * zc(end_date) / zc_mat; - tmp_arrs[i].ci = fact_aici; // reuse the space to hold the factor of t1_cs - tmp_arrs[i].t1_cs = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; - // hold only the exponent of the original t1_cs; - - tmp_arrs[i].bai = baii; - tmp_arrs[i].bbi = bbii; - tmp_arrs[i].aici = fact_aici * exp( expo_aici ); - tmp_arrs[i].log_aici = log( fact_aici ) + expo_aici; - tmp_arrs[i].scale = - ( baii + bbii * t4 ); - - sanity = ! ( isinf(tmp_arrs[i].aici) || isnan(tmp_arrs[i].aici) ); - assert(sanity && "Nan aici in pricer of swaption. Exiting!\n"); - } - - const REAL eps = 0.5 * sigmax; - - const REAL f = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, - mux, muy, tmp_arrs, mux ); - - const REAL g = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, - mux, muy, tmp_arrs, mux + eps ); - - const REAL h = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, - mux, muy, tmp_arrs, mux - eps ); - - const REAL df = 0.5 * ( g - h ) / eps; - - const REAL sqrt2sigmax = sqrt(2.0) * sigmax;; - const REAL t2 = rhoxy / (sigmax*rhoxycs);; - - REAL accum = 0.0; - - for( UINT j = 0; j < NUM_HERMITE; j++ ) { - const REAL x_quad = HermiteCoeffs [j]; - const REAL w_quad = HermiteWeights[j]; - - const REAL x = sqrt2sigmax * x_quad + mux; - const REAL yhat_x = f + df*(x - mux); - const REAL h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); - - REAL accum1 = 0.0; - for( UINT i = 0; i < n_schedi; i++ ) { - const REAL h2 = h1 + tmp_arrs[i].bbi * sigmay_rhoxycs; - - const REAL expo_aici = tmp_arrs[i].t1_cs + tmp_arrs[i].scale*x; - const REAL fact_aici = tmp_arrs[i].ci; - const REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); - accum1 += fact_aici * expo_part; - } - - sanity = ! ( isnan(accum1) || isinf(accum1) ); - assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); - - REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; - const REAL t1 = exp( - 0.5 * tmp * tmp ); - - accum += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); - } - - sanity = ! ( isnan(accum) || isinf(accum) ); - assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); - - new_price = zc_mat * ( accum / sqrt( PI ) ); - } -} - - - -#endif // end ifndef EVAL_GENOME_INLINED - diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h b/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h deleted file mode 100644 index 5f324a4..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef G2PPORIG -#define G2PPORIG - -#include "Constants.h" -#include "Date.h" -#include "MathModule.h" -#include "G2ppUtil.h" - -#include "GenAlgUtil.h" - -REAL to_solve_orig( const UINT& N, - const IntermElem* tmp_arrs, - const REAL& yhat ) { - REAL accum = 0.0; - for( UINT i = 0; i < N; i++ ) { - accum += tmp_arrs[i].hat_scale * exp( - tmp_arrs[i].bbi * yhat ); - } - return accum - 1.0; -} - -////////////////////////// -// Root finder -////////////////////////// - -void rootFinding_Brent_orig ( - const UINT& N, - IntermElem* tmp_arrs, - const REAL& lb, - const REAL& ub, - const REAL& toll, - const UINT& it_mx, - REAL& root, // result - UINT& it, - REAL& fb -) { - const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; - const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; - - REAL a = lb, b = ub; - - REAL fa = to_solve_orig(N, tmp_arrs, a); - fb = to_solve_orig(N, tmp_arrs, b); - - if( fa*fb >= 0.0 ) { - root = 0.0; it = 0; - if ( a >= 0.0 ) fb = INFTY; - else fb = -INFTY; - return; - } - - if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } - - REAL c = a, fc = fa; - bool mflag = true; - REAL d = 0.0; - it = 0; - - for( UINT i = 0; i < iter_max; i++ ) { - if ( fb != 0.0 && fabs(b-a) >= tol ) { - REAL s; - if( fa == fc || fb == fc ) { - s = b - fb * (b - a) / (fb - fa); - } else { - REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); - REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); - REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); - s = s1 + s2 + s3; - } - - if ( ( (3.0 * a + b) /4.0 > s || s > b) || - ( mflag && fabs(b-c)/2.0 <= fabs(s-b) ) || - ( !mflag && fabs(c-d)/2.0 <= fabs(s-b) ) || - ( mflag && fabs(b-c) <= fabs(tol) ) || - ( !mflag && fabs(c-d) <= fabs(tol) ) ) { - mflag = true; - s = (a + b) / 2.0; - } else { - mflag = false; - } - - REAL fs = to_solve_orig(N, tmp_arrs, s); - - // d is assigned for the first time here: - // it's not used above because mflag is set - d = c; - c = b; fc = fb; - - if( fa*fs < 0.0 ) { b = s; fb = fs; } - else { a = s; fa = fs; } - - if( fabs(fa) < fabs(fb) ) { - REAL tmp; - tmp = a; a = b; b = tmp; - tmp = fa; fa = fb; fb = tmp; - } - - // reporting non-convergence! - if(i == iter_max-1) { - printf("# ERROR: Brent method not converged, error: %f %f %d\n\n", b, fb, i); - } - - it = i; - } - } - - root = b; - - //return BrentRes(b, it, fb); -} - -REAL exactYhatOrig( - const UINT& n_schedi, - - const REAL& b, // scals begins - const REAL& sigmax, - const REAL& sigmay, - const REAL& rhoxy, - const REAL& rhoxyc, - const REAL& rhoxycs, - const REAL& mux, - const REAL& muy, // scals ends - IntermElem* tmp_arrs, - - const REAL& x // output -) { - // ugaussian_Pinv(k)=1.0e~4 - const REAL k = - 3.71901648545568; - - REAL up = 0.0, lo = -INFTY; - for( UINT i = 0; i < n_schedi; i++ ) { - REAL baix = tmp_arrs[i].bai * x; - - REAL up_term = tmp_arrs[i].aici * exp( -baix ); - tmp_arrs[i].hat_scale = up_term; - up += up_term; - lo = std::max( lo, ( tmp_arrs[i].log_aici - baix ) / tmp_arrs[i].bbi ); - } - -// CHECKING uplo!!!! - - const REAL log_s = log(up); - REAL tmp = log_s / tmp_arrs[n_schedi-1].bbi; - - if ( tmp <= 0.0 ) { - up = tmp; - } else { - tmp = log_s / tmp_arrs[0].bbi; - if ( 0.0 <= tmp ) up = tmp; - else up = - INFTY; - } - - const REAL yl = lo - EPS; - const REAL yu = up + EPS; - - const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; - const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; - - REAL res; - if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS - else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) - else { - const REAL root_lb = std::max( yl, y0 ); - const REAL root_ub = std::min( yu, y1 ); - - REAL root, error; UINT iter; - rootFinding_Brent_orig(n_schedi, tmp_arrs, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); - //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); - - res = ( error == -INFTY ) ? y0 - 1.0 : ( error == INFTY ) ? y1 + 1.0 : root; - } - - return res; -} - - -#endif // ifndef G2PP diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h deleted file mode 100644 index 3643bc3..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h +++ /dev/null @@ -1,281 +0,0 @@ -#ifndef GEN_ALG_FLAT -#define GEN_ALG_FLAT - -using namespace std; - -#include "Constants.h" -#include "GenAlgUtil.h" -#include "Genome.h" -#include "UtilCPU.h" -#include "EvalGenomeOrig.h" - - -/** - * Printing Swaption / Calibrated Price / Black Price / RMS - * The result is an array REAL[NUM_SWAP_QUOTES, 3] recording - * for each swaption the calibrated price, the black price - * and the percentagewise difference between the two. - */ -void makeSummary( const int winner, - const Genome& wgene, - const REAL* new_quote, - const REAL* new_price, - REAL* result // output -) { - REAL rms = 0.0; - - fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); - fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", - wgene.a, wgene.b, wgene.sigma, wgene.nu, wgene.rho, wgene.logLik ); - fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); - - for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { - REAL black_price = new_quote[i]; - REAL calib_price = new_price[i]; - REAL err_ratio = (calib_price - black_price) / black_price; - - result[3*i + 0] = 10000.0*calib_price; - result[3*i + 1] = 10000.0*black_price; - result[3*i + 2] = 100.0*fabs(err_ratio); - - rms += err_ratio * err_ratio; - - fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", - i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], - result[3*i + 0], result[3*i + 1], result[3*i + 2] ); - } - - rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); - fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); -} - - -/** - * Utility function: find the genome with the best likelihood: - * scans the logLik array and fill in the index and likelihood - * of the best genome. - */ -void find_best(const Genome* genomes, int& best_ind, REAL& best_lik) { - bool sanity = true; - - best_lik = -INFINITY; - best_ind = 0; - - // this is in fact a reduction, but POP_SIZE is - // not big enough to warrant a parallel execution. - for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX - REAL val = genomes[i].logLik; - - sanity = !( isnan(val) || isinf(val) ); - assert( sanity && "val is NaN in find_best" ); - - if( val > best_lik ) { best_ind = i; best_lik = val; } - } -} - -Move_Type selectMoveType(REAL move_selected) { - Move_Type move_type = NONE; - - REAL prob; - Move_Type type; - UINT k = 0; - do { - prob = mcmc_moves_selection_cumdensfct[k].fst; - type = mcmc_moves_selection_cumdensfct[k].snd; - - if( move_selected <= prob ) { - move_type = type; - } - k ++; - } while ( move_selected > prob && k < CUMDENSFCT_CARD ); - - assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); - - return move_type; -} - -/** - * Main Entry Point for Swaption Calibration - * The (out) arguments are in fact the resulted - * winning genome result & its likelihood. - * The array result has size 3*NUM_SWAP_QUOTES - * and records for each swaption the calibrated - * price, the black price and the percentage - * difference between the two. - */ -REAL* mainKernelSeqCPU( Genome& winner ) { - - UINT n_schedi_max = 0; - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - const UINT n_schedi = static_cast(12.0 * SwaptionQuotes[4*ttt+2] / SwaptionQuotes[4*ttt+1]); - n_schedi_max = max(n_schedi_max, n_schedi); - } - - SeqArrays cpu_arrs(n_schedi_max); - Genome* genomes = cpu_arrs.genomes; - - srand ( SEED ); - srand48 ( SEED ); - - // initialized the genomes with random numbers inside - // their acceptable bounds => requires 5*POP_SIZE randoms - for( int i = 0; i < POP_SIZE; i++ ) { - REAL r01, tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; - genomes[i].a = genomes[i+POP_SIZE].a = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; - genomes[i].b = genomes[i+POP_SIZE].b = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; - genomes[i].rho = genomes[i+POP_SIZE].rho = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; - genomes[i].nu = genomes[i+POP_SIZE].nu = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; - genomes[i].sigma = genomes[i+POP_SIZE].sigma = tmp; - -// genomes[i].fbRat = genomes[i+POP_SIZE].fbRat = 1.0; - } - - // Initial evaluation of the genomes! - REAL quote, price; - for( int i = 0; i < POP_SIZE; i++ ) { - Genome& gene = genomes[i]; - REAL rms = 0.0; - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - eval_genome_new ( - gene.a, gene.b, gene.rho, gene.nu, gene.sigma, - SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price - ); - rms += logLikelihood( quote, price ); - } - gene.logLik = rms; - } - - // convergence loop that runs the genetic algorithms - // (takes a population and returns a population) - for( int j = 0; j < MCMC_LOOPS; j++ ) { - - // select which move to perform. - // Note: this block can also be a loop (in fixed order) - // over the various move types - REAL move_selected = getRandUnifNorm(); - Move_Type move_type = selectMoveType(move_selected); - - if ( move_type == DIMS_ALL ) { - for( int i = 0; i < POP_SIZE; i++ ) { - genomes[i+POP_SIZE].mutate_dims_all( genomes[i] ); - } - - } else if ( move_type == DIMS_ONE ) { - - UINT dim_j = getRandIntNorm(GENOME_DIM); - - for( int i = 0; i < POP_SIZE; i++ ) { - genomes[i+POP_SIZE].mutate_dims_one( genomes[i], dim_j ); - } - } else /* if ( move_type == DEMCMC ) */ { - - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums - // compute the k^th and the l^th genes - UINT cand_UB = POP_SIZE - 1; - UINT k = getRandIntNorm(cand_UB); // random in [0,pop_size-1) - if ( k == i ) { - k = cand_UB; - cand_UB -= 1; - } - UINT l = getRandIntNorm(cand_UB); - if ( l == i || l == k ) { - l = cand_UB; - } - - // do DEMCMC base on k^th and l^th genomes - genomes[i+POP_SIZE].mcmc_DE( genomes[i], genomes[k], genomes[l] ); - } - } - - // evaluate the proposals - for( int i = 0; i < POP_SIZE; i++ ) { - Genome& gene = genomes[i+POP_SIZE]; - - REAL rms = 0.0; - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - eval_genome_new ( - gene.a, gene.b, gene.rho, gene.nu, gene.sigma, - SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price - ); - rms += logLikelihood( quote, price ); - } - gene.logLik = rms; - } - - // mcmc_acceptance_rejection(); - // Deciding whether to accept or reject the proposal, - // obtained by mutating/crossover of the individual. - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel - // Metropolis: get a random U[0,1) for each candidate - REAL rand = getRandUnifNorm(); - - Genome& orig = genomes[i]; - Genome& muta = genomes[i+POP_SIZE]; - // selection: dimensions considered independent - // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) - REAL acceptance = std::min( 1.0, exp( muta.logLik - orig.logLik ) * muta.fbRat ); - - // if acceptance criterion is met then p->p' else does nothing - if ( rand < acceptance ) - orig = muta; - } - - // print best candidate for the current iteration: - if ( (j % 16) == 0 ){ - int best_ind; REAL best_lik; - find_best(genomes, best_ind, best_lik); - fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", - j, best_lik, best_ind ); - } - } - - REAL* result = new REAL[3*NUM_SWAP_QUOTES]; - { // print best candidate for the current iteration: - int best_ind; REAL best_lik; - find_best(genomes, best_ind, best_lik); - //winner = genomes[best_ind]; - winner.a = genomes[best_ind].a; winner.b = genomes[best_ind].b; - winner.rho = genomes[best_ind].rho; winner.nu = genomes[best_ind].nu; - winner.sigma = genomes[best_ind].sigma; winner.logLik = genomes[best_ind].logLik; - - // recompute the calibrated price and the black price! - REAL* quotes = cpu_arrs.get_quote(); - REAL* prices = cpu_arrs.get_price(); - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - eval_genome_new ( - winner.a, winner.b, winner.rho, winner.nu, winner.sigma, - SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price - ); - quotes[ttt] = quote; - prices[ttt] = price; - } - - - - // write summary - makeSummary( best_ind, winner, quotes, prices, result ); - } - - // Releasing the CPU resources: - cpu_arrs.releaseResources(); - - return result; -} - -#endif // end ifndef GEN_ALG_FLAT - diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h b/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h deleted file mode 100644 index a99d977..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h +++ /dev/null @@ -1,238 +0,0 @@ -#ifndef CANDIDATE_CLASS -#define CANDIDATE_CLASS - -#include "Constants.h" -#include "GenAlgUtil.h" - - -//========================================================================= -/** - * Candidate: - * - identified by parameters (target, and nuisance) - * - holds one proposal, to be accepted or rejected - * - holds fitness results - * - holds MCMC selection regions - * Population: - * - container of candidates - * - container of proposals - * - caller of mutation functions - * - select if to keep/update candidates and proposals - * MCMC: moves: - * - TODO: Gibbs sampling: single dimension update - * - all dimensions update - * - crossover - */ -//========================================================================= - -/** - * Genome min/max ranges and proposed initial values (not used) - * { g_a, g_b, g_rho, g_nu, g_sigma } - */ -const REAL g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; -const REAL g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; -const REAL g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; -//const REAL Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; - - -/** - * perturbing a genome; requires one random uniform number in [0,1) - */ -inline -REAL perturbation( - const REAL gene, - const REAL gene_k, - const REAL gene_l, - const UINT i, - const REAL gamma1, - const REAL amplitude_ratio -) { - REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - REAL semiamplitude = amplitude / 2.0; - REAL r01 = getRandRandNorm(); - REAL perturb = ( amplitude * r01 - semiamplitude ); - - return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); -} - -/* - * contraining gene i to be within accepted bounds! - */ -inline -REAL constrain_dim1( const int i, const REAL gene ) { - return std::max( g_mins[i], std::min( g_maxs[i], gene ) ); -} - - -/** - * Helper mutate function: requires one uniform random number - */ -Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int i, const REAL amplitude_ratio ) { - REAL forward_range, backward_range; - REAL tmp_min_max, tmp_max_min; - - const REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - const REAL semiamplitude = amplitude / 2.0; - - tmp_min_max = std::min( g_maxs[i], gene + semiamplitude ); - tmp_max_min = std::max( g_mins[i], gene - semiamplitude ); - forward_range = tmp_min_max - tmp_max_min; - - tmp_min_max = std::min( g_maxs[i], gene_prop + semiamplitude ); - tmp_max_min = std::max( g_mins[i], gene_prop - semiamplitude ); - backward_range = tmp_min_max - tmp_max_min; - - const REAL bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; - - // assign p' - REAL r01 = getRandRandNorm(); - REAL diff = amplitude * r01 - semiamplitude; - return Tuple(gene + diff, bf_fact); -} - - -struct Genome { - REAL a; - REAL b; - REAL rho; - REAL nu; - REAL sigma; - REAL logLik; - REAL fbRat; - REAL padding; - - Genome() { - this->a = 0.0; this->b = 0.0; this->rho = 0.0; - this->nu = 0.0; this->sigma = 0.0; this->logLik = 0.0; - this->fbRat = 0.0; - } - Genome( const REAL a, const REAL b, const REAL rho, const REAL nu, - const REAL sigma, const REAL logLik, const REAL fbRat) { - this->a = a; this->b = b; this->rho = rho; - this->nu = nu; this->sigma = sigma; this->logLik = logLik; - this->fbRat = fbRat; - } - Genome(const Genome& gene) { - this->a = gene.a; this->b = gene.b; this->rho = gene.rho; - this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; - this->fbRat = gene.fbRat; - } - Genome& operator=(const Genome& gene) { - this->a = gene.a; this->b = gene.b; this->rho = gene.rho; - this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; - this->fbRat = gene.fbRat; - return (*this); - } - - - /** - * mutate all dimensions. martingale with uniform prior. - * requires 5 * POP_SIZE uniform random numbers! - * I took out the evaluation of the proposal, since it should be - * done for all types of crossover/mutation/etc - */ - void mutate_dims_all( const Genome& orig, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { - REAL fb_rat = 1.0; - Tuple tmp(EPS0, 1.0); - - tmp = mutate_helper( orig.a, this->a, 0, amplitude_ratio ); - this->a = constrain_dim1(0, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.b, this->b, 1, amplitude_ratio ); - this->b = constrain_dim1(1, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.rho, this->rho, 2, amplitude_ratio ); - this->rho = constrain_dim1(2, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.nu, this->nu, 3, amplitude_ratio ); - this->nu = constrain_dim1(3, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.sigma, this->sigma, 4, amplitude_ratio ); - this->sigma = constrain_dim1(4, tmp.fst); - fb_rat *= tmp.snd; - - this->fbRat = fb_rat; - } - - /** - * mutate ONE dimension (Gibbs sampling). martingale with uniform prior - * dimension to be changed is given as input: has to be the same for - * all population. Memory coalescence? - * Requires POP_SIZE random uniform numbers! - */ - void mutate_dims_one( const Genome& orig, - const int dim_j, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO - ) { - REAL fb_rat = 1.0; - - Tuple tmp(EPS0, 1.0); - tmp = mutate_helper( orig.a, this->a, 0, (dim_j == 0) ? amplitude_ratio : 0.0 ); - this->a = constrain_dim1(0, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.b, this->b, 1, (dim_j == 1) ? amplitude_ratio : 0.0 ); - this->b = constrain_dim1(1, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.rho, this->rho, 2, (dim_j == 2) ? amplitude_ratio : 0.0 ); - this->rho = constrain_dim1(2, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.nu, this->nu, 3, (dim_j == 3) ? amplitude_ratio : 0.0 ); - this->nu = constrain_dim1(3, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.sigma, this->sigma, 4, (dim_j == 4) ? amplitude_ratio : 0.0 ); - this->sigma = constrain_dim1(4, tmp.fst); - fb_rat *= tmp.snd; - - this->fbRat = fb_rat; - } - - /** - * Crossover - */ - void mcmc_DE( const Genome& orig, - const Genome& gene_k, - const Genome& gene_l, - const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), - const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO - ) { - // proposal - // gamma: integrated out from the adviced - // Multivariate Gaussian with Gaussian target (Braak, 2006) - REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); - - this->a = constrain_dim1( 0, perturbation( orig.a, gene_k.a, gene_l.a, 0, gamma1, ampl_ratio ) ); - this->b = constrain_dim1( 1, perturbation( orig.b, gene_k.b, gene_l.b, 1, gamma1, ampl_ratio ) ); - this->rho = constrain_dim1( 2, perturbation( orig.rho, gene_k.rho, gene_l.rho, 2, gamma1, ampl_ratio ) ); - this->nu = constrain_dim1( 3, perturbation( orig.nu, gene_k.nu, gene_l.nu, 3, gamma1, ampl_ratio ) ); - this->sigma = constrain_dim1( 4, perturbation( orig.sigma, gene_k.sigma, gene_l.sigma, 4, gamma1, ampl_ratio ) ); - - this->fbRat = 1.0; // TODO: fix - } - - /** - * accepting the proposal - */ - void accept( const Genome& mutated ) { - this->a = mutated.a; - this->b = mutated.b; - this->rho = mutated.rho; - this->nu = mutated.nu; - this->sigma = mutated.sigma; - this->logLik = mutated.logLik; - this->fbRat = mutated.fbRat; - } -}; - -#endif // #ifndef CANDIDATE_CLASS - - - - diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile deleted file mode 100644 index 8817c4f..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -include setup.mk - -ifndef ($(HAVE_GPU)) -include platform.mk -endif - -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -#-fno-unsafe-math-optimizations -fno-finite-math-only -#-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans - -SOURCES_CPP =SwapCalib.cpp -OBJECTS =SwapCalib.o -EXECUTABLE =SwapCalib - - -default: cpu - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -# The GPU version is in: ../CppAndGPU. This folder is CPU only! -gpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - -cpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) - diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp deleted file mode 100644 index 2f88021..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************/ -/*** Translated to C++ Cosmin Oancea ***/ -/*** from an original OCaml code ***/ -/*** (sequential) by LexiFi ***/ -/*** and a sequential Python implem ***/ -/*** using a different genetic alg.***/ -/*** by Christian Andreetta ***/ -/****************************************/ - -#include "Util.h" -#include "Constants.h" -#include "ParseInput.h" -#include "GenAlgFlat.h" -#include "WriteResult.h" - -int main() -{ - Genome gene; - REAL* calib_arr = NULL; - - printf("\n// Running Original Sequential Swaption-Calibration Benchmark\n"); - - readDataSet( POP_SIZE, MCMC_LOOPS, - NUM_SWAP_QUOTES, SwaptionQuotes, - NUM_HERMITE, HermiteCoeffs, HermiteWeights, - NUM_SOBOL_BITS, SobolDirVct - ); - - unsigned long int elapsed_usec = 0; - { // Main Computational Kernel - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); - - calib_arr = mainKernelSeqCPU(gene); - - gettimeofday(&t_end, NULL); - timeval_subtract(&t_diff, &t_end, &t_start); - elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; - } - - { // validation and writeback of the result - FILE* runtime = fopen("runtime.txt", "w"); - FILE* result = fopen("result.json", "w"); - const int Ps = get_CPU_num_threads(); - fprintf(runtime, "%d\n", elapsed_usec / 1000); - fclose(runtime); - - writeResult(result, - gene.a, - gene.b, - gene.sigma, - gene.nu, - gene.rho, - gene.logLik, - calib_arr); - - fclose(result); - } - - return 1; -} diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h b/benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h deleted file mode 100644 index c7d4640..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef CPU_UTILITIES -#define CPU_UTILITIES - -struct IntermElem { - REAL ci; - REAL t1_cs; - REAL bai; - REAL bbi; - REAL aici; - REAL log_aici; - REAL scale; - REAL hat_scale; - - IntermElem() { } -}; - -struct SeqArrays { - - // max size of temp arrays - const uint MaxSzTmpArrs; - - // [ MaxSzTmpArrs ] - IntermElem* tmp_arrs; - - // [ 2 * POP_SIZE ] - Genome* genomes; - - // [ 2 * NUM_SWAP_QUOTES ] - REAL* new_quote_price; - - SeqArrays (const uint m) : MaxSzTmpArrs(m) { - genomes = new Genome[ 2 * POP_SIZE ]; - tmp_arrs = new IntermElem[MaxSzTmpArrs]; - - new_quote_price = new REAL [ 2 * NUM_SWAP_QUOTES ]; - } - - void releaseResources() { - delete[] genomes; - delete[] tmp_arrs; - delete[] new_quote_price; - } - - // get the quotes prices for genome i - REAL* get_quote () { return new_quote_price; } - REAL* get_price () { return new_quote_price + NUM_SWAP_QUOTES; } -}; -#endif // CPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/instantiate b/benchmarks/InterestCalib/implementations/cpp_sequential/instantiate deleted file mode 100755 index 52e44cb..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/instantiate +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -set -e - -cp $FINPAR_LIB_DIR/setup.mk . -cp $FINPAR_LIB_DIR/include/ParserC.h . -cp $FINPAR_LIB_DIR/include/Util.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Constants.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/KerConsts.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Date.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/GenAlgUtil.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/Candidate.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/IrregShape.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/EvalGenomeInl.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/G2PP.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/G2ppUtil.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/MathModule.h . -cp $FINPAR_BENCHMARK_LIB_DIR/include/WriteResult.h . -cp $FINPAR_IMPLEMENTATION/GenAlgFlat.h . -cp $FINPAR_IMPLEMENTATION/UtilCPU.h . -cp $FINPAR_IMPLEMENTATION/Genome.h . -cp $FINPAR_IMPLEMENTATION/EvalGenomeOrig.h . -cp $FINPAR_IMPLEMENTATION/G2PPorig.h . -cp $FINPAR_IMPLEMENTATION/*cpp $FINPAR_IMPLEMENTATION/Makefile . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > input.data -$FINPAR_LIB_DIR/generate_platform_mk.py $FINPAR_PLATFORM > platform.mk -NCORES=$($FINPAR_LIB_DIR/json_get.py $FINPAR_PLATFORM num_cores) - -cat > run < Double -> Bool -equalEps x1 x2 = abs (x1 - x2) <= 1.0e-8 - -selectMoveType :: Double -> MOVE_TYPE -selectMoveType move_selected = - if move_selected <= 0.2 then DIMS_ALL - else if move_selected <= 0.5 then DIMS_ONE - else {- move_selected <= 1.0 -} DEMCMC - - -eps0 :: Double -eps0 = 1.0e-3 - -eps :: Double -eps = 1.0e-5 - -infty :: Double -infty = 1.0e49 - ---pop_size :: Int ---pop_size = 128 --- ---num_mcmc_its :: Int ---num_mcmc_its = truncate $ (2.0 + (log (fromIntegral genome_dim))) * --- (1.0 + (log genome_scale)) * 100.0 - -genome_scale :: Double -genome_scale = 1.0 - -genome_dim :: Int -genome_dim = 5 - ---------------------------------------------- ---- Definition of lish-homomorphic reduce --- ---- requires a binary associative op --- ---------------------------------------------- - -reduce :: (a -> a -> a) -> a -> [a] -> a -reduce bop ne lst = foldl bop ne lst - ---------------------------------- ---- Sobol Numbers Computation --- ---------------------------------- - -num_sobol_bits :: Int -num_sobol_bits = 30 - -sobol_norm :: Double -sobol_norm = 1.0 / (1.0 + (2.0 ** (fromIntegral num_sobol_bits))) - -grayCode :: Int -> Int -grayCode x = (x `shiftR` 1) `xor` x - -sobolNum :: Vector Int -> Int -> Double -sobolNum dir_vct n = - let n_gray = grayCode n - ires = V.ifoldl (\res i dir -> - if testBit n_gray i - then res `xor` dir - else res - ) 0 dir_vct - rres = sobol_norm * (fromIntegral ires) - in rres -- trace ("Sobol Num "++show n++" is: "++show rres) rres - ---sobolNums :: Vector int -> Int -> Int -> Vector Double ---sobolNums dir_vct beg_offs end_offs = - - --- ifoldl :: Unbox b => (a -> Int -> b -> a) -> a -> Vector b -> a diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Date.hs b/benchmarks/InterestCalib/implementations/haskell_lh/Date.hs deleted file mode 100644 index fe3be36..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/Date.hs +++ /dev/null @@ -1,155 +0,0 @@ -module Date ( - today - , max_date - , min_date - , dateAct365 - , addMonths - , addYears - , test_dates - ) where - -import Constants -import Debug.Trace - -type GregDate = (Int,Int,Int,Int,Int) -- (year,month,day,hour,min) - -today :: Double -today = fromIntegral $ date_of_gregorian (2012, 1, 1, 12, 0) - ---"2299-12-31T23:59:59" -max_date :: Double -max_date = 168307199.0 - ---"1980-01-01T12:00:00" -min_date :: Double -min_date = 3600.0 - -hours_in_day :: Int -hours_in_day = 24 -minutes_in_day = hours_in_day * 60 -minutes_to_noon = (hours_in_day `div` 2) * 60 - - -date_of_gregorian :: GregDate -> Int -date_of_gregorian (year,month,day,hour,min) = - let ym = if month == 1 || month == 2 - then ( 1461 * ( year + 4800 - 1 ) ) `div` 4 + - ( 367 * ( month + 10 ) ) `div` 12 - - ( 3 * ( ( year + 4900 - 1 ) `div` 100 ) ) `div` 4 - - else ( 1461 * ( year + 4800 ) ) `div` 4 + - ( 367 * ( month - 2 ) ) `div` 12 - - ( 3 * ( ( year + 4900 ) `div` 100 ) ) `div` 4 - - tmp = ym + day - 32075 - 2444238 - - in tmp * minutes_in_day + hour * 60 + min - - -gregorian_of_date :: Int -> GregDate -gregorian_of_date minutes_since_epoch = - let jul = minutes_since_epoch `div` minutes_in_day - l1 = jul + 68569 + 2444238 - n = ( 4 * l1 ) `div` 146097 - l2 = l1 - ( 146097 * n + 3 ) `div` 4 - i = ( 4000 * ( l2 + 1 ) ) `div` 1461001 - - l3 = l2 - ( 1461 * i ) `div` 4 + 31 - j = ( 80 * l3 ) `div` 2447 - d = l3 - ( 2447 * j ) `div` 80 - l = j `div` 11 - - m = j + 2 - ( 12 * l ) - y = 100 * ( n - 49 ) + i + l - - daytime = mod minutes_since_epoch minutes_in_day - - in if ( daytime == minutes_to_noon ) - then (y, m, d, 12, 0) - else (y, m, d, daytime `div` 60, mod daytime 60) - -check_date :: Int -> Int -> Int -> Bool -check_date year month day = - let tmp1 = (1 <= day) && (1 <= month) && (month <= 12) && (1980 <= year) && (year <= 2299) - tmp2 = (day <= 28) - tmp3 = if (month == 2) - then (day == 29) && ((mod year 4) == 0) && ( year == 2000 || (not ((mod year 100) == 0)) ) - else if ( month == 4 || month == 6 || month == 9 || month == 11 ) - then ( day <= 30 ) - else ( day <= 31 ) - in tmp1 && (tmp2 || tmp3) - - -days_between :: Double -> Double -> Double -days_between t1 t2 = (t1 - t2) / (fromIntegral minutes_in_day) - -dateAct365 :: Double -> Double -> Double -dateAct365 t1 t2 = (days_between t1 t2) / 365.0 - -leap :: Int -> Bool -leap y = ( (mod y 4) == 0 ) && ( not ( (mod y 100) == 0 ) || ( (mod y 400) == 0 ) ) - -end_of_month :: Int -> Int -> Int -end_of_month year month = - let leap_year = leap year - in if ( month == 2 && leap_year ) then 29 - else if ( month == 2 ) then 28 - else if ( month == 4 || month == 6 || month == 9 || month == 11 ) then 30 - else 31 - -addMonths :: Double -> Double -> Double -addMonths time rnbmonths = - let nbmonths = truncate rnbmonths - (year,month,day,hour,min) = gregorian_of_date (truncate time) - - month1 = month + nbmonths - year'' = year + (month1 - 1) `div` 12 - month'' = (mod (month1 - 1) 12) + 1 - - (year''', month''') = if (month'' <= 0) - then (year''-1, month'' + 12) - else (year'', month'') - month_end = end_of_month year''' month''' - day''' = if ( day < month_end ) - then day - else month_end - in fromIntegral $ date_of_gregorian (year''', month''', day''', 12, 0) - - -addYears :: Double -> Double -> Double -addYears date nbyears = addMonths date (nbyears * 12.0) - -test_dates :: Int -> Int -test_dates arg = - let tmp1 = trace ("addMonths(min_date,1)==48240 : ") $ addMonths min_date 1.0 - arg1 = if equalEps tmp1 48240.0 - then trace ("... SUCCESS !") arg - else trace ("... FAILS !") arg - - tmp2 = trace ("addMonths(min_date,2)==90000 : ") $ addMonths min_date 2.0 - arg2 = if equalEps tmp2 90000.0 - then trace ("... SUCCESS !") arg1 - else trace ("... FAILS !") arg1 - - tmp3 = trace ("addYears(min_date,1)==530640 : ") $ addYears min_date 1.0 - arg3 = if equalEps tmp3 530640.0 - then trace ("... SUCCESS !") arg2 - else trace ("... FAILS !") arg2 - - tmp4 = trace ("addYears(min_date,5)==2634480 : ") $ addYears min_date 5.0 - arg4 = if equalEps tmp4 2634480.0 - then trace ("... SUCCESS !") arg3 - else trace ("... FAILS !") arg3 - - tmp5 = trace ("days_between(max_date(),min_date()) == 116877.499306 : ") $ days_between max_date min_date - arg5 = if equalEps tmp5 116877.499305555 - then trace ("... SUCCESS !") arg4 - else trace ("... FAILS !") arg4 - - tmp6 = trace ("act_365(max_date,min_date) == 320.212327 : ") $ dateAct365 max_date min_date - arg6 = if equalEps tmp6 320.2123268645 - then trace ("... SUCCESS !") arg5 - else trace ("... FAILS !") arg5 - - in arg6 - diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs b/benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs deleted file mode 100644 index 847b008..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs +++ /dev/null @@ -1,214 +0,0 @@ -module EvalGenome - ( - evalGenome - , testSwaptionPricer - ) where - -import Data.List -import Data.Vector.Unboxed(Vector) -import qualified Data.Vector.Unboxed as V -import Control.DeepSeq - -import Constants -import Date -import MathMod - -import Debug.Trace - - - ----------------------------------- ---- Main Export of this Module --- ----------------------------------- -evalGenome :: [Double] -> [Double] -> [Swaption] -> Vector Double - -> ( Double, Vector Double, Vector Double ) -- (logLik,calib_prices, black_prices) [NUM_SWAP_QUOTES] -evalGenome hermite_coeffs hermite_weights swaption_quotes genome = - let genome_tup = -- (a, b, rho, nu, sigma) = - (genome V.! 0, genome V.! 1, genome V.! 2, genome V.! 3, genome V.! 4) - - (black_prices, swap_prices, swap_logLiks) = unzip3 $ - map (pricerOfSwaption hermite_coeffs hermite_weights genome_tup) swaption_quotes - - swap_logLik = reduce (+) 0.0 swap_logLiks - swap_price_vct = V.fromList swap_prices - black_price_vct= V.fromList black_prices - - in swap_logLik `deepseq` swap_price_vct `deepseq` black_price_vct `deepseq` - ( swap_logLik, swap_price_vct, black_price_vct ) - -- ( swap_logLik, V.fromList swap_prices, V.fromList black_prices ) - - -pricerOfSwaption :: [Double] -> [Double] -> Genome -> Swaption - -> (Double, Double, Double) -- (Black Price, Swapt Price, LogLikelihood) -pricerOfSwaption hermite_coeffs hermite_weights -- Hermite coefficients & weights - genome (sw_mat, sw_freq, sw_ty, sw_quote) = -- swaption - - let (a, b, rho, nu, sigma) = genome - maturity = addYears today sw_mat - n_schedi = truncate $ 12.0 * sw_ty / sw_freq - tmat0 = dateAct365 maturity today - - -- 1. compute quote, i.e., black price inlined - (lvl,t0,tn) = swapSchedule n_schedi maturity sw_freq - strike = ( (zc t0) - (zc tn) ) / lvl - d1 = 0.5 * sw_quote * tmat0 - d2 = 0.0 - d1 - black_price = ( lvl * ( strike * (uGaussianP d1) - strike * (uGaussianP d2) ) ) - - -- 2. estimate the swaption price for this particular genome, - -- and also compute its likelihood - (v0_mat,_,_) = bigV genome tmat0 - mux = 0.0 - (bigmX genome today maturity today maturity) - muy = 0.0 - (bigmY genome today maturity today maturity) - zc_mat = zc maturity - sqrt_bfun_a = sqrt $ bFun (2.0*a) tmat0 - sqrt_bfun_b = sqrt $ bFun (2.0*b) tmat0 - rhoxy = rho * (bFun (a+b) tmat0) / (sqrt_bfun_a * sqrt_bfun_b) - sigmax = sigma * sqrt_bfun_a - sigmay = nu * sqrt_bfun_b - rhoxyc = 1.0 - rhoxy * rhoxy - rhoxycs = sqrt rhoxyc - sigmay_rhoxycs = sigmay * rhoxycs - t4 = (rhoxy * sigmay) / sigmax - - (cs, t1_cs, bas, bbs, aics, log_aics, scales) = unzip7 $ - map (\ i -> - let beg_date = addMonths maturity (sw_freq*(fromIntegral i)) - end_date = addMonths beg_date sw_freq - res = (dateAct365 end_date beg_date) * strike - - cii = if i == n_schedi-1 then 1.0 + res else res - - date_tod1 = dateAct365 end_date today - (v0_end,_,_) = bigV genome date_tod1 - - date_tod2 = dateAct365 end_date maturity - (vt_end,bai,bbi) = bigV genome date_tod2 - - expo_aici = 0.5 * (vt_end - v0_end + v0_mat) - fact_aici = cii * zc(end_date) / zc_mat - - t1_c = bbi * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbi) ) + expo_aici - -- sanity = ! ( isinf(aici[i]) || isnan(aici[i]) ); - in ( fact_aici, t1_c, bai, bbi, fact_aici * (exp expo_aici), - expo_aici + (log fact_aici), 0.0 - (bai + bbi * t4) ) - ) [0..n_schedi-1] - - exactYhatSpec = exactYhat n_schedi b sigmax sigmay - rhoxy rhoxyc rhoxycs mux muy - bas bbs aics log_aics - eps = 0.5 * sigmax; - f = exactYhatSpec mux - g = exactYhatSpec (mux + eps) - h = exactYhatSpec (mux - eps) - df = 0.5 * ( g - h ) / eps; - - sqrt2sigmax = (sqrt 2.0) * sigmax - t2 = rhoxy / (sigmax*rhoxycs) - - accums = - zipWith (\x_quad w_quad -> - let x = sqrt2sigmax * x_quad + mux - yhat_x = f + df*(x - mux) - h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ) - - accs1= zipWith4 (\bbi t1_csi ci scalei -> - let h2 = h1 + bbi * sigmay_rhoxycs - expo_aici = t1_csi + scalei*x - fact_aici = ci - --fact_aici * (exp expo_aici) * (uGaussianP (-h2)) - expo_part = uGaussianPwithExpFactor (-h2) expo_aici - in fact_aici * expo_part - ) bbs t1_cs cs scales - accum= reduce (+) 0.0 accs1 - - tmp = (sqrt 2.0) * x_quad; --(x - mux) / sigmax; - t1 = exp $ 0.0 - 0.5*tmp*tmp - - in w_quad * t1 * ( (uGaussianP (-h1)) - accum ) - - ) hermite_coeffs hermite_weights - - accum = reduce (+) 0.0 accums - - swap_price = zc_mat * ( accum / (sqrt pi) ) - logLik = logLikelihood black_price swap_price - in (black_price, swap_price, logLik) --- tmp = (swap_price - black_price) / black_price --- in (black_price, swap_price, tmp * tmp) - - ---kkk :: Double ---kkk = -3.71901648545568 - -exactYhat :: Int -> Double -> Double -> Double -> Double - -> Double -> Double -> Double -> Double - -> [Double] -> [Double] -> [Double] -> [Double] - -> Double -> Double -exactYhat n_schedi b sigmax sigmay rhoxy rhoxyc rhoxycs mux muy - bai bbi aici log_aici x = - let kkk = -3.71901648545568 - (scales, los) = unzip $ zipWith4 - (\ baii bbii aicii log_aicii -> - let baix = baii * x - up_term = aicii * (exp (-baix)) - lo_term = ( log_aicii - baix ) / bbii - in (up_term, lo_term) - ) bai bbi aici log_aici - (up0,lo) = reduce (\(u,l) (cu,cl) -> (u+cu, max l cl) ) - (0.0, -infty) (zip scales los) - - in if n_schedi == 1 then lo - else - let log_s = log up0 - tmp = log_s / (last bbi) -- [n_schedi-1]; - up = if tmp <= 0.0 - then tmp - else let tmp2 = log_s / (head bbi) - in if 0.0 <= tmp2 - then tmp2 - else (-infty) - yl = lo - eps - yu = up + eps - - y0 = sigmay * ( rhoxy * (x-mux) / sigmax + kkk * rhoxycs ) - rhoxyc/b + muy - y1 = sigmay * ( rhoxy * (x-mux) / sigmax - kkk * rhoxycs ) + muy - in if ( y1 <= yl ) then y1 + 1.0 - else if ( yu <= y0 ) then y0 - 1.0 - else let root_lb = max yl y0 - root_ub = min yu y1 - (root,_,err) = rootFindBrent scales bbi root_lb root_ub 1.0e-4 - in if err == (-infty) then y0 - 1.0 - else if err == infty then y1 + 1.0 - else root - - -testSwaptionPricer :: [Double] -> [Double] -> Int -> Int -testSwaptionPricer hermite_coeffs hermite_weights arg0 = - let genome = (0.02453, 0.98376, -0.82400, 0.11830, 0.02398) - - swaption1 = (10.0, 6.0, 4.0, 0.2454) - (_,price1,_) = pricerOfSwaption hermite_coeffs hermite_weights genome swaption1 - price1' = trace ("# Pricer_of_swaption test I = 657.8215929143189 => ") $ - 1.0e4 * price1 - arg1 = if equalEps price1' 657.8215929143189 -- 657.82158867845 - then trace ("... SUCCESS !") arg0 - else trace ("... FAILS !"++show price1') arg0 - - swaption2 = (30.0, 6.0, 30.0, 0.16355) - (_,price2,_) = pricerOfSwaption hermite_coeffs hermite_weights genome swaption2 - price2' = trace ("# Pricer_of_swaption test II = 1902.97628191498 => ") $ - 1.0e4 * price2 - arg2 = if equalEps price2' 1902.97628191498 - then trace ("... SUCCESS !") arg1 - else trace ("... FAILS !") arg1 - - swaption3 = (30.0, 6.0, 25.0, 0.1686) - (_,price3,_) = pricerOfSwaption hermite_coeffs hermite_weights genome swaption3 - price3' = trace ("# Pricer_of_swaption test III = 1840.859126408099 => ") $ - 1.0e4 * price3 - arg3 = if equalEps price3' 1840.859126408099 - then trace ("... SUCCESS !") arg2 - else trace ("... FAILS !") arg2 - in arg3 - diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs b/benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs deleted file mode 100644 index ee5d8fd..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs +++ /dev/null @@ -1,128 +0,0 @@ -module Genome ( - g_mins - , g_maxs - , mutateDimsALL - , mutateDimsONE - , mcmcDE - ) where - -import Constants - -import Data.Vector.Unboxed(Vector) -import qualified Data.Vector.Unboxed as V - -import Debug.Trace - -g_mins :: Vector Double -g_mins = V.fromList [ eps0, eps0, -1.0+eps0, eps0, eps0 ] - -g_maxs :: Vector Double -g_maxs = V.fromList [ 1.0-eps0, 1.0-eps0, 1.0-eps0, 0.2, 0.2 ] - -g_inis :: Vector Double -g_inis = V.fromList [ 0.02, 0.02, 0.0, 0.01, 0.04 ] --- [ g_a, g_b, g_rho, g_nu, g_sigma ] - -unif_ampl_ratio :: Double -unif_ampl_ratio = 0.005 / genome_scale - - - --- rand_vct[5], i.e., needs 5 random numbers -mutateDimsALL :: Vector Double -> Vector Double -> Vector Double - -> (Vector Double, Double) -mutateDimsALL genome genome_prop rand_vct = -- 5 rand nums - let (genome_res, bf_facts) = V.unzip $ - V.zipWith5 (mutateHelper unif_ampl_ratio) - rand_vct g_mins g_maxs genome genome_prop - bf_res = V.foldl (*) 1.0 bf_facts - in (genome_res, bf_res) - - --- needs one random number -mutateDimsONE :: Int -> Vector Double -> Vector Double -> Vector Double - -> (Vector Double, Double) -mutateDimsONE dim_j genome genome_prop rand_vct = -- r01 1 rand num - let (gene, gene_prop) = (genome V.! dim_j, genome_prop V.! dim_j) - (gene_min, gene_max) = (g_mins V.! dim_j, g_maxs V.! dim_j) - r01 = rand_vct V.! dim_j - - (gene_new, bf_res) = mutateHelper unif_ampl_ratio r01 - gene_min gene_max gene gene_prop - genome_res = V.imap (\i g -> if i == dim_j then gene_new else g) genome - in (genome_res, bf_res) - - --- rand_vct[8], i.e., needs 8 random numbers -mcmcDE :: Int -> [Vector Double] -> Vector Double -> Int - -> (Vector Double, Double) -mcmcDE pop_size genomes rand_vct j = -- 8 rand nums - let gamma_avg = 2.38 / (sqrt (2.0*(fromIntegral genome_dim))) - ampl_ratio = 0.1 * unif_ampl_ratio - - k0 = truncate $ (fromIntegral (pop_size-1))*(rand_vct V.! 0) - (k, cand_UB) = if ( k0 == j ) - then (pop_size - 1, pop_size - 2) - else (k0, pop_size - 1) - - l0 = truncate $ (fromIntegral cand_UB)*(rand_vct V.! 1) - l = -- trace ("(k,j,l0,cand_UB) is: "++show k++" "++show j++" "++show l0++" "++show cand_UB) $ - if l0 == j || l0 == k - then cand_UB - else l0 - - -- proposal gamma: integrated out from the adviced - -- Multivariate Gaussian with Gaussian target (Braak, 2006) - gamma1 = gamma_avg - 0.5 + (rand_vct V.! 2) -- * instead of + ? - - gene_rands = V.drop 3 rand_vct - (genome_j, genome_k, genome_l) = (genomes !! j, genomes !! k, genomes !! l) - -- g_a [j + POP_SIZE] = constrain_dim1( 0, perturbation( g_a [j], g_a [k], g_a [l], 0, gamma1, ampl_ratio ) ); - genome_res = V.zipWith6 (perturbation gamma1 ampl_ratio) - gene_rands g_mins g_maxs genome_j genome_k genome_l - in (genome_res, 1.0) - ---perturbation gamma1 amplitude_ratio r01 gene_min gene_max gene gene_k gene_l - ----------------------------------------- ----------------------------------------- ----------- Helper Functions ------------ ----------------------------------------- ----------------------------------------- - -mutateHelper :: Double -> Double -> Double -> Double -> Double -> Double - -> (Double, Double) -mutateHelper amplitude_ratio r01 gene_min gene_max gene gene_prop = - let amplitude = abs $ (gene_max - gene_min) * amplitude_ratio - semiamplitude = amplitude / 2.0 - - tmp_min_max_f = min gene_max (gene + semiamplitude) - tmp_max_min_f = max gene_min (gene - semiamplitude) - forward_range = tmp_min_max_f - tmp_max_min_f - - bf_fact = if forward_range > 0.0 && amplitude > 0.0 - then let tmp_min_max_b = min gene_max (gene_prop + semiamplitude) - tmp_max_min_b = max gene_min (gene_prop - semiamplitude) - backward_range = tmp_min_max_b - tmp_max_min_b - in backward_range / forward_range - else 1.0 - diff = amplitude * r01 - semiamplitude - new_gene = constrainDim gene_min gene_max (gene+diff) - in (new_gene, bf_fact) - -constrainDim :: Double -> Double -> Double -> Double -constrainDim gene_min gene_max gene = - max gene_min $ min gene_max gene - - -perturbation :: Double -> Double -> Double -> Double - -> Double -> Double -> Double -> Double - -> Double -perturbation gamma1 amplitude_ratio r01 gene_min gene_max gene gene_k gene_l = - let amplitude = abs $ (gene_max - gene_min) * amplitude_ratio - semiamplitude = amplitude / 2.0 - perturb = amplitude * r01 - semiamplitude - new_gene = constrainDim gene_min gene_max $ - gene + perturb + gamma1 * ( gene_k - gene_l ) - in new_gene - diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs b/benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs deleted file mode 100644 index bc90ded..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs +++ /dev/null @@ -1,390 +0,0 @@ -module MathMod - ( - uGaussianP - , uGaussianPwithExpFactor - , zc - , bigV - , bigmX - , bigmY - , bFun - , rootFindBrent - , swapSchedule - , blackPrice - , logLikelihood - , testMathMod - , testG2ppUtil - ) where - -import Constants -import Date - -import Debug.Trace - ---let (p, a1, a2, a3, a4, a5) = --- (0.3275911, 0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429) - ---------------------------------------------------------------------------- ---- polynomial expansion of the erf() function, with error<=1.5e-7 ---- formula 7.1.26 (page 300), Handbook of Mathematical Functions, Abramowitz and Stegun ---- http://people.math.sfu.ca/~cbm/aands/frameindex.htm ---------------------------------------------------------------------------- -erffPolyOnly :: Double -> Double -erffPolyOnly x = - let (p, a1, a2, a3, a4, a5) = - (0.3275911, 0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429) - t = 1.0/(1.0+p*x) - t2 = t * t - t3 = t * t2 - t4 = t2 * t2 - t5 = t2 * t3 - in (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5) - -erff1 :: Double -> Double -erff1 x = - let poly = erffPolyOnly x - in ( 1.0 - poly * exp(0.0-(x*x)) ) - --- Cumulative Distribution Function for a standard normal distribution -uGaussianP :: Double -> Double -uGaussianP x = - let u = x / sqrt(2.0) - e = if u < 0.0 - then 0.0 - (erff1 (0.0-u)) - else erff1 u - in ( 0.5 * (1.0 + e) ) - -uGaussianPwithExpFactor :: Double -> Double -> Double -uGaussianPwithExpFactor x exp_factor = - let u = abs ( x / (sqrt 2.0) ) - e = erffPolyOnly u - res = 0.5 * e * ( exp (exp_factor - u*u) ) - in if x >= 0.0 - then (exp exp_factor) - res - else res - ---------------------------------------------------------------------------- --- THE FUNction-PARAMeter to rootFinding_Brent --- if fid = 33 then for testing to_solve(real x) = (x+3.0)*(x-1.0)*(x-1.0) --- Otherwise follows the real implementation --- N is the size of scales (bbi) ---------------------------------------------------------------------------- -toSolve :: [Double] -> [Double] -> Double -> Double -toSolve scales bbs yhat = - let res_map = zipWith ( \scale bb -> scale * (exp (0.0 - bb * yhat)) ) scales bbs - res_red = reduce (+) 0.0 res_map - in res_red - 1.0 - -toSolveTest :: [Double] -> [Double] -> Double -> Double -toSolveTest _ _ yhat = - (yhat+3.0)*(yhat-1.0)*(yhat-1.0) - -max_num_brent_iters :: Int -max_num_brent_iters = 10000 - -rootFindBrentGen :: ([Double] -> [Double] -> Double -> Double) -- toSolve function - -> [Double] -> [Double] -> Double -> Double -> Double -- scales bbs lb ub tolerance - -> (Double, Int, Double) -- Result: (root, # needed iter, fb) -rootFindBrentGen toSolveFun scales bbs lb ub toll = - let tol = if toll <= 0.0 then 1.0e-9 else toll - (a, b) = (lb, ub) - fa = toSolveFun scales bbs a - fb = toSolveFun scales bbs b - - in if fa*fb >= 0.0 - then (0.0, 0, if a >= 0.0 then infty else 0.0-infty) - else - let (a', fa', b', fb') = if (abs fa) < (abs fb) - then (b, fb, a, fa) - else (a, fa, b, fb) - in brentWhileLoop (toSolveFun scales bbs) - tol 0 True 0.0 a' fa' b' fb' a' fa' - -rootFindBrent :: [Double] -> [Double] -- scales bbs - -> Double -> Double -> Double -- lb ub tolerance - -> (Double, Int, Double) -rootFindBrent = rootFindBrentGen toSolve - -brentWhileLoop :: (Double -> Double) -- toSolve function - -> Double -> Int -> Bool -> Double - -> Double -> Double -> Double -> Double -> Double -> Double - -> (Double, Int, Double) -brentWhileLoop toSolveFun tol i mflag d a fa b fb c fc = - if (fb == 0.0) || (abs (b-a)) < tol || i >= max_num_brent_iters - then (b, i, fb) - else let s = if (fa == fc) || (fb == fc) - then b - fb * (b - a) / (fb - fa) - else let s1 = ( a*fb*fc ) / ( (fa-fb)*(fa-fc) ) - s2 = ( b*fa*fc ) / ( (fb-fa)*(fb-fc) ) - s3 = ( c*fa*fb ) / ( (fc-fa)*(fc-fb) ) - in s1 + s2 + s3 - cond = ( (3.0 * a + b) / 4.0 > s || s > b ) || - ( mflag && (abs (b-c)) / 2.0 <= (abs (s-b)) ) || - ( not mflag && (abs (c-d)) / 2.0 <= (abs (s-b)) ) || - ( mflag && (abs (b-c)) <= (abs tol) ) || - ( not mflag && (abs (c-d)) <= (abs tol) ) - (mflag', s') = if cond - then ( True , (a+b)/2.0 ) - else ( False, s ) - - fs' = toSolveFun s' - - (d', c', fc') = (c, b, fb) - (a', fa', b', fb') = if fa*fs' < 0.0 - then (a, fa, s', fs') - else (s', fs', b, fb) - (a'', fa'', b'', fb'') = - if (abs fa') < (abs fb') - then (b', fb', a', fa') - else (a', fa', b', fb') - - in brentWhileLoop toSolveFun tol (i+1) mflag' d' a'' fa'' b'' fb'' c' fc' - -testMathMod :: Int -> Int -testMathMod arg0 = - let (scales, bbs) = ([ 0.0 ], [ 0.0 ]) - - -- Rootfinder.brent (fun x -> (x+.3.)*.(x-.1.)**2.) (-4.) (4./.3.) 1e-4 == -3 - (tmp1,_,_) = trace ("# Brent test: -3.0 => ") $ - rootFindBrentGen toSolveTest scales bbs (0.0-4.0) (4.0/3.0) 0.0 - arg1 = if equalEps tmp1 (0.0 - 3.0) - then trace ("... SUCCESS !") arg0 - else trace ("... FAILS !") arg0 - - -- erff 0. == 0. ;; 100. *. erff (1./.sqrt 2.) - tmp2 = trace ("# Erf test => ") $ - 100.0 * ( erff1 (1.0 / (sqrt 2.0)) ) - arg2 = if (equalEps (erff1 0.0) 0.0) && (equalEps tmp2 68.26894723352726) - then trace ("... SUCCESS !") arg1 - else trace ("... FAILS !") arg1 - - -- ugaussian_P 0. ;; ugaussian_P 1. +. ugaussian_P (-1.) - tmp3 = trace ("# Gaussian test => ") $ - (uGaussianP (0.0-1.0)) + (uGaussianP 1.0) - arg3 = if (equalEps (uGaussianP 0.0) 0.5) && (equalEps tmp3 1.0) - then trace ("... SUCCESS !") arg2 - else trace ("... FAILS !") arg3 - in arg3 - --------------------------------------- --------------------------------------- -rrr :: Double -rrr = 0.03 - -zc :: Double -> Double -zc t = exp (0.0 - rrr * (dateAct365 t today) ) - -bFun :: Double -> Double -> Double -bFun z0 tau = ( 1.0 - (exp (0.0 - z0*tau)) ) / z0 - -tFun :: Double -> Double -> Double -> Double -tFun sigma x0 tau = - let expxtau = exp ( 0.0 - x0*tau ) - exp2xtau = expxtau*expxtau - in sigma*sigma/(x0*x0) * ( tau + 2.0/x0*expxtau-1.0/(2.0*x0)*exp2xtau-3.0/(2.0*x0) ) - --- the first parameter `genome' is the five-genes genome used in --- the genetic algorithms that models the interest rate --- the second parameter is the time --- the result is V in Brigo and Mercurio's book page 148. --- \var(\int_t^T [x(u)+y(u)]du) -bigV :: Genome -> Double - -> (Double,Double,Double) -bigV (a,b,rho,nu,sigma) tau = - let bai = bFun a tau - bbi = bFun b tau - v = tFun sigma a tau - o1 = tFun nu b tau - o2 = 2.0 * rho * nu * sigma / (a * b)* - ( tau - bai - bbi + (bFun (a+b) tau) ) - in (v + o1 + o2, bai, bbi) - - --- the first parameter `genome' is the five-genes genome used in --- the genetic algorithms that models the interest rate --- the other parameter are times: today, maturity, and the --- lower and upper bound of the considered time interval --- --- the result is: x drift term in tmat-forward measure - -bigmX :: Genome -> Double -> Double -> Double -> Double - -> Double -bigmX (a,b,rho,nu,sigma) iday tmat s t = - let ts = dateAct365 t s - tmatt = dateAct365 tmat t - - tmat0 = dateAct365 tmat iday - tmats = dateAct365 tmat s - - t0 = dateAct365 t iday - s0 = dateAct365 s iday - - tmp0 = (sigma*sigma)/(a*a)+(sigma*rho*nu)/(a*b) - tmp1 = 1.0 - (exp (0.0 - a*ts)) - - tmp2 = sigma * sigma / (2.0 * a * a) - tmp3 = (exp (0.0 - a*tmatt)) - (exp (0.0 - a*(tmats+ts))) - - tmp4 = rho * sigma * nu / (b * (a + b)) - tmp5 = (exp (0.0 - b*tmatt)) - (exp (0.0 -b*tmat0 - a*t0 + (a+b)*s0)) - - in tmp0*tmp1 - tmp2*tmp3 - tmp4*tmp5 - - --- the first parameter `genome' is the five-genes genome used in --- the genetic algorithms that models the interest rate --- the other parameter are times: today, maturity, and the --- lower and upper bound of the considered time interval --- --- the result is: y drift term in tmat-forward measure -bigmY :: Genome -> Double -> Double -> Double -> Double - -> Double -bigmY (a,b,rho,nu,sigma) iday tmat s t = - let ts = dateAct365 t s - tmatt = dateAct365 tmat t - tmat0 = dateAct365 tmat iday - tmats = dateAct365 tmat s - t0 = dateAct365 t iday - s0 = dateAct365 s iday - - tmp0 = nu*nu/(b*b)+sigma*rho*nu/(a*b) - tmp1 = 1.0 - (exp (0.0 - b*ts)) - - tmp2 = nu * nu / (2.0 * b * b) - tmp3 = (exp (0.0 -b*tmatt)) - (exp (0.0 - b*(tmats + ts))) - - tmp4 = sigma * rho * nu / (a * (a + b)) - tmp5 = (exp (0.0 - a*tmatt)) - (exp (0.0 - a*tmat0 - b*t0 + (a+b)*s0)) - - in tmp0*tmp1 - tmp2*tmp3 - tmp4*tmp5 - - - -swapSchedule :: Int -> Double -> Double - -> (Double, Double, Double) -swapSchedule nschedule maturity freq = - let lvlt0tns = - map (\j -> let i = fromIntegral j - a1 = addMonths maturity (freq*i) - a2 = addMonths a1 freq - lvl = (zc a2) * (dateAct365 a2 a1) - in (lvl, a1, a2) - ) [0..nschedule-1] - -- Reduction( lvl: +, t0 : min, tn : max ) - in reduce (\ (l,ti,tf) (lvl,tini, tfin) -> - (l+lvl, min ti tini, max tf tfin) - ) (0.0, max_date, min_date) lvlt0tns - - -blackPrice :: Double -> Swaption -> Double -blackPrice iday (sw_mat, sw_freq, sw_ty, sw_vol) = - let maturity = addYears iday sw_mat - sqrtt = dateAct365 maturity iday - n_schedule = truncate $ 12.0 * sw_ty / sw_freq - (lvl,t0,tn) = swapSchedule n_schedule maturity sw_freq - - strike = ( (zc t0) - (zc tn) ) / lvl - d1 = 0.5 * sw_vol * sqrtt - d2 = 0.0 - d1 - in ( lvl * ( strike * (uGaussianP d1) - strike * (uGaussianP d2) ) ) - - -testG2ppUtil :: Int -> Int -testG2ppUtil arg0 = - let (iday, tmat, s, t) = (9000.0, 18000.0, 400000.0, 9000000.0) - - res_b_fun = trace ("# bFun test = 0.30490117 => ") $ - bFun 3.24 1.362 - arg1 = if equalEps res_b_fun 0.30490117 - then trace ("... SUCCESS !") arg0 - else trace ("... FAILS !") arg0 - - res_bigmX = trace ("# bigmX test = -0.2356067470979 => ") $ - bigmX (0.02, 0.02, 0.0, 0.01, 0.04) iday tmat s t - arg2 = if equalEps res_bigmX (-0.2356067470979) - then trace ("... SUCCESS !") arg1 - else trace ("... FAILS !") arg1 - - res_bigmY = trace ("# bigmY test = -0.01472542169362 => ") $ - bigmY (0.02, 0.02, 0.0, 0.01, 0.04) iday tmat s t - arg3 = if equalEps res_bigmY (-0.01472542169362) - then trace ("... SUCCESS !") arg2 - else trace ("... FAILS !") arg2 - - (res_bigv1, res_bigv2, res_bigv3) = - trace ("# bigv test = { 7.8288965347e-4, 1.107549139, 1.107549139 } => ") $ - bigV (0.02, 0.02, 0.0, 0.01, 0.04) 1.12 - arg4 = if (equalEps res_bigv1 7.8288965347e-4) && - (equalEps res_bigv2 1.107549139) && - (equalEps res_bigv3 1.107549139) - then trace ("... SUCCESS !") arg3 - else trace ("... FAILS !") arg3 - - (sw_mat,freq,sw_ty) = (10.0, 6.0, 4.0) - - (maturity, strike) = (22094640.0, 0.030226283149239714) - swap_schedule1 = [ 22094640.0, 22355280.0, 22620240.0, 22880880.0, - 23145840.0, 23407920.0, 23672880.0, 23933520.0 ] - swap_schedule2 = [ 22355280.0, 22620240.0, 22880880.0, 23145840.0, - 23407920.0, 23672880.0, 23933520.0, 24198480.0 ] - - vol = 0.2454 - black_price_res = - trace ("# Testing Black Price = 654.1429648454 => ") $ - (blackPrice today (sw_mat, freq, sw_ty, vol)) * 10000.0 - arg5 = if (equalEps black_price_res 654.1429648454) - then trace ("... SUCCESS !") arg4 - else trace ("... FAILS !") arg4 - in arg5 - - --------------------------------------- -------- Likelihood Measures ---------- --------------------------------------- - -sqrtTwoPi :: Double -sqrtTwoPi = sqrt (2*pi) - -data Likelihood_Type = CAUCHY | NORMAL - -llhood_type :: Likelihood_Type -llhood_type = CAUCHY -- NORMAL; - -llhood_cauchy_offs :: Double -llhood_cauchy_offs = 5.0 - -llhood_normal_offs :: Double -llhood_normal_offs = 1.0 - - - -normalPdf :: Double -> Double -> Double -> Double -normalPdf z mu sigma = - let sigmap = abs sigma - res = 1.0 / (sigmap * sqrtTwoPi) - ecf = (z - mu) * (z - mu) / (2.0 * sigmap * sigmap) - in res * (exp (0.0 - ecf)) - -cauchyPdf :: Double -> Double -> Double -> Double -cauchyPdf z mu gamma = - let x = (z - mu) / gamma - in 1.0 / ( pi * gamma * ( 1.0 + x*x ) ) - -logLikelihoodNormal :: Double -> Double -> Double -logLikelihoodNormal y_ref y = - let sigma = (y_ref / 50.0) * llhood_normal_offs - pdfs = normalPdf y y_ref sigma - in log (1.0e-20 + pdfs) - -logLikelihoodCauchy :: Double -> Double -> Double -logLikelihoodCauchy y_ref y = - let gamma = ( (abs y_ref) / 50.0 ) * llhood_cauchy_offs + 0.01 - pdfs = cauchyPdf y y_ref gamma - in log (1.0e-20 + pdfs) - - -logLikelihood :: Double -> Double -> Double -logLikelihood y_ref y = - case llhood_type of - NORMAL -> logLikelihoodNormal y_ref y - CAUCHY -> logLikelihoodCauchy y_ref y - diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs b/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs deleted file mode 100644 index 4a40bbe..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs +++ /dev/null @@ -1,308 +0,0 @@ -module Main where - -import Control.DeepSeq -import Control.Applicative -import Control.Monad -import Data.Maybe -import System.CPUTime - ------------------------------------- ---- Requires the installation of --- ---- Parsec package, i.e., --- ---- cabal install parsec --- ------------------------------------- - -import Text.Parsec hiding (optional, (<|>), token) -import Text.Parsec.String - -import Data.Bits -import Data.List -import Prelude - -import Control.DeepSeq -import Data.Vector.Unboxed(Vector) -import qualified Data.Vector.Unboxed as V - -import Constants -import Date -import Genome -import EvalGenome -import MathMod - -import Debug.Trace - ------------------------------- ---- Parser-related Helpers --- ------------------------------- -signed :: Parser String -> Parser String -signed p = (char '-' >> (('-':) <$> p)) <|> p - -whitespace :: Parser () -whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) - -lexeme :: Parser a -> Parser a -lexeme p = p <* whitespace - -token :: String -> Parser () -token = void . lexeme . string - -readInt :: Parser Int -readInt = lexeme $ read <$> signed (many1 digit) - -readDouble :: Parser Double -readDouble = lexeme $ read <$> signed (s2 <|> s1) - where s1 = do bef <- many1 digit - aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) - return $ bef ++ aft - s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit - -readArray :: Parser a -> Parser [a] -readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") - ---------------------------------------------- ---------------------------------------------- - -findBestLik :: Int -> [Double] -> (Int, Double) -findBestLik pop_size log_liks = - reduce (\ (best_ind, best_logLik) (ind, logLik) -> - if (logLik > best_logLik) - then (ind, logLik) - else (best_ind, best_logLik) - ) (0, -100000000.0) (zip [0..pop_size-1] log_liks) - -makeSummary :: Vector Double -> Double -> Vector Double -> Vector Double - -> (Genome, Double, [[Double]]) -makeSummary win_genome win_logLik calib_prices black_prices = - let res_genome = ( win_genome V.! 0, win_genome V.! 1, win_genome V.! 2, - win_genome V.! 3, win_genome V.! 4 ) - res_summary= zipWith (\ price quote -> - let err_ratio = abs $ 100.0 * (price - quote) / quote - in [10000.0*price, 10000.0*quote, err_ratio] - ) (V.toList calib_prices) (V.toList black_prices) - in (res_genome, win_logLik, res_summary) - ---------------------------------------------- ----- The Monte-Carlo Convergence Loop ------- ---------------------------------------------- - -mcmcConvergenceLoop :: Int -> Int -> [Swaption] -> Vector Int -> [Double] -> [Double] -- loop read-only args - -> [Vector Double] -> [Vector Double] -> [Double] -> Int -> Int -- loop variant args - -> ( [Vector Double], [Vector Double], [Double], Int ) -mcmcConvergenceLoop pop_size num_mcmc_its swaption_quotes sobol_dir_vct hermite_coeffs hermite_weights - genomes_old genomes_new logLiks_old j sob_offs0 = - if j == num_mcmc_its - then (genomes_old, genomes_new, logLiks_old, sob_offs0) - else - -- select the way in which genomes are perturbed - let move_selected = sobolNum sobol_dir_vct sob_offs0 - sob_offs1 = sob_offs0 + 1 - move_type = selectMoveType move_selected - - -- perturb the genome population based on the selection - (sob_offs2, genomes_new', bf_rats') = - case move_type of - DIMS_ALL -> let sob_offs_new = sob_offs1 + pop_size*5 - rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) - [5*i+sob_offs1..5*i+sob_offs1+4] - ) [0..pop_size-1] - (g, bfrat) = unzip $ zipWith3 mutateDimsALL - genomes_old genomes_new rand_vcts - in sob_offs_new `deepseq` g `deepseq` bfrat `deepseq` - (sob_offs_new, g, bfrat) - - DIMS_ONE -> let sob_offs_new = sob_offs1 + pop_size*5 + 1 -- *1 - dim_j = truncate $ (fromIntegral genome_dim) * (sobolNum sobol_dir_vct sob_offs1) --- rand_nums = map (sobolNum sobol_dir_vct) --- [sob_offs1+1..sob_offs1+pop_size] - rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) - [5*i+sob_offs1+1..5*i+sob_offs1+5] - ) [0..pop_size-1] - -- create sobol numbers - (g, bfrat) = unzip $ zipWith3 (mutateDimsONE dim_j) - genomes_old genomes_new rand_vcts -- rand_nums - in sob_offs_new `deepseq` g `deepseq` bfrat `deepseq` - (sob_offs_new, g, bfrat) - - DEMCMC -> let sob_offs_new = sob_offs1 + pop_size*8 - rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) - [8*i+sob_offs1..8*i+sob_offs1+7] - ) [0..pop_size-1] - (g, bfrat) = unzip $ zipWith (mcmcDE pop_size genomes_old) - rand_vcts [0..pop_size-1] - - in sob_offs_new `deepseq` g `deepseq` bfrat `deepseq` - (sob_offs_new, g, bfrat) - - -- evaluate the new genome population - --(logLiks_new', _, _) = unzip3 $ map (evalGenome hermite_coeffs hermite_weights swaption_quotes) genomes_new' - (logLiks_new_th, sw_pr_th, bl_pr_th) = - unzip3 $ map (evalGenome hermite_coeffs hermite_weights swaption_quotes) genomes_new' - logLiks_new' = logLiks_new_th `deepseq` sw_pr_th `deepseq` bl_pr_th `deepseq` - logLiks_new_th - - -- decide which genomes to ACCEPT/update - rand_nums = map (sobolNum sobol_dir_vct) [sob_offs2..sob_offs2+pop_size-1] - sob_offs3 = sob_offs2 + pop_size - (genomes_old', logLiks_old') = unzip $ - zipWith6 (\ genome_old genome_new logLik_old logLik_new bf_rat r01 -> - let exp_term = logLik_new - logLik_old - acceptance = min 1.0 $ (exp exp_term) * bf_rat - in if r01 < acceptance - then (genome_new, logLik_new) - else (genome_old, logLik_old) - ) genomes_old genomes_new' logLiks_old logLiks_new' bf_rats' rand_nums -{- - sob_offs3' = if (j `mod` 16) == 0 - then let (w_ind, w_lik) = findBestLik pop_size logLiks_old' - in trace ("It: "++show j++" Best Lik: "++show w_lik++" Genome Index: "++show w_ind) - sob_offs3 - else sob_offs3 --} - in sob_offs3 `deepseq` genomes_old' `deepseq` genomes_new' `deepseq` logLiks_old' `deepseq` - mcmcConvergenceLoop pop_size num_mcmc_its swaption_quotes sobol_dir_vct hermite_coeffs hermite_weights - genomes_old' genomes_new' logLiks_old' (j+1) sob_offs3 - - ------------------------------------------------- ---- Main Entry Point: volatility calibration --- ------------------------------------------------- --- genome == { g_a, g_b, g_rho, g_nu, g_sigma } -compute :: Int -> Int -> [Swaption] -> [Double] -> [Double] -> Vector Int - -> (Genome,Double,[[Double]]) -compute pop_size num_mcmc_its swaption_quotes - hermite_coeffs hermite_weights sobol_dir_vct = - - let ---------------------------------------------------- - -- initialization stage: compute POP_SIZE genomes -- - ---------------------------------------------------- - sobol_off0= 1 - -- compute 5*POP_SIZE random numbers! - rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) - [5*i+sobol_off0..5*i+sobol_off0+4] - ) [0..pop_size-1] - -- initalize the genomes! - genomes = map (\ r01_vct5 -> - V.zipWith3 (\ g_max g_min r01 -> (g_max - g_min)*r01 + g_min ) - g_maxs g_mins r01_vct5 - ) rand_vcts - sobol_off1= sobol_off0 + pop_size*5 - - -- evaluate the just initalized genomes! - (logLiks_th,sw_pth,bl_pth)= unzip3 $ map (evalGenome hermite_coeffs hermite_weights swaption_quotes) genomes - (logLiks,_,_)= deepseq (logLiks_th,sw_pth,bl_pth) (logLiks_th,sw_pth,bl_pth) - - -- run the MCMC Convergence Loop - (genomes', genomes_prop', logLiks', sobol_off2) = - mcmcConvergenceLoop pop_size num_mcmc_its - swaption_quotes sobol_dir_vct - hermite_coeffs hermite_weights - genomes genomes logLiks 0 sobol_off1 - - -- find the best genome and recompute - -- the calibrated and reference price for it - (win_ind, win_logLik) = findBestLik pop_size logLiks' - win_genome = genomes' !! win_ind - (_, calib_prices, black_prices) = - evalGenome hermite_coeffs hermite_weights swaption_quotes win_genome - - -- format the result for printing - (res_genome, res_logLik, res_swap_arr) = makeSummary win_genome win_logLik calib_prices black_prices - - in (res_genome, res_logLik, res_swap_arr) - - - - ----------------------------------------------- ---- Formatting the Output of the Benchmark --- ----------------------------------------------- -validate :: (Genome,Double,[[Double]]) -> - (Genome,Double,[[Double]]) -> - (Int,Int,Int) -> [String] -validate ref_res win_res (pop_size, num_mcmc_its, num_of_swaptions) = - let ((ref_a, ref_b, ref_rho, ref_nu, ref_sigma), ref_logLik, ref_swap_arr) = ref_res - ((win_a, win_b, win_rho, win_nu, win_sigma), win_logLik, win_swap_arr) = win_res - - (is_valid, err_msg) = - if (abs (ref_logLik - win_logLik)) > 1.0 - then (False, "Difference in logLikelihood > 1.0: result logLik " - ++ show win_logLik ++", reference logLik = " ++ show ref_logLik ++ "!") - else if (win_logLik < ref_logLik) && (abs (ref_logLik - win_logLik)) > 0.4 - then (False, "Result likelihood is worse than reference with more than 0.3: result logLik " - ++ show win_logLik ++ ", reference logLik = " ++ show ref_logLik ++ "!") - else foldl (\ (acc,err_msg) (ref_row, win_row, i) -> - if not acc then (acc, err_msg) - else let ref_logLik = logLikelihood (ref_row!!1) (ref_row!!0) - cur_logLik = logLikelihood (win_row!!1) (win_row!!0) - dif_logLik = if cur_logLik > ref_logLik - then 0.0 else ref_logLik - cur_logLik - in if dif_logLik > 1.1 - then (False, "Error[" ++ show i ++ "] = " ++ - show dif_logLik ++ ", Acceptable <= 1.1!") - else (True, err_msg) - ) - (True, "") (zip3 ref_swap_arr win_swap_arr [0..num_of_swaptions]) - - in ["// Swaption-Calibration Haskell Benchmark (List-Homomorphism Style):", - "// Dataset with Population "++show pop_size++", Convergence-Loop Count: " - ++show num_mcmc_its++", Number of Swaption Quotes = " ++ show num_of_swaptions ++ ".", - ( if is_valid - then "1\t\t// VALID Result," - else "0\t\t// INVALID Result," ++ err_msg ), - "0\t\t// Runtime in microseconds,", - "1\t\t// CPU Threads,", - show win_a ++ "\t// a-field of the winning genome", - show win_b ++ "\t// b-field of the winning genome", - show win_sigma ++ "\t// sigma-field of the winning genome", - show win_nu ++ "\t// nu-field of the winning genome", - show win_rho ++ "\t// rho-field of the winning genome", - show win_logLik ++ "\t// logLik-field of the winning genome", - show win_swap_arr ++ "\t//Reference Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff]" ] - - ------------------------------------------ ---- Entry point for Generic Pricing --- ---- The only place where using Monads,--- ---- e.g., parsing Dataset from StdIn --- ------------------------------------------ -main :: IO () -main = do s <- getContents - case parse run "input" s of - Left e -> error $ show e - Right m -> do - (v, runtime) <- m - writeFile "result.json" $ show v - writeFile "runtime.txt" $ show runtime - where run = do whitespace - pop_size <- readInt - num_mcmc_its <- readInt - num_swap_quotes <- readInt - swaption_quotes <- readDouble2d - num_hermite <- readInt - hermite_coeffs <- readDouble1d - hermite_weights <- readDouble1d - num_sobol_bits <- readInt - sobol_dir_vct <- readInt1d - --- let num_swap_quotes = testSwaptionPricer hermite_coeffs hermite_weights $ --- testG2ppUtil $ testMathMod $ test_dates num_swap_quotes0 - - let swaption_quotes'= map (\x -> (x!!0, x!!1, x!!2, x!!3)) swaption_quotes - - let (win_genome, win_logLik, win_swap_arr) = - compute pop_size num_mcmc_its swaption_quotes' - hermite_coeffs hermite_weights (V.fromList sobol_dir_vct) - - return $ do - start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. - let v = ((win_genome, win_logLik, win_swap_arr), - (pop_size, num_mcmc_its, num_swap_quotes)) - end <- v `deepseq` getCPUTime - return (v, (end - start) `div` 1000000000) - - readInt1d = readArray readInt - readDouble1d = readArray readDouble - readDouble2d = readArray $ readArray readDouble - --- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs --- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/instantiate b/benchmarks/InterestCalib/implementations/haskell_lh/instantiate deleted file mode 100755 index 764b7de..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/instantiate +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -set -e # Die on error. - -impl_dir=$FINPAR_IMPLEMENTATION -input=$FINPAR_INPUT - -cp $impl_dir/*hs . -cp $impl_dir/run . - -$FINPAR_LIB_DIR/linearise_data.py $FINPAR_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > input.data - -ghc -Wall -O2 -msse2 -rtsopts SwapCalib.hs -o SwapCalib diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/run b/benchmarks/InterestCalib/implementations/haskell_lh/run deleted file mode 100755 index fab10ee..0000000 --- a/benchmarks/InterestCalib/implementations/haskell_lh/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -./SwapCalib +RTS -K128m -RTS < input.data From 471abff678e2ff5951834c49d12492659e99596f Mon Sep 17 00:00:00 2001 From: Thor Date: Thu, 13 Aug 2015 15:46:40 +0200 Subject: [PATCH 039/122] removed old finpar program --- finpar_old | 355 ----------------------------------------------------- 1 file changed, 355 deletions(-) delete mode 100755 finpar_old diff --git a/finpar_old b/finpar_old deleted file mode 100755 index 80264f9..0000000 --- a/finpar_old +++ /dev/null @@ -1,355 +0,0 @@ -#!/usr/bin/env python - -import os -import subprocess -import json -import sys - -def executable(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - -class Implementation: - def __init__(self, finpar_lib_dir, benchmark_lib_dir, name, directory): - if os.path.isdir(directory): - self.directory = directory - else: - if os.path.isfile(directory): - raise Exception("File %s exists, but should be an implementation directory" % directory) - else: - raise Exception("Implementation directory %s does not exist " % directory) - - self.directory = directory - self.name = name - self.finpar_lib_dir = finpar_lib_dir - self.benchmark_lib_dir = benchmark_lib_dir - - instantiatefile = os.path.join(self.directory, "instantiate") - if not executable(instantiatefile): - raise Exception("%s is not an executable file" % instantiatefile) - self.instantiatefile = instantiatefile - - def instantiate(self, where, input_data, platform_file): - if not os.path.isdir(where): - os.mkdir(where) - - # We use the current environment as a template, and then - # extend it with some new variables. - instantiate_env = os.environ.copy() - instantiate_env["FINPAR_LIB_DIR"] = self.finpar_lib_dir - instantiate_env["FINPAR_BENCHMARK_LIB_DIR"] = self.benchmark_lib_dir - instantiate_env["FINPAR_IMPLEMENTATION"] = self.directory - instantiate_env["FINPAR_INPUT"] = input_data - instantiate_env["FINPAR_PLATFORM"] = platform_file - - # Here we are running the "instantiate" program with appropriate vars. "instantiate" should be replaced by a call to make. - proc = subprocess.Popen(self.instantiatefile, - env=instantiate_env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - close_fds=True, - cwd=where) - (stdoutdata, stderrdata) = proc.communicate(input=None) - # returncode = 0 upon success. If retcode = 0, then stdout & stderr are empty. - return (proc.returncode, stdoutdata, stderrdata) - -class Benchmark: - # In the constructor, we do some basic sanity-checking. The - # primary purpose here is to provide better error messages than if - # we fail to read files later down the line. - def __init__(self, finpardir, name, directory): - self.finpardir = finpardir - self.name = name - - if os.path.isdir(directory): - self.directory = directory - else: - raise Exception("Benchmark directory %s does not exist" % directory) - dircontents = os.listdir(self.directory) - - # The lib directories do not have to exist. - self.benchmark_lib_dir = os.path.join(self.directory, "lib") - self.finpar_lib_dir = os.path.join(self.finpardir, "lib") - - if "implementations" in dircontents: - self.__gather_implementations() - else: - raise Exception("No implementation directory in %s" % directory) - - if "datasets" in dircontents: - self.datasets = os.path.join(self.directory, "datasets") - self.__gather_datasets() - else: - raise Exception("No datasets directory in %s" % directory) - - def __gather_implementations(self): - self.implementations = [] - for impl in os.listdir(os.path.join(self.directory, "implementations")): - implpath = os.path.join(self.directory, "implementations", impl) - if os.path.isdir(implpath): - self.implementations.append(Implementation(self.finpar_lib_dir, - self.benchmark_lib_dir, - impl, - os.path.join(self.directory, "implementations", impl))) - - def __gather_datasets(self): - self.datasets = {} - for dataset in os.listdir(os.path.join(self.directory, "datasets")): - datasetpath = os.path.join(self.directory, "datasets", dataset) - if os.path.isdir(datasetpath): - inputfile = os.path.join(self.directory, "datasets", dataset, "input.json") - outputfile = os.path.join(self.directory, "datasets", dataset, "output.json") - if not os.path.isfile(inputfile): - raise Exception("File %s missing or not a file." % inputfile) - if not os.path.isfile(outputfile): - raise Exception("File %s missing or not a file." % outputfile) - - self.datasets[dataset] = { 'input_file' : inputfile, - 'expected_output' : read_json_file(outputfile) - } - -def desc_triple(benchmark, implementation, dataset): - return "Benchmark %s, implementation %s, dataset %s" % (benchmark, implementation, dataset) - -def note_result(results, benchmark, implementation, dataset, runtime): - results[(benchmark,implementation,dataset)] = runtime - -def run_some_benchmark_implementations(finpar_dir, - workdir, - benchmarkdir, - platform, - run_implementation_fn, - use_dataset_fn): - b = Benchmark(finpar_dir, os.path.basename(benchmarkdir), benchmarkdir) - insts = [] - failed_insts = [] - results = {} - - for impl in b.implementations: - if not run_implementation_fn(impl): - continue - for dataset in b.datasets: - if not use_dataset_fn(dataset): - continue - instdir = os.path.join(workdir, - "%s-%s-%s" % (b.name, impl.name, dataset)) - print("Instantiating in %s" % instdir) - (retcode, stdout, stderr) = impl.instantiate(instdir, b.datasets[dataset]['input_file'], platform) - if retcode != 0: - failed_insts.append({ 'benchmark' : b.name, - 'implementation' : impl.name, - 'dataset' : dataset, - 'instantiation_directory' : instdir, - 'retcode' : retcode, - 'stdout' : stdout, - 'stderr' : stderr}) - print("Spoiler: failed") - else: - insts.append({ 'benchmark' : b.name, - 'implementation' : impl.name, - 'dataset' : dataset, - 'instantiation_directory' : instdir, - 'expected_output' : b.datasets[dataset]['expected_output'] - }) - - for inst in insts: - instdir = inst['instantiation_directory'] - print("\nRunning %s" % instdir) - stdoutpath = os.path.join(instdir, "stdout.log") - stderrpath = os.path.join(instdir, "stderr.log") - with open(stdoutpath, "w") as stdout: - with open(stderrpath, "w") as stderr: - print("Output can be found in %s and %s" % (stdoutpath, stderrpath)) - try: - proc = subprocess.Popen(os.path.join(instdir, "run"), - stdout=stdout, - stderr=stderr, - stdin=subprocess.PIPE, - close_fds=True, - cwd=instdir) - proc.stdin.close() # Make sure stdin EOFs. - proc.wait() - except: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "could not run") - continue - - if proc.returncode != 0: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "non-zero exit code") - continue - - try: - runtime = read_runtime(instdir) - except IOError: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "no runtime measurement") - continue - except ValueError: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "non-integer runtime measurement") - continue - - try: - result = read_json_file(os.path.join(instdir, "result.json")) - expected = inst['expected_output'] - if compare_json(result, expected): - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - runtime) - else: - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "invalid result") - except (IOError, ValueError): - note_result(results, - inst['benchmark'], - inst['implementation'], - inst['dataset'], - "cannot read result") - return (results, failed_insts) - -def read_runtime(instdir): - with open(os.path.join(instdir, "runtime.txt"), "r") as file: - return int(file.read()) - -def read_json_file(filename): - with open(filename, "r") as file: - return json.loads(file.read()) - -epsilon = 0.001 - -# Generic comparison function using epsilon for comparing floats. -def compare_json(json1, json2): - if type(json1) != type(json2): - return False - - if type(json1) is float: - return abs(json1-json2) < epsilon - - if type(json1) is list: - if len(json1) != len(json2): - return False - for x,y in zip(json1, json2): - if not compare_json(x,y): - return False - return True - - if type(json1) is dict: - keys1 = json1.keys() - keys2 = json2.keys() - keys1.sort() - keys2.sort() - if keys1 == keys2: - for key in keys1: - if not compare_json(json1[key], json2[key]): - return False - return True - else: - return False - - return json1 == json2 - -def what_to_run(): - if len(sys.argv) == 1: - return ("benchmarks/CalibVolDiff", None, None) - elif len(sys.argv) == 2: - return (sys.argv[1], None, None) - elif len(sys.argv) == 3: - return (sys.argv[1], sys.argv[2].split(','), None) - elif len(sys.argv) == 4: - return (sys.argv[1], sys.argv[2].split(','), sys.argv[3].split(',')) - else: - exit("Usage: %s [benchmark] [implementation1,implementation2,...] [dataset1,dataset2,...]" % - sys.argv[0]) - -if __name__ == '__main__': - (benchmark, implementations, datasets) = what_to_run() - instantiations_dir = "instantiations" - platform_file = "config/platform_example.json" - - print("Assuming I am being run from main finpar directory.") - print("Will run benchmark %s." % benchmark) - - if implementations is None: - print("Will run all implementations.") - else: - print("Will run these implementations: %s" % implementations) - - if datasets is None: - print("Will use all datasets.") - else: - print("Will use these datasets: %s" % datasets) - - print("Will instantiate in %s." % instantiations_dir) - print("Will use platform configuration %s." % platform_file) - finpar_dir = os.getcwd() - - def run_implementation_fn(impl): - if implementations is None: - return True - else: - return impl.name in implementations - - def use_dataset_fn(dataset): - if datasets is None: - return True - else: - return dataset in datasets - - (results, failed_to_instantiate) = ( - run_some_benchmark_implementations(finpar_dir, - os.path.join(finpar_dir, instantiations_dir), - os.path.join(finpar_dir, benchmark), - os.path.join(finpar_dir, platform_file), - run_implementation_fn, - use_dataset_fn) - ) - - for failed in failed_to_instantiate: - print("Failed to instantiate implementation %s with dataset %s; exit code %d." % - (failed['implementation'], failed['dataset'], failed['retcode'])) - print("Stdout\n") - print(failed['stdout']) - print("Stderr\n") - print(failed['stderr']) - print("") - - successful = {} - failed = {} - - for result in results: - if type(results[result]) is int: - successful[result] = results[result] - else: - failed[result] = results[result] - - print "\nFailed:" - for f in failed: - (benchmark, implementation, dataset) = f - print("%s: %s" % - (desc_triple(benchmark, implementation, dataset), - failed[f])) - - print "\nSucceeded:" - for s in successful: - (benchmark, implementation, dataset) = s - print("%s: %s" % - (desc_triple(benchmark, implementation, dataset), - successful[s])) From 0558ff563bc8a286d5bb9f43d4f4c162514e8f0a Mon Sep 17 00:00:00 2001 From: Thor Date: Thu, 13 Aug 2015 16:01:04 +0200 Subject: [PATCH 040/122] library functions for InterestCalib have been copied from the master branch. So has the two included InterestCalib implementations. --- .../InterestCalib/lib/include/ParseInput.h | 97 +++++++++++++++++++ .../InterestCalib/lib/include/WriteResult.h | 37 ------- 2 files changed, 97 insertions(+), 37 deletions(-) delete mode 100644 benchmarks/InterestCalib/lib/include/WriteResult.h diff --git a/benchmarks/InterestCalib/lib/include/ParseInput.h b/benchmarks/InterestCalib/lib/include/ParseInput.h index efddda2..042725c 100644 --- a/benchmarks/InterestCalib/lib/include/ParseInput.h +++ b/benchmarks/InterestCalib/lib/include/ParseInput.h @@ -98,5 +98,102 @@ void readDataSet( UINT& pop_size, } } +REAL* readOutput( const int& N, REAL& ref_logLik ) { + REAL* result; + int64_t shape[3]; + + REAL ref_a, ref_b, ref_sigma, ref_nu, ref_rho; + + // reading the reference genome! + if( read_real( &ref_a ) || read_real( &ref_b ) || + read_real( &ref_sigma ) || read_real( &ref_nu ) || + read_real( &ref_rho ) || read_real( &ref_logLik ) ) { + fprintf(stderr, "Syntax error when reading the reference genome or its likelihood.\n"); + exit(1); + } + + // reading the standard output + if ( read_array(sizeof(REAL), read_real, (void**)&result, shape, 2) ) { + fprintf(stderr, "Syntax error when reading the output.\n"); + exit(1); + } + bool ok = ( shape[0] == N ) && ( shape[1] == 3 ); + assert(ok && "Incorrect shape of the reference array result!"); + + return result; +} + +bool validate( const REAL& logLik, const REAL* res, const int& N ) { + bool is_valid = true; + + REAL ref_logLik; + REAL* ref_res = readOutput( N, ref_logLik ); + + if( fabs(ref_logLik - logLik) > 1.0 ) { + is_valid = false; + fprintf(stderr, "Difference in logLikelihood > 1.0: result logLik %f, reference logLik = %f!\n", + logLik, ref_logLik ); + return is_valid; + } else if ( logLik < ref_logLik && fabs(ref_logLik - logLik) > 0.5 ) { + is_valid = false; + fprintf(stderr, "Result likelihood is worse than reference with more than 0.5: result logLik %f, reference logLik = %f!\n", + logLik, ref_logLik ); + return is_valid; + } + + for ( int i = 0; i < N; i ++ ) { + REAL lgLik_cur = logLikelihood( res[3*i+1], res[3*i]); + REAL lgLik_ref = logLikelihood(ref_res[3*i+1],ref_res[3*i]); + REAL diff_curr_lgLik = (lgLik_cur > lgLik_ref) ? + 0.0 : lgLik_ref - lgLik_cur ; + + if (diff_curr_lgLik > 0.7) { + is_valid = false; + fprintf(stderr, "Error[%d] = %f, Acceptable = 1.1!\n", + i, diff_curr_lgLik ); + break; + } + } + + return is_valid; +} + +void writeStatsAndResult( const bool& valid, + const REAL& wg_a, + const REAL& wg_b, + const REAL& wg_sigma, + const REAL& wg_nu, + const REAL& wg_rho, + const REAL& wg_logLik, + const REAL* calib_arr, + const int & NUM_SWAP_QUOTES, + const bool& is_gpu, + const int & P, + const unsigned long int& elapsed +) { + // print stats to stdout + fprintf(stdout, "// Dataset with Number of Swaption Quotes = %d.\n", + NUM_SWAP_QUOTES ); + + if(valid) { fprintf(stdout, "1\t\t// VALID Result,\n"); } + else { fprintf(stdout, "0\t\t// INVALID Result,\n"); } + + fprintf(stdout, "%ld\t\t// Runtime in microseconds,\n", elapsed); + if(is_gpu) fprintf(stdout, "%d\t\t// GPU Threads,\n\n", P); + else fprintf(stdout, "%d\t\t// CPU Threads,\n\n", P); + + // write the genome + write_scal(&wg_a, "a-field of the winning genome"); + write_scal(&wg_b, "b-field of the winning genome"); + write_scal(&wg_sigma, "sigma-field of the winning genome"); + write_scal(&wg_nu, "nu-field of the winning genome"); + write_scal(&wg_rho, "rho-field of the winning genome"); + write_scal(&wg_logLik,"LgLikelihood of the winning genome"); + + // write the result + write_2Darr( calib_arr, static_cast(NUM_SWAP_QUOTES), 3, + "Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff]" ); +} + #endif // PARSE_INPUT diff --git a/benchmarks/InterestCalib/lib/include/WriteResult.h b/benchmarks/InterestCalib/lib/include/WriteResult.h deleted file mode 100644 index a263cdc..0000000 --- a/benchmarks/InterestCalib/lib/include/WriteResult.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef WRITERESULT_H -#define WRITERESULT_H - -#include - -/* Writes trailing comma and newline. */ -void writeRealField(FILE *stream, const char* field, REAL x) -{ - fprintf(stream, "\"%s\": %f,\n", field, x); -} - -void writeResult(FILE *stream, - REAL a, - REAL b, - REAL sigma, - REAL nu, - REAL rho, - REAL logLik, - REAL* calib_arr) -{ - /* Hackily manually generate JSON. It would be nice with some - proper library support. */ - fprintf(stream, "{\n"); - - writeRealField(stream, "a_field", a); - writeRealField(stream, "b_field", b); - writeRealField(stream, "sigma_field", sigma); - writeRealField(stream, "nu_field", nu); - writeRealField(stream, "rho_field", rho); - writeRealField(stream, "lg_likelyhood", logLik); - - fprintf(stream, "\"swaption_calibration_result\":\n"); - write_2Darr(stream, calib_arr, static_cast(NUM_SWAP_QUOTES), 3); - fprintf(stream, "}\n"); -} - -#endif From 93449e3f9ea759cc612d1bafbe7f9420e05815b2 Mon Sep 17 00:00:00 2001 From: Thor Date: Thu, 13 Aug 2015 16:07:30 +0200 Subject: [PATCH 041/122] library functions for InterestCalib have been copied from the master branch. So has the two included InterestCalib implementations. --- .../implementations/CppOpenMP/GenAlgFlat.h | 266 +++++++++++++++++ .../implementations/CppOpenMP/Makefile | 42 +++ .../implementations/CppOpenMP/SwapCalib | Bin 0 -> 85584 bytes .../implementations/CppOpenMP/SwapCalib.cpp | 62 ++++ .../implementations/CppOpenMP/UtilCPU.h | 102 +++++++ .../implementations/OrigCpp/EvalGenomeOrig.h | 155 ++++++++++ .../implementations/OrigCpp/G2PPorig.h | 176 +++++++++++ .../implementations/OrigCpp/GenAlgFlat.h | 281 ++++++++++++++++++ .../implementations/OrigCpp/Genome.h | 238 +++++++++++++++ .../implementations/OrigCpp/Makefile | 42 +++ .../implementations/OrigCpp/SwapCalib | Bin 0 -> 76488 bytes .../implementations/OrigCpp/SwapCalib.cpp | 49 +++ .../implementations/OrigCpp/UtilCPU.h | 48 +++ 13 files changed, 1461 insertions(+) create mode 100644 benchmarks/InterestCalib/implementations/CppOpenMP/GenAlgFlat.h create mode 100644 benchmarks/InterestCalib/implementations/CppOpenMP/Makefile create mode 100755 benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib create mode 100644 benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp create mode 100644 benchmarks/InterestCalib/implementations/CppOpenMP/UtilCPU.h create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/Genome.h create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/Makefile create mode 100755 benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib.cpp create mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/UtilCPU.h diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/CppOpenMP/GenAlgFlat.h new file mode 100644 index 0000000..4dac1f3 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/GenAlgFlat.h @@ -0,0 +1,266 @@ +#ifndef GEN_ALG_FLAT +#define GEN_ALG_FLAT + +#include "Constants.h" +#include "GenAlgUtil.h" +#include "Candidate.h" + +#include "IrregShape.h" +#include "EvalGenomeInl.h" +#include "UtilCPU.h" + +/** + * Printing Swaption / Calibrated Price / Black Price / RMS + * The result is an array REAL[NUM_SWAP_QUOTES, 3] recording + * for each swaption the calibrated price, the black price + * and the percentagewise difference between the two. + */ +REAL* makeSummary(uint winner, CpuArrays& arrs) { + REAL* res = (REAL*) malloc( 3*NUM_SWAP_QUOTES*sizeof(REAL) ); + + REAL rms = 0.0; + + fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); + fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", + arrs.get_a() [winner], arrs.get_b() [winner], arrs.get_sigma ()[winner], + arrs.get_nu()[winner], arrs.get_rho()[winner], arrs.get_logLik()[winner] ); + fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); + + for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { + REAL black_price = arrs.get_quote(winner)[i]; + REAL calib_price = arrs.get_price(winner)[i]; + REAL err_ratio = (calib_price - black_price) / black_price; + + res[3*i + 0] = 10000.0*calib_price; + res[3*i + 1] = 10000.0*black_price; + res[3*i + 2] = 100.0*fabs(err_ratio); + + rms += err_ratio * err_ratio; + + fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", + i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], + res[3*i + 0], res[3*i + 1], res[3*i + 2] ); + } + + rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); + fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); + + return res; +} + + +/** + * Utility function: find the genome with the best likelihood: + * scans the logLik array and fill in the index and likelihood + * of the best genome. + */ +void find_best(const REAL* logLik, int& best_ind, REAL& best_lik) { + bool sanity = true; + + best_lik = -INFINITY; + best_ind = 0; + + // this is in fact a reduction, but POP_SIZE is + // not big enough to warrant a parallel execution. + for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX + REAL val = logLik[i]; + + sanity = !( isnan(val) || isinf(val) ); + assert( sanity && "val is NaN in find_best" ); + + if( val > best_lik ) { best_ind = i; best_lik = val; } + } +} + +Move_Type selectMoveType(REAL move_selected) { + Move_Type move_type = NONE; + + REAL prob; + Move_Type type; + UINT k = 0; + do { + prob = mcmc_moves_selection_cumdensfct[k].fst; + type = mcmc_moves_selection_cumdensfct[k].snd; + + if( move_selected <= prob ) { + move_type = type; + } + k ++; + } while ( move_selected > prob && k < CUMDENSFCT_CARD ); + + assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); + + return move_type; +} + +/** + * Main Entry Point for Swaption Calibration + * The (out) arguments are in fact the resulted + * winning genome result & its likelihood. + * The array result has size 3*NUM_SWAP_QUOTES + * and records for each swaption the calibrated + * price, the black price and the percentage + * difference between the two. + */ +REAL* mainKernelCPU(REAL& wg_a, + REAL& wg_b, + REAL& wg_sigma, + REAL& wg_nu, + REAL& wg_rho, + REAL& wg_logLik +) { + uint FLAT_SZ; + short* shape = getIregShapeAdjusted( LWG_EG, FLAT_SZ ); + int * start_inds = getStartInd( FLAT_SZ, shape, NUM_SWAP_QUOTES ); + + CpuArrays cpu_arrs(FLAT_SZ, shape); + REAL *g_a, *g_b, *g_rho, *g_nu, *g_sigma, *logLik, *bf_rat; + { // getting the cpu arrays + g_a = cpu_arrs.get_a (); + g_b = cpu_arrs.get_b (); + g_rho = cpu_arrs.get_rho (); + g_nu = cpu_arrs.get_nu (); + g_sigma = cpu_arrs.get_sigma (); + logLik = cpu_arrs.get_logLik(); + bf_rat = cpu_arrs.get_bf_rat(); + } + + srand ( SEED ); + srand48 ( SEED ); + + // initialized the genomes with random numbers inside + // their acceptable bounds => requires 5*POP_SIZE randoms + for( int i = 0; i < POP_SIZE; i++ ) { + REAL r01, tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; + g_a [i ] = tmp; + g_a [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; + g_b [i ] = tmp; + g_b [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; + g_rho [i ] = tmp; + g_rho [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; + g_nu [i ] = tmp; + g_nu [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; + g_sigma [i ] = tmp; + g_sigma [i + POP_SIZE] = tmp; + + bf_rat [i ] = 1.0; + } + + // Initial evaluation of the genomes! +#pragma omp parallel for default(shared) schedule(dynamic) if(POP_SIZE>3) + for( int i = 0; i < POP_SIZE; i++ ) { + logLik[i] = eval_genome( g_a[i], g_b[i], g_rho[i], g_nu[i], g_sigma[i], + cpu_arrs.get_quote(i), cpu_arrs.get_price(i), + FLAT_SZ, shape, start_inds + ); + } + + // convergence loop that runs the genetic algorithms + // (takes a population and returns a population) + for( int j = 0; j < MCMC_LOOPS; j++ ) { + + // select which move to perform. + // Note: this block can also be a loop (in fixed order) + // over the various move types + REAL move_selected = getRandUnifNorm(); + Move_Type move_type = selectMoveType(move_selected); + + if ( move_type == DIMS_ALL ) { + for( int i = 0; i < POP_SIZE; i++ ) { + mutate_dims_all( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); + } + + } else if ( move_type == DIMS_ONE ) { + + UINT dim_j = getRandIntNorm(GENOME_DIM); + + for( int i = 0; i < POP_SIZE; i++ ) { + mutate_dims_one( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i, dim_j ); + } + } else /* if ( move_type == DEMCMC ) */ { + + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums + mcmc_DE( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); + } + } + + // evaluate the proposal +#pragma omp parallel for default(shared) schedule(dynamic) if(POP_SIZE>3) + for( int i = 0; i < POP_SIZE; i++ ) { + logLik[i+POP_SIZE] = + eval_genome( g_a [i+POP_SIZE], g_b [i+POP_SIZE], g_rho[i+POP_SIZE], + g_nu[i+POP_SIZE], g_sigma[i+POP_SIZE], + cpu_arrs.get_quote(i), cpu_arrs.get_price(i), + FLAT_SZ, shape, start_inds ); + } + + // mcmc_acceptance_rejection(); + // Deciding whether to accept or reject the proposal, + // obtained by mutating/crossover of the individual. + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel + // Metropolis: get a random U[0,1) for each candidate + REAL rand = getRandUnifNorm(); + + // selection: dimensions considered independent + // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) + REAL acceptance = std::min( 1.0, exp( logLik[i+POP_SIZE] - logLik[i] ) * bf_rat[i] ); + + // if acceptance criterion is met then p->p' else does nothing + if ( rand < acceptance ) accept( i, g_a, g_b, g_rho, g_nu, g_sigma, logLik ); + } + + // print best candidate for the current iteration: + if ( (j % 16) == 0 ){ + int best_ind; REAL best_lik; + find_best(logLik, best_ind, best_lik); + fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", + j, best_lik, best_ind ); + } + } + + REAL* result; + { // print best candidate for the current iteration: + int best_ind; REAL best_lik; + find_best(logLik, best_ind, best_lik); + + // recompute the calibrated price and the black price! + logLik[best_ind] = + eval_genome( g_a[best_ind], g_b[best_ind], g_rho[best_ind], g_nu[best_ind], + g_sigma[best_ind], cpu_arrs.get_quote(best_ind), + cpu_arrs.get_price(best_ind), FLAT_SZ, shape, start_inds ); + + // Finally, make/print the result! + wg_a = cpu_arrs.get_a() [best_ind]; + wg_b = cpu_arrs.get_b() [best_ind]; + wg_sigma = cpu_arrs.get_sigma ()[best_ind]; + wg_nu = cpu_arrs.get_nu() [best_ind]; + wg_rho = cpu_arrs.get_rho() [best_ind]; + wg_logLik = cpu_arrs.get_logLik()[best_ind]; + + result = makeSummary( best_ind, cpu_arrs ); + } + + delete[] start_inds; + // Releasing the CPU resources: + cpu_arrs.releaseResources(); + + return result; +} + +#endif // end ifndef + diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile new file mode 100644 index 0000000..0cac6e1 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile @@ -0,0 +1,42 @@ +include ../../setup.mk + +ifndef ($(HAVE_GPU)) +include ../../platform.mk +endif + +INCLUDES += -I../includeC +GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) +#-fno-unsafe-math-optimizations -fno-finite-math-only +#-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans + +SOURCES_CPP =SwapCalib.cpp +HELPERS =../includeC/ParseInput.h +OBJECTS =SwapCalib.o +EXECUTABLE =SwapCalib + + +default: cpu + +.cpp.o: $(SOURCES_CPP) $(HELPERS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< + +# The GPU version is in: ../CppAndGPU. This folder is CPU only! +gpu: $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + +cpu: $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + + +run_small: $(EXECUTABLE) + cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_medium: $(EXECUTABLE) + cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_large: $(EXECUTABLE) + cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib b/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib new file mode 100755 index 0000000000000000000000000000000000000000..b8aafbb55bf017f712e1f7c2f0946e2efacb952b GIT binary patch literal 85584 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ⅆ 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 literal 0 HcmV?d00001 diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp new file mode 100644 index 0000000..231217d --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp @@ -0,0 +1,62 @@ +/****************************************/ +/*** Translated to C++ & parallelized ***/ +/*** in OpenCL by Cosmin E. Oancea ***/ +/*** from an original OCaml code ***/ +/*** (sequential) by LexiFi ***/ +/*** and a sequential Python implem ***/ +/*** using a different genetic alg.***/ +/*** by Christian Andreetta ***/ +/****************************************/ + +#include "Util.h" +#include "Constants.h" +#include "ParseInput.h" +#include "GenAlgFlat.h" + +int main() +{ + REAL wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, + wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; + REAL* calib_arr = NULL; + + printf("\n// Running Original (CPU Parallel) Swaption-Calibration Benchmark\n"); + + readDataSet( POP_SIZE, MCMC_LOOPS, + NUM_SWAP_QUOTES, SwaptionQuotes, + NUM_HERMITE, HermiteCoeffs, HermiteWeights, + NUM_SOBOL_BITS, SobolDirVct + ); + + unsigned long int elapsed = 0; + { // Main Computational Kernel + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + calib_arr = mainKernelCPU(wg_a, wg_b, wg_sigma, wg_nu, wg_rho, wg_logLik); + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + } + + { // validation and writeback of the result + const int Ps = get_CPU_num_threads(); + bool is_valid = validate( wg_logLik, calib_arr, NUM_SWAP_QUOTES ); + writeStatsAndResult( is_valid, wg_a, wg_b, wg_sigma, wg_nu, wg_rho, + wg_logLik, calib_arr, NUM_SWAP_QUOTES, + false, Ps, elapsed ); + } + + return 1; +} + + +#if 0 +void test_all() { + test_dates (); + test_math (); + test_g2ppUtil (); + test_pricer_of_swaption(); +} +#endif + diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/UtilCPU.h b/benchmarks/InterestCalib/implementations/CppOpenMP/UtilCPU.h new file mode 100644 index 0000000..4ed4ec9 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/UtilCPU.h @@ -0,0 +1,102 @@ +#ifndef CPU_UTILITIES +#define CPU_UTILITIES + +/************************/ +/*** Helper Functions ***/ +/************************/ +bool is_pow2(uint n) { + uint c = 1; + while(c < n) { + c = c << 1; + } + return (c == n); +} + + +struct CpuArrays { + // size of the shape array + const uint SS; + + // shape of the irregular arrays for one genome + short* shape; + + // [13 * POP_SIZE] = + // { a, a_p, b, b_p, rho, rho_p, nu, nu_p, + // sigma, sigma_p, logLik, logLik_p, bf_rat } + REAL* genomes; + + // [ 4 * SS * POP_SIZE ] + REAL* ci_t1cs_scale; + + // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] + REAL* new_quote_price; + + // [ NUM_SWAP_QUOTES*NUM_HERMITE ] + REAL* accum0; + + // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] + // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, + // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } + REAL* scalars; + + REAL gene_ranges[10]; + + CpuArrays (const uint n, short* shp) : SS(n) { + shape = shp; + + genomes = new REAL[ 13 * POP_SIZE ]; + ci_t1cs_scale = new REAL[ 4 * SS * POP_SIZE ]; + scalars = new REAL[ 8 * NUM_SWAP_QUOTES * POP_SIZE ]; + + new_quote_price = new REAL [ 2 * NUM_SWAP_QUOTES * POP_SIZE ]; + accum0 = new REAL [ NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE ]; + + for(int i=0; i<5; i++) { gene_ranges[i] = g_mins[i]; } + for(int i=0; i<5; i++) { gene_ranges[i+5] = g_maxs[i]; } + } + + void releaseResources() { + delete[] shape; + delete[] genomes; + delete[] ci_t1cs_scale; + delete[] scalars; + delete[] new_quote_price; + delete[] accum0; + } + + // genome helpers + REAL* get_a () { return genomes; } + REAL* get_b () { return genomes + POP_SIZE*2; } + REAL* get_rho () { return genomes + POP_SIZE*4; } + REAL* get_nu () { return genomes + POP_SIZE*6; } + REAL* get_sigma () { return genomes + POP_SIZE*8; } + REAL* get_logLik() { return genomes + POP_SIZE*10;} + REAL* get_bf_rat() { return genomes + POP_SIZE*12;} + + // get the shape of the irregular array (for one genome) + short* get_shape (){ return shape; } + + // get the start iterator into arrays ci, t1cs, scale for genome i + REAL* get_ci (int i) { return ci_t1cs_scale + SS*i; } + REAL* get_t1cs (int i) { return ci_t1cs_scale + SS*i + SS*POP_SIZE; } + REAL* get_scale (int i) { return ci_t1cs_scale + SS*i + 2*SS*POP_SIZE; } + REAL* get_bbi (int i) { return ci_t1cs_scale + SS*i + 3*SS*POP_SIZE; } + + // get the start iterator into array-expanded scalars for genome i + REAL* get_mux (int i) { return scalars + i * NUM_SWAP_QUOTES ; } + REAL* get_muy (int i) { return scalars + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } + REAL* get_sqsigx(int i) { return scalars + i * NUM_SWAP_QUOTES + 2 * NUM_SWAP_QUOTES * POP_SIZE; } + REAL* get_t2 (int i) { return scalars + i * NUM_SWAP_QUOTES + 3 * NUM_SWAP_QUOTES * POP_SIZE; } + REAL* get_sigrho(int i) { return scalars + i * NUM_SWAP_QUOTES + 4 * NUM_SWAP_QUOTES * POP_SIZE; } + REAL* get_zcmat (int i) { return scalars + i * NUM_SWAP_QUOTES + 5 * NUM_SWAP_QUOTES * POP_SIZE; } + REAL* get_f (int i) { return scalars + i * NUM_SWAP_QUOTES + 6 * NUM_SWAP_QUOTES * POP_SIZE; } + REAL* get_df (int i) { return scalars + i * NUM_SWAP_QUOTES + 7 * NUM_SWAP_QUOTES * POP_SIZE; } + + // get the quotes prices for genome i + REAL* get_quote (int i) { return new_quote_price + i * NUM_SWAP_QUOTES; } + REAL* get_price (int i) { return new_quote_price + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } + + // get the accumulator for the irregular array for genome i + REAL* get_accum (int i) { return accum0 + i * NUM_SWAP_QUOTES * NUM_HERMITE; } +}; +#endif // CPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h b/benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h new file mode 100644 index 0000000..efea067 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h @@ -0,0 +1,155 @@ +#ifndef EVAL_GENOME_INLINED +#define EVAL_GENOME_INLINED + +#include "Constants.h" +#include "GenAlgUtil.h" +#include "G2PP.h" +#include "G2PPorig.h" + + +/** + * MOST IMPORTANTLY: GENOME EVALUATION By Pricer of Swaption & BLACK PRICE + */ +void eval_genome_new ( + const REAL& a, + const REAL& b, + const REAL& rho, + const REAL& nu, + const REAL& sigma, + const REAL* swaption, + IntermElem* tmp_arrs, + REAL& new_quote, // output + REAL& new_price // output +) { + bool sanity = true; + + const REAL swap_freq = swaption[1]; + const REAL maturity = add_years( TODAY, swaption[0] ); + const UINT n_schedi = static_cast(12.0 * swaption[2] / swap_freq); + const REAL tmat0 = date_act_365( maturity, TODAY ); + + REAL strike; + { // BLACK PRICE computation + REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; + + for(UINT i = 0; i < n_schedi; i++) { // reduce o map + // Map computes a1 and a2 (depends on i) + const REAL a1 = add_months( maturity, swap_freq*i ); + const REAL a2 = add_months( a1, swap_freq ); + + // Reduction( lvl: +, t0 : min, tn : max ) + lvl += zc(a2) * date_act_365(a2, a1); + t0 = std::min(t0, a1); + tn = std::max(tn, a2); + } + + strike = ( zc(t0) - zc(tn) ) / lvl; + const REAL d1 = 0.5 * swaption[3] * tmat0; + new_quote = lvl * strike * ( uGaussian_P(d1) - uGaussian_P(-d1) ); + } // END BLACK PRICE + + { // PRICER OF SWAPTION COMPUTATION + REAL v0_mat, dummy1, dummy2; + bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); +// + const REAL mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); + const REAL muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); +// + const REAL zc_mat = zc(maturity); +// + const REAL sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); + const REAL sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); + const REAL rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); + const REAL sigmax = sigma * sqrt_bfun_a; + const REAL sigmay = nu * sqrt_bfun_b; + + const REAL rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel + const REAL rhoxycs = sqrt( rhoxyc ); // used in reduction kernel + const REAL sigmay_rhoxycs = sigmay * rhoxycs; + const REAL t4 = (rhoxy * sigmay) / sigmax; + + for( UINT i = 0; i < n_schedi; i++ ) { + const REAL beg_date = add_months( maturity, swap_freq*i ); //scheduleix[i]; + const REAL end_date = add_months( beg_date, swap_freq ); //scheduleiy[i]; + const REAL res = date_act_365( end_date, beg_date ) * strike; + + const REAL cii = ( i == n_schedi-1 ) ? 1.0 + res : res; + + REAL v0_end, vt_end, baii, bbii, date_tod1, date_tod2; + date_tod1 = date_act_365(end_date, TODAY); + bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); + date_tod2 = date_act_365(end_date, maturity); + bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); + + const REAL expo_aici = 0.5 * (vt_end - v0_end + v0_mat); + const REAL fact_aici = cii * zc(end_date) / zc_mat; + tmp_arrs[i].ci = fact_aici; // reuse the space to hold the factor of t1_cs + tmp_arrs[i].t1_cs = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; + // hold only the exponent of the original t1_cs; + + tmp_arrs[i].bai = baii; + tmp_arrs[i].bbi = bbii; + tmp_arrs[i].aici = fact_aici * exp( expo_aici ); + tmp_arrs[i].log_aici = log( fact_aici ) + expo_aici; + tmp_arrs[i].scale = - ( baii + bbii * t4 ); + + sanity = ! ( isinf(tmp_arrs[i].aici) || isnan(tmp_arrs[i].aici) ); + assert(sanity && "Nan aici in pricer of swaption. Exiting!\n"); + } + + const REAL eps = 0.5 * sigmax; + + const REAL f = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + mux, muy, tmp_arrs, mux ); + + const REAL g = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + mux, muy, tmp_arrs, mux + eps ); + + const REAL h = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + mux, muy, tmp_arrs, mux - eps ); + + const REAL df = 0.5 * ( g - h ) / eps; + + const REAL sqrt2sigmax = sqrt(2.0) * sigmax;; + const REAL t2 = rhoxy / (sigmax*rhoxycs);; + + REAL accum = 0.0; + + for( UINT j = 0; j < NUM_HERMITE; j++ ) { + const REAL x_quad = HermiteCoeffs [j]; + const REAL w_quad = HermiteWeights[j]; + + const REAL x = sqrt2sigmax * x_quad + mux; + const REAL yhat_x = f + df*(x - mux); + const REAL h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); + + REAL accum1 = 0.0; + for( UINT i = 0; i < n_schedi; i++ ) { + const REAL h2 = h1 + tmp_arrs[i].bbi * sigmay_rhoxycs; + + const REAL expo_aici = tmp_arrs[i].t1_cs + tmp_arrs[i].scale*x; + const REAL fact_aici = tmp_arrs[i].ci; + const REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); + accum1 += fact_aici * expo_part; + } + + sanity = ! ( isnan(accum1) || isinf(accum1) ); + assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); + + REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; + const REAL t1 = exp( - 0.5 * tmp * tmp ); + + accum += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); + } + + sanity = ! ( isnan(accum) || isinf(accum) ); + assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); + + new_price = zc_mat * ( accum / sqrt( PI ) ); + } +} + + + +#endif // end ifndef EVAL_GENOME_INLINED + diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h b/benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h new file mode 100644 index 0000000..5f324a4 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h @@ -0,0 +1,176 @@ +#ifndef G2PPORIG +#define G2PPORIG + +#include "Constants.h" +#include "Date.h" +#include "MathModule.h" +#include "G2ppUtil.h" + +#include "GenAlgUtil.h" + +REAL to_solve_orig( const UINT& N, + const IntermElem* tmp_arrs, + const REAL& yhat ) { + REAL accum = 0.0; + for( UINT i = 0; i < N; i++ ) { + accum += tmp_arrs[i].hat_scale * exp( - tmp_arrs[i].bbi * yhat ); + } + return accum - 1.0; +} + +////////////////////////// +// Root finder +////////////////////////// + +void rootFinding_Brent_orig ( + const UINT& N, + IntermElem* tmp_arrs, + const REAL& lb, + const REAL& ub, + const REAL& toll, + const UINT& it_mx, + REAL& root, // result + UINT& it, + REAL& fb +) { + const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; + const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; + + REAL a = lb, b = ub; + + REAL fa = to_solve_orig(N, tmp_arrs, a); + fb = to_solve_orig(N, tmp_arrs, b); + + if( fa*fb >= 0.0 ) { + root = 0.0; it = 0; + if ( a >= 0.0 ) fb = INFTY; + else fb = -INFTY; + return; + } + + if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } + + REAL c = a, fc = fa; + bool mflag = true; + REAL d = 0.0; + it = 0; + + for( UINT i = 0; i < iter_max; i++ ) { + if ( fb != 0.0 && fabs(b-a) >= tol ) { + REAL s; + if( fa == fc || fb == fc ) { + s = b - fb * (b - a) / (fb - fa); + } else { + REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); + REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); + REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); + s = s1 + s2 + s3; + } + + if ( ( (3.0 * a + b) /4.0 > s || s > b) || + ( mflag && fabs(b-c)/2.0 <= fabs(s-b) ) || + ( !mflag && fabs(c-d)/2.0 <= fabs(s-b) ) || + ( mflag && fabs(b-c) <= fabs(tol) ) || + ( !mflag && fabs(c-d) <= fabs(tol) ) ) { + mflag = true; + s = (a + b) / 2.0; + } else { + mflag = false; + } + + REAL fs = to_solve_orig(N, tmp_arrs, s); + + // d is assigned for the first time here: + // it's not used above because mflag is set + d = c; + c = b; fc = fb; + + if( fa*fs < 0.0 ) { b = s; fb = fs; } + else { a = s; fa = fs; } + + if( fabs(fa) < fabs(fb) ) { + REAL tmp; + tmp = a; a = b; b = tmp; + tmp = fa; fa = fb; fb = tmp; + } + + // reporting non-convergence! + if(i == iter_max-1) { + printf("# ERROR: Brent method not converged, error: %f %f %d\n\n", b, fb, i); + } + + it = i; + } + } + + root = b; + + //return BrentRes(b, it, fb); +} + +REAL exactYhatOrig( + const UINT& n_schedi, + + const REAL& b, // scals begins + const REAL& sigmax, + const REAL& sigmay, + const REAL& rhoxy, + const REAL& rhoxyc, + const REAL& rhoxycs, + const REAL& mux, + const REAL& muy, // scals ends + IntermElem* tmp_arrs, + + const REAL& x // output +) { + // ugaussian_Pinv(k)=1.0e~4 + const REAL k = - 3.71901648545568; + + REAL up = 0.0, lo = -INFTY; + for( UINT i = 0; i < n_schedi; i++ ) { + REAL baix = tmp_arrs[i].bai * x; + + REAL up_term = tmp_arrs[i].aici * exp( -baix ); + tmp_arrs[i].hat_scale = up_term; + up += up_term; + lo = std::max( lo, ( tmp_arrs[i].log_aici - baix ) / tmp_arrs[i].bbi ); + } + +// CHECKING uplo!!!! + + const REAL log_s = log(up); + REAL tmp = log_s / tmp_arrs[n_schedi-1].bbi; + + if ( tmp <= 0.0 ) { + up = tmp; + } else { + tmp = log_s / tmp_arrs[0].bbi; + if ( 0.0 <= tmp ) up = tmp; + else up = - INFTY; + } + + const REAL yl = lo - EPS; + const REAL yu = up + EPS; + + const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; + const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; + + REAL res; + if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS + else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) + else { + const REAL root_lb = std::max( yl, y0 ); + const REAL root_ub = std::min( yu, y1 ); + + REAL root, error; UINT iter; + rootFinding_Brent_orig(n_schedi, tmp_arrs, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); + //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); + + res = ( error == -INFTY ) ? y0 - 1.0 : ( error == INFTY ) ? y1 + 1.0 : root; + } + + return res; +} + + +#endif // ifndef G2PP diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h new file mode 100644 index 0000000..3643bc3 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h @@ -0,0 +1,281 @@ +#ifndef GEN_ALG_FLAT +#define GEN_ALG_FLAT + +using namespace std; + +#include "Constants.h" +#include "GenAlgUtil.h" +#include "Genome.h" +#include "UtilCPU.h" +#include "EvalGenomeOrig.h" + + +/** + * Printing Swaption / Calibrated Price / Black Price / RMS + * The result is an array REAL[NUM_SWAP_QUOTES, 3] recording + * for each swaption the calibrated price, the black price + * and the percentagewise difference between the two. + */ +void makeSummary( const int winner, + const Genome& wgene, + const REAL* new_quote, + const REAL* new_price, + REAL* result // output +) { + REAL rms = 0.0; + + fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); + fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", + wgene.a, wgene.b, wgene.sigma, wgene.nu, wgene.rho, wgene.logLik ); + fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); + + for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { + REAL black_price = new_quote[i]; + REAL calib_price = new_price[i]; + REAL err_ratio = (calib_price - black_price) / black_price; + + result[3*i + 0] = 10000.0*calib_price; + result[3*i + 1] = 10000.0*black_price; + result[3*i + 2] = 100.0*fabs(err_ratio); + + rms += err_ratio * err_ratio; + + fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", + i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], + result[3*i + 0], result[3*i + 1], result[3*i + 2] ); + } + + rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); + fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); +} + + +/** + * Utility function: find the genome with the best likelihood: + * scans the logLik array and fill in the index and likelihood + * of the best genome. + */ +void find_best(const Genome* genomes, int& best_ind, REAL& best_lik) { + bool sanity = true; + + best_lik = -INFINITY; + best_ind = 0; + + // this is in fact a reduction, but POP_SIZE is + // not big enough to warrant a parallel execution. + for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX + REAL val = genomes[i].logLik; + + sanity = !( isnan(val) || isinf(val) ); + assert( sanity && "val is NaN in find_best" ); + + if( val > best_lik ) { best_ind = i; best_lik = val; } + } +} + +Move_Type selectMoveType(REAL move_selected) { + Move_Type move_type = NONE; + + REAL prob; + Move_Type type; + UINT k = 0; + do { + prob = mcmc_moves_selection_cumdensfct[k].fst; + type = mcmc_moves_selection_cumdensfct[k].snd; + + if( move_selected <= prob ) { + move_type = type; + } + k ++; + } while ( move_selected > prob && k < CUMDENSFCT_CARD ); + + assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); + + return move_type; +} + +/** + * Main Entry Point for Swaption Calibration + * The (out) arguments are in fact the resulted + * winning genome result & its likelihood. + * The array result has size 3*NUM_SWAP_QUOTES + * and records for each swaption the calibrated + * price, the black price and the percentage + * difference between the two. + */ +REAL* mainKernelSeqCPU( Genome& winner ) { + + UINT n_schedi_max = 0; + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + const UINT n_schedi = static_cast(12.0 * SwaptionQuotes[4*ttt+2] / SwaptionQuotes[4*ttt+1]); + n_schedi_max = max(n_schedi_max, n_schedi); + } + + SeqArrays cpu_arrs(n_schedi_max); + Genome* genomes = cpu_arrs.genomes; + + srand ( SEED ); + srand48 ( SEED ); + + // initialized the genomes with random numbers inside + // their acceptable bounds => requires 5*POP_SIZE randoms + for( int i = 0; i < POP_SIZE; i++ ) { + REAL r01, tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; + genomes[i].a = genomes[i+POP_SIZE].a = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; + genomes[i].b = genomes[i+POP_SIZE].b = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; + genomes[i].rho = genomes[i+POP_SIZE].rho = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; + genomes[i].nu = genomes[i+POP_SIZE].nu = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; + genomes[i].sigma = genomes[i+POP_SIZE].sigma = tmp; + +// genomes[i].fbRat = genomes[i+POP_SIZE].fbRat = 1.0; + } + + // Initial evaluation of the genomes! + REAL quote, price; + for( int i = 0; i < POP_SIZE; i++ ) { + Genome& gene = genomes[i]; + REAL rms = 0.0; + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + eval_genome_new ( + gene.a, gene.b, gene.rho, gene.nu, gene.sigma, + SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price + ); + rms += logLikelihood( quote, price ); + } + gene.logLik = rms; + } + + // convergence loop that runs the genetic algorithms + // (takes a population and returns a population) + for( int j = 0; j < MCMC_LOOPS; j++ ) { + + // select which move to perform. + // Note: this block can also be a loop (in fixed order) + // over the various move types + REAL move_selected = getRandUnifNorm(); + Move_Type move_type = selectMoveType(move_selected); + + if ( move_type == DIMS_ALL ) { + for( int i = 0; i < POP_SIZE; i++ ) { + genomes[i+POP_SIZE].mutate_dims_all( genomes[i] ); + } + + } else if ( move_type == DIMS_ONE ) { + + UINT dim_j = getRandIntNorm(GENOME_DIM); + + for( int i = 0; i < POP_SIZE; i++ ) { + genomes[i+POP_SIZE].mutate_dims_one( genomes[i], dim_j ); + } + } else /* if ( move_type == DEMCMC ) */ { + + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums + // compute the k^th and the l^th genes + UINT cand_UB = POP_SIZE - 1; + UINT k = getRandIntNorm(cand_UB); // random in [0,pop_size-1) + if ( k == i ) { + k = cand_UB; + cand_UB -= 1; + } + UINT l = getRandIntNorm(cand_UB); + if ( l == i || l == k ) { + l = cand_UB; + } + + // do DEMCMC base on k^th and l^th genomes + genomes[i+POP_SIZE].mcmc_DE( genomes[i], genomes[k], genomes[l] ); + } + } + + // evaluate the proposals + for( int i = 0; i < POP_SIZE; i++ ) { + Genome& gene = genomes[i+POP_SIZE]; + + REAL rms = 0.0; + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + eval_genome_new ( + gene.a, gene.b, gene.rho, gene.nu, gene.sigma, + SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price + ); + rms += logLikelihood( quote, price ); + } + gene.logLik = rms; + } + + // mcmc_acceptance_rejection(); + // Deciding whether to accept or reject the proposal, + // obtained by mutating/crossover of the individual. + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel + // Metropolis: get a random U[0,1) for each candidate + REAL rand = getRandUnifNorm(); + + Genome& orig = genomes[i]; + Genome& muta = genomes[i+POP_SIZE]; + // selection: dimensions considered independent + // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) + REAL acceptance = std::min( 1.0, exp( muta.logLik - orig.logLik ) * muta.fbRat ); + + // if acceptance criterion is met then p->p' else does nothing + if ( rand < acceptance ) + orig = muta; + } + + // print best candidate for the current iteration: + if ( (j % 16) == 0 ){ + int best_ind; REAL best_lik; + find_best(genomes, best_ind, best_lik); + fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", + j, best_lik, best_ind ); + } + } + + REAL* result = new REAL[3*NUM_SWAP_QUOTES]; + { // print best candidate for the current iteration: + int best_ind; REAL best_lik; + find_best(genomes, best_ind, best_lik); + //winner = genomes[best_ind]; + winner.a = genomes[best_ind].a; winner.b = genomes[best_ind].b; + winner.rho = genomes[best_ind].rho; winner.nu = genomes[best_ind].nu; + winner.sigma = genomes[best_ind].sigma; winner.logLik = genomes[best_ind].logLik; + + // recompute the calibrated price and the black price! + REAL* quotes = cpu_arrs.get_quote(); + REAL* prices = cpu_arrs.get_price(); + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + eval_genome_new ( + winner.a, winner.b, winner.rho, winner.nu, winner.sigma, + SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price + ); + quotes[ttt] = quote; + prices[ttt] = price; + } + + + + // write summary + makeSummary( best_ind, winner, quotes, prices, result ); + } + + // Releasing the CPU resources: + cpu_arrs.releaseResources(); + + return result; +} + +#endif // end ifndef GEN_ALG_FLAT + diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/Genome.h b/benchmarks/InterestCalib/implementations/OrigCpp/Genome.h new file mode 100644 index 0000000..a99d977 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/OrigCpp/Genome.h @@ -0,0 +1,238 @@ +#ifndef CANDIDATE_CLASS +#define CANDIDATE_CLASS + +#include "Constants.h" +#include "GenAlgUtil.h" + + +//========================================================================= +/** + * Candidate: + * - identified by parameters (target, and nuisance) + * - holds one proposal, to be accepted or rejected + * - holds fitness results + * - holds MCMC selection regions + * Population: + * - container of candidates + * - container of proposals + * - caller of mutation functions + * - select if to keep/update candidates and proposals + * MCMC: moves: + * - TODO: Gibbs sampling: single dimension update + * - all dimensions update + * - crossover + */ +//========================================================================= + +/** + * Genome min/max ranges and proposed initial values (not used) + * { g_a, g_b, g_rho, g_nu, g_sigma } + */ +const REAL g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; +const REAL g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; +const REAL g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; +//const REAL Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; + + +/** + * perturbing a genome; requires one random uniform number in [0,1) + */ +inline +REAL perturbation( + const REAL gene, + const REAL gene_k, + const REAL gene_l, + const UINT i, + const REAL gamma1, + const REAL amplitude_ratio +) { + REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + REAL semiamplitude = amplitude / 2.0; + REAL r01 = getRandRandNorm(); + REAL perturb = ( amplitude * r01 - semiamplitude ); + + return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); +} + +/* + * contraining gene i to be within accepted bounds! + */ +inline +REAL constrain_dim1( const int i, const REAL gene ) { + return std::max( g_mins[i], std::min( g_maxs[i], gene ) ); +} + + +/** + * Helper mutate function: requires one uniform random number + */ +Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int i, const REAL amplitude_ratio ) { + REAL forward_range, backward_range; + REAL tmp_min_max, tmp_max_min; + + const REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + const REAL semiamplitude = amplitude / 2.0; + + tmp_min_max = std::min( g_maxs[i], gene + semiamplitude ); + tmp_max_min = std::max( g_mins[i], gene - semiamplitude ); + forward_range = tmp_min_max - tmp_max_min; + + tmp_min_max = std::min( g_maxs[i], gene_prop + semiamplitude ); + tmp_max_min = std::max( g_mins[i], gene_prop - semiamplitude ); + backward_range = tmp_min_max - tmp_max_min; + + const REAL bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; + + // assign p' + REAL r01 = getRandRandNorm(); + REAL diff = amplitude * r01 - semiamplitude; + return Tuple(gene + diff, bf_fact); +} + + +struct Genome { + REAL a; + REAL b; + REAL rho; + REAL nu; + REAL sigma; + REAL logLik; + REAL fbRat; + REAL padding; + + Genome() { + this->a = 0.0; this->b = 0.0; this->rho = 0.0; + this->nu = 0.0; this->sigma = 0.0; this->logLik = 0.0; + this->fbRat = 0.0; + } + Genome( const REAL a, const REAL b, const REAL rho, const REAL nu, + const REAL sigma, const REAL logLik, const REAL fbRat) { + this->a = a; this->b = b; this->rho = rho; + this->nu = nu; this->sigma = sigma; this->logLik = logLik; + this->fbRat = fbRat; + } + Genome(const Genome& gene) { + this->a = gene.a; this->b = gene.b; this->rho = gene.rho; + this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; + this->fbRat = gene.fbRat; + } + Genome& operator=(const Genome& gene) { + this->a = gene.a; this->b = gene.b; this->rho = gene.rho; + this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; + this->fbRat = gene.fbRat; + return (*this); + } + + + /** + * mutate all dimensions. martingale with uniform prior. + * requires 5 * POP_SIZE uniform random numbers! + * I took out the evaluation of the proposal, since it should be + * done for all types of crossover/mutation/etc + */ + void mutate_dims_all( const Genome& orig, + const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { + REAL fb_rat = 1.0; + Tuple tmp(EPS0, 1.0); + + tmp = mutate_helper( orig.a, this->a, 0, amplitude_ratio ); + this->a = constrain_dim1(0, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.b, this->b, 1, amplitude_ratio ); + this->b = constrain_dim1(1, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.rho, this->rho, 2, amplitude_ratio ); + this->rho = constrain_dim1(2, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.nu, this->nu, 3, amplitude_ratio ); + this->nu = constrain_dim1(3, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.sigma, this->sigma, 4, amplitude_ratio ); + this->sigma = constrain_dim1(4, tmp.fst); + fb_rat *= tmp.snd; + + this->fbRat = fb_rat; + } + + /** + * mutate ONE dimension (Gibbs sampling). martingale with uniform prior + * dimension to be changed is given as input: has to be the same for + * all population. Memory coalescence? + * Requires POP_SIZE random uniform numbers! + */ + void mutate_dims_one( const Genome& orig, + const int dim_j, + const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO + ) { + REAL fb_rat = 1.0; + + Tuple tmp(EPS0, 1.0); + tmp = mutate_helper( orig.a, this->a, 0, (dim_j == 0) ? amplitude_ratio : 0.0 ); + this->a = constrain_dim1(0, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.b, this->b, 1, (dim_j == 1) ? amplitude_ratio : 0.0 ); + this->b = constrain_dim1(1, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.rho, this->rho, 2, (dim_j == 2) ? amplitude_ratio : 0.0 ); + this->rho = constrain_dim1(2, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.nu, this->nu, 3, (dim_j == 3) ? amplitude_ratio : 0.0 ); + this->nu = constrain_dim1(3, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.sigma, this->sigma, 4, (dim_j == 4) ? amplitude_ratio : 0.0 ); + this->sigma = constrain_dim1(4, tmp.fst); + fb_rat *= tmp.snd; + + this->fbRat = fb_rat; + } + + /** + * Crossover + */ + void mcmc_DE( const Genome& orig, + const Genome& gene_k, + const Genome& gene_l, + const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), + const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO + ) { + // proposal + // gamma: integrated out from the adviced + // Multivariate Gaussian with Gaussian target (Braak, 2006) + REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); + + this->a = constrain_dim1( 0, perturbation( orig.a, gene_k.a, gene_l.a, 0, gamma1, ampl_ratio ) ); + this->b = constrain_dim1( 1, perturbation( orig.b, gene_k.b, gene_l.b, 1, gamma1, ampl_ratio ) ); + this->rho = constrain_dim1( 2, perturbation( orig.rho, gene_k.rho, gene_l.rho, 2, gamma1, ampl_ratio ) ); + this->nu = constrain_dim1( 3, perturbation( orig.nu, gene_k.nu, gene_l.nu, 3, gamma1, ampl_ratio ) ); + this->sigma = constrain_dim1( 4, perturbation( orig.sigma, gene_k.sigma, gene_l.sigma, 4, gamma1, ampl_ratio ) ); + + this->fbRat = 1.0; // TODO: fix + } + + /** + * accepting the proposal + */ + void accept( const Genome& mutated ) { + this->a = mutated.a; + this->b = mutated.b; + this->rho = mutated.rho; + this->nu = mutated.nu; + this->sigma = mutated.sigma; + this->logLik = mutated.logLik; + this->fbRat = mutated.fbRat; + } +}; + +#endif // #ifndef CANDIDATE_CLASS + + + + diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/Makefile b/benchmarks/InterestCalib/implementations/OrigCpp/Makefile new file mode 100644 index 0000000..0cac6e1 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/OrigCpp/Makefile @@ -0,0 +1,42 @@ +include ../../setup.mk + +ifndef ($(HAVE_GPU)) +include ../../platform.mk +endif + +INCLUDES += -I../includeC +GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) +#-fno-unsafe-math-optimizations -fno-finite-math-only +#-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans + +SOURCES_CPP =SwapCalib.cpp +HELPERS =../includeC/ParseInput.h +OBJECTS =SwapCalib.o +EXECUTABLE =SwapCalib + + +default: cpu + +.cpp.o: $(SOURCES_CPP) $(HELPERS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< + +# The GPU version is in: ../CppAndGPU. This folder is CPU only! +gpu: $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + +cpu: $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + + +run_small: $(EXECUTABLE) + cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_medium: $(EXECUTABLE) + cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_large: $(EXECUTABLE) + cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib b/benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib new file mode 100755 index 0000000000000000000000000000000000000000..8ba2d1de5f1c6cf8f7f9902645c77de02426026d GIT binary patch literal 76488 zcmdqK4|r6?)%d>&S&T@$8zqVrB-W)}6e3Yjs32M0=%Uf01W7^&Py#}UN+Cg1T7e|s z8rP!I*0#3As@1A}Yx`P@6v>9a0sjI10Yn89^{xR#un<7a?{m)FyV(TdYrntu`#itr z2TyYE%$zyr%$YN1&YYP$xjVn$s??MekNYpxbGb)SS7+vFmig`RgwJb*$@2{Iob1W- zoZ~s$(-|l)KQ3IJ^X5LAooeng9a#C-iJvrn2Bk_$o_X>}JbP%$<8hxZb$JTC)_-}< zt9icpl}Wl!k0)C*q@M7))hXZl)p*T!pM}B@|F$|$x1O*k^_rb}%}zb{>2dgXpKkl4 zZSqs-lozJvk&<+tJUk)&-TD+*`8VRD%5tsysY$1Onx`-BbB=@0eY*8-pq}vgZU6Zk zz#AQU9myr&&~u+|KU`Qb^+%TsxUizUU&Yj0t7i9`J?N5tmkh|6d0Wm!+HS!wuvcF{ zN+}5%;V+vX;kg?>B5EmrZ^DKDeRF-yz&qam=lB2q)uo4azJB*ADLaoJx8FP|*`B#6 zzEsKc^CSQI^t`Xfs($=l)t2d{7XB)Bkj!Qr~SWP zWMsF`Bz>5l6VaX8LH?c&^3U#opB){*&+P#I@ecCGbdY~B__O(G|F3@s@C6;@|DuEZ zl^{Nmd|v1P{bt-8kvysWU4l&A75+!pxbIW_rdAFT8GC`J@?6cHwnb zR@`>$q{0b5s+eTTPFzxQ>x5f8<4VdWjF=@vZ!z>H&7SU=`I8xylRXu;-K=j?c=K(y zOqcRp4=>|xo>V#R)~Z{^RZf{PX+rr-&(%M?Zp66h6J|`PsF+ldfH0*3C>SQX&6z%9 z>aCTN$4#6v%`<8C)Jo6H853?T_e`&uX}VyP2049l%LG`PJY&)%&(#IP zueh?PXxzm)1B^%p;4TQ%U(*ZYIy?lJd_?%3qq4-#sZmmXv>1 zQhsAn{&$k{Hzwtuos_>dDL>hn+L@H!GYQ^K%0DM5e}7WG_(1Nz=A`^=H&dR@ydk=C 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 Date: Thu, 13 Aug 2015 21:33:26 +0200 Subject: [PATCH 042/122] working on Makefiles, instantiate files etc. --- .../implementations/CppOpenMP/Makefile | 19 ++----------------- .../implementations/CppOpenMP/instantiate | 4 ++++ 2 files changed, 6 insertions(+), 17 deletions(-) create mode 100644 benchmarks/InterestCalib/implementations/CppOpenMP/instantiate diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile index 0cac6e1..d58dbf9 100644 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile @@ -1,7 +1,7 @@ -include ../../setup.mk +include setup.mk ifndef ($(HAVE_GPU)) -include ../../platform.mk +include platform.mk endif INCLUDES += -I../includeC @@ -14,29 +14,14 @@ HELPERS =../includeC/ParseInput.h OBJECTS =SwapCalib.o EXECUTABLE =SwapCalib - default: cpu .cpp.o: $(SOURCES_CPP) $(HELPERS) $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< # The GPU version is in: ../CppAndGPU. This folder is CPU only! -gpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - cpu: $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate new file mode 100644 index 0000000..81dd8a6 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate @@ -0,0 +1,4 @@ +#!/bin/sh + +set -r + From 9571daa59fa95c3249b68bf1377fb1c72cd5f16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Thu, 13 Aug 2015 22:44:03 +0200 Subject: [PATCH 043/122] Working on the compilation of InterestCalib/CppOpenMp --- .../implementations/CppOpenMP/Makefile | 2 +- .../implementations/CppOpenMP/instantiate | 22 +- .../CppOpenMP/instantiate_data | 8 + .../implementations/CppOpenMP/run | 3 + .../implementations/OrigCpp/EvalGenomeOrig.h | 155 ---------- .../implementations/OrigCpp/G2PPorig.h | 176 ----------- .../implementations/OrigCpp/GenAlgFlat.h | 281 ------------------ .../implementations/OrigCpp/Genome.h | 238 --------------- .../implementations/OrigCpp/Makefile | 42 --- .../implementations/OrigCpp/SwapCalib | Bin 76488 -> 0 bytes .../implementations/OrigCpp/SwapCalib.cpp | 49 --- .../implementations/OrigCpp/UtilCPU.h | 48 --- 12 files changed, 33 insertions(+), 991 deletions(-) mode change 100644 => 100755 benchmarks/InterestCalib/implementations/CppOpenMP/instantiate create mode 100755 benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data create mode 100755 benchmarks/InterestCalib/implementations/CppOpenMP/run delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/Genome.h delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/Makefile delete mode 100755 benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib.cpp delete mode 100644 benchmarks/InterestCalib/implementations/OrigCpp/UtilCPU.h diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile index d58dbf9..4224d4d 100644 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile @@ -10,7 +10,7 @@ GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) #-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans SOURCES_CPP =SwapCalib.cpp -HELPERS =../includeC/ParseInput.h +HELPERS =ParseInput.h #Can this be correct?? OBJECTS =SwapCalib.o EXECUTABLE =SwapCalib diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate old mode 100644 new mode 100755 index 81dd8a6..857c549 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate @@ -1,4 +1,24 @@ #!/bin/sh -set -r +set -e +cp $HIPERMARK_LIB_DIR/setup.mk . +cp $HIPERMARK_LIB_DIR/include/ParserC.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Constants.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/KerConsts.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/GenAlgUtil.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Date.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Candidate.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/IrregShape.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/EvalGenomeInl.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/G2PP.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/G2ppUtil.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/MathModule.h . +cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . +cp $HIPERMARK_IMPLEMENTATION/run . +cp $HIPERMARK_LIB_DIR/include/Util.h . + + + +$HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data new file mode 100755 index 0000000..be356dd --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +mkdir -p datasets/$HIPERMARK_INPUT_NAME + +# the linearisation might not be needed!! +cp $HIPERMARK_INPUT datasets/$HIPERMARK_INPUT_NAME/input.data \ No newline at end of file diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/run b/benchmarks/InterestCalib/implementations/CppOpenMP/run new file mode 100755 index 0000000..ff0deb0 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/run @@ -0,0 +1,3 @@ +#!/bin/sh +#export OMP_NUM_THREADS=$NCORES +cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./SwapCalib diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h b/benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h deleted file mode 100644 index efea067..0000000 --- a/benchmarks/InterestCalib/implementations/OrigCpp/EvalGenomeOrig.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef EVAL_GENOME_INLINED -#define EVAL_GENOME_INLINED - -#include "Constants.h" -#include "GenAlgUtil.h" -#include "G2PP.h" -#include "G2PPorig.h" - - -/** - * MOST IMPORTANTLY: GENOME EVALUATION By Pricer of Swaption & BLACK PRICE - */ -void eval_genome_new ( - const REAL& a, - const REAL& b, - const REAL& rho, - const REAL& nu, - const REAL& sigma, - const REAL* swaption, - IntermElem* tmp_arrs, - REAL& new_quote, // output - REAL& new_price // output -) { - bool sanity = true; - - const REAL swap_freq = swaption[1]; - const REAL maturity = add_years( TODAY, swaption[0] ); - const UINT n_schedi = static_cast(12.0 * swaption[2] / swap_freq); - const REAL tmat0 = date_act_365( maturity, TODAY ); - - REAL strike; - { // BLACK PRICE computation - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; - - for(UINT i = 0; i < n_schedi; i++) { // reduce o map - // Map computes a1 and a2 (depends on i) - const REAL a1 = add_months( maturity, swap_freq*i ); - const REAL a2 = add_months( a1, swap_freq ); - - // Reduction( lvl: +, t0 : min, tn : max ) - lvl += zc(a2) * date_act_365(a2, a1); - t0 = std::min(t0, a1); - tn = std::max(tn, a2); - } - - strike = ( zc(t0) - zc(tn) ) / lvl; - const REAL d1 = 0.5 * swaption[3] * tmat0; - new_quote = lvl * strike * ( uGaussian_P(d1) - uGaussian_P(-d1) ); - } // END BLACK PRICE - - { // PRICER OF SWAPTION COMPUTATION - REAL v0_mat, dummy1, dummy2; - bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); -// - const REAL mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); - const REAL muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); -// - const REAL zc_mat = zc(maturity); -// - const REAL sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); - const REAL sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); - const REAL rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); - const REAL sigmax = sigma * sqrt_bfun_a; - const REAL sigmay = nu * sqrt_bfun_b; - - const REAL rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel - const REAL rhoxycs = sqrt( rhoxyc ); // used in reduction kernel - const REAL sigmay_rhoxycs = sigmay * rhoxycs; - const REAL t4 = (rhoxy * sigmay) / sigmax; - - for( UINT i = 0; i < n_schedi; i++ ) { - const REAL beg_date = add_months( maturity, swap_freq*i ); //scheduleix[i]; - const REAL end_date = add_months( beg_date, swap_freq ); //scheduleiy[i]; - const REAL res = date_act_365( end_date, beg_date ) * strike; - - const REAL cii = ( i == n_schedi-1 ) ? 1.0 + res : res; - - REAL v0_end, vt_end, baii, bbii, date_tod1, date_tod2; - date_tod1 = date_act_365(end_date, TODAY); - bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); - date_tod2 = date_act_365(end_date, maturity); - bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); - - const REAL expo_aici = 0.5 * (vt_end - v0_end + v0_mat); - const REAL fact_aici = cii * zc(end_date) / zc_mat; - tmp_arrs[i].ci = fact_aici; // reuse the space to hold the factor of t1_cs - tmp_arrs[i].t1_cs = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; - // hold only the exponent of the original t1_cs; - - tmp_arrs[i].bai = baii; - tmp_arrs[i].bbi = bbii; - tmp_arrs[i].aici = fact_aici * exp( expo_aici ); - tmp_arrs[i].log_aici = log( fact_aici ) + expo_aici; - tmp_arrs[i].scale = - ( baii + bbii * t4 ); - - sanity = ! ( isinf(tmp_arrs[i].aici) || isnan(tmp_arrs[i].aici) ); - assert(sanity && "Nan aici in pricer of swaption. Exiting!\n"); - } - - const REAL eps = 0.5 * sigmax; - - const REAL f = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, - mux, muy, tmp_arrs, mux ); - - const REAL g = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, - mux, muy, tmp_arrs, mux + eps ); - - const REAL h = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, - mux, muy, tmp_arrs, mux - eps ); - - const REAL df = 0.5 * ( g - h ) / eps; - - const REAL sqrt2sigmax = sqrt(2.0) * sigmax;; - const REAL t2 = rhoxy / (sigmax*rhoxycs);; - - REAL accum = 0.0; - - for( UINT j = 0; j < NUM_HERMITE; j++ ) { - const REAL x_quad = HermiteCoeffs [j]; - const REAL w_quad = HermiteWeights[j]; - - const REAL x = sqrt2sigmax * x_quad + mux; - const REAL yhat_x = f + df*(x - mux); - const REAL h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); - - REAL accum1 = 0.0; - for( UINT i = 0; i < n_schedi; i++ ) { - const REAL h2 = h1 + tmp_arrs[i].bbi * sigmay_rhoxycs; - - const REAL expo_aici = tmp_arrs[i].t1_cs + tmp_arrs[i].scale*x; - const REAL fact_aici = tmp_arrs[i].ci; - const REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); - accum1 += fact_aici * expo_part; - } - - sanity = ! ( isnan(accum1) || isinf(accum1) ); - assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); - - REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; - const REAL t1 = exp( - 0.5 * tmp * tmp ); - - accum += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); - } - - sanity = ! ( isnan(accum) || isinf(accum) ); - assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); - - new_price = zc_mat * ( accum / sqrt( PI ) ); - } -} - - - -#endif // end ifndef EVAL_GENOME_INLINED - diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h b/benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h deleted file mode 100644 index 5f324a4..0000000 --- a/benchmarks/InterestCalib/implementations/OrigCpp/G2PPorig.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef G2PPORIG -#define G2PPORIG - -#include "Constants.h" -#include "Date.h" -#include "MathModule.h" -#include "G2ppUtil.h" - -#include "GenAlgUtil.h" - -REAL to_solve_orig( const UINT& N, - const IntermElem* tmp_arrs, - const REAL& yhat ) { - REAL accum = 0.0; - for( UINT i = 0; i < N; i++ ) { - accum += tmp_arrs[i].hat_scale * exp( - tmp_arrs[i].bbi * yhat ); - } - return accum - 1.0; -} - -////////////////////////// -// Root finder -////////////////////////// - -void rootFinding_Brent_orig ( - const UINT& N, - IntermElem* tmp_arrs, - const REAL& lb, - const REAL& ub, - const REAL& toll, - const UINT& it_mx, - REAL& root, // result - UINT& it, - REAL& fb -) { - const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; - const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; - - REAL a = lb, b = ub; - - REAL fa = to_solve_orig(N, tmp_arrs, a); - fb = to_solve_orig(N, tmp_arrs, b); - - if( fa*fb >= 0.0 ) { - root = 0.0; it = 0; - if ( a >= 0.0 ) fb = INFTY; - else fb = -INFTY; - return; - } - - if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } - - REAL c = a, fc = fa; - bool mflag = true; - REAL d = 0.0; - it = 0; - - for( UINT i = 0; i < iter_max; i++ ) { - if ( fb != 0.0 && fabs(b-a) >= tol ) { - REAL s; - if( fa == fc || fb == fc ) { - s = b - fb * (b - a) / (fb - fa); - } else { - REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); - REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); - REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); - s = s1 + s2 + s3; - } - - if ( ( (3.0 * a + b) /4.0 > s || s > b) || - ( mflag && fabs(b-c)/2.0 <= fabs(s-b) ) || - ( !mflag && fabs(c-d)/2.0 <= fabs(s-b) ) || - ( mflag && fabs(b-c) <= fabs(tol) ) || - ( !mflag && fabs(c-d) <= fabs(tol) ) ) { - mflag = true; - s = (a + b) / 2.0; - } else { - mflag = false; - } - - REAL fs = to_solve_orig(N, tmp_arrs, s); - - // d is assigned for the first time here: - // it's not used above because mflag is set - d = c; - c = b; fc = fb; - - if( fa*fs < 0.0 ) { b = s; fb = fs; } - else { a = s; fa = fs; } - - if( fabs(fa) < fabs(fb) ) { - REAL tmp; - tmp = a; a = b; b = tmp; - tmp = fa; fa = fb; fb = tmp; - } - - // reporting non-convergence! - if(i == iter_max-1) { - printf("# ERROR: Brent method not converged, error: %f %f %d\n\n", b, fb, i); - } - - it = i; - } - } - - root = b; - - //return BrentRes(b, it, fb); -} - -REAL exactYhatOrig( - const UINT& n_schedi, - - const REAL& b, // scals begins - const REAL& sigmax, - const REAL& sigmay, - const REAL& rhoxy, - const REAL& rhoxyc, - const REAL& rhoxycs, - const REAL& mux, - const REAL& muy, // scals ends - IntermElem* tmp_arrs, - - const REAL& x // output -) { - // ugaussian_Pinv(k)=1.0e~4 - const REAL k = - 3.71901648545568; - - REAL up = 0.0, lo = -INFTY; - for( UINT i = 0; i < n_schedi; i++ ) { - REAL baix = tmp_arrs[i].bai * x; - - REAL up_term = tmp_arrs[i].aici * exp( -baix ); - tmp_arrs[i].hat_scale = up_term; - up += up_term; - lo = std::max( lo, ( tmp_arrs[i].log_aici - baix ) / tmp_arrs[i].bbi ); - } - -// CHECKING uplo!!!! - - const REAL log_s = log(up); - REAL tmp = log_s / tmp_arrs[n_schedi-1].bbi; - - if ( tmp <= 0.0 ) { - up = tmp; - } else { - tmp = log_s / tmp_arrs[0].bbi; - if ( 0.0 <= tmp ) up = tmp; - else up = - INFTY; - } - - const REAL yl = lo - EPS; - const REAL yu = up + EPS; - - const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; - const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; - - REAL res; - if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS - else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) - else { - const REAL root_lb = std::max( yl, y0 ); - const REAL root_ub = std::min( yu, y1 ); - - REAL root, error; UINT iter; - rootFinding_Brent_orig(n_schedi, tmp_arrs, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); - //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); - - res = ( error == -INFTY ) ? y0 - 1.0 : ( error == INFTY ) ? y1 + 1.0 : root; - } - - return res; -} - - -#endif // ifndef G2PP diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h deleted file mode 100644 index 3643bc3..0000000 --- a/benchmarks/InterestCalib/implementations/OrigCpp/GenAlgFlat.h +++ /dev/null @@ -1,281 +0,0 @@ -#ifndef GEN_ALG_FLAT -#define GEN_ALG_FLAT - -using namespace std; - -#include "Constants.h" -#include "GenAlgUtil.h" -#include "Genome.h" -#include "UtilCPU.h" -#include "EvalGenomeOrig.h" - - -/** - * Printing Swaption / Calibrated Price / Black Price / RMS - * The result is an array REAL[NUM_SWAP_QUOTES, 3] recording - * for each swaption the calibrated price, the black price - * and the percentagewise difference between the two. - */ -void makeSummary( const int winner, - const Genome& wgene, - const REAL* new_quote, - const REAL* new_price, - REAL* result // output -) { - REAL rms = 0.0; - - fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); - fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", - wgene.a, wgene.b, wgene.sigma, wgene.nu, wgene.rho, wgene.logLik ); - fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); - - for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { - REAL black_price = new_quote[i]; - REAL calib_price = new_price[i]; - REAL err_ratio = (calib_price - black_price) / black_price; - - result[3*i + 0] = 10000.0*calib_price; - result[3*i + 1] = 10000.0*black_price; - result[3*i + 2] = 100.0*fabs(err_ratio); - - rms += err_ratio * err_ratio; - - fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", - i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], - result[3*i + 0], result[3*i + 1], result[3*i + 2] ); - } - - rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); - fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); -} - - -/** - * Utility function: find the genome with the best likelihood: - * scans the logLik array and fill in the index and likelihood - * of the best genome. - */ -void find_best(const Genome* genomes, int& best_ind, REAL& best_lik) { - bool sanity = true; - - best_lik = -INFINITY; - best_ind = 0; - - // this is in fact a reduction, but POP_SIZE is - // not big enough to warrant a parallel execution. - for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX - REAL val = genomes[i].logLik; - - sanity = !( isnan(val) || isinf(val) ); - assert( sanity && "val is NaN in find_best" ); - - if( val > best_lik ) { best_ind = i; best_lik = val; } - } -} - -Move_Type selectMoveType(REAL move_selected) { - Move_Type move_type = NONE; - - REAL prob; - Move_Type type; - UINT k = 0; - do { - prob = mcmc_moves_selection_cumdensfct[k].fst; - type = mcmc_moves_selection_cumdensfct[k].snd; - - if( move_selected <= prob ) { - move_type = type; - } - k ++; - } while ( move_selected > prob && k < CUMDENSFCT_CARD ); - - assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); - - return move_type; -} - -/** - * Main Entry Point for Swaption Calibration - * The (out) arguments are in fact the resulted - * winning genome result & its likelihood. - * The array result has size 3*NUM_SWAP_QUOTES - * and records for each swaption the calibrated - * price, the black price and the percentage - * difference between the two. - */ -REAL* mainKernelSeqCPU( Genome& winner ) { - - UINT n_schedi_max = 0; - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - const UINT n_schedi = static_cast(12.0 * SwaptionQuotes[4*ttt+2] / SwaptionQuotes[4*ttt+1]); - n_schedi_max = max(n_schedi_max, n_schedi); - } - - SeqArrays cpu_arrs(n_schedi_max); - Genome* genomes = cpu_arrs.genomes; - - srand ( SEED ); - srand48 ( SEED ); - - // initialized the genomes with random numbers inside - // their acceptable bounds => requires 5*POP_SIZE randoms - for( int i = 0; i < POP_SIZE; i++ ) { - REAL r01, tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; - genomes[i].a = genomes[i+POP_SIZE].a = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; - genomes[i].b = genomes[i+POP_SIZE].b = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; - genomes[i].rho = genomes[i+POP_SIZE].rho = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; - genomes[i].nu = genomes[i+POP_SIZE].nu = tmp; - - r01 = getRandRandNorm(); - tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; - genomes[i].sigma = genomes[i+POP_SIZE].sigma = tmp; - -// genomes[i].fbRat = genomes[i+POP_SIZE].fbRat = 1.0; - } - - // Initial evaluation of the genomes! - REAL quote, price; - for( int i = 0; i < POP_SIZE; i++ ) { - Genome& gene = genomes[i]; - REAL rms = 0.0; - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - eval_genome_new ( - gene.a, gene.b, gene.rho, gene.nu, gene.sigma, - SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price - ); - rms += logLikelihood( quote, price ); - } - gene.logLik = rms; - } - - // convergence loop that runs the genetic algorithms - // (takes a population and returns a population) - for( int j = 0; j < MCMC_LOOPS; j++ ) { - - // select which move to perform. - // Note: this block can also be a loop (in fixed order) - // over the various move types - REAL move_selected = getRandUnifNorm(); - Move_Type move_type = selectMoveType(move_selected); - - if ( move_type == DIMS_ALL ) { - for( int i = 0; i < POP_SIZE; i++ ) { - genomes[i+POP_SIZE].mutate_dims_all( genomes[i] ); - } - - } else if ( move_type == DIMS_ONE ) { - - UINT dim_j = getRandIntNorm(GENOME_DIM); - - for( int i = 0; i < POP_SIZE; i++ ) { - genomes[i+POP_SIZE].mutate_dims_one( genomes[i], dim_j ); - } - } else /* if ( move_type == DEMCMC ) */ { - - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums - // compute the k^th and the l^th genes - UINT cand_UB = POP_SIZE - 1; - UINT k = getRandIntNorm(cand_UB); // random in [0,pop_size-1) - if ( k == i ) { - k = cand_UB; - cand_UB -= 1; - } - UINT l = getRandIntNorm(cand_UB); - if ( l == i || l == k ) { - l = cand_UB; - } - - // do DEMCMC base on k^th and l^th genomes - genomes[i+POP_SIZE].mcmc_DE( genomes[i], genomes[k], genomes[l] ); - } - } - - // evaluate the proposals - for( int i = 0; i < POP_SIZE; i++ ) { - Genome& gene = genomes[i+POP_SIZE]; - - REAL rms = 0.0; - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - eval_genome_new ( - gene.a, gene.b, gene.rho, gene.nu, gene.sigma, - SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price - ); - rms += logLikelihood( quote, price ); - } - gene.logLik = rms; - } - - // mcmc_acceptance_rejection(); - // Deciding whether to accept or reject the proposal, - // obtained by mutating/crossover of the individual. - for ( int i = 0; i < POP_SIZE; i++ ) { // parallel - // Metropolis: get a random U[0,1) for each candidate - REAL rand = getRandUnifNorm(); - - Genome& orig = genomes[i]; - Genome& muta = genomes[i+POP_SIZE]; - // selection: dimensions considered independent - // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) - REAL acceptance = std::min( 1.0, exp( muta.logLik - orig.logLik ) * muta.fbRat ); - - // if acceptance criterion is met then p->p' else does nothing - if ( rand < acceptance ) - orig = muta; - } - - // print best candidate for the current iteration: - if ( (j % 16) == 0 ){ - int best_ind; REAL best_lik; - find_best(genomes, best_ind, best_lik); - fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", - j, best_lik, best_ind ); - } - } - - REAL* result = new REAL[3*NUM_SWAP_QUOTES]; - { // print best candidate for the current iteration: - int best_ind; REAL best_lik; - find_best(genomes, best_ind, best_lik); - //winner = genomes[best_ind]; - winner.a = genomes[best_ind].a; winner.b = genomes[best_ind].b; - winner.rho = genomes[best_ind].rho; winner.nu = genomes[best_ind].nu; - winner.sigma = genomes[best_ind].sigma; winner.logLik = genomes[best_ind].logLik; - - // recompute the calibrated price and the black price! - REAL* quotes = cpu_arrs.get_quote(); - REAL* prices = cpu_arrs.get_price(); - for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - eval_genome_new ( - winner.a, winner.b, winner.rho, winner.nu, winner.sigma, - SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price - ); - quotes[ttt] = quote; - prices[ttt] = price; - } - - - - // write summary - makeSummary( best_ind, winner, quotes, prices, result ); - } - - // Releasing the CPU resources: - cpu_arrs.releaseResources(); - - return result; -} - -#endif // end ifndef GEN_ALG_FLAT - diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/Genome.h b/benchmarks/InterestCalib/implementations/OrigCpp/Genome.h deleted file mode 100644 index a99d977..0000000 --- a/benchmarks/InterestCalib/implementations/OrigCpp/Genome.h +++ /dev/null @@ -1,238 +0,0 @@ -#ifndef CANDIDATE_CLASS -#define CANDIDATE_CLASS - -#include "Constants.h" -#include "GenAlgUtil.h" - - -//========================================================================= -/** - * Candidate: - * - identified by parameters (target, and nuisance) - * - holds one proposal, to be accepted or rejected - * - holds fitness results - * - holds MCMC selection regions - * Population: - * - container of candidates - * - container of proposals - * - caller of mutation functions - * - select if to keep/update candidates and proposals - * MCMC: moves: - * - TODO: Gibbs sampling: single dimension update - * - all dimensions update - * - crossover - */ -//========================================================================= - -/** - * Genome min/max ranges and proposed initial values (not used) - * { g_a, g_b, g_rho, g_nu, g_sigma } - */ -const REAL g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; -const REAL g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; -const REAL g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; -//const REAL Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; - - -/** - * perturbing a genome; requires one random uniform number in [0,1) - */ -inline -REAL perturbation( - const REAL gene, - const REAL gene_k, - const REAL gene_l, - const UINT i, - const REAL gamma1, - const REAL amplitude_ratio -) { - REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - REAL semiamplitude = amplitude / 2.0; - REAL r01 = getRandRandNorm(); - REAL perturb = ( amplitude * r01 - semiamplitude ); - - return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); -} - -/* - * contraining gene i to be within accepted bounds! - */ -inline -REAL constrain_dim1( const int i, const REAL gene ) { - return std::max( g_mins[i], std::min( g_maxs[i], gene ) ); -} - - -/** - * Helper mutate function: requires one uniform random number - */ -Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int i, const REAL amplitude_ratio ) { - REAL forward_range, backward_range; - REAL tmp_min_max, tmp_max_min; - - const REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - const REAL semiamplitude = amplitude / 2.0; - - tmp_min_max = std::min( g_maxs[i], gene + semiamplitude ); - tmp_max_min = std::max( g_mins[i], gene - semiamplitude ); - forward_range = tmp_min_max - tmp_max_min; - - tmp_min_max = std::min( g_maxs[i], gene_prop + semiamplitude ); - tmp_max_min = std::max( g_mins[i], gene_prop - semiamplitude ); - backward_range = tmp_min_max - tmp_max_min; - - const REAL bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; - - // assign p' - REAL r01 = getRandRandNorm(); - REAL diff = amplitude * r01 - semiamplitude; - return Tuple(gene + diff, bf_fact); -} - - -struct Genome { - REAL a; - REAL b; - REAL rho; - REAL nu; - REAL sigma; - REAL logLik; - REAL fbRat; - REAL padding; - - Genome() { - this->a = 0.0; this->b = 0.0; this->rho = 0.0; - this->nu = 0.0; this->sigma = 0.0; this->logLik = 0.0; - this->fbRat = 0.0; - } - Genome( const REAL a, const REAL b, const REAL rho, const REAL nu, - const REAL sigma, const REAL logLik, const REAL fbRat) { - this->a = a; this->b = b; this->rho = rho; - this->nu = nu; this->sigma = sigma; this->logLik = logLik; - this->fbRat = fbRat; - } - Genome(const Genome& gene) { - this->a = gene.a; this->b = gene.b; this->rho = gene.rho; - this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; - this->fbRat = gene.fbRat; - } - Genome& operator=(const Genome& gene) { - this->a = gene.a; this->b = gene.b; this->rho = gene.rho; - this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; - this->fbRat = gene.fbRat; - return (*this); - } - - - /** - * mutate all dimensions. martingale with uniform prior. - * requires 5 * POP_SIZE uniform random numbers! - * I took out the evaluation of the proposal, since it should be - * done for all types of crossover/mutation/etc - */ - void mutate_dims_all( const Genome& orig, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { - REAL fb_rat = 1.0; - Tuple tmp(EPS0, 1.0); - - tmp = mutate_helper( orig.a, this->a, 0, amplitude_ratio ); - this->a = constrain_dim1(0, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.b, this->b, 1, amplitude_ratio ); - this->b = constrain_dim1(1, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.rho, this->rho, 2, amplitude_ratio ); - this->rho = constrain_dim1(2, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.nu, this->nu, 3, amplitude_ratio ); - this->nu = constrain_dim1(3, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.sigma, this->sigma, 4, amplitude_ratio ); - this->sigma = constrain_dim1(4, tmp.fst); - fb_rat *= tmp.snd; - - this->fbRat = fb_rat; - } - - /** - * mutate ONE dimension (Gibbs sampling). martingale with uniform prior - * dimension to be changed is given as input: has to be the same for - * all population. Memory coalescence? - * Requires POP_SIZE random uniform numbers! - */ - void mutate_dims_one( const Genome& orig, - const int dim_j, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO - ) { - REAL fb_rat = 1.0; - - Tuple tmp(EPS0, 1.0); - tmp = mutate_helper( orig.a, this->a, 0, (dim_j == 0) ? amplitude_ratio : 0.0 ); - this->a = constrain_dim1(0, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.b, this->b, 1, (dim_j == 1) ? amplitude_ratio : 0.0 ); - this->b = constrain_dim1(1, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.rho, this->rho, 2, (dim_j == 2) ? amplitude_ratio : 0.0 ); - this->rho = constrain_dim1(2, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.nu, this->nu, 3, (dim_j == 3) ? amplitude_ratio : 0.0 ); - this->nu = constrain_dim1(3, tmp.fst); - fb_rat *= tmp.snd; - - tmp = mutate_helper( orig.sigma, this->sigma, 4, (dim_j == 4) ? amplitude_ratio : 0.0 ); - this->sigma = constrain_dim1(4, tmp.fst); - fb_rat *= tmp.snd; - - this->fbRat = fb_rat; - } - - /** - * Crossover - */ - void mcmc_DE( const Genome& orig, - const Genome& gene_k, - const Genome& gene_l, - const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), - const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO - ) { - // proposal - // gamma: integrated out from the adviced - // Multivariate Gaussian with Gaussian target (Braak, 2006) - REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); - - this->a = constrain_dim1( 0, perturbation( orig.a, gene_k.a, gene_l.a, 0, gamma1, ampl_ratio ) ); - this->b = constrain_dim1( 1, perturbation( orig.b, gene_k.b, gene_l.b, 1, gamma1, ampl_ratio ) ); - this->rho = constrain_dim1( 2, perturbation( orig.rho, gene_k.rho, gene_l.rho, 2, gamma1, ampl_ratio ) ); - this->nu = constrain_dim1( 3, perturbation( orig.nu, gene_k.nu, gene_l.nu, 3, gamma1, ampl_ratio ) ); - this->sigma = constrain_dim1( 4, perturbation( orig.sigma, gene_k.sigma, gene_l.sigma, 4, gamma1, ampl_ratio ) ); - - this->fbRat = 1.0; // TODO: fix - } - - /** - * accepting the proposal - */ - void accept( const Genome& mutated ) { - this->a = mutated.a; - this->b = mutated.b; - this->rho = mutated.rho; - this->nu = mutated.nu; - this->sigma = mutated.sigma; - this->logLik = mutated.logLik; - this->fbRat = mutated.fbRat; - } -}; - -#endif // #ifndef CANDIDATE_CLASS - - - - diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/Makefile b/benchmarks/InterestCalib/implementations/OrigCpp/Makefile deleted file mode 100644 index 0cac6e1..0000000 --- a/benchmarks/InterestCalib/implementations/OrigCpp/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -include ../../setup.mk - -ifndef ($(HAVE_GPU)) -include ../../platform.mk -endif - -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -#-fno-unsafe-math-optimizations -fno-finite-math-only -#-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans - -SOURCES_CPP =SwapCalib.cpp -HELPERS =../includeC/ParseInput.h -OBJECTS =SwapCalib.o -EXECUTABLE =SwapCalib - - -default: cpu - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -# The GPU version is in: ../CppAndGPU. This folder is CPU only! -gpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - -cpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - - -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - -clean: - rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) - diff --git a/benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib b/benchmarks/InterestCalib/implementations/OrigCpp/SwapCalib deleted file mode 100755 index 8ba2d1de5f1c6cf8f7f9902645c77de02426026d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76488 zcmdqK4|r6?)%d>&S&T@$8zqVrB-W)}6e3Yjs32M0=%Uf01W7^&Py#}UN+Cg1T7e|s z8rP!I*0#3As@1A}Yx`P@6v>9a0sjI10Yn89^{xR#un<7a?{m)FyV(TdYrntu`#itr z2TyYE%$zyr%$YN1&YYP$xjVn$s??MekNYpxbGb)SS7+vFmig`RgwJb*$@2{Iob1W- zoZ~s$(-|l)KQ3IJ^X5LAooeng9a#C-iJvrn2Bk_$o_X>}JbP%$<8hxZb$JTC)_-}< zt9icpl}Wl!k0)C*q@M7))hXZl)p*T!pM}B@|F$|$x1O*k^_rb}%}zb{>2dgXpKkl4 zZSqs-lozJvk&<+tJUk)&-TD+*`8VRD%5tsysY$1Onx`-BbB=@0eY*8-pq}vgZU6Zk zz#AQU9myr&&~u+|KU`Qb^+%TsxUizUU&Yj0t7i9`J?N5tmkh|6d0Wm!+HS!wuvcF{ zN+}5%;V+vX;kg?>B5EmrZ^DKDeRF-yz&qam=lB2q)uo4azJB*ADLaoJx8FP|*`B#6 zzEsKc^CSQI^t`Xfs($=l)t2d{7XB)Bkj!Qr~SWP zWMsF`Bz>5l6VaX8LH?c&^3U#opB){*&+P#I@ecCGbdY~B__O(G|F3@s@C6;@|DuEZ zl^{Nmd|v1P{bt-8kvysWU4l&A75+!pxbIW_rdAFT8GC`J@?6cHwnb zR@`>$q{0b5s+eTTPFzxQ>x5f8<4VdWjF=@vZ!z>H&7SU=`I8xylRXu;-K=j?c=K(y zOqcRp4=>|xo>V#R)~Z{^RZf{PX+rr-&(%M?Zp66h6J|`PsF+ldfH0*3C>SQX&6z%9 z>aCTN$4#6v%`<8C)Jo6H853?T_e`&uX}VyP2049l%LG`PJY&)%&(#IP zueh?PXxzm)1B^%p;4TQ%U(*ZYIy?lJd_?%3qq4-#sZmmXv>1 zQhsAn{&$k{Hzwtuos_>dDL>hn+L@H!GYQ^K%0DM5e}7WG_(1Nz=A`^=H&dR@ydk=C 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 Date: Fri, 14 Aug 2015 11:17:32 +0200 Subject: [PATCH 044/122] Port of InterestCalib CppOpenMP. --- .../implementations/CppOpenMP/SwapCalib.cpp | 37 ++++--- .../implementations/CppOpenMP/instantiate | 4 +- .../CppOpenMP/instantiate_data | 3 +- .../InterestCalib/lib/include/ParseInput.h | 97 ------------------- .../InterestCalib/lib/include/WriteResult.h | 37 +++++++ 5 files changed, 65 insertions(+), 113 deletions(-) create mode 100644 benchmarks/InterestCalib/lib/include/WriteResult.h diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp index 231217d..948bb78 100644 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp @@ -5,29 +5,30 @@ /*** (sequential) by LexiFi ***/ /*** and a sequential Python implem ***/ /*** using a different genetic alg.***/ -/*** by Christian Andreetta ***/ -/****************************************/ +/*** by Christian Andreetta ***/ +/****************************************/ #include "Util.h" #include "Constants.h" #include "ParseInput.h" #include "GenAlgFlat.h" +#include "WriteResult.h" int main() { - REAL wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, + REAL wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; REAL* calib_arr = NULL; printf("\n// Running Original (CPU Parallel) Swaption-Calibration Benchmark\n"); readDataSet( POP_SIZE, MCMC_LOOPS, - NUM_SWAP_QUOTES, SwaptionQuotes, + NUM_SWAP_QUOTES, SwaptionQuotes, NUM_HERMITE, HermiteCoeffs, HermiteWeights, NUM_SOBOL_BITS, SobolDirVct - ); + ); - unsigned long int elapsed = 0; + unsigned long int elapsed_usec = 0; { // Main Computational Kernel struct timeval t_start, t_end, t_diff; gettimeofday(&t_start, NULL); @@ -36,18 +37,29 @@ int main() gettimeofday(&t_end, NULL); timeval_subtract(&t_diff, &t_end, &t_start); - elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; } { // validation and writeback of the result + FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); + FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); const int Ps = get_CPU_num_threads(); - bool is_valid = validate( wg_logLik, calib_arr, NUM_SWAP_QUOTES ); - writeStatsAndResult( is_valid, wg_a, wg_b, wg_sigma, wg_nu, wg_rho, - wg_logLik, calib_arr, NUM_SWAP_QUOTES, - false, Ps, elapsed ); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + + writeResult(result, + wg_a, + wg_b, + wg_sigma, + wg_nu, + wg_rho, + wg_logLik, + calib_arr); + + fclose(result); } - return 1; + return 0; } @@ -59,4 +71,3 @@ void test_all() { test_pricer_of_swaption(); } #endif - diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate index 857c549..ee90c75 100755 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate @@ -5,6 +5,7 @@ set -e cp $HIPERMARK_LIB_DIR/setup.mk . cp $HIPERMARK_LIB_DIR/include/ParserC.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/ParseInput.h . +cp $HIPERMARK_BENCHMARK_LIB_DIR/include/WriteResult.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Constants.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/KerConsts.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/GenAlgUtil.h . @@ -20,5 +21,6 @@ cp $HIPERMARK_IMPLEMENTATION/run . cp $HIPERMARK_LIB_DIR/include/Util.h . - $HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk + +make diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data index be356dd..b8ccb2b 100755 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data @@ -4,5 +4,4 @@ set -e mkdir -p datasets/$HIPERMARK_INPUT_NAME -# the linearisation might not be needed!! -cp $HIPERMARK_INPUT datasets/$HIPERMARK_INPUT_NAME/input.data \ No newline at end of file +$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/InterestCalib/lib/include/ParseInput.h b/benchmarks/InterestCalib/lib/include/ParseInput.h index 042725c..efddda2 100644 --- a/benchmarks/InterestCalib/lib/include/ParseInput.h +++ b/benchmarks/InterestCalib/lib/include/ParseInput.h @@ -98,102 +98,5 @@ void readDataSet( UINT& pop_size, } } -REAL* readOutput( const int& N, REAL& ref_logLik ) { - REAL* result; - int64_t shape[3]; - - REAL ref_a, ref_b, ref_sigma, ref_nu, ref_rho; - - // reading the reference genome! - if( read_real( &ref_a ) || read_real( &ref_b ) || - read_real( &ref_sigma ) || read_real( &ref_nu ) || - read_real( &ref_rho ) || read_real( &ref_logLik ) ) { - fprintf(stderr, "Syntax error when reading the reference genome or its likelihood.\n"); - exit(1); - } - - // reading the standard output - if ( read_array(sizeof(REAL), read_real, (void**)&result, shape, 2) ) { - fprintf(stderr, "Syntax error when reading the output.\n"); - exit(1); - } - bool ok = ( shape[0] == N ) && ( shape[1] == 3 ); - assert(ok && "Incorrect shape of the reference array result!"); - - return result; -} - -bool validate( const REAL& logLik, const REAL* res, const int& N ) { - bool is_valid = true; - - REAL ref_logLik; - REAL* ref_res = readOutput( N, ref_logLik ); - - if( fabs(ref_logLik - logLik) > 1.0 ) { - is_valid = false; - fprintf(stderr, "Difference in logLikelihood > 1.0: result logLik %f, reference logLik = %f!\n", - logLik, ref_logLik ); - return is_valid; - } else if ( logLik < ref_logLik && fabs(ref_logLik - logLik) > 0.5 ) { - is_valid = false; - fprintf(stderr, "Result likelihood is worse than reference with more than 0.5: result logLik %f, reference logLik = %f!\n", - logLik, ref_logLik ); - return is_valid; - } - - for ( int i = 0; i < N; i ++ ) { - REAL lgLik_cur = logLikelihood( res[3*i+1], res[3*i]); - REAL lgLik_ref = logLikelihood(ref_res[3*i+1],ref_res[3*i]); - REAL diff_curr_lgLik = (lgLik_cur > lgLik_ref) ? - 0.0 : lgLik_ref - lgLik_cur ; - - if (diff_curr_lgLik > 0.7) { - is_valid = false; - fprintf(stderr, "Error[%d] = %f, Acceptable = 1.1!\n", - i, diff_curr_lgLik ); - break; - } - } - - return is_valid; -} - -void writeStatsAndResult( const bool& valid, - const REAL& wg_a, - const REAL& wg_b, - const REAL& wg_sigma, - const REAL& wg_nu, - const REAL& wg_rho, - const REAL& wg_logLik, - const REAL* calib_arr, - const int & NUM_SWAP_QUOTES, - const bool& is_gpu, - const int & P, - const unsigned long int& elapsed -) { - // print stats to stdout - fprintf(stdout, "// Dataset with Number of Swaption Quotes = %d.\n", - NUM_SWAP_QUOTES ); - - if(valid) { fprintf(stdout, "1\t\t// VALID Result,\n"); } - else { fprintf(stdout, "0\t\t// INVALID Result,\n"); } - - fprintf(stdout, "%ld\t\t// Runtime in microseconds,\n", elapsed); - if(is_gpu) fprintf(stdout, "%d\t\t// GPU Threads,\n\n", P); - else fprintf(stdout, "%d\t\t// CPU Threads,\n\n", P); - - // write the genome - write_scal(&wg_a, "a-field of the winning genome"); - write_scal(&wg_b, "b-field of the winning genome"); - write_scal(&wg_sigma, "sigma-field of the winning genome"); - write_scal(&wg_nu, "nu-field of the winning genome"); - write_scal(&wg_rho, "rho-field of the winning genome"); - write_scal(&wg_logLik,"LgLikelihood of the winning genome"); - - // write the result - write_2Darr( calib_arr, static_cast(NUM_SWAP_QUOTES), 3, - "Swaption Calibration Result: foreach swaption [CalibPrice,BlackPrice,PercentDiff]" ); -} - #endif // PARSE_INPUT diff --git a/benchmarks/InterestCalib/lib/include/WriteResult.h b/benchmarks/InterestCalib/lib/include/WriteResult.h new file mode 100644 index 0000000..a263cdc --- /dev/null +++ b/benchmarks/InterestCalib/lib/include/WriteResult.h @@ -0,0 +1,37 @@ +#ifndef WRITERESULT_H +#define WRITERESULT_H + +#include + +/* Writes trailing comma and newline. */ +void writeRealField(FILE *stream, const char* field, REAL x) +{ + fprintf(stream, "\"%s\": %f,\n", field, x); +} + +void writeResult(FILE *stream, + REAL a, + REAL b, + REAL sigma, + REAL nu, + REAL rho, + REAL logLik, + REAL* calib_arr) +{ + /* Hackily manually generate JSON. It would be nice with some + proper library support. */ + fprintf(stream, "{\n"); + + writeRealField(stream, "a_field", a); + writeRealField(stream, "b_field", b); + writeRealField(stream, "sigma_field", sigma); + writeRealField(stream, "nu_field", nu); + writeRealField(stream, "rho_field", rho); + writeRealField(stream, "lg_likelyhood", logLik); + + fprintf(stream, "\"swaption_calibration_result\":\n"); + write_2Darr(stream, calib_arr, static_cast(NUM_SWAP_QUOTES), 3); + fprintf(stream, "}\n"); +} + +#endif From 000d4260d5fa6692acc95cfe052d3640ee7d97b8 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 14 Aug 2015 16:55:46 +0200 Subject: [PATCH 045/122] Validation function for InterestCalib/CppOpenMP ported from C++ to Python --- .../lib/include/validation_function | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100755 benchmarks/InterestCalib/lib/include/validation_function diff --git a/benchmarks/InterestCalib/lib/include/validation_function b/benchmarks/InterestCalib/lib/include/validation_function new file mode 100755 index 0000000..ae0e43b --- /dev/null +++ b/benchmarks/InterestCalib/lib/include/validation_function @@ -0,0 +1,75 @@ +#!/usr/bin/env python + +import os +import sys +import json +import math + +LG_LIKELIHOOD_TOLERANCE1 = 1.0 +LG_LIKELIHOOD_TOLERANCE2 = 0.5 +LG_LIKELIHOOD_TOLERANCE3 = 0.7 +LLHOOD_CAUCHY_OFFS = 5.0 + +def read_json_file(filename): + """ returns an array containing the content of the JSON file. + + keyword arguments: + filename -- name of json file to interpret + """ + with open(filename, "r") as file: + return json.loads(file.read()) + +def get_arguments(): + if len(sys.argv) != 3: + raise Exception("Usage: %s "% (sys.argv[0]) ) + return (sys.argv[1], sys.argv[2]) + +def cauchy_pdf(z, mu, gamma): + x = (z-mu) / gamma + return 1/(math.pi * gamma * (1+x*x)) + +def log_likelihood(y_ref, y): # CAUCHY + gamma = (abs(y_ref) / 50.0) * LLHOOD_CAUCHY_OFFS + 0.01 + pdfs = cauchy_pdf(y, y_ref, gamma) + pdfs += 1e-20 # avoid NaNs + return math.log(pdfs) + +def validate_swaption(calc_swap, expt_swap): + N = len(calc_swap) + if N != len(expt_swap): + raise Exception("The length of the swaption result array is different for the calculated and expected result: len(calculated swaption result array: %d. Expected result array: %d)" % (N, len(expt_swap))) + for i in range(N): + lg_lh_calc = log_likelihood(calc_swap[i][1], calc_swap[i][0]) + lg_lh_expt = log_likelihood(expt_swap[i][1], expt_swap[i][0]) + diff_curr_lg_lh = 0.0 if (lg_lh_calc > lg_lh_expt) else (lg_lh_expt - lg_lh_calc) + if diff_curr_lg_lh > LG_LIKELIHOOD_TOLERANCE3: + raise Exception("Error in swaption result validation. Error of result number %d: %f. Acceptable: %f" % + (i, diff_curr_lg_lh, LG_LIKELIHOOD_TOLERANCE3)) + +def validate(calculated_result_file, expected_result_file): + """ Checks if the calculated result and the expected result are close enough to be considered valid. + All errors in validation must throw an exception, otherwise validate will wrongly return succesful. + """ + calc = read_json_file(os.path.join(os.getcwd(), calculated_result_file)) + expt = read_json_file(os.path.join(os.getcwd(), expected_result_file)) + calc_lg_lh = calc['lg_likelyhood'] + expt_lg_lh = expt['lg_likelyhood'] + dev = abs(calc_lg_lh - expt_lg_lh) + if (dev > LG_LIKELIHOOD_TOLERANCE1): + raise Exception("Difference in log likelihood > %f. Result log likelihood: %f, reference log likelihood: %f" % + (LG_LIKELIHOOD_TOLERANCE1, calc_lg_lh, expt_lg_lh)) + if (expt_lg_lh - calc_lg_lh) > LG_LIKELIHOOD_TOLERANCE2: + raise Exception("Result likelihood is worse than reference with more than %f. Result log likelihood: %f, reference log likelihood %f" % (LG_LIKELIHOOD_TOLERANCE2, calc_lg_lh, expt_lg_lh)) + expt_res = expt['swaption_calibration_result'] + calc_res = calc['swaption_calibration_result'] + validate_swaption(calc_res, expt_res) + +if __name__ == "__main__": + (calculated_result, expected_result) = get_arguments() + try: + validate(calculated_result, expected_result) + print("Validation succesfull") + exit(0) + except Exception as e: + print(e.args) + exit(1) From af808c1c717856d48f585ee25a45cd4004b4a328 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 14 Aug 2015 20:36:09 +0200 Subject: [PATCH 046/122] external validation function for InterestCalib now works with hipermark and with calculated results for InterestCalib --- benchmarks/InterestCalib/lib/include/validation_function | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/benchmarks/InterestCalib/lib/include/validation_function b/benchmarks/InterestCalib/lib/include/validation_function index ae0e43b..8c0fd56 100755 --- a/benchmarks/InterestCalib/lib/include/validation_function +++ b/benchmarks/InterestCalib/lib/include/validation_function @@ -37,13 +37,15 @@ def log_likelihood(y_ref, y): # CAUCHY def validate_swaption(calc_swap, expt_swap): N = len(calc_swap) if N != len(expt_swap): - raise Exception("The length of the swaption result array is different for the calculated and expected result: len(calculated swaption result array: %d. Expected result array: %d)" % (N, len(expt_swap))) + raise Exception("The length of the swaption resulta rray is different for the calculated and expected result: len(calculated swaption result array: %d. Expected result array: %d)" % (N, len(expt_swap))) + print(N) for i in range(N): + print(1) lg_lh_calc = log_likelihood(calc_swap[i][1], calc_swap[i][0]) lg_lh_expt = log_likelihood(expt_swap[i][1], expt_swap[i][0]) diff_curr_lg_lh = 0.0 if (lg_lh_calc > lg_lh_expt) else (lg_lh_expt - lg_lh_calc) if diff_curr_lg_lh > LG_LIKELIHOOD_TOLERANCE3: - raise Exception("Error in swaption result validation. Error of result number %d: %f. Acceptable: %f" % + raise Exception("Error in swaption result validation.git Error of result number %d: %f. Acceptable: %f" % (i, diff_curr_lg_lh, LG_LIKELIHOOD_TOLERANCE3)) def validate(calculated_result_file, expected_result_file): From f26f5712562b0bf454985078406a52f5d25074d1 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 14 Aug 2015 20:59:05 +0200 Subject: [PATCH 047/122] Run scripts for hipermark are now provided. --- run_hipermark_CalibVolDiff | 9 +++++++++ run_hipermark_InterestCalib | 9 +++++++++ run_hipermark_OptionPricing | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100755 run_hipermark_CalibVolDiff create mode 100755 run_hipermark_InterestCalib create mode 100755 run_hipermark_OptionPricing diff --git a/run_hipermark_CalibVolDiff b/run_hipermark_CalibVolDiff new file mode 100755 index 0000000..173ca43 --- /dev/null +++ b/run_hipermark_CalibVolDiff @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/CalibVolDiff +echo Running hipermark CalibVolDiff cpp_openmp_naive + cpp_sequential small + medium dataset, two times. +echo Storing all results in instantiations/ + +rm -rf instantiations/CalibVolDiff +../hipermark/hipermark instantiations/ 2 benchmarks/CalibVolDiff cpp_openmp_naive,cpp_sequential small,medium diff --git a/run_hipermark_InterestCalib b/run_hipermark_InterestCalib new file mode 100755 index 0000000..3a55487 --- /dev/null +++ b/run_hipermark_InterestCalib @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/InterestCalib +echo Running hipermark InterestCalib CppOpenMP small dataset, 2 times. +echo Storing all results in instantiations/ + +rm -rf instantiations/InterestCalib +../hipermark/hipermark instantiations/ 2 benchmarks/InterestCalib CppOpenMP small \ No newline at end of file diff --git a/run_hipermark_OptionPricing b/run_hipermark_OptionPricing new file mode 100755 index 0000000..e613272 --- /dev/null +++ b/run_hipermark_OptionPricing @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/OptionPricing/ +echo Running hipermark OptionPricing cpp_openmp small + medium dataset, 10 times. +echo Storing all results in instantiations/ + +rm -rf instantiations/OptionPricing/ +../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_openmp small,medium From c30948bae08210ae72ba10c9b8f5da2ac974e987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sat, 15 Aug 2015 17:50:46 +0200 Subject: [PATCH 048/122] validation_function for InterestCalib moved. --- benchmarks/InterestCalib/{lib/include => }/validation_function | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename benchmarks/InterestCalib/{lib/include => }/validation_function (100%) diff --git a/benchmarks/InterestCalib/lib/include/validation_function b/benchmarks/InterestCalib/validation_function similarity index 100% rename from benchmarks/InterestCalib/lib/include/validation_function rename to benchmarks/InterestCalib/validation_function From 4aceb38aa6bc174194bfa81e5b0af5c5b935c678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sat, 15 Aug 2015 18:15:00 +0200 Subject: [PATCH 049/122] Removed a few poor man's debugger instructions from validation_function --- benchmarks/InterestCalib/validation_function | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/InterestCalib/validation_function b/benchmarks/InterestCalib/validation_function index 8c0fd56..dfe7707 100755 --- a/benchmarks/InterestCalib/validation_function +++ b/benchmarks/InterestCalib/validation_function @@ -35,12 +35,12 @@ def log_likelihood(y_ref, y): # CAUCHY return math.log(pdfs) def validate_swaption(calc_swap, expt_swap): + """ Checks whether the result (excluding the lg_likelyhood part of the JSON object) validates. + """ N = len(calc_swap) if N != len(expt_swap): - raise Exception("The length of the swaption resulta rray is different for the calculated and expected result: len(calculated swaption result array: %d. Expected result array: %d)" % (N, len(expt_swap))) - print(N) + raise Exception("The length of the swaption result array is different for the calculated and expected result: len(calculated swaption result array: %d. Expected result array: %d)" % (N, len(expt_swap))) for i in range(N): - print(1) lg_lh_calc = log_likelihood(calc_swap[i][1], calc_swap[i][0]) lg_lh_expt = log_likelihood(expt_swap[i][1], expt_swap[i][0]) diff_curr_lg_lh = 0.0 if (lg_lh_calc > lg_lh_expt) else (lg_lh_expt - lg_lh_calc) From 6e5bd5460e3da90290bc142fbfab3aacb9f4438b Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 19 Aug 2015 18:10:49 +0200 Subject: [PATCH 050/122] removed file --- hipermark_op | 9 --------- 1 file changed, 9 deletions(-) delete mode 100755 hipermark_op diff --git a/hipermark_op b/hipermark_op deleted file mode 100755 index 036fb83..0000000 --- a/hipermark_op +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -clear -echo Deleting all files in instantiations/OptionPricing/ -echo Running hipermark OptionPricing cpp_openmp small dataset, 20 times. -echo Storing all results in instantiations/ - -rm -rf instantiations/OptionPricing/ -../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_openmp small,medium \ No newline at end of file From dfc88111596ccfec3ed85789804525011234967c Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 19 Aug 2015 21:03:40 +0200 Subject: [PATCH 051/122] statconfig file added to CalibVolDiff/cpp_openmp_naive so hipermark can compile with different environment variables --- .../CalibVolDiff/implementations/cpp_openmp_naive/instantiate | 2 +- .../implementations/cpp_openmp_naive/statconfig.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate index 4a94a33..8eee718 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate @@ -11,6 +11,6 @@ cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/Makefile . cp $HIPERMARK_IMPLEMENTATION/run . $HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk -NCORES=$($HIPERMARK_LIB_DIR/json_get.py $HIPERMARK_PLATFORM num_cores) +NCORES=$HIPERMARK_NCORES make diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json new file mode 100644 index 0000000..ba6f5a7 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json @@ -0,0 +1 @@ +{"NCORES": [1,2,3,4]} From 973187810dcd12e62e42a946e9334d70aaad0730 Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 19 Aug 2015 21:14:31 +0200 Subject: [PATCH 052/122] file names changed --- .../implementations/cpp_openmp_naive/statconfig.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json deleted file mode 100644 index ba6f5a7..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/statconfig.json +++ /dev/null @@ -1 +0,0 @@ -{"NCORES": [1,2,3,4]} From bf0183b112afe7001551c77d94637ea1231de622 Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 19 Aug 2015 21:15:18 +0200 Subject: [PATCH 053/122] file names for static_configuration_options_template changed --- .../cpp_openmp_naive/static_configuration_options_template.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json new file mode 100644 index 0000000..ba6f5a7 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json @@ -0,0 +1 @@ +{"NCORES": [1,2,3,4]} From 99aecf5652d6183ce9bb9ce89e2ac53babb77ee0 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Wed, 19 Aug 2015 21:17:04 +0200 Subject: [PATCH 054/122] Float/double configuration choice for CalibVolDiff cpp_sequential. --- .../CalibVolDiff/implementations/cpp_sequential/Makefile | 2 +- .../implementations/cpp_sequential/VolCalibOrig.cpp | 7 +++++-- .../static_configuration_options_template.json | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_options_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile index 0ddc64c..b7a1d56 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile @@ -14,7 +14,7 @@ EXECUTABLE =VolCalib #g++ -I. -I/usr/local/cuda/include -O3 NordeaVect.cpp -lOpenCL default: cpu -.cpp.o: $(SOURCES_CPP) $(HELPERS) +.cpp.o: $(SOURCES_CPP) $(HELPERS) -DREAL_TYPE=${REAL_TYPE} $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< cpu: $(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp index 94662d3..5626694 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp @@ -1,10 +1,13 @@ #include #include -#define WITH_FLOATS 0 -#define WORKGROUP_SIZE 512 +#define WORKGROUP_SIZE 512 +#ifdef REAL_TYPE +typedef REAL_TYPE REAL; +#else typedef double REAL; +#endif #include "Util.h" #include "ParseInput.h" diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_options_template.json b/benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_options_template.json new file mode 100644 index 0000000..5087e27 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_options_template.json @@ -0,0 +1,3 @@ +{ + "REAL_TYPE": ["float", "double"] +} From 8245d501615d998ec019ca0f0a2709374de84e25 Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 19 Aug 2015 21:20:14 +0200 Subject: [PATCH 055/122] environment var name changed --- .../CalibVolDiff/implementations/cpp_openmp_naive/instantiate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate index 8eee718..849ae59 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate @@ -11,6 +11,6 @@ cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/Makefile . cp $HIPERMARK_IMPLEMENTATION/run . $HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk -NCORES=$HIPERMARK_NCORES +NCORES=$HIPERMARK_CONFIG_NCORES make From 1494006a0e4eff4504c545bffba0b0d727123e87 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Wed, 19 Aug 2015 21:41:36 +0200 Subject: [PATCH 056/122] Fix float/double selection. --- .../implementations/cpp_sequential/Makefile | 4 +- .../cpp_sequential/VolCalibOrig.cpp | 70 +++++++++---------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile index b7a1d56..8f554e7 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile @@ -11,10 +11,12 @@ HELPERS =../includeC/ParseInput.h OBJECTS =VolCalibOrig.o EXECUTABLE =VolCalib +CXXFLAGS += -DREAL_TYPE=$(HIPERMARK_CONFIG_REAL_TYPE) + #g++ -I. -I/usr/local/cuda/include -O3 NordeaVect.cpp -lOpenCL default: cpu -.cpp.o: $(SOURCES_CPP) $(HELPERS) -DREAL_TYPE=${REAL_TYPE} +.cpp.o: $(SOURCES_CPP) $(HELPERS) $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< cpu: $(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp index 5626694..fb8bd02 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp @@ -4,9 +4,9 @@ #define WORKGROUP_SIZE 512 #ifdef REAL_TYPE -typedef REAL_TYPE REAL; +typedef REAL_TYPE real_t; #else -typedef double REAL; +typedef double real_t; #endif #include "Util.h" @@ -15,24 +15,24 @@ typedef double REAL; using namespace std; // grid -vector myX, myY, myTimeline; +vector myX, myY, myTimeline; unsigned myXindex, myYindex; // variable -vector > myResult; +vector > myResult; // coeffs -vector > myMuX, myVarX, myMuY, myVarY; +vector > myMuX, myVarX, myMuY, myVarY; // operators -vector > myDx, myDxx, myDy, myDyy; +vector > myDx, myDxx, myDy, myDyy; /***********************************/ -void updateParams(const unsigned g, const double alpha, const double beta, const double nu) +void updateParams(const unsigned g, const real_t alpha, const real_t beta, const real_t nu) { for(unsigned i=0;i(s0/dx); for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) +void initOperator(const vector& x, vector >& Dx, vector >& Dxx) { const unsigned n = x.size(); @@ -96,7 +96,7 @@ void initOperator(const vector& x, vector >& Dx, vector& x, vector >& Dx, vector& a, - const vector& b, - const vector& c, - const vector& r, + const vector& a, + const vector& b, + const vector& c, + const vector& r, const int n, - vector& u, - vector& uu) + vector& u, + vector& uu) { int i, offset; - REAL beta; + real_t beta; u[0] = r[0]; uu[0] = b[0]; @@ -194,11 +194,11 @@ rollback(const unsigned g) int kl, ku, ll, lu; - double dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]); + real_t dtInv = 1.0/(myTimeline[g+1]-myTimeline[g]); - vector > u(numY,vector(numX)), v(numX,vector(numY)); + vector > u(numY,vector(numX)), v(numX,vector(numY)); - vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); + vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); // explicit x for(i=0;i strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); + vector strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); for(unsigned i=0;i Date: Thu, 20 Aug 2015 09:24:12 +0200 Subject: [PATCH 057/122] Switch from instantiate_data to 'make data' targets. --- .../implementations/cpp_openmp_naive/Makefile | 16 ++++++------- .../cpp_openmp_naive/instantiate_data | 7 ------ .../implementations/cpp_openmp_naive/run | 2 +- .../implementations/cpp_sequential/Makefile | 24 ++++++++++++------- .../cpp_sequential/instantiate | 11 ++------- .../cpp_sequential/instantiate_data | 7 ------ .../implementations/cpp_sequential/run | 2 +- .../implementations/haskell_lh/Makefile | 18 ++++++++++++++ .../haskell_lh/instantiate_data | 7 ------ lib/setup.mk | 6 ++++- 10 files changed, 50 insertions(+), 50 deletions(-) delete mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data delete mode 100755 benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data create mode 100644 benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile delete mode 100755 benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile index 447ba3c..6317209 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile @@ -1,19 +1,16 @@ -include setup.mk +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ -ifndef ($(HAVE_GPU)) -include platform.mk -endif +include $(HIPERMARK_LIB_DIR)/setup.mk SOURCES_CPP =VolCalibOrig.cpp -HELPERS =../includeC/ParseInput.h +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/ParseInput.h OBJECTS =VolCalibOrig.o -EXECUTABLE =VolCalib +EXECUTABLE =VolCalibOrig .cpp.o: $(SOURCES_CPP) $(HELPERS) $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< -# The GPU version is in: ../VectAll and ../VectOuters. This folder is CPU only! - cpu: $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) @@ -21,3 +18,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data deleted file mode 100755 index 1054784..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate_data +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e - -mkdir -p datasets/$HIPERMARK_INPUT_NAME - -$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT outer num_x num_y num_t > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run index 8caf40b..e54405c 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run @@ -1,3 +1,3 @@ #!/bin/sh export OMP_NUM_THREADS=$NCORES -cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalib \ No newline at end of file +cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalibOrig diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile index 8f554e7..7f9f34a 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile @@ -1,19 +1,21 @@ -include setup.mk +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ -ifndef ($(HAVE_GPU)) -include platform.mk -endif +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double -INCLUDES += -I../includeC +include $(HIPERMARK_LIB_DIR)/setup.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include SOURCES_CPP =VolCalibOrig.cpp -HELPERS =../includeC/ParseInput.h -OBJECTS =VolCalibOrig.o -EXECUTABLE =VolCalib +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h +OBJECTS =VolCalibOrig.o +EXECUTABLE =VolCalibOrig CXXFLAGS += -DREAL_TYPE=$(HIPERMARK_CONFIG_REAL_TYPE) -#g++ -I. -I/usr/local/cuda/include -O3 NordeaVect.cpp -lOpenCL default: cpu .cpp.o: $(SOURCES_CPP) $(HELPERS) @@ -36,3 +38,7 @@ run_large: $(EXECUTABLE) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate index 81ea6b7..f3b331d 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate @@ -2,14 +2,7 @@ set -e -cp $HIPERMARK_LIB_DIR/setup.mk . -cp $HIPERMARK_LIB_DIR/include/ParserC.h . -cp $HIPERMARK_LIB_DIR/include/Util.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Constants.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/Makefile . +cp $HIPERMARK_IMPLEMENTATION/*cpp . cp $HIPERMARK_IMPLEMENTATION/run . -$HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk - -make +make -f $HIPERMARK_IMPLEMENTATION/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data deleted file mode 100755 index 1054784..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate_data +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e - -mkdir -p datasets/$HIPERMARK_INPUT_NAME - -$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT outer num_x num_y num_t > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/run b/benchmarks/CalibVolDiff/implementations/cpp_sequential/run index c9863c8..07e2b55 100755 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/run +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/run @@ -1,3 +1,3 @@ #!/bin/sh -cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalib +cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalibOrig diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile b/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile new file mode 100644 index 0000000..8f398de --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile @@ -0,0 +1,18 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +include $(HIPERMARK_LIB_DIR)/setup.mk + +SOURCES = VolCalib.hs +EXECUTABLE = VolCalib +GHC_FLAGS = -Wall -O2 -msse2 -rtsopts + +$(EXECUTABLE): $(SOURCES) + ghc $(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) + +clean: + rm $(EXECUTABLE) *o *hi + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data deleted file mode 100755 index 2a92a4b..0000000 --- a/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate_data +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e #Die on error - -mkdir -p datasets/$HIPERMARK_INPUT_NAME - -$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT outer num_x num_y num_t > datasets/$HIPERMARK_INPUT_NAME/input.data \ No newline at end of file diff --git a/lib/setup.mk b/lib/setup.mk index 3cd65f4..8c7761d 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -1,3 +1,8 @@ +# If we are run from outside Hipermark itself, a number of environment +# variables will be missing. Set these to hopefully-working values to +# support standalone compilation. +HIPERMARK_BENCHMARK_LIB_DIR ?= ../../lib/ + OS=$(shell uname -s) ifeq ($(OS),Darwin) @@ -17,4 +22,3 @@ else CXXFLAGS = -DENABLE_OPENMP -fopenmp -O3 INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include endif - From a722d51076bd6874898381638f2c954fd977b471 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 10:22:39 +0200 Subject: [PATCH 058/122] Get rid of instantiate and run files. --- .../implementations/cpp_openmp_naive/Makefile | 21 ++++++++++++++----- .../cpp_openmp_naive/instantiate | 16 -------------- .../implementations/cpp_openmp_naive/run | 3 --- .../implementations/cpp_sequential/Makefile | 13 ++++++------ .../cpp_sequential/instantiate | 8 ------- .../implementations/cpp_sequential/run | 3 --- .../implementations/haskell_lh/Makefile | 9 ++++++-- .../implementations/haskell_lh/instantiate | 8 ------- .../implementations/haskell_lh/run | 6 ------ lib/setup.mk | 1 + 10 files changed, 30 insertions(+), 58 deletions(-) delete mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate delete mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run delete mode 100755 benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate delete mode 100755 benchmarks/CalibVolDiff/implementations/cpp_sequential/run delete mode 100755 benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate delete mode 100755 benchmarks/CalibVolDiff/implementations/haskell_lh/run diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile index 6317209..abd493d 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile @@ -1,17 +1,25 @@ # Permit standalone compilation. HIPERMARK_LIB_DIR ?= ../../../../lib/ +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + include $(HIPERMARK_LIB_DIR)/setup.mk -SOURCES_CPP =VolCalibOrig.cpp -HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/ParseInput.h +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h OBJECTS =VolCalibOrig.o EXECUTABLE =VolCalibOrig -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< +CXXFLAGS += -DREAL_TYPE=$(HIPERMARK_CONFIG_REAL_TYPE) + +default: $(EXECUTABLE) + +%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< -cpu: $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) @@ -21,3 +29,6 @@ clean: data: $(HIPERMARK_INPUT) mkdir -p datasets/$(HIPERMARK_INPUT_NAME) $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate deleted file mode 100755 index 849ae59..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/instantiate +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -set -e - -cp $HIPERMARK_LIB_DIR/setup.mk . -cp $HIPERMARK_LIB_DIR/include/ParserC.h . -cp $HIPERMARK_LIB_DIR/include/Util.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Constants.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/Makefile . -cp $HIPERMARK_IMPLEMENTATION/run . - -$HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk -NCORES=$HIPERMARK_CONFIG_NCORES - -make diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run deleted file mode 100755 index e54405c..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -export OMP_NUM_THREADS=$NCORES -cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalibOrig diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile index 7f9f34a..92c6b76 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile @@ -9,24 +9,20 @@ include $(HIPERMARK_LIB_DIR)/setup.mk INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include INCLUDES += -I$(HIPERMARK_LIB_DIR)/include -SOURCES_CPP =VolCalibOrig.cpp HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h OBJECTS =VolCalibOrig.o EXECUTABLE =VolCalibOrig CXXFLAGS += -DREAL_TYPE=$(HIPERMARK_CONFIG_REAL_TYPE) -default: cpu +default: $(EXECUTABLE) -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< - -cpu: $(EXECUTABLE) +%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) - run_small: $(EXECUTABLE) cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt @@ -42,3 +38,6 @@ clean: data: $(HIPERMARK_INPUT) mkdir -p datasets/$(HIPERMARK_INPUT_NAME) $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate b/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate deleted file mode 100755 index f3b331d..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/instantiate +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -e - -cp $HIPERMARK_IMPLEMENTATION/*cpp . -cp $HIPERMARK_IMPLEMENTATION/run . - -make -f $HIPERMARK_IMPLEMENTATION/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/run b/benchmarks/CalibVolDiff/implementations/cpp_sequential/run deleted file mode 100755 index 07e2b55..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalibOrig diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile b/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile index 8f398de..618e7aa 100644 --- a/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile +++ b/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile @@ -7,8 +7,10 @@ SOURCES = VolCalib.hs EXECUTABLE = VolCalib GHC_FLAGS = -Wall -O2 -msse2 -rtsopts -$(EXECUTABLE): $(SOURCES) - ghc $(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) +default: $(EXECUTABLE) + +$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) + ghc $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) clean: rm $(EXECUTABLE) *o *hi @@ -16,3 +18,6 @@ clean: data: $(HIPERMARK_INPUT) mkdir -p datasets/$(HIPERMARK_INPUT_NAME) $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate b/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate deleted file mode 100755 index 6a0342d..0000000 --- a/benchmarks/CalibVolDiff/implementations/haskell_lh/instantiate +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -e # Die on error. - -cp $HIPERMARK_IMPLEMENTATION/*hs . -cp $HIPERMARK_IMPLEMENTATION/run . - -ghc -Wall -O2 -msse2 -rtsopts VolCalib.hs -o VolCalib diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/run b/benchmarks/CalibVolDiff/implementations/haskell_lh/run deleted file mode 100755 index bada098..0000000 --- a/benchmarks/CalibVolDiff/implementations/haskell_lh/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -set -e - -./VolCalib +RTS -K128m -RTS < ./datasets/$HIPERMARK_INPUT_NAME/input.data -#cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./VolCalib +RTS -K128m -RTS diff --git a/lib/setup.mk b/lib/setup.mk index 8c7761d..096b916 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -2,6 +2,7 @@ # variables will be missing. Set these to hopefully-working values to # support standalone compilation. HIPERMARK_BENCHMARK_LIB_DIR ?= ../../lib/ +HIPERMARK_IMPLEMENTATION ?= . OS=$(shell uname -s) From 74f1b25d3a34b5a57bb506366eb799e4d6f36f4c Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 10:29:38 +0200 Subject: [PATCH 059/122] Use dynamic options for OpenMP implementation. --- .../CalibVolDiff/implementations/cpp_openmp_naive/Makefile | 3 ++- .../cpp_openmp_naive/dynamic_configuration_options.json | 1 + .../static_configuration_options_template.json | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_options.json delete mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile index abd493d..6d4b81f 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile @@ -31,4 +31,5 @@ data: $(HIPERMARK_INPUT) $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + OMP_NUM_THREADS=$(HIPERMARK_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_options.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_options.json new file mode 100644 index 0000000..14298aa --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_options.json @@ -0,0 +1 @@ +{"NUM_THREADS": [1,2,3,4]} diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json deleted file mode 100644 index ba6f5a7..0000000 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json +++ /dev/null @@ -1 +0,0 @@ -{"NCORES": [1,2,3,4]} From 54a901a6a504c8c1440ad950040d20036ead2bdc Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 10:46:29 +0200 Subject: [PATCH 060/122] Port InterestCalib to brave new world. --- .../InterestCalib/datasets/medium/input.json | 2 +- .../implementations/CppOpenMP/Makefile | 38 ++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/benchmarks/InterestCalib/datasets/medium/input.json b/benchmarks/InterestCalib/datasets/medium/input.json index d5814b7..0379260 100644 --- a/benchmarks/InterestCalib/datasets/medium/input.json +++ b/benchmarks/InterestCalib/datasets/medium/input.json @@ -221,7 +221,7 @@ -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, 3.6684708465595856630159, -3.6684708465595838866591 - ] + ], "hermite_coefficient_weights": [ 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile index 4224d4d..f975376 100644 --- a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile +++ b/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile @@ -1,27 +1,37 @@ -include setup.mk +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ -ifndef ($(HAVE_GPU)) -include platform.mk -endif +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_IMPLEMENTATION) -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) #-fno-unsafe-math-optimizations -fno-finite-math-only #-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans -SOURCES_CPP =SwapCalib.cpp -HELPERS =ParseInput.h #Can this be correct?? -OBJECTS =SwapCalib.o +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h +OBJECTS =SwapCalib.o EXECUTABLE =SwapCalib -default: cpu +default: $(EXECUTABLE) -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< +%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< -# The GPU version is in: ../CppAndGPU. This folder is CPU only! -cpu: $(OBJECTS) +$(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) From 8b26759a2515d2d0b9b6d87f08fd433e2b901707 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 10:47:56 +0200 Subject: [PATCH 061/122] Fix environment syntax. --- benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile index 92c6b76..d66ddf2 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile @@ -37,7 +37,7 @@ clean: data: $(HIPERMARK_INPUT) mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data + $HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$HIPERMARK_INPUT_NAME/input.data run: cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) From bdb8d8197a9ac18934defc8b999355cab5d0b25d Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 10:56:50 +0200 Subject: [PATCH 062/122] Clearer error message. --- benchmarks/InterestCalib/validation_function | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmarks/InterestCalib/validation_function b/benchmarks/InterestCalib/validation_function index dfe7707..51bbeff 100755 --- a/benchmarks/InterestCalib/validation_function +++ b/benchmarks/InterestCalib/validation_function @@ -73,5 +73,6 @@ if __name__ == "__main__": print("Validation succesfull") exit(0) except Exception as e: - print(e.args) + print("Validation failed:") + print("%s: %s" % (type(e), e.args)) exit(1) From 11dfd8dc12dd938f791fc6a06e18d9f2f6919f9e Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 10:57:17 +0200 Subject: [PATCH 063/122] Fix typo in large reference dataset. --- benchmarks/InterestCalib/datasets/large/output.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/InterestCalib/datasets/large/output.json b/benchmarks/InterestCalib/datasets/large/output.json index 6367af8..c21426d 100644 --- a/benchmarks/InterestCalib/datasets/large/output.json +++ b/benchmarks/InterestCalib/datasets/large/output.json @@ -5,7 +5,7 @@ "nu_field": 0.018683, "rho_field": -0.083963, "lg_likelyhood": 624.116935, - "swaption_calibration_results": + "swaption_calibration_result": [ [ 74.172585 , 115.320470 , 35.681337 ], [ 100.626570 , 162.945479 , 38.245252 ], From b7b9ec1256e7cf311e05e711a96ff1aed8856dd3 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Thu, 20 Aug 2015 11:04:49 +0200 Subject: [PATCH 064/122] Enable float/double switch for cpp_openmp_naive. --- .../cpp_openmp_naive/VolCalibOrig.cpp | 105 +++++++++--------- ...static_configuration_options_template.json | 3 + 2 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp index f907517..9cf2e1d 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp +++ b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp @@ -1,7 +1,12 @@ #include #include -typedef double REAL; +#ifdef REAL_TYPE +typedef REAL_TYPE real_t; +#else +typedef double real_t; +#endif + #define WORKGROUP_SIZE 512 #include "Util.h" @@ -12,27 +17,27 @@ using namespace std; struct PrivGlobs { // grid - vector myX; - vector myY; - vector myTimeline; + vector myX; + vector myY; + vector myTimeline; unsigned myXindex; unsigned myYindex; // variable - vector > myResult; + vector > myResult; // coeffs - vector > myMuX; - vector > myVarX; - vector > myMuY; - vector > myVarY; + vector > myMuX; + vector > myVarX; + vector > myMuY; + vector > myVarY; // operators - vector > myDx; - vector > myDxx; + vector > myDx; + vector > myDxx; - vector > myDy; - vector > myDyy; + vector > myDy; + vector > myDyy; } __attribute__ ((aligned (128))); @@ -41,7 +46,7 @@ struct PrivGlobs { /***********************************/ -void updateParams(const unsigned g, const double alpha, const double beta, const double nu, PrivGlobs& globs) +void updateParams(const unsigned g, const real_t alpha, const real_t beta, const real_t nu, PrivGlobs& globs) { for(unsigned i=0;i(s0/dx); for(unsigned i=0;i& x, vector >& Dx, vector >& Dxx) +void initOperator(const vector& x, vector >& Dx, vector >& Dxx) { const unsigned n = x.size(); @@ -107,7 +112,7 @@ void initOperator(const vector& x, vector >& Dx, vector& x, vector >& Dx, vector& a, - const vector& b, - const vector& c, - const vector& r, + const vector& a, + const vector& b, + const vector& c, + const vector& r, const int n, - vector& u, - vector& uu) + vector& u, + vector& uu) { int i, offset; - REAL beta; + real_t beta; u[0] = r[0]; uu[0] = b[0]; @@ -204,10 +209,10 @@ rollback( const unsigned g, PrivGlobs& globs ) { int kl, ku, ll, lu; - double dtInv = 1.0/(globs.myTimeline[g+1]-globs.myTimeline[g]); + real_t dtInv = 1.0/(globs.myTimeline[g+1]-globs.myTimeline[g]); - vector > u(numY,vector(numX)), v(numX,vector(numY)); - vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); + vector > u(numY,vector(numX)), v(numX,vector(numY)); + vector a(numZ), b(numZ), c(numZ), y(numZ), yy(numZ); // explicit x for(i=0;i& strikes, - vector& res + const real_t& s0, + const real_t& t, + const real_t& alpha, + const real_t& nu, + const real_t& beta, + const vector& strikes, + vector& res ) { #pragma omp parallel for default(shared) schedule(static) if(outer>4) for( unsigned i = 0; i < outer; ++ i ) { @@ -311,13 +316,13 @@ double* run_CPUkernel( int main() { unsigned int OUTER_LOOP_COUNT, NUM_X, NUM_Y, NUM_T; - const double s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; + const real_t s0 = 0.03, strike = 0.03, t = 5.0, alpha = 0.2, nu = 0.6, beta = 0.5; cout<<"\n// Running Original (Parallel) Volatility-Calibration Benchmark"< strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); + vector strikes(OUTER_LOOP_COUNT),res(OUTER_LOOP_COUNT); for(unsigned i=0;i Date: Thu, 20 Aug 2015 15:23:27 +0200 Subject: [PATCH 065/122] this repo should work with runtime var configurations through hipermark --- ...iguration_options.json => dynamic_configuration_template.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/{dynamic_configuration_options.json => dynamic_configuration_template.json} (100%) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_options.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_options.json rename to benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_template.json From c725df995c6d0b749ce87f640bbf0bc9a49006d0 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 07:38:27 +0200 Subject: [PATCH 066/122] Correct naming. --- ...n_options_template.json => static_configuration_template.json} | 0 ...n_options_template.json => static_configuration_template.json} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/{static_configuration_options_template.json => static_configuration_template.json} (100%) rename benchmarks/CalibVolDiff/implementations/cpp_sequential/{static_configuration_options_template.json => static_configuration_template.json} (100%) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json b/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_options_template.json rename to benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_options_template.json b/benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_options_template.json rename to benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_template.json From 58d4e04952bf328dc61351c07e9d1e465dde49b8 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 07:39:44 +0200 Subject: [PATCH 067/122] Add more CalibVolDiff implementations. --- .../cpp_openclmp_all/CrankNicolson.cl | 1033 +++++++++++ .../implementations/cpp_openclmp_all/Makefile | 54 + .../cpp_openclmp_all/PrepareKernels.h | 1576 +++++++++++++++++ .../cpp_openclmp_all/Vect_CPU.h | 159 ++ .../cpp_openclmp_all/Vect_GPU.h | 190 ++ .../cpp_openclmp_all/VolCalibAll.cpp | 166 ++ .../cpp_openclmp_all/VolCalibInit.h | 127 ++ .../static_configuration_template.json | 3 + .../cpp_openclmp_outer/CrankNicolson.cl | 274 +++ .../cpp_openclmp_outer/Makefile | 54 + .../cpp_openclmp_outer/PrepareKernels.h | 529 ++++++ .../cpp_openclmp_outer/Vect_CPU.h | 122 ++ .../cpp_openclmp_outer/Vect_GPU.h | 180 ++ .../cpp_openclmp_outer/VolCalibInit.h | 137 ++ .../cpp_openclmp_outer/VolCalibOuter | Bin 0 -> 68448 bytes .../cpp_openclmp_outer/VolCalibOuter.cpp | 168 ++ .../static_configuration_template.json | 3 + .../implementations/cpp_openmp_naive/Makefile | 5 +- .../cpp_openmp_naive/VolCalibOrig.cpp | 11 +- .../implementations/cpp_sequential/Makefile | 5 +- .../CalibVolDiff/lib/include/Constants.h | 64 +- .../lib/include/DataStructConst.h | 40 +- .../CalibVolDiff/lib/include/ParPrefixUtil.h | 102 +- lib/include/SDK_stub.h | 24 +- lib/include/Util.h | 2 +- lib/platform.mk | 28 + lib/setup.mk | 4 + lib/setup_real_type.mk | 16 + 28 files changed, 4970 insertions(+), 106 deletions(-) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_CPU.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_GPU.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibInit.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/static_configuration_template.json create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_CPU.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_GPU.h create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h create mode 100755 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/static_configuration_template.json create mode 100644 lib/platform.mk create mode 100644 lib/setup_real_type.mk diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl new file mode 100644 index 0000000..bd57356 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl @@ -0,0 +1,1033 @@ +#include "Constants.h" + + +/**************************************************************************/ +/**************** SHARED-MEMORY ACCESSOR FUNCTIONS ************************/ +/**************************************************************************/ + +#define WITH_INTERLEAVED_BANKS4 1 +#define WITH_INTERLEAVED_BANKS2 1 + +#if WITH_INTERLEAVED_BANKS2 +inline void store2(real2_t val, unsigned int ind, __local real_t* cache) { + ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+1) ); + cache[ind] = val.x; + ind += WORKGROUP_SIZE; + cache[ind] = val.y; +} + +inline real2_t load2(unsigned int ind, __local real_t* cache) { + ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+1) ); + real2_t val; + val.x = cache[ind]; + ind += WORKGROUP_SIZE; + val.y = cache[ind]; + return val; +} +#else +inline void store2(real2_t val, unsigned int ind, volatile __local real2_t* cache) { + cache[ind] = val; +} + +inline real2_t load2(unsigned int ind, volatile __local real2_t* cache) { + return cache[ind]; +} +#endif + + +#if WITH_INTERLEAVED_BANKS4 +inline void store4(real4_t val, unsigned int ind, __local real_t* cache) { + //ind = (ind / WORKGROUP_SIZE)*(WORKGROUP_SIZE) * 4 + (ind % WORKGROUP_SIZE); + ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+2) ); + cache[ind] = val.x; + ind += WORKGROUP_SIZE; + cache[ind] = val.y; + ind += WORKGROUP_SIZE; + cache[ind] = val.z; + ind += WORKGROUP_SIZE; + cache[ind] = val.w; +} + +inline real4_t load4(unsigned int ind, __local real_t* cache) { + real4_t val; + //ind = (ind / WORKGROUP_SIZE)*(WORKGROUP_SIZE) * 4 + (ind % WORKGROUP_SIZE); + ind = (ind & (WORKGROUP_SIZE-1)) + ( (ind >> logWORKGROUP_SIZE) << (logWORKGROUP_SIZE+2) ); + val.x = cache[ind]; + ind += WORKGROUP_SIZE; + val.y = cache[ind]; + ind += WORKGROUP_SIZE; + val.z = cache[ind]; + ind += WORKGROUP_SIZE; + val.w = cache[ind]; + return val; +} +#else +inline void store4(real4_t val, unsigned int ind, volatile __local real4_t* cache) { + cache[ind] = val; +} + +inline real4_t load4(unsigned int ind, volatile __local real4_t* cache) { + return cache[ind]; +} +#endif +/**************************************************************************/ +/*********** PREPARE FOR TRIDAG X *****************************************/ +/**************************************************************************/ +__kernel void prepare_tridag_x ( + /*** Read-Only Scalars ***/ + __global RWScalars* ro_scals, // __constant + /*** Read-Only Arrays ***/ + __global real_t* myX, + __global real3_t* myDx, + __global real3_t* myDxx, + __constant real_t* myY, + __constant real_t* myDy, + __constant real_t* myDyy, + /*** Read-Write Temporary Arrays ***/ + __global real_t* a, + __global real_t* b, + __global real_t* c, + __global real_t* y, + __global real_t* u, + __global real_t* v, + __global real4_t* scan_tmp, + /*** Temporary Array in Shared Space ***/ + __local real_t* cache_tmp, + /*** The Result Array ***/ + __global real_t* res_arr +) { + real3_t myDy_elem, myDyy_elem, myres_elem; + real_t cur_myVar = ro_scals->nu; + real_t cur_myMu = 0.0; + + unsigned int glob_ind = get_global_id(2) * get_global_size(1) * get_global_size(0); + const unsigned int ind = glob_ind + get_global_id(1)*get_global_size(0) + get_global_id(0); + + real_t tmp = 0.0; + + cur_myVar *= cur_myVar; + + // second loop + { + myres_elem = (real3_t)( (get_global_id(1)!=0) ? res_arr[ind - get_global_size(0)] : 0.0, + res_arr[ind], + (get_global_id(1) != get_global_size(1)-1) ? res_arr[ind + get_global_size(0)] : 0.0 + ); + + myDy_elem = (real3_t)( myDy[get_global_id(1)<<2], myDy[ (get_global_id(1)<<2)+1], myDy[(get_global_id(1)<<2)+2] ); + myDyy_elem = (real3_t)( myDyy[get_global_id(1)<<2], myDyy[(get_global_id(1)<<2)+1], myDyy[(get_global_id(1)<<2)+2] ); + + myDy_elem = cur_myMu*myDy_elem + 0.5f*cur_myVar*myDyy_elem; + myDy_elem *= myres_elem; + tmp += myDy_elem.x + myDy_elem.y + myDy_elem.z; + + v[glob_ind + get_global_id(0)*get_global_size(1) + get_global_id(1)] = tmp; + } + + glob_ind = get_local_id(2)*get_local_size(1)*get_local_size(0) + get_local_id(1)*get_local_size(0) + get_local_id(0); + + // first loop + cur_myMu = 0.0; // X + cur_myVar = exp( 2 * ( ro_scals->beta*log(myX[get_global_id(0)]) + + myY[get_global_id(1)] - 0.5f*cur_myVar*ro_scals->timeline_i // cur_myVar == nu*nu + ) + ); + { + // CACHING ASSUMES ALL ELEMENTS IN X DIMENSION fit in the LOCALGROUP! + cache_tmp[glob_ind] = res_arr[ ind ]; + + myDy_elem = myDx[ get_global_id(0) ]; + myDyy_elem = myDxx[ get_global_id(0) ]; + + barrier(CLK_LOCAL_MEM_FENCE); + + + myres_elem = (real3_t)( (get_global_id(0)!=0) ? cache_tmp[ glob_ind - 1 ] : 0.0, + cache_tmp[ glob_ind ], + (get_global_id(0) != get_global_size(0)-1) ? cache_tmp[ glob_ind + 1 ] : 0.0 + ); + + tmp += ro_scals->dtInv*myres_elem.y; + myDy_elem = 0.5f*( cur_myMu*myDy_elem + 0.5f*cur_myVar*myDyy_elem ); + + c[ind] = - myDy_elem.z; + + barrier(CLK_GLOBAL_MEM_FENCE); + + a[ind] = - myDy_elem.x; // b[ind] = ro_scals->dtInv - myDy_elem.y; + + myDyy_elem = myDy_elem*myres_elem; + tmp += myDyy_elem.x + myDyy_elem.y + myDyy_elem.z; + } + + u[ind] = tmp; + + + + tmp = ro_scals->dtInv - myDy_elem.y; + + // third loop + if( get_global_id(0) > 0 ) { + scan_tmp[ind] = (real4_t) ( tmp, myDy_elem.x * c[ind-1], 1.0, 0.0 ); + } else { // i == get_global_id(0) == 0 + y[ind] = tmp; // = b [ind] + scan_tmp[ind] = (real4_t) ( tmp, 0.0, 0.0, tmp ); + } +} + + +/**************************************************************************/ +/*********** IN-BETWEEN TRIDAGS -- i.e., prepare for TRIDAG Y *************/ +/**************************************************************************/ +//#define USE_LOCAL_Y + +__kernel void prepare_tridag_y ( + /*** Read-Only Scalars ***/ + __global RWScalars* ro_scals, // __constant + /*** Read-Only Arrays ***/ + __global real3_t* myDy, + __global real3_t* myDyy, + /*** Read-Write Temporary Arrays ***/ + __global real_t* a, + __global real_t* b, + __global real_t* c, + __global real_t* u, + __global real_t* v, + __global real_t* y, + __global real4_t* scan_tmp, + /*** Temporary Array in Shared Space ***/ + __local real_t* cache_tmp +) { + + // !!!0 <-> j; 1<-> i; 2 <-> k!!! + const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) + + get_global_id(1) * get_global_size(0) + get_global_id(0); + // + get_global_id(1)*NUM_Y + get_global_id(0); + const unsigned int glob_ind = get_local_id(2)*get_local_size(1)*get_local_size(0) + + get_local_id(1)*get_local_size(0) + get_local_id(0); + real3_t myDy_elem; + real_t dt_inv = ro_scals->dtInv; + + real_t cur_myMuY = 0.0; + real_t cur_myVarY = ro_scals->nu; cur_myVarY *= cur_myVarY*0.5f; //nu*nu; + + myDy_elem = 0.5f*( cur_myMuY*myDy [get_global_id(0)] + cur_myVarY*myDyy[get_global_id(0)] ); + +#ifdef USE_LOCAL_Y + cache_tmp[glob_ind] = - myDy_elem.z; +#endif + + a[ind] = - myDy_elem.x; c[ind] = - myDy_elem.z; + + // NUM_X = get_global_size(1) + v[ind] = dt_inv * + u[ get_global_id(2)* get_global_size(1) * get_global_size(0) + + get_global_id(0)*get_global_size(1) + get_global_id(1) ] + - 0.5f*v[ind]; // y[j] = dtInv*u[j][i] - 0.5*v[i][j]; + +#ifdef USE_LOCAL_Y + barrier(CLK_LOCAL_MEM_FENCE); +#endif + + // third loop + if( get_global_id(0) > 0 ) { +#ifdef USE_LOCAL_Y + scan_tmp[ind] = (real4_t) ( dt_inv - myDy_elem.y, myDy_elem.x * cache_tmp[glob_ind-1], 1.0, 0.0 ); +#else + const real_t elem = - 0.5f*(cur_myMuY*myDy[get_global_id(0)-1].z + cur_myVarY*myDyy[get_global_id(0)-1].z); + scan_tmp[ind] = (real4_t) ( dt_inv - myDy_elem.y, myDy_elem.x * elem, 1.0, 0.0 ); +#endif + //scan_tmp[ind] = (real4_t) ( dt_inv - myDy_elem.y, myDy_elem.x*c[ind-1], 1.0, 0.0 ); + + } else { // j == get_global_id(0) == 0 + y[ind] = dt_inv - myDy_elem.y; //b[ind]; + scan_tmp[ind] = (real4_t) ( dt_inv - myDy_elem.y, 0.0, 0.0, dt_inv - myDy_elem.y ); + } +} + + +/**********************************************************************/ +/************* TRIDAG KERNELS *****************************************/ +/**********************************************************************/ + +/*************************************/ +/*** 1. Scan with Matrix Multiply ****/ +/*************************************/ + +/** + * Multiplies 2x2 matrixes `a' and `b' and + * stores the result in(-place in) `a'. + */ +inline real4_t matmult2(real4_t a, real4_t b) { + real_t val = (a.x*b.x + a.y*b.z); + + a = (real4_t) (val, a.x*b.y + a.y*b.w, a.z*b.x + a.w*b.z, a.z*b.y + a.w*b.w); + val = 1.0/val; + return a * val; +} + + + +//#define LOG2_WARP_SIZE 5U +//#define WARP_SIZE (1U << LOG2_WARP_SIZE) + +#if WITH_INTERLEAVED_BANKS4 +inline real4_t warpScanInclMatMult(real4_t idata, volatile __local real4_t *l_Data4, uint size){ + volatile __local real_t* l_Data = (volatile __local real_t*) l_Data4; + + uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); + store4( (real4_t)(1.0, 0.0, 0.0, 1.0), pos, l_Data ); + pos += size; + store4( idata, pos, l_Data ); + + if(size >= 2) { real4_t tmp = matmult2( load4(pos, l_Data),load4(pos-1, l_Data) ); store4(tmp, pos, l_Data); } + if(size >= 4) { real4_t tmp = matmult2( load4(pos, l_Data),load4(pos-2, l_Data) ); store4(tmp, pos, l_Data); } + if(size >= 8) { real4_t tmp = matmult2( load4(pos, l_Data),load4(pos-4, l_Data) ); store4(tmp, pos, l_Data); } + if(size >= 16) { real4_t tmp = matmult2( load4(pos, l_Data),load4(pos-8, l_Data) ); store4(tmp, pos, l_Data); } +#if WARP == 32 + if(size >= 32) { real4_t tmp = matmult2( load4(pos, l_Data),load4(pos-16,l_Data) ); store4(tmp, pos, l_Data); } +#endif + return load4(pos, l_Data); +} +#else +inline real4_t warpScanInclMatMult(real4_t idata, volatile __local real4_t *l_Data, uint size){ + uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); + l_Data[pos] = (real4_t)(1.0, 0.0, 0.0, 1.0); + pos += size; + l_Data[pos] = idata; + + if(size >= 2) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-1] ); + if(size >= 4) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-2] ); + if(size >= 8) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-4] ); + if(size >= 16) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-8] ); +#if WARP == 32 + if(size >= 32) l_Data[pos] = matmult2( l_Data[pos], l_Data[pos-16]); +#endif + return l_Data[pos]; +} +#endif + +//Vector scan: the array to be scanned is stored +//in work-item private memory as uint4 +inline real4_t scanMatMultInclLocal(real4_t idata4, __local real4_t *l_Data, uint size){ + if(size > WARP){ + //Bottom-level inclusive warp scan + real4_t warpResult = warpScanInclMatMult(idata4, l_Data, WARP); + + //Save top elements of each warp for exclusive warp scan + //sync to wait for warp scans to complete (because l_Data is being overwritten) + barrier(CLK_LOCAL_MEM_FENCE); + if( (get_local_id(0) & (WARP - 1)) == (WARP - 1) ) { +#if WITH_INTERLEAVED_BANKS4 + store4(warpResult, get_local_id(0) >> lgWARP, (__local real_t*)l_Data); +#else + l_Data[get_local_id(0) >> lgWARP] = warpResult; +#endif + } + //wait for warp scans to complete + barrier(CLK_LOCAL_MEM_FENCE); + + if( get_local_id(0) < (WORKGROUP_SIZE >> lgWARP) ){ +#if WITH_INTERLEAVED_BANKS4 + real4_t val = load4(get_local_id(0), (__local real_t*)l_Data); + store4( warpScanInclMatMult(val, l_Data, size >> lgWARP), get_local_id(0), (__local real_t*)l_Data); +#else + //grab top warp elements + real4_t val = l_Data[get_local_id(0)]; + //calculate inclusive scan and write back to shared memory + l_Data[get_local_id(0)] = warpScanInclMatMult(val, l_Data, size >> lgWARP); +#endif + } + + //return updated warp scans with exclusive scan results + barrier(CLK_LOCAL_MEM_FENCE); + + //if( (get_local_id(0) >> LOG2_WARP_SIZE) > 0 ) + if( ( (get_local_id(0) & (size-1)) >> lgWARP ) > 0 ) { +#if WITH_INTERLEAVED_BANKS4 + real4_t tmp = load4( (get_local_id(0) >> lgWARP) - 1, (__local real_t*)l_Data ); + warpResult = matmult2( warpResult, tmp ); +#else + warpResult = matmult2( warpResult, l_Data[ (get_local_id(0) >> lgWARP) - 1] ); +#endif + } + + return warpResult; + }else{ + return warpScanInclMatMult(idata4, l_Data, size); + } +} + +__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) +void scanMatMultIncl( + __global real4_t *data, + __local real4_t *l_Data, + uint size +){ + //Load data + real4_t idata4 = data[get_global_id(0)]; + + //Calculate exclusive scan + real4_t odata4 = scanMatMultInclLocal( idata4, l_Data, size ); + + //Write back + data[get_global_id(0)] = odata4; +} + + +/*************************************************/ +/*** 1. Scan with Linear Function Composition ****/ +/*************************************************/ + +// Linear Function Composition and Scan +inline real2_t linfuncomp(real2_t ab2, real2_t ab1) { + ab2.x = ab2.y * ab1.x + ab2.x; + ab2.y = ab2.y * ab1.y; + return ab2; +} + +#if WITH_INTERLEAVED_BANKS2 +inline real2_t warpScanInclLinFunComp(real2_t idata, volatile __local real2_t *l_Data2, uint size){ + volatile __local real_t* l_Data = (volatile __local real_t*) l_Data2; + + uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); + store2( (real2_t)(0.0, 1.0), pos, l_Data ); + pos += size; + store2( idata, pos, l_Data ); + + if(size >= 2) { real2_t tmp = linfuncomp( load2(pos, l_Data),load2(pos-1, l_Data) ); store2(tmp, pos, l_Data); } + if(size >= 4) { real2_t tmp = linfuncomp( load2(pos, l_Data),load2(pos-2, l_Data) ); store2(tmp, pos, l_Data); } + if(size >= 8) { real2_t tmp = linfuncomp( load2(pos, l_Data),load2(pos-4, l_Data) ); store2(tmp, pos, l_Data); } + if(size >= 16) { real2_t tmp = linfuncomp( load2(pos, l_Data),load2(pos-8, l_Data) ); store2(tmp, pos, l_Data); } +#if WARP == 32 + if(size >= 32) { real2_t tmp = linfuncomp( load2(pos, l_Data),load2(pos-16,l_Data) ); store2(tmp, pos, l_Data); } +#endif + return load2(pos, l_Data); +} +#else +inline real2_t warpScanInclLinFunComp(real2_t idata, volatile __local real2_t *l_Data, uint size){ + uint pos = 2 * get_local_id(0) - (get_local_id(0) & (size - 1)); + l_Data[pos] = (real2_t)(0.0, 1.0); + pos += size; + l_Data[pos] = idata; + + if(size >= 2) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-1] ); + if(size >= 4) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-2] ); + if(size >= 8) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-4] ); + if(size >= 16) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-8] ); +#if WARP == 32 + if(size >= 32) l_Data[pos] = linfuncomp( l_Data[pos], l_Data[pos-16]); +#endif + return l_Data[pos]; +} +#endif + +inline real2_t scanLinFunCompInclLocal(real2_t idata4, __local real2_t *l_Data, uint size){ + if(size > WARP){ + //Bottom-level inclusive warp scan + real2_t warpResult = warpScanInclLinFunComp(idata4, l_Data, WARP); + + //Save top elements of each warp for exclusive warp scan + //sync to wait for warp scans to complete (because l_Data is being overwritten) + barrier(CLK_LOCAL_MEM_FENCE); + if( (get_local_id(0) & (WARP - 1)) == (WARP - 1) ) { +#if WITH_INTERLEAVED_BANKS2 + store2(warpResult, get_local_id(0) >> lgWARP, (__local real_t*)l_Data); +#else + l_Data[get_local_id(0) >> lgWARP] = warpResult; +#endif + } + + //wait for warp scans to complete + barrier(CLK_LOCAL_MEM_FENCE); + + if( get_local_id(0) < (WORKGROUP_SIZE / WARP) ){ +#if WITH_INTERLEAVED_BANKS2 + real2_t val = load2(get_local_id(0), (__local real_t*)l_Data); + store2( warpScanInclLinFunComp(val, l_Data, size >> lgWARP), get_local_id(0), (__local real_t*)l_Data); +#else + //grab top warp elements + real2_t val = l_Data[get_local_id(0)]; + //calculate inclusive scan and write back to shared memory + l_Data[get_local_id(0)] = warpScanInclLinFunComp(val, l_Data, size >> lgWARP); +#endif + } + + //return updated warp scans with exclusive scan results + barrier(CLK_LOCAL_MEM_FENCE); + + if( ( (get_local_id(0) & (size-1)) >> lgWARP ) > 0 ) { +#if WITH_INTERLEAVED_BANKS2 + real2_t tmp = load2( (get_local_id(0) >> lgWARP) - 1, (__local real_t*)l_Data ); + warpResult = linfuncomp( warpResult, tmp ); +#else + warpResult = linfuncomp( warpResult, l_Data[ (get_local_id(0) >> lgWARP) - 1] ); +#endif + } + return warpResult; + }else{ + return warpScanInclLinFunComp(idata4, l_Data, size); + } +} + + +__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) +void scanLinFunCompIncl( + __global real2_t *data, + __local real2_t *l_Data, + uint size +){ + //Load data + real2_t idata4 = data[get_global_id(0)]; + + //Calculate exclusive scan + real2_t odata4 = scanLinFunCompInclLocal( idata4, l_Data, size ); + + //Write back + data[get_global_id(0)] = odata4; +} + + +/*************************************/ +/*** 2. TRIDAG - in between scans ****/ +/*************************************/ + +inline real_t map_matmult(real4_t tmp, real_t val1) { + + real_t nom = tmp.x*val1+tmp.y; + real_t denom = tmp.z*val1+tmp.w; + + return nom/denom; + + //real_t denom = tmp.z*val1+tmp.w*val2; + //real_t nom = (tmp.x/denom)*val1 + (tmp.y/denom)*val2; + //return nom; +} + +__kernel void conclude_matmult ( + /*** Read-Write Temporary Arrays ***/ + __global real_t* b, + __global real_t* d, + __global real_t* y, + __global real_t* u, + __global real4_t* scan_tmp +) { + unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) + + get_global_id(1) * get_global_size(0); + real_t b0 = u[ind]; //b[ ind ]; + ind += get_global_id(0); + + if(get_global_id(0) > 0) { + u[ind] = map_matmult( scan_tmp[ind], b0 ); + } else { + y[ind] = d[ind]; + } +} + + +__kernel void prelude_fwd_fun_comp ( + /*** Read-Write Temporary Arrays ***/ + __global real_t* a, + __global real_t* d, + __global real_t* u, + __global real2_t* scan_tmp +) { + const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) + + get_global_id(1) * get_global_size(0) + get_global_id(0); + + if( get_global_id(0) > 0 ) { + scan_tmp[ind] = (real2_t) ( d[ind], (0.0 - (a[ind]/u[ind-1])) ); + } else { + scan_tmp[ind] = (real2_t) (0.0, 1.0); + } +} + +///// + +__kernel void post_fwd_fun_comp ( + /*** Read-Write Temporary Arrays ***/ + __global real_t* y, + __global real2_t* scan_tmp +) { + unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) + + get_global_id(1) * get_global_size(0); + + real_t y0 = y[ ind ]; + + ind += get_global_id(0); + + if( get_global_id(0) > 0 ) { + real2_t fun = scan_tmp[ind]; + y[ind] = fun.x + y0 * fun.y; + } +} + +__kernel void prelude_bwd_fun_comp ( + /*** Read-Write Temporary Arrays ***/ + __global real_t* c, + __global real_t* y, + __global real_t* u, + __global real2_t* scan_tmp +) { + const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) + + get_global_id(1) * get_global_size(0) + get_global_id(0); + const unsigned int inv_ind = ind - 2*get_global_id(0) + get_global_size(0) - 2; + + if( get_global_id(0) < get_global_size(0) - 1 ) { + scan_tmp[ind] = (real2_t)(y[inv_ind]/u[inv_ind], 0.0 - c[inv_ind]/u[inv_ind]); + } else { // get_global_id(0) == get_global_size(0) - 1 + scan_tmp[ind] = (real2_t)(0.0, 1.0); + y[ind] = y[ind]/u[ind]; + } +} + +/** + * 1. map back the result from the (bacward) parallel prefix + * with linear function composition + * 2. update the RW scalars rw_scals->dtInv and rw_scals->timeline_i + */ +__kernel void post_bwd_fun_comp ( + __global real_t* y, + __global real2_t* scan_tmp +) { + // map back the result from the (bacward) parallel prefix + // with linear function composition + + const unsigned int ind = get_global_id(2) * get_global_size(1) * get_global_size(0) + + get_global_id(1) * get_global_size(0) + get_global_id(0); + const unsigned int inv_ind = ind - 2*get_global_id(0) + get_global_size(0) - 2; + + real_t ynm1 = y[inv_ind + get_global_id(0) + 1]; + + if( get_global_id(0) < get_global_size(0) - 1 ) { + real2_t fun = scan_tmp[ind]; + y[inv_ind] = fun.x + ynm1 * fun.y; + } +} + + +/*********************************************/ +/*********** Matrix Transposition ************/ +/*********************************************/ + +// This kernel is optimized to ensure all global reads and writes are coalesced, +// and to avoid bank conflicts in shared memory. The shared memory array is sized +// to (BLOCK_DIM+1)*BLOCK_DIM. This pads each row of the 2D block in shared memory +// so that bank conflicts do not occur when threads address the array column-wise. +inline void transposeMatrix( + __global real_t *odata, + __global real_t *idata, + unsigned int width, + unsigned int height, + __local real_t* block) +{ + unsigned int xIndex, yIndex; + + // adjust the input and output arrays for the third dimension! + yIndex = get_global_id(2) * width * height; + odata = odata + yIndex; + idata = idata + yIndex; + + // read the matrix tile into shared memory + xIndex = get_global_id(0); + yIndex = get_global_id(1); + + if((xIndex < width) && (yIndex < height)) + { + unsigned int index_in = yIndex * width + xIndex; + block[get_local_id(1)*(BLOCK_DIM+1)+get_local_id(0)] = idata[index_in]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // write the transposed matrix tile to global memory + xIndex = get_group_id(1) * BLOCK_DIM + get_local_id(0); + yIndex = get_group_id(0) * BLOCK_DIM + get_local_id(1); + if((xIndex < height) && (yIndex < width)) + { + unsigned int index_out = yIndex * height + xIndex; + odata[index_out] = block[get_local_id(0)*(BLOCK_DIM+1)+get_local_id(1)]; + } +} + +__kernel void transpose( + __global real_t *odata, + __global real_t *idata, + //int offset, + unsigned int width, + unsigned int height, + __local real_t* block) +{ + transposeMatrix( odata, idata, width, height, block ); +} + +__kernel void transposeUpdateScalars( + __global real_t *odata, + __global real_t *idata, + //int offset, + unsigned int width, + unsigned int height, + __local real_t* block, + __global RWScalars* ro_scals, // __constant + __constant real_t* timeline +) { + transposeMatrix( odata, idata, width, height, block ); + //odata[get_global_id(2)*get_global_size(1)*get_global_size(0) + get_global_id(1)*get_global_size(0) + get_global_id(0)] + // = 33.33; + + // update time-loop-variant scalars + if(get_global_id(2) + get_global_id(1) + get_global_id(0) == 0) { + int t_ind = --ro_scals->t_ind; + ro_scals->dtInv = 1.0 / ( timeline[t_ind+1] - timeline[t_ind] ); + ro_scals->timeline_i = timeline[ t_ind ]; + } +} + + +/***************************************************************/ +/**************** INLINED TRIDAG VERSION ***********************/ +/***************************************************************/ + +inline void tridag_inline_local ( + /*** Read-Write Temporary Arrays ***/ +// __global real_t* a, + real_t a_elem, +// __global real_t* c, + real_t c_elem, +// __global real_t* d, + real_t d_elem, + __global real_t* y, +// __global real4_t* scan_tmp4, + real4_t data4, + const unsigned int SIZE, +/*** Temporary Array in Shared Space ***/ + __local real_t* cache_tmp, // size: [8*WORKSIZE*sizeof(real_t)] + const size_t first_id, + real_t b0, + real_t d0 +) { + //const size_t first_id = get_global_id(0) - (get_global_id(0) & (SIZE-1)); + //real_t b0; + + { // SCAN with matrix multiplication + __local real4_t* l_data = (__local real4_t*)cache_tmp; + + //Calculate exclusive scan + data4 = scanMatMultInclLocal( data4, l_data, SIZE ); + barrier(CLK_LOCAL_MEM_FENCE); // IMPORTANT! + + real_t data = map_matmult( data4, b0 ); + cache_tmp[get_local_id(0)] = data; + barrier(CLK_LOCAL_MEM_FENCE); + } + + { // Forward scan with linear function composition + real2_t data2; + // prepare for scan + if(get_global_id(0) == first_id) { + //y[get_global_id(0)] = d0; //d[get_global_id(0)]; // y[ind] = d[ind]; + data2 = (real2_t) (0.0, 1.0); + } else { + data2 = (real2_t) ( d_elem, (0.0 - (a_elem/cache_tmp[get_local_id(0)-1])) ); + } + + {//Calculate exclusive scan + __local real2_t* l_Data = ((__local real2_t*)cache_tmp) + get_local_size(0); + data2 = scanLinFunCompInclLocal( data2, l_Data, SIZE ); + } + + //POST FWD MAP: y[ind] = fun.x + y0 * fun.y; + //y[get_global_id(0)] = data2.x + d0 * data2.y; + { + cache_tmp[get_local_size(0) + get_local_id(0)] = data2.x + d0 * data2.y; + barrier(CLK_LOCAL_MEM_FENCE); + } + } + + { // Backward scan with linear function composition + const unsigned int inv_ind = (SIZE-1) - (get_global_id(0) & (SIZE-1)); + real2_t data2; + + unsigned int local_offset = get_local_id(0) - (get_local_id(0) & (SIZE-1)); + b0 = cache_tmp[local_offset + get_local_size(0) + (SIZE-1)]/cache_tmp[local_offset + (SIZE-1)]; + + // prepare for scan! + if(get_global_id(0) == first_id) { + data2 = (real2_t) (0.0, 1.0); + } else { + real_t myu = cache_tmp[local_offset + inv_ind]; + data2 = (real2_t) ( cache_tmp[local_offset + inv_ind + get_local_size(0)] / myu, + 0.0 - c_elem / myu ); + //0.0 - c[first_id + inv_ind]/myu ); + } + + {// BACKWARD SCAN with linear function compsition + __local real2_t* l_Data = ((__local real2_t*)cache_tmp) + get_local_size(0); + data2 = scanLinFunCompInclLocal( data2, l_Data, SIZE ); + } + + // //POST BWD MAP: y[ind] = fun.x + y0 * fun.y; + y[first_id + inv_ind] = data2.x + b0 * data2.y; + } + +} + +__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) +void tridag_inlined ( + /*** Read-Write Temporary Arrays ***/ + __global real_t* a, + __global real_t* c, + __global real_t* d, + __global real_t* y, + __global real_t* u, + __global real4_t* scan_tmp4, + const unsigned int SIZE, +/*** Temporary Array in Shared Space ***/ + __local real_t* cache_tmp // size: [8*WORKSIZE*sizeof(real_t)] +) { + const size_t first_id = get_global_id(0) - (get_global_id(0) & (SIZE-1)); + //const unsigned int inv_ind = (SIZE-1) - (get_global_id(0) & (SIZE-1)); + + tridag_inline_local ( + a[get_global_id(0)], + c[first_id + (SIZE-1) - (get_global_id(0) & (SIZE-1))], + //(get_global_id(0) != first_id) ? c[first_id + (SIZE-1) - (get_global_id(0) & (SIZE-1))] : 0.0, //c + d[get_global_id(0)], + y, + scan_tmp4[get_global_id(0)], + SIZE, + cache_tmp, + first_id, + scan_tmp4[first_id].x, + d[first_id] + ); +} + + + +/***************************************************************/ +/************* TWO KERNELS VERSION: X & Y **********************/ +/***************************************************************/ + +__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) +void nordea_kernel_x ( + /*** Read-Only Scalars ***/ + __constant RWScalars* ro_scals, // __constant + /*** Read-Only Arrays ***/ + __global real_t* myX, + __global real3_t* myDx, + __global real3_t* myDxx, + __constant real_t* myY, + __constant real_t* myDy, + __constant real_t* myDyy, + /*** Read-Write Temporary Arrays ***/ + __global real_t* u, + __global real_t* v, + /*** Temporary Array in Shared Space ***/ + __local real_t* cache_tmp, + /*** The Result Array ***/ + __global real_t* res_arr +) { + + real3_t myD_elem; + + unsigned int ind_x = get_global_id(0) & (ro_scals->NUM_X-1); + unsigned int ind_y = (get_global_id(0) & (ro_scals->NUM_XY-1)) / ro_scals->NUM_X; + + real_t tmp = 0.0; + + { + // I. second loop + real3_t myres_elem; + real_t cur_myMu = 0.0; + real_t cur_myVar = ro_scals->nu; + cur_myVar *= cur_myVar; + + myres_elem = (real3_t)( myDyy[ind_y<<2], myDyy[(ind_y<<2)+1], myDyy[(ind_y<<2)+2] ); + myD_elem = (real3_t)( myDy [ind_y<<2], myDy [(ind_y<<2)+1], myDy [(ind_y<<2)+2] ); + + myD_elem = cur_myMu*myD_elem + 0.5f*cur_myVar*myres_elem; + + myres_elem = (real3_t)( (ind_y != 0) ? res_arr[get_global_id(0) - ro_scals->NUM_X] : 0.0, + res_arr[get_global_id(0)], + (ind_y != ro_scals->NUM_Y-1) ? res_arr[get_global_id(0) + ro_scals->NUM_X] : 0.0 + ); + + myD_elem *= myres_elem; + tmp += myD_elem.x + myD_elem.y + myD_elem.z; + +#if TRANSPOSE_UV + v[ get_global_id(0) ] = tmp; +#else + v[ (get_global_id(0)/ro_scals->NUM_XY)*ro_scals->NUM_XY + ind_x*ro_scals->NUM_Y + ind_y] = tmp; +#endif + + // II. first loop + cur_myMu = 0.0; // X + cur_myVar = exp( 2 * ( ro_scals->beta*log(myX[ind_x]) + + myY[ind_y] - 0.5f*cur_myVar*ro_scals->timeline_i // cur_myVar == nu*nu + ) + ); + // CACHING ASSUMES ALL ELEMENTS IN X DIMENSION fit in the LOCALGROUP! + cache_tmp[get_local_id(0)] = res_arr[ get_global_id(0) ]; + + myD_elem = myDx[ ind_x ]; + + barrier(CLK_LOCAL_MEM_FENCE); + + + myres_elem = (real3_t)( (ind_x!=0) ? cache_tmp[ get_local_id(0) - 1 ] : 0.0, + cache_tmp[ get_local_id(0) ], + (ind_x != ro_scals->NUM_X-1) ? cache_tmp[ get_local_id(0) + 1 ] : 0.0 + ); + + tmp += ro_scals->dtInv*myres_elem.y; + myD_elem = 0.5f*( cur_myMu*myD_elem + 0.5f*cur_myVar*myDxx[ ind_x ] ); + + // write in cache the values of c! + cache_tmp[get_local_size(0) + get_local_id(0)] = - myD_elem.z; // c[get_global_id(0)] = - myD_elem.z; + + barrier(CLK_LOCAL_MEM_FENCE); + + myres_elem = myD_elem*myres_elem; + tmp += myres_elem.x + myres_elem.y + myres_elem.z; + + //a[get_global_id(0)] = - myD_elem.x; // b[ind] = ro_scals->dtInv - myDy_elem.y; + myD_elem.x = - myD_elem.x; // holds `a[glb_ind]' + } + + + { + // prepare for and call TRIDAG + real4_t scan_elem; + //u[get_global_id(0)] = tmp; //u[j*NUM_X + i] = tmp1 + tmp2; //u[j][i] = tmp1 + tmp2; + myD_elem.z = tmp; + + tmp = ro_scals->dtInv - myD_elem.y; // b[ind] = tmp; + + //barrier(CLK_LOCAL_MEM_FENCE); + + + // third loop + if( ind_x > 0 ) { + myD_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) - 1]; // i.e., c[glob_ind-1] + scan_elem = (real4_t) ( tmp, 0.0 - myD_elem.x * myD_elem.y, 1.0, 0.0 ); + myD_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) + (ro_scals->NUM_X-1) - 2*ind_x]; // i.e., c[glb_ind_inv] + } else { // i == get_global_id(0) == 0 + scan_elem = (real4_t) ( tmp, 0.0, 0.0, tmp ); //(real4_t) ( 1.0, 0.0, 0.0, 1.0 ); + myD_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) + (ro_scals->NUM_X-1) ]; + + cache_tmp[get_local_id(0) ] = tmp; + cache_tmp[get_local_id(0) + 1] = myD_elem.z; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + tmp = cache_tmp[get_local_id(0) - ind_x ]; + real_t d0 = cache_tmp[get_local_id(0) - ind_x + 1]; + + barrier(CLK_LOCAL_MEM_FENCE); + + // CALL TRIDAG + tridag_inline_local ( + myD_elem.x, // a[glb_ind] + myD_elem.y, // c[glb_ind_inv] + myD_elem.z, // d[glb_ind] == u[glb_ind] + u, // y + scan_elem, // scan_tmp[glb_ind] + ro_scals->NUM_X, // SIZE + cache_tmp, // cache + get_global_id(0) - ind_x, // first_id + tmp, // b0 + d0 // d0 + ); + } +} + +//////////////////////////////////////////////////////////////// +////////// AND KERNEL FOR THE Y-INNERMOST DIMENSION //////////// +//////////////////////////////////////////////////////////////// + +__kernel __attribute__((reqd_work_group_size(WORKGROUP_SIZE, 1, 1))) +void nordea_kernel_y ( + /*** Read-Only Scalars ***/ + __constant RWScalars* ro_scals, // __constant + /*** Read-Only Arrays ***/ + __global real3_t* myDy, + __global real3_t* myDyy, + /*** Read-Write Temporary Arrays ***/ + __global real_t* u, + __global real_t* v, + /*** Temporary Array in Shared Space ***/ + __local real_t* cache_tmp // SIZE: 8 * WORKGROUP_SIZE * sizeof(real_t) +) { + + real3_t myDy_elem; + + unsigned int ind_y = get_global_id(0) & (ro_scals->NUM_Y-1); + unsigned int ind_x = (get_global_id(0) & (ro_scals->NUM_XY-1)) / ro_scals->NUM_Y; + + { + real_t dt_inv = ro_scals->dtInv; +#if TRANSPOSE_UV + real_t my_u = u[get_global_id(0)]; +#else + real_t my_u = u[ (get_global_id(0)/ro_scals->NUM_XY)*ro_scals->NUM_XY + + ind_y * ro_scals->NUM_X + ind_x ]; +#endif + + real_t tmp = 0.0; + real_t cur_myVarY = ro_scals->nu; cur_myVarY *= cur_myVarY*0.5f; //nu*nu; + + myDy_elem = 0.0f - 0.5f*( tmp*myDy[ind_y] + cur_myVarY*myDyy[ind_y] ); + + // a[ind] = myDy_elem.x; c[ind] = myDy_elem.z; + cache_tmp[get_local_size(0) + get_local_id(0)] = myDy_elem.z; // c[ind] + myDy_elem.y = dt_inv + myDy_elem.y; // b[ind] + + + //v[get_global_id(0)] = dt_inv * my_u - 0.5 * v[get_global_id(0)]; + myDy_elem.z = dt_inv * my_u - 0.5f * v[get_global_id(0)]; // i.e., v[ind] + + if(ind_y == 0) { + cache_tmp[get_local_id(0) ] = myDy_elem.y; // b0 + cache_tmp[get_local_id(0) + 1] = myDy_elem.z; // d0, i.e., v[0] + } + + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + real4_t scan_elem; + real_t b0, d0; + + // third loop + if( ind_y > 0 ) { + scan_elem = (real4_t) ( myDy_elem.y, 0.0 - myDy_elem.x * cache_tmp[get_local_size(0)+get_local_id(0)-1], 1.0, 0.0 ); + } else { + scan_elem = (real4_t) ( 1.0, 0.0, 0.0, 1.0 ); + } + + myDy_elem.y = cache_tmp[get_local_size(0) + get_local_id(0) + (ro_scals->NUM_Y-1) - 2*ind_y]; // i.e., c[ind_inv] + + b0 = cache_tmp[get_local_id(0) - ind_y ]; + d0 = cache_tmp[get_local_id(0) - ind_y + 1]; // d0 + + barrier(CLK_LOCAL_MEM_FENCE); + + // CALL TRIDAG + tridag_inline_local ( + myDy_elem.x, // a[glb_ind] + myDy_elem.y, // c[glb_ind_inv] + myDy_elem.z, // d[glb_ind] == v[glb_ind] + v, // y + scan_elem, // scan_tmp[glb_ind] + ro_scals->NUM_Y, // SIZE + cache_tmp, // cache + get_global_id(0) - ind_y, // first_id + b0, // b0 + d0 // d0 + ); + } +} diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile new file mode 100644 index 0000000..d29cf70 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile @@ -0,0 +1,54 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +# FIXME - this should not even exist! +include $(HIPERMARK_LIB_DIR)/platform.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ + -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ + -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ + -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ + -D CURR_DIR_PATH='"$(MAKE_DIR)"' + +SOURCES_CPP =$(HIPERMARK_IMPLEMENTATION)/VolCalibAll.cpp +HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/Constants.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/ParseInput.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/DataStructConst.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/ParPrefixUtil.h +EXECUTABLE =VolCalibAll + +$(EXECUTABLE): + cp $(HIPERMARK_IMPLEMENTATION)/*cl . + $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) + + +run_small: + cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_medium: + cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_large: + cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt + +clean: + rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt + @# clean nVidia compiler cache + rm -rf $(HOME)/.nv/ComputeCache/* + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h new file mode 100644 index 0000000..04a5a4f --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h @@ -0,0 +1,1576 @@ +/***********************************************************/ +/*************** Helper DATA STRUCTURES ********************/ +/***********************************************************/ + +// GPU BUFFERS +struct oclNordeaArrays { + /* RO scalars */ + cl_mem ro_scals; + + /* RO arrays */ + cl_mem timeline; // [NUM_T] + + cl_mem myX; // [NUM_X] + cl_mem myDx; // [NUM_X * 3] + cl_mem myDxx; // [NUM_X * 3] + + cl_mem myY; // [NUM_Y] + cl_mem myDy; // [NUM_Y * 3] + cl_mem myDyy; // [NUM_Y * 3] + + /* TRIDAG helpers */ + cl_mem a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem tmp4; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem tmp2; // [2 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + cl_mem res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + /* WRITE ONLY OUTPUT stored in "res"*/ + //cl_mem res; +}; + +// CPU BUFFERS +struct NordeaArrays { + /* RO arrays */ + real_t* timeline; // [NUM_T] + + real_t* myX; // [NUM_X] + real_t* myDx; // [NUM_X * 3] + real_t* myDxx; // [NUM_X * 3] + + real_t* myY; // [NUM_Y] + real_t* myDy; // [NUM_Y * 3] + real_t* myDyy; // [NUM_Y * 3] + + /* TRIDAG helpers are created on GPU only! no need for them to exist in main memory*/ + real_t* a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* tmp; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + real_t* res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + /* NOT USED FOR NOW! WRITE ONLY OUTPUT stored in "res"*/ + //real_t* res; +}; + +// GPU KERNELS +typedef struct { + // PRE/POST TRIDAG KERNELS + cl_kernel ckPreTridagX; // NUM_X x NUM_Y x OUTER_LOOP_COUNT + cl_kernel ckPreTridagY; // NUM_Y x NUM_X x OUTER_LOOP_COUNT + cl_kernel ckMatTranspUpdate; + + cl_kernel ckMatTransposeU; + cl_kernel ckMatTransposeV; + + // TRIDAG KERNELS + cl_kernel ckTridagMatMult [2]; // scan with matrix multiplication: + cl_kernel ckConcludeMatMult[2]; + + cl_kernel ckPreludeFwdFunComp[2]; + cl_kernel ckTridagFwdFunComp[2]; // scan with linear function composition + cl_kernel ckPostFwdFunComp[2]; + + cl_kernel ckPreludeBwdFunComp[2]; + cl_kernel ckPostBwdFunComp[2]; + + cl_kernel ckTridagAllOpt[2]; + + cl_kernel ckNordeaKernelX; + cl_kernel ckNordeaKernelY; + + size_t GWS_XYZ [3]; + size_t LWS_XYZ [3]; + + size_t GWS_YXZ [3]; + size_t LWS_YXZ [3]; + + // NOT USED + //cl_kernel ckMatTransp; // NUM_Y x NUM_X x OUTER_LOOP_COUNT +} GPUkernels __attribute__ ((aligned (32))); + +/******************************************************/ +/******* compute global/local grid dimensions *********/ +/******************************************************/ + +static void local_block_size( + size_t size_x, size_t size_y, size_t size_z, + size_t& loc_x, size_t& loc_y, size_t& loc_z +) { + bool ok = is_pow2(size_x) && is_pow2(size_y); + assert( ok && "Global Size X or Y is not a power of 2!"); + assert( size_x * size_y >= WORKGROUP_SIZE && "NUM_X * NUM_Y < WORKGROUP_SIZE!!!"); + + loc_x = WORKGROUP_SIZE; loc_y = 1; loc_z = 1; + while(size_x / loc_x == 0) { + loc_x /= 2; + loc_y *= 2; + } + + ok = is_pow2(loc_x) && is_pow2(loc_y) && (loc_x*loc_y == WORKGROUP_SIZE) && (loc_x <= size_x) && (loc_y <= size_y); + assert( ok && "Local Block Size is not a power of 2!"); +} + + +void initGPUgrid ( GPUkernels& kernels ) { + { // find a convenient local block size + size_t loc_x, loc_y, loc_z; + + kernels.GWS_XYZ[0] = NUM_X; kernels.GWS_XYZ[1] = NUM_Y; kernels.GWS_XYZ[2] = OUTER_LOOP_COUNT; + kernels.GWS_YXZ[0] = NUM_Y; kernels.GWS_YXZ[1] = NUM_X; kernels.GWS_YXZ[2] = OUTER_LOOP_COUNT; + + local_block_size(NUM_X, NUM_Y, OUTER_LOOP_COUNT, loc_x, loc_y, loc_z); + kernels.LWS_XYZ[0] = loc_x; kernels.LWS_XYZ[1] = loc_y; kernels.LWS_XYZ[2] = loc_z; + + local_block_size(NUM_Y, NUM_X, OUTER_LOOP_COUNT, loc_y, loc_x, loc_z); + kernels.LWS_YXZ[0] = loc_y; kernels.LWS_YXZ[1] = loc_x; kernels.LWS_YXZ[2] = loc_z; + } + +} + +/************************************************************/ +/*************** KERNELS OTHER THAN TRIDAG ****************** +/************************************************************/ + +cl_kernel make_prepare_tridag_X( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs, + size_t* globalWorkSize, + size_t* localWorkSize +) { + cl_kernel ckPreTridagX = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckPreTridagX = clCreateKernel(cpProgram, "prepare_tridag_x", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + { // 1. RO SCALARS // + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); + } + + { // 2. RO ARRAYS // + //ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.timeline); + + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myX); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDx); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDxx); + + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myY); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); + } + + { // 3. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); + } + +#if 1 + { // 4. LOCAL (PRIVATE ARRAYS) + const int PRIV_MULT = sizeof(real_t) * localWorkSize[0] * localWorkSize[1] * localWorkSize[2]; + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, PRIV_MULT, NULL); + } +#endif + { // 5. OUT ARRAY! + ciErr1 |= clSetKernelArg(ckPreTridagX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.res_arr ); + } +#if 0 + { // Finally, enqueue kernel + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreTridagX, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckPreTridagX; +} + +void run_prepare_tridag_X( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreTridagX, 3, NULL, + kernels.GWS_XYZ, kernels.LWS_XYZ, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + +/////////////////////////// +/// NORDEA_ALL_KERNEL_X /// +/////////////////////////// + +cl_kernel make_NordeaKernelX( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs +) { + cl_kernel ckAllX = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckAllX = clCreateKernel(cpProgram, "nordea_kernel_x", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + // 1. RO SCALARS // + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); + + // 2. RO ARRAYS // + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myX); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDx); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDxx); + + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myY); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); + + // 3. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); + + // 4. LOCAL (PRIVATE ARRAYS) + const int PRIV_MULT = sizeof(real_t) * 8 * WORKGROUP_SIZE; + ciErr1 |= clSetKernelArg(ckAllX, counter++, PRIV_MULT, NULL); + + // 5. OUT ARRAY! + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.res_arr ); + + oclCheckError(ciErr1, CL_SUCCESS); + + return ckAllX; +} + +void run_NordeaKernelX( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelX, 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL); + + ciErr1 |= clFinish(cqCommandQueue); + + oclCheckError(ciErr1, CL_SUCCESS); +} + + +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// + +cl_kernel make_prepare_tridag_Y( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + size_t* globalWorkSize, + size_t* localWorkSize +) { + cl_kernel ckPreTridagY = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckPreTridagY = clCreateKernel(cpProgram, "prepare_tridag_y", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + { // 1. RO SCALARS // here we do not have to reload ro_scals! + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); + } + + { // 2. RO ARRAYS // + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); + } + + { // 3. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); + } +#if 1 + { // 4. LOCAL (PRIVATE ARRAYS) + const int PRIV_MULT = sizeof(real_t) * localWorkSize[0] * localWorkSize[1] * localWorkSize[2]; + ciErr1 |= clSetKernelArg(ckPreTridagY, counter++, PRIV_MULT, NULL); + } +#endif +#if 0 + { // Finally, enqueue kernel + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreTridagY, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckPreTridagY; +} + +void run_prepare_tridag_Y( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreTridagY, 3, NULL, + &kernels.GWS_YXZ[0], &kernels.LWS_YXZ[0], 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + + +/////////////////////////// +/// NORDEA_ALL_KERNEL_X /// +/////////////////////////// + +cl_kernel make_NordeaKernelY( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs +) { + cl_kernel ckAllY = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckAllY = clCreateKernel(cpProgram, "nordea_kernel_y", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + // 1. RO SCALARS // + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); + + // 2. RO ARRAYS // + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); + + // 3. GPU-ONLY GLOBAL ARRAYS // +#if TRANSPOSE_UV + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); // y <- u^T + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); // u <- v^T +#else + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); +#endif + + // 4. LOCAL (PRIVATE ARRAYS) + const int PRIV_MULT = sizeof(real_t) * 8 * WORKGROUP_SIZE; + ciErr1 |= clSetKernelArg(ckAllY, counter++, PRIV_MULT, NULL); + + oclCheckError(ciErr1, CL_SUCCESS); + + return ckAllY; +} + +void run_NordeaKernelY( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelY, 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL); + + ciErr1 |= clFinish(cqCommandQueue); + + oclCheckError(ciErr1, CL_SUCCESS); +} + + +/************************************************************/ +/******************** TRIDAG KERNELS ************************/ +/************************************************************/ + + + +/** + * Parallel Prefix with matrix multiplication + */ +cl_kernel make_MatMultScan( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + const unsigned int* NUM_P +) { + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + cl_kernel ckTridagMatMultX = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckTridagMatMultX = clCreateKernel(cpProgram, "scanMatMultIncl", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + { // 1. GPU-ONLY GLOBAL ARRAYS /(4 * NUM_X * NUM_Y * OUTER_LOOP_COUNT) + ciErr1 |= clSetKernelArg(ckTridagMatMultX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); + } + + { // 2. LOCAL: 8 * sizeof(real_t) * worksize + const int PRIV_MULT = sizeof(real_t) * 8 * localWorkSize; + ciErr1 |= clSetKernelArg(ckTridagMatMultX, counter++, PRIV_MULT, NULL); + } + + { // 1. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckTridagMatMultX, counter++, sizeof(uint), (void *)NUM_P); + } + +#if 0 + { // Finally, the array size: + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckTridagMatMultX, 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckTridagMatMultX; +} + +void run_MatMultScan( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckTridagMatMult[X], 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + + + +/** + * Parallel Prefix with linear function composition + */ +cl_kernel make_FwdFunCompScan( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + const unsigned int* NUM_P +) { + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + cl_kernel ckTridagFwdFunComp = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; + unsigned long int cur_size; + + // find kernel + ckTridagFwdFunComp = clCreateKernel(cpProgram, "scanLinFunCompIncl", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + // 1. GPU-ONLY GLOBAL ARRAYS /(4 * NUM_X * NUM_Y * OUTER_LOOP_COUNT) + ciErr1 |= clSetKernelArg(ckTridagFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); + + // 2. LOCAL: 4 * sizeof(real_t) * worksize + const int PRIV_MULT = sizeof(real_t) * 4 * localWorkSize; + ciErr1 |= clSetKernelArg(ckTridagFwdFunComp, counter++, PRIV_MULT, NULL); + + // 1. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckTridagFwdFunComp, counter++, sizeof(uint), (void *)NUM_P); + + // Finally, the array size: +#if 0 + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckTridagFwdFunComp, 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckTridagFwdFunComp; +} + +void run_FwdFunCompScan( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckTridagFwdFunComp[X], 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +/** + * Mapping back the results of parallel prefix with matrix multiplication + */ +cl_kernel make_conclude_matmult ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + cl_mem d, + cl_mem y, + cl_mem u +) { + cl_kernel ckConcludeMatMult = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckConcludeMatMult = clCreateKernel(cpProgram, "conclude_matmult", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b ); // b + ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&d ); + ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&y ); + ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&u ); + ciErr1 |= clSetKernelArg(ckConcludeMatMult, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); + + +#if 0 + { // Finally, enqueue kernel! + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckConcludeMatMult, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckConcludeMatMult; +} + + +void run_conclude_matmult( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; + size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckConcludeMatMult[X], 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + +/** + * Preparing for parallel prefix with linear function composition + * (i.e., filling in ocl_arrs.tmp) + */ +cl_kernel make_preludeFwdMapFunComp ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + cl_mem d, + cl_mem u +) { + cl_kernel ckPreludeFwdFunComp = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckPreludeFwdFunComp = clCreateKernel(cpProgram, "prelude_fwd_fun_comp", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a ); // b + ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&d ); + ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&u ); + ciErr1 |= clSetKernelArg(ckPreludeFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); + + +#if 0 + { // Finally, enqueue kernel! + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreludeFwdFunComp, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckPreludeFwdFunComp; +} + +void run_preludeFwdMapFunComp( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; + size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreludeFwdFunComp[X], 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + +/** + * Mapping back the results of parallel prefix with linear function composition + */ +cl_kernel make_postFwdMapFunComp ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + cl_mem y +) { + cl_kernel ckPostFwdFunComp = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckPostFwdFunComp = clCreateKernel(cpProgram, "post_fwd_fun_comp", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + ciErr1 |= clSetKernelArg(ckPostFwdFunComp, counter++, sizeof(cl_mem), (void*)&y ); + ciErr1 |= clSetKernelArg(ckPostFwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); + +#if 0 + { // Finally, enqueue kernel! + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPostFwdFunComp, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckPostFwdFunComp; +} + +void run_postFwdMapFunComp ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; + size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPostFwdFunComp[X], 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + + +/** + * Preparing for forward-parallel prefix with linear function composition + * (i.e., filling in ocl_arrs.tmp) + */ +cl_kernel make_preludeBwdMapFunComp ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + cl_mem y, + cl_mem u +) { + cl_kernel ckPreludeBwdFunComp = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckPreludeBwdFunComp = clCreateKernel(cpProgram, "prelude_bwd_fun_comp", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c ); // b + ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&y ); + ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&u ); + ciErr1 |= clSetKernelArg(ckPreludeBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2); + +#if 0 + { // Finally, enqueue kernel! + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPreludeBwdFunComp, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckPreludeBwdFunComp; +} + +void run_preludeBwdMapFunComp ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; + size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPreludeBwdFunComp[X], 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +/** + * Mapping back the results of parallel prefix with linear function composition + */ +cl_kernel make_postBwdMapFunComp ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + cl_mem y +) { + cl_kernel ckPostBwdFunComp = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckPostBwdFunComp = clCreateKernel(cpProgram, "post_bwd_fun_comp", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&y ); + ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp2 ); + //ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals); + //ciErr1 |= clSetKernelArg(ckPostBwdFunComp, counter++, sizeof(cl_mem), (void*)&ocl_arrs.timeline); + +#if 0 + { // Finally, enqueue kernel! + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckPostBwdFunComp, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + } +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckPostBwdFunComp; +} + +void run_postBwdMapFunComp ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; + size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; + + assert( (X==0 || X==1) && "INVALID MatMultScan Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckPostBwdFunComp[X], 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +//////////////////////////////////////////////////////// +//////////////////////////////////////////////////////// +//////////////////////////////////////////////////////// + +/** + * Mapping back the results of parallel prefix with matrix multiplication + */ +cl_kernel make_TRIDAG_ALL_OPT ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + cl_mem d, + cl_mem y, + cl_mem u, + const unsigned int* NUM_P +) { + cl_kernel ckTridagAll = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckTridagAll = clCreateKernel(cpProgram, "tridag_inlined", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a ); // a + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c ); // c + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&d ); + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&y ); + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&u ); + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(cl_mem), (void*)&ocl_arrs.tmp4); + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, sizeof(uint) , (void *)NUM_P ); + + { + const int PRIV_MULT = sizeof(real_t) * 8 * WORKGROUP_SIZE; + ciErr1 |= clSetKernelArg(ckTridagAll, counter++, PRIV_MULT, NULL); + } + + oclCheckError(ciErr1, CL_SUCCESS); + + return ckTridagAll; +} + + +void run_TRIDAG_ALL_OPT ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + int X +) { + cl_int ciErr1; + + size_t globalWorkSize = NUM_X * NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + //size_t* globalWorkSize = (X==0) ? kernels.GWS_XYZ : kernels.GWS_YXZ; + //size_t* localWorkSize = (X==0) ? kernels.LWS_XYZ : kernels.LWS_YXZ; + + assert( (X==0 || X==1) && "INVALID TRIDAG_ALL_OPT Kernel!"); + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckTridagAllOpt[X], 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL ); + + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + + + + + +/***************************************************/ +/********* Segmented Matrix Transposition ********/ +/***************************************************/ + +cl_kernel make_transposeGPU( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + cl_mem inp_arr, + cl_mem out_arr, + const unsigned int* size_x, + const unsigned int* size_y, + const unsigned int* size_z, + const char* kernel_name +// size_t* globalWorkSize, +// size_t* localWorkSize +) { + cl_kernel ckMatTransp = NULL; + cl_int ciErr1, ciErr2; + unsigned int counter = 0; + + ckMatTransp = clCreateKernel(cpProgram, kernel_name, &ciErr1); // "transposeUpdateScalars" + oclCheckError(ciErr1, CL_SUCCESS); + + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &out_arr); // input array + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &inp_arr); // output array + //ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), &offset); + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_x); // size of 0 dim + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_y); // size of 1 dim + + // shared memory space + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, (BLOCK_DIM + 1) * BLOCK_DIM * sizeof(real_t), 0 ); + +#if 0 + // enqueue kernel + ciErr1 |= clEnqueueNDRangeKernel(cqCommandQueue, ckMatTransp, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); +#endif + oclCheckError(ciErr1, CL_SUCCESS); + + return ckMatTransp; +} + +void run_transposeGPU ( + cl_command_queue& cqCommandQueue, + cl_kernel kernel, + size_t* globalWorkSize + +) { + cl_int ciErr1; + size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernel, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +cl_kernel make_transposeGPU_WithUpdate( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + cl_mem inp_arr, + cl_mem out_arr, + const unsigned int* size_x, + const unsigned int* size_y, + const unsigned int* size_z, + oclNordeaArrays& ocl_arrs +// size_t* globalWorkSize, +// size_t* localWorkSize +) { + cl_int ciErr1; + cl_kernel kernel = make_transposeGPU( + cqCommandQueue, cpProgram, inp_arr, + out_arr, size_x, size_y, size_z, "transposeUpdateScalars" + ); + + ciErr1 = clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *) &ocl_arrs.ro_scals); + ciErr1 = clSetKernelArg(kernel, 6, sizeof(cl_mem), (void *) &ocl_arrs.timeline); + oclCheckError(ciErr1, CL_SUCCESS); + + return kernel; +} + +void run_transposeGPU_WithUpdate ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + size_t* globalWorkSize = kernels.GWS_YXZ; + size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; + //size_t* localWorkSize = kernels.LWS_YXZ; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckMatTranspUpdate, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +/**********************************************************/ +/**************** MAKE ALL KERNELS ************************/ +/**********************************************************/ + +void make_TRIDAG( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + oclNordeaArrays& ocl_arrs, + GPUkernels& kernels, + const int X +) { + assert( (X==0 || X==1) && "INVALID argument X to make_TRIDAG Kernels!"); + + cl_mem d; cl_mem y; cl_mem u; + const unsigned int* NUM_P = NULL; + //size_t* globalWorkSize = NULL; + //size_t* localWorkSize = NULL; + + if(X == 0) { + // first tridag run: d <- u; y <- u; u <- y NUM_P <- &NUM_X + d = ocl_arrs.u; y = ocl_arrs.u; u = ocl_arrs.y; NUM_P = &NUM_X; + //globalWorkSize = kernels.GWS_XYZ; + //localWorkSize = kernels.LWS_XYZ; + } else { // X == 1 + // second tridag run: d <- v; y <- y; u <- u NUM_P <- &NUM_Y + d = ocl_arrs.v; y = ocl_arrs.v; u = ocl_arrs.y; NUM_P = &NUM_Y; //y = ocl_arrs.y; u = ocl_arrs.u; + //globalWorkSize = kernels.GWS_XYZ; + //localWorkSize = kernels.LWS_XYZ; + } + + + // scan with matrix multiply! + kernels.ckTridagMatMult[X] = make_MatMultScan ( + cqCommandQueue, cpProgram, ocl_arrs, NUM_P + ); + + // map the results of the parallel prefix with matrix multiplication! + kernels.ckConcludeMatMult[X] = make_conclude_matmult ( + cqCommandQueue, cpProgram, ocl_arrs, d, y, u + ); + + // prepare for forward scan with function composition! + kernels.ckPreludeFwdFunComp[X] = make_preludeFwdMapFunComp ( + cqCommandQueue, cpProgram, ocl_arrs, d, u + ); + + // (forward) scan with function composition! + kernels.ckTridagFwdFunComp[X] = make_FwdFunCompScan ( + cqCommandQueue, cpProgram, ocl_arrs, NUM_P + ); + + // post_fwd_fun_comp + kernels.ckPostFwdFunComp[X] = make_postFwdMapFunComp ( + cqCommandQueue, cpProgram, ocl_arrs, y + ); + + // prepare for backward scan with linear-function composition + kernels.ckPreludeBwdFunComp[X] = make_preludeBwdMapFunComp ( + cqCommandQueue, cpProgram, ocl_arrs, y, u + ); + + // (backward) scan with function composition! + // have already been computed in "kernels.ckTridagFwdFunComp[X]" needs to be run twice!!! + //kernels.ckTridagFwdFunComp2[X] = make_FwdFunCompScan ( + // cqCommandQueue, cpProgram, ocl_arrs, NUM_P + // ); + + // post_bwd_fun_comp + kernels.ckPostBwdFunComp[X] = make_postBwdMapFunComp ( + cqCommandQueue, cpProgram, ocl_arrs, y + ); + + ///////////////////////// + // Finally, TRIDAG ALL // + ///////////////////////// + kernels.ckTridagAllOpt[X] = make_TRIDAG_ALL_OPT ( + cqCommandQueue, cpProgram, ocl_arrs, d, y, u, NUM_P + ); +} + + +void make_kernels ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs, + GPUkernels& kernels +) { + initGPUgrid ( kernels ); + + kernels.ckPreTridagX = make_prepare_tridag_X ( + cqCommandQueue, + cpProgram, + ro_scal, + ocl_arrs, + kernels.GWS_XYZ, + kernels.LWS_XYZ + ); + + make_TRIDAG( cqCommandQueue, cpProgram, ocl_arrs, kernels, 0 ); + + kernels.ckPreTridagY = make_prepare_tridag_Y ( + cqCommandQueue, + cpProgram, + ocl_arrs, + kernels.GWS_YXZ, + kernels.LWS_YXZ + ); + + make_TRIDAG( cqCommandQueue, cpProgram, ocl_arrs, kernels, 1 ); + +#if TRANSPOSE_UV + kernels.ckMatTranspUpdate = make_transposeGPU_WithUpdate ( + cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.res_arr, // ocl_arrs.y + &NUM_Y, &NUM_X, &OUTER_LOOP_COUNT, ocl_arrs + ); +#else + // transpose y into res_arr + kernels.ckMatTranspUpdate = make_transposeGPU_WithUpdate ( + cqCommandQueue, cpProgram, ocl_arrs.v, ocl_arrs.res_arr, // ocl_arrs.y + &NUM_Y, &NUM_X, &OUTER_LOOP_COUNT, ocl_arrs + ); +#endif + + ////////////////////////////////// + // Finally, Finally, TRIDAG ALL // + ////////////////////////////////// + kernels.ckNordeaKernelX = make_NordeaKernelX ( + cqCommandQueue, cpProgram, ro_scal, ocl_arrs + ); + + kernels.ckNordeaKernelY = make_NordeaKernelY ( + cqCommandQueue, cpProgram, ro_scal, ocl_arrs + ); + + // transpose U into Y + kernels.ckMatTransposeU = make_transposeGPU ( + cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.y, + &NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" + ); + + // transpose V into U + kernels.ckMatTransposeV = make_transposeGPU ( + cqCommandQueue, cpProgram, ocl_arrs.v, ocl_arrs.u, + &NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" + ); + +} + + +/**********************************************************/ +/********************* RUN KERNELS ************************/ +/**********************************************************/ + +void run_TRIDAG( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + const int X +) { + assert( (X==0 || X==1) && "INVALID argument X to make_TRIDAG Kernels!"); + +#ifdef TRIDAG_ALL_OPT_ON + run_TRIDAG_ALL_OPT( cqCommandQueue, kernels, X ); +#else + // scan with matrix multiply! + run_MatMultScan( cqCommandQueue, kernels, X ); + + // map the results of the parallel prefix with matrix multiplication! + run_conclude_matmult( cqCommandQueue, kernels, X ); + + + // prepare for forward scan with function composition! + run_preludeFwdMapFunComp( cqCommandQueue, kernels, X ); + + // (forward) scan with function composition! + run_FwdFunCompScan( cqCommandQueue, kernels, X); + + // post_fwd_fun_comp + run_postFwdMapFunComp( cqCommandQueue, kernels, X ); + + // prepare for backward scan with linear-function composition + run_preludeBwdMapFunComp( cqCommandQueue, kernels, X ); + + // (backward) scan with function composition! + run_FwdFunCompScan( cqCommandQueue, kernels, X ); + + // post_bwd_fun_comp + run_postBwdMapFunComp( cqCommandQueue, kernels, X ); +#endif +} + +void run_GPUkernels_one_time_iteration ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { +#ifdef MOST_OPTIMISED_ON + run_NordeaKernelX( cqCommandQueue, kernels ); + +#if TRANSPOSE_UV + run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeU, kernels.GWS_XYZ ); // y <- transpose(u) + run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeV, kernels.GWS_XYZ ); // u <- transpose(v) +#endif + + run_NordeaKernelY( cqCommandQueue, kernels ); + +#else + + run_prepare_tridag_X( cqCommandQueue, kernels ); + + run_TRIDAG( cqCommandQueue, kernels, 0); + + run_prepare_tridag_Y( cqCommandQueue, kernels ); + + run_TRIDAG( cqCommandQueue, kernels, 1); +#endif + + run_transposeGPU_WithUpdate( cqCommandQueue, kernels ); +} + +/**********************************************************/ +/******************* RELEASE KERNELS **********************/ +/**********************************************************/ + +void release_all_kernels ( GPUkernels& kernels ) { + clReleaseKernel(kernels.ckPreTridagX); + clReleaseKernel(kernels.ckPreTridagY); + clReleaseKernel(kernels.ckMatTranspUpdate); + + clReleaseKernel(kernels.ckTridagMatMult[0]); + clReleaseKernel(kernels.ckTridagMatMult[1]); + + clReleaseKernel(kernels.ckConcludeMatMult[0]); + clReleaseKernel(kernels.ckConcludeMatMult[1]); + + clReleaseKernel(kernels.ckPreludeFwdFunComp[0]); + clReleaseKernel(kernels.ckPreludeFwdFunComp[1]); + + clReleaseKernel(kernels.ckTridagFwdFunComp[0]); + clReleaseKernel(kernels.ckTridagFwdFunComp[1]); + + clReleaseKernel(kernels.ckPostFwdFunComp[0]); + clReleaseKernel(kernels.ckPostFwdFunComp[1]); + + clReleaseKernel(kernels.ckPreludeBwdFunComp[0]); + clReleaseKernel(kernels.ckPreludeBwdFunComp[1]); + + clReleaseKernel(kernels.ckPostBwdFunComp[0]); + clReleaseKernel(kernels.ckPostBwdFunComp[1]); + + clReleaseKernel(kernels.ckTridagAllOpt[0]); + clReleaseKernel(kernels.ckTridagAllOpt[1]); + + clReleaseKernel(kernels.ckNordeaKernelX); + clReleaseKernel(kernels.ckNordeaKernelY); + + clReleaseKernel(kernels.ckMatTransposeU); + clReleaseKernel(kernels.ckMatTransposeV); +} + +void release_all_GPU_resources( + cl_command_queue& cqCommandQueue, + cl_context& cxGPUContext, + cl_program cpProgram, + cl_device_id* cdDevices, + oclNordeaArrays& ocl_arrs, + GPUkernels& kernels +) { + + shrLog(stdlog, "Release Kernels...\n"); + release_all_kernels( kernels ); + + shrLog(stdlog, "Release CPU buffers and OpenCL objects...\n"); + clReleaseProgram(cpProgram); + + clReleaseMemObject(ocl_arrs.ro_scals); + clReleaseMemObject(ocl_arrs.timeline); + + clReleaseMemObject(ocl_arrs.a); + clReleaseMemObject(ocl_arrs.b); + clReleaseMemObject(ocl_arrs.c); + + clReleaseMemObject(ocl_arrs.y); + clReleaseMemObject(ocl_arrs.u); + clReleaseMemObject(ocl_arrs.v); + + clReleaseMemObject(ocl_arrs.tmp2); + clReleaseMemObject(ocl_arrs.tmp4); + clReleaseMemObject(ocl_arrs.res_arr); + + clReleaseMemObject(ocl_arrs.myX); + clReleaseMemObject(ocl_arrs.myDx); + clReleaseMemObject(ocl_arrs.myDxx); + + clReleaseMemObject(ocl_arrs.myY); + clReleaseMemObject(ocl_arrs.myDy); + clReleaseMemObject(ocl_arrs.myDyy); + + clReleaseCommandQueue(cqCommandQueue); + free(cdDevices); + clReleaseContext(cxGPUContext); +} + + +/**********************************************************/ +/******************* DEBUG TESTING **********************/ +/**********************************************************/ + +void testMatMultScan ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + cl_context& cxGPUContext +) { + //const unsigned NUM_X = 64, NUM_Y = 1; + + cl_mem cl_tmp; cl_int ciErr; + real_t* tmp = new real_t[NUM_X*NUM_Y*4]; + + for(int i=0; i4) + for( k=0; k4) + for( k=0; k4) + for( k=0; k4) + for( k=0; k4) + for( k=0; k( USER_MEM * 101.0 / 100.0 ); + const size_t lb = static_cast( USER_MEM * 99.0 / 100.0 ); + if ( !(glob_mem_size >= lb && glob_mem_size <= ub) ) { + fprintf(stderr, "WARNING! Querried GPU global memory %lu DIFFERS from what user declared: [%ld,%ld]!\n", + glob_mem_size, lb, ub); + glob_mem_size = static_cast(USER_MEM); + fprintf(stderr, "Using user-declared size for global memory: %lu\n", glob_mem_size); + } + } + + cl_ulong glob_mem_required = 15 * OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(real_t); + assert( glob_mem_required <= glob_mem_size && "Not Enough Global Memory. A possible fix is to strip-mine all kernels.\n" ); + //fprintf(stderr, "GPU global memory: %lu, needed: %lu bytes\n", glob_mem_size, glob_mem_required); +} + + +void makeOclBuffers ( + cl_context cxGPUContext, + cl_command_queue& cqCommandQueue, + RWScalars& ro_scal, + NordeaArrays& cpu_arrs, + oclNordeaArrays& ocl_arrs +) { + cl_int ciErr; + cl_int ciErr2; + unsigned long int cur_size; + + /*********************/ + /*** 1. RO scalars ***/ + /*********************/ + { + cur_size = sizeof(RWScalars); + ocl_arrs.ro_scals = clCreateBuffer( + cxGPUContext, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 + ); + + ciErr = ciErr2; + ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, + cur_size, &ro_scal, 0, NULL, NULL); + //oclCheckError(ciErr, CL_SUCCESS); + } + + /*********************/ + /*** 1. RO Arrays! ***/ + /*********************/ + { + cur_size = NUM_T*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(timeline); + + cur_size = NUM_X*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myX); + + cur_size *= REAL3_CT; + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDx); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDxx); + + cur_size = NUM_Y*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myY); + + cur_size *= REAL3_CT; + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDy); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDyy); + } + + //oclCheckError(ciErr, CL_SUCCESS); + + /*********************/ + /*** 1. RW Arrays! ***/ + /*********************/ + { + cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(real_t); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(a); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(b); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(c); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(y); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(u); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(v); + + cur_size *= 2; + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(tmp2); + + cur_size *= 2; + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(tmp4); + } + + { // Finally the result array (i.e., Read-Write but needs to be brought back to CPU in the end) + cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(real_t); + CREATE_AND_ENQUEUE_OUT_CL_BUFFER(res_arr); + } + + oclCheckError(ciErr, CL_SUCCESS); + + //shrLog("Before EXITING ALLOC ARRAYS!!! ...\n"); + +} + +#define USE_GPU_ITER 1 + +//extern "C" +unsigned long int +runOnGPU ( RWScalars& ro_scal, NordeaArrays& cpu_arrs, oclNordeaArrays& ocl_arrs ) { + cl_context cxGPUContext; // OpenCL context + cl_command_queue cqCommandQueue[16]; // OpenCL command que + cl_uint nDevice; // OpenCL device count + cl_device_id* cdDevices; // OpenCL device list + cl_program cpProgram; // OpenCL program + GPUkernels kernels; // OpenCL kernel + const unsigned int dev_id = GPU_DEV_ID; + + assert(GPU_DEV_ID >= 0 && "GPU DEVICE ID < 0 !\n"); + + { // initialize the loop-variant scalars! + ro_scal.t_ind = NUM_T - 2; + ro_scal.dtInv = 1.0/(cpu_arrs.timeline[ro_scal.t_ind+1]-cpu_arrs.timeline[ro_scal.t_ind]); + ro_scal.timeline_i = cpu_arrs.timeline[ro_scal.t_ind]; + } + + { // making command queue, building program, etc + char compile_opts[1024]; + sprintf(compile_opts, + "-D lgWARP=%d -D%s -I%s/include -I%s/include", + lgWARP, REAL_FLAG, HIPERMARK_BENCHMARK_LIB_DIR, HIPERMARK_LIB_DIR); + + build_for_GPU( + cxGPUContext, cqCommandQueue, + nDevice, cdDevices, cpProgram, dev_id, compile_opts, "", "CrankNicolson" + ); + + verifyEnoughResources(cdDevices[dev_id]); + } + + // allocate space for the RO and RW arrays on GPU! + makeOclBuffers ( + cxGPUContext, cqCommandQueue[dev_id], ro_scal, cpu_arrs, ocl_arrs + ); + + + { // make all kernels! + make_kernels( cqCommandQueue[dev_id], cpProgram, ro_scal, ocl_arrs, kernels ); + } + + unsigned long int elapsed; + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + // now execute kernels and record the time! + for(int t_ind = NUM_T-2; t_ind>=0; --t_ind) { + run_GPUkernels_one_time_iteration ( cqCommandQueue[dev_id], kernels ); + } // END TIME LOOP! + + + { // WRITE BACK THE RESULT ARRAY TO CPU !!! // + cl_int ciErr; + const unsigned int ARR_SIZE = NUM_X * NUM_Y * OUTER_LOOP_COUNT * sizeof(real_t); + ciErr = clEnqueueReadBuffer ( + cqCommandQueue[dev_id], ocl_arrs.res_arr, CL_TRUE, + 0, ARR_SIZE, cpu_arrs.res_arr, 0, NULL, NULL + ); + oclCheckError(ciErr, CL_SUCCESS); + + // RELEASE ALL GPU RESOURCES + release_all_GPU_resources ( + cqCommandQueue[dev_id], cxGPUContext, cpProgram, cdDevices, ocl_arrs, kernels + ); + } + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + + return elapsed; +} + +#endif // end include NORDEA_GPU diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp new file mode 100644 index 0000000..93c2320 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp @@ -0,0 +1,166 @@ +#include "Util.h" +#include "Constants.h" +#include "DataStructConst.h" +#include "ParseInput.h" +#include "VolCalibInit.h" +#include "Vect_CPU.h" +#include "Vect_GPU.h" + + +unsigned long int +whole_loop_nest ( + real_t* res, + const real_t* strikes, + const real_t s0, + const real_t t, + const real_t alpha, + const real_t nu, + const real_t beta +) { + // loop index + unsigned int i; + unsigned long int elapsed; + //const unsigned int NUM_XY = NUM_X*NUM_Y; + + // arrays: + real_t *a = NULL, *b = NULL, *c = NULL, + *y = NULL, *u = NULL, *v = NULL, + *scan_tmp = NULL; + + { // allocate arrays + a = new real_t __attribute__ ((aligned (32))) [OUTER_LOOP_COUNT*NUM_XY]; + b = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + c = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + + y = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + u = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + v = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + + scan_tmp = new real_t[4*OUTER_LOOP_COUNT*NUM_XY]; + } + + // parallel! + whole_loop_nest_init ( s0, t, alpha, nu, beta ); + + // parallel! + for( i=0; i 0 ) { + RWScalars ro_scal; + NordeaArrays cpu_arrs; + oclNordeaArrays ocl_arrs; + + { // init arrays + cpu_arrs.myX = myX; cpu_arrs.myDx = myDx; cpu_arrs.myDxx = myDxx; + cpu_arrs.myY = myY; cpu_arrs.myDy = myDy; cpu_arrs.myDyy = myDyy; + cpu_arrs.timeline = myTimeline; + cpu_arrs.a = a; cpu_arrs.b = b; cpu_arrs.c = c; + cpu_arrs.y = y; cpu_arrs.u = u; cpu_arrs.v = v; + cpu_arrs.tmp = scan_tmp; + cpu_arrs.res_arr = &myResArr[0]; + } + + { // init scalars + ro_scal.NUM_X = NUM_X; ro_scal.NUM_Y = NUM_Y; ro_scal.NUM_XY = NUM_X * NUM_Y; + ro_scal.alpha = alpha; ro_scal.beta = beta; ro_scal.nu = nu; + } + + { // SAFETY CHECK! + bool is_safe = (NUM_X <= WORKGROUP_SIZE) && (NUM_Y <= WORKGROUP_SIZE) && + is_pow2(NUM_X) && is_pow2(NUM_Y) && + (WORKGROUP_SIZE % NUM_X == 0) && (WORKGROUP_SIZE % NUM_Y == 0); + assert(is_safe && "NOT SAFE TO PARALLELISE ON GPU!"); + } + + elapsed = runOnGPU ( ro_scal, cpu_arrs, ocl_arrs ); + } else { + // CPU instrumentation here: + + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + for(int t_ind = NUM_T-2; t_ind>=0; --t_ind) { + + iteration_expanded_CPU ( + t_ind, alpha, beta, nu, + a, b, c, y, u, v, scan_tmp + ); + } + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + } + + for( i=0; i(s0/dx); + + for( i=0; i=0; i-=WARP) { + y[i] = (y[i] - c[i]*y[i+WARP]) / u[i]; + } +} + +/**************************************************************************/ +/*********** PREPARE FOR TRIDAG X *****************************************/ +/**************************************************************************/ + +__kernel void nordea_kernel_x ( + /*** Read-Only Scalars ***/ + __constant RWScalars* ro_scals, + /*** Read-Only Arrays ***/ + __constant real_t* myX, + __constant real_t* myDx, + __constant real_t* myDxx, + __global real_t* myY, + __global real4_t* myDy, + __global real4_t* myDyy, + /*** Read-Write Temporary Arrays ***/ + __global real_t* a, + __global real_t* b, + __global real_t* c, + __global real_t* y, + __global real_t* u, + __global real_t* v, + /*** The Result Array ***/ + __global real_t* res_arr +) { + unsigned int ind, i, ind_rev; + //const unsigned int step_rev = ro_scals->NUM_Y; //(ro_scals->NUM_Y << LOG2_WARP_SIZE); + real_t cur_myVar, cur_myMu, exp_add; + real4_t myDy_el; + + { // cur_myVarY = nu*nu; cur_myMuY = 0.0; compute ind_y and exp_add + cur_myVar = ro_scals->nu; cur_myVar *= cur_myVar; + cur_myMu = 0.0; + + //ind_y = get_global_id(0) & (ro_scals->NUM_Y - 1); + exp_add = myY[get_global_id(0) & (ro_scals->NUM_Y - 1)] - 0.5*cur_myVar*ro_scals->timeline_i; + } + + { // adjust arrays: except for `res_arr' and `v' which are accesses as `v[i,j]', hence memory is already coalesced! + unsigned int offset = (get_global_id(0)>>lgWARP); + offset *= ( ro_scals->NUM_X << lgWARP ); + offset += ( get_global_id(0) & (WARP-1) ); + + a += offset; + b += offset; + c += offset; + y += offset; + u += offset; + } + + { // computing myDy_el = (cur_myMuY*myDy[j] + 0.5*cur_myVarY*myDyy[j]) + i = get_global_id(0) & (ro_scals->NUM_Y - 1); + myDy_el = cur_myMu*myDy[i] + (0.5f*cur_myVar)*myDyy[i]; + //i = REAL3_CT*(get_global_id(0) & (ro_scals->NUM_Y - 1)); + //myDy_el = (real4_t)(myDyy[i], myDyy[i+1], myDyy[i+2], 1.0); + //myDy_el = myDy_el * (0.5*cur_myVar); + //myDy_el += cur_myMu*((real4_t)(myDy[i], myDy[i+1], myDy[i+2], 1.0)); + } + + + ind_rev = (get_global_id(0)/ro_scals->NUM_Y)*ro_scals->NUM_XY + (get_global_id(0) & (ro_scals->NUM_Y - 1)); + for( i=0, ind=0; iNUM_X; i++, ind+=WARP, ind_rev+=ro_scals->NUM_Y ) { + myDy_el.w = 0.0; + + { // comput cur_myMy and cur_myVar + cur_myMu = 0.0; // X + cur_myVar = exp( 2 * ( ro_scals->beta*log(myX[i]) + exp_add ) ); + //cur_myVar = exp(2*(ro_scals->beta*log(myX[i]) + myY[get_global_id(0) & (ro_scals->NUM_Y - 1)] - 0.5*ro_scals->nu*ro_scals->nu*ro_scals->timeline_i)); + } + + { // compute v[i, j] + if( (ind_rev & (ro_scals->NUM_Y-1)) != 0 ) myDy_el.w += myDy_el.x*res_arr[ind_rev-1]; //[(j-1)*NUM_X+i]; + myDy_el.w += myDy_el.y*res_arr[ind_rev ]; // [j*NUM_X+i]; + if( (ind_rev & (ro_scals->NUM_Y-1)) != ro_scals->NUM_Y-1 ) myDy_el.w += myDy_el.z*res_arr[ind_rev+1]; //[(j+1)*NUM_X+i]; + + //v[k*NUM_X*NUM_Y + i*NUM_Y + j] = tmp; // v[i*NUM_Y + j] = tmp; //v[i][j] = tmp2; + + v[ ind_rev ] = myDy_el.w; + } + + { // compute u, a, b, c + const unsigned int im3 = REAL3_CT*i; + + if(i!=0) + myDy_el.w += 0.5*(cur_myMu*myDx[im3 ] + 0.5*cur_myVar*myDxx[im3 ])*res_arr[ind_rev-ro_scals->NUM_Y]; //[j*NUM_X+i-1]; + + // tmp += ro_scals->dtInv * res_arr[ind]; WAS included in the next line! + myDy_el.w += ( 0.5*(cur_myMu*myDx[im3+1] + 0.5*cur_myVar*myDxx[im3+1]) + ro_scals->dtInv)*res_arr[ind_rev ]; //[j*NUM_X+i]; + + if(i!=ro_scals->NUM_X-1) + myDy_el.w += 0.5*(cur_myMu*myDx[im3+2] + 0.5*cur_myVar*myDxx[im3+2])*res_arr[ind_rev+ro_scals->NUM_Y]; //[j*NUM_X+i+1]; + + u[ind] = myDy_el.w; + + // compute a,b,c + a[ind] = 0.0 - 0.5*(cur_myMu*myDx[im3 ] + 0.5*cur_myVar*myDxx[im3 ]); // a[j*NUM_X+i] = ... + b[ind] = ro_scals->dtInv - 0.5*(cur_myMu*myDx[im3+1] + 0.5*cur_myVar*myDxx[im3+1]); // b[j*NUM_X+i] = ... + c[ind] = 0.0 - 0.5*(cur_myMu*myDx[im3+2] + 0.5*cur_myVar*myDxx[im3+2]); // c[j*NUM_X+i] = ... + } + } + + tridag_seq(a, b, c, u, ro_scals->NUM_X, u, y); +} + + +/**************************************************************************/ +/*********** IN-BETWEEN TRIDAGS -- i.e., prepare for TRIDAG Y *************/ +/**************************************************************************/ + +__kernel void nordea_kernel_y ( + /*** Read-Only Scalars ***/ + __constant RWScalars* ro_scals, // __constant + /*** Read-Only Arrays ***/ + __constant real_t* myDy, + __constant real_t* myDyy, + /*** Read-Write Temporary Arrays ***/ + __global real_t* a, + __global real_t* b, + __global real_t* c, + __global real_t* u, + __global real_t* v, + __global real_t* y +) { + //const unsigned int step_rev = ro_scals->NUM_X; //(ro_scals->NUM_X << LOG2_WARP_SIZE); + unsigned int ind, ind_rev, i; + real_t cur_myVar, cur_myMu; + + { // cur_myVarY = nu*nu; cur_myMuY = 0.0; compute ind_y and exp_add + cur_myVar = ro_scals->nu; cur_myVar *= cur_myVar; + cur_myMu = 0.0; + } + + { // adjust arrays! except for `u' whose access pattern is `u[j,i]' which is already coalesced! + unsigned int offset = (get_global_id(0)>>lgWARP); + offset *= ( ro_scals->NUM_Y << lgWARP ); + offset += ( get_global_id(0) & (WARP-1) ); + + a += offset; + b += offset; + c += offset; + y += offset; + v += offset; + } + + ind_rev = (get_global_id(0)/ro_scals->NUM_X)*ro_scals->NUM_XY + (get_global_id(0) & (ro_scals->NUM_X - 1)); // should step with `NUM_Y*32' + for( i=0, ind=0; iNUM_Y; i++, ind+=WARP, ind_rev+=ro_scals->NUM_X) { + unsigned int im3 = REAL3_CT*i; + + a[ind] = 0.0 - 0.5*(cur_myMu*myDy[im3 ] + 0.5*cur_myVar*myDyy[im3 ]); // a[i*NUM_Y+j] = ... + b[ind] = ro_scals->dtInv - 0.5*(cur_myMu*myDy[im3+1] + 0.5*cur_myVar*myDyy[im3+1]); // b[i*NUM_Y+j] = ... + c[ind] = 0.0 - 0.5*(cur_myMu*myDy[im3+2] + 0.5*cur_myVar*myDyy[im3+2]); // c[i*NUM_Y+j] = ... + + v[ind] = ro_scals->dtInv * u[ind_rev] - 0.5 * v[ind]; + //u[ (get_global_id(0)/ro_scals->NUM_XY)*ro_scals->NUM_XY + i*ro_scals->NUM_X + ind_x] - + } + + tridag_seq(a, b, c, v, ro_scals->NUM_Y, v, y); +} + + +/*********************************************/ +/*********** Matrix Transposition ************/ +/*********************************************/ + +// This kernel is optimized to ensure all global reads and writes are coalesced, +// and to avoid bank conflicts in shared memory. The shared memory array is sized +// to (BLOCK_DIM+1)*BLOCK_DIM. This pads each row of the 2D block in shared memory +// so that bank conflicts do not occur when threads address the array column-wise. +inline void transposeMatrix( + __global real_t *odata, + __global real_t *idata, + unsigned int width, + unsigned int height, + __local real_t* block) +{ + unsigned int xIndex, yIndex; + + // adjust the input and output arrays for the third dimension! + yIndex = get_global_id(2) * width * height; + odata = odata + yIndex; + idata = idata + yIndex; + + // read the matrix tile into shared memory + xIndex = get_global_id(0); + yIndex = get_global_id(1); + + if((xIndex < width) && (yIndex < height)) + { + unsigned int index_in = yIndex * width + xIndex; + block[get_local_id(1)*(BLOCK_DIM+1)+get_local_id(0)] = idata[index_in]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // write the transposed matrix tile to global memory + xIndex = get_group_id(1) * BLOCK_DIM + get_local_id(0); + yIndex = get_group_id(0) * BLOCK_DIM + get_local_id(1); + if((xIndex < height) && (yIndex < width)) + { + unsigned int index_out = yIndex * height + xIndex; + odata[index_out] = block[get_local_id(0)*(BLOCK_DIM+1)+get_local_id(1)]; + } +} + +__kernel void transpose( + __global real_t *odata, + __global real_t *idata, + //int offset, + unsigned int width, + unsigned int height, + __local real_t* block) +{ + transposeMatrix( odata, idata, width, height, block ); +} + +__kernel void transposeUpdateScalars( + __global real_t *odata, + __global real_t *idata, + //int offset, + unsigned int width, + unsigned int height, + __local real_t* block, + __global RWScalars* ro_scals, // __constant + __constant real_t* timeline +) { + transposeMatrix( odata, idata, width, height, block ); + + // update time-loop-variant scalars + if(get_global_id(2) + get_global_id(1) + get_global_id(0) == 0) { + int t_ind = --ro_scals->t_ind; + ro_scals->dtInv = 1.0 / ( timeline[t_ind+1] - timeline[t_ind] ); + ro_scals->timeline_i = timeline[ t_ind ]; + } +} + + + diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile new file mode 100644 index 0000000..51c9586 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile @@ -0,0 +1,54 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +# FIXME - this should not even exist! +include $(HIPERMARK_LIB_DIR)/platform.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ + -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ + -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ + -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ + -D CURR_DIR_PATH='"$(MAKE_DIR)"' + +SOURCES_CPP =$(HIPERMARK_IMPLEMENTATION)/VolCalibOuter.cpp +HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/Constants.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/ParseInput.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/DataStructConst.h \ + $(HIPERMARK_BENCHMARK_LIB_DIR)/ParPrefixUtil.h +EXECUTABLE =VolCalibOuter + +$(EXECUTABLE): + cp $(HIPERMARK_IMPLEMENTATION)/*cl . + $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) + + +run_small: + cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_medium: + cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt + +run_large: + cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt + +clean: + rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt + @# clean nVidia compiler cache + rm -rf $(HOME)/.nv/ComputeCache/* + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h new file mode 100644 index 0000000..65d9745 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h @@ -0,0 +1,529 @@ +#ifndef PREPARE_KERNELS +#define PREPARE_KERNELS + +/************************************************************/ +/*************** HELPER DATA STRUCTURES ******************/ +/************************************************************/ + +// GPU BUFFERS +struct oclNordeaArrays { + /* RO scalars */ + cl_mem ro_scals; + + /* RO arrays */ + cl_mem timeline; // [NUM_T] + + cl_mem myX; // [NUM_X] + cl_mem myDx; // [NUM_X * 3] + cl_mem myDxx; // [NUM_X * 3] + + cl_mem myY; // [NUM_Y] + cl_mem myDy; // [NUM_Y * 3] + cl_mem myDyy; // [NUM_Y * 3] + + /* TRIDAG helpers */ + cl_mem a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem tmp4; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] + cl_mem tmp2; // [2 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + cl_mem res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + /* WRITE ONLY OUTPUT stored in "res"*/ + //cl_mem res; +}; + +// CPU BUFFERS +struct NordeaArrays { + /* RO arrays */ + real_t* timeline; // [NUM_T] + + real_t* myX; // [NUM_X] + real_t* myDx; // [NUM_X * 3] + real_t* myDxx; // [NUM_X * 3] + + real_t* myY; // [NUM_Y] + real_t* myDy; // [NUM_Y * 3] + real_t* myDyy; // [NUM_Y * 3] + + /* TRIDAG helpers are created on GPU only! no need for them to exist in main memory*/ + real_t* a; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* b; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* c; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* y; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* u; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* v; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + real_t* tmp; // [4 * OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + real_t* res_arr; // [OUTER_LOOP_COUNT * NUM_X * NUM_Y] + + /* NOT USED FOR NOW! WRITE ONLY OUTPUT stored in "res"*/ + //real_t* res; +}; + +// GPU KERNELS +typedef struct { + cl_kernel ckMatTranspUpdate; + cl_kernel ckMatTransposeU; + cl_kernel ckMatTransposeV; + + // TRIDAG KERNELS + cl_kernel ckNordeaKernelX; // OUTER_LOOP_COUNT x NUM_Y + cl_kernel ckNordeaKernelY; // OUTER_LOOP_COUNT x NUM_X + + size_t FORM_32X [3]; + size_t FORM_32Y [3]; + size_t FORM_Y32 [3]; +} GPUkernels __attribute__ ((aligned (32))); + +/******************************************************/ +/******* compute global/local grid dimensions *********/ +/******************************************************/ + +static bool is_pow2(unsigned int x) { + while(x > 1) { + if( x & 1 ) return false; + x = x >> 1; + } + return true; +} + +void initGPUgrid ( GPUkernels& kernels ) { + // fill transposition layouts! + + bool is_safe = ( (OUTER_LOOP_COUNT*NUM_X) % NUM_Y == 0 ) && + //( (OUTER_LOOP_COUNT*NUM_Y) % NUM_X == 0 ) && + ( (OUTER_LOOP_COUNT*NUM_X) % WORKGROUP_SIZE == 0 ) && + ( (OUTER_LOOP_COUNT*NUM_Y) % WORKGROUP_SIZE == 0 ) && + ( NUM_X % 32 == 0 && NUM_Y % 32 == 0); + assert( is_safe && "CANNOT EXECUTE ON GPU: sizes do not match!"); + + kernels.FORM_32X[0] = 32; kernels.FORM_32X[1] = NUM_X; kernels.FORM_32X[2] = (OUTER_LOOP_COUNT*NUM_Y)/32; + kernels.FORM_32Y[0] = 32; kernels.FORM_32Y[1] = NUM_Y; kernels.FORM_32Y[2] = (OUTER_LOOP_COUNT*NUM_X)/32; + kernels.FORM_Y32[0] = NUM_Y; kernels.FORM_Y32[1] = 32; kernels.FORM_Y32[2] = (OUTER_LOOP_COUNT*NUM_X)/32; +} + +/************************************************************/ +/*************** KERNELS OTHER THAN TRIDAG ****************** +/************************************************************/ + +/////////////////////////// +/// NORDEA_ALL_KERNEL_X /// +/////////////////////////// + +cl_kernel make_NordeaKernelX( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs +) { + //size_t* globalWorkSize, + //size_t* localWorkSize + cl_kernel ckAllX = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckAllX = clCreateKernel(cpProgram, "nordea_kernel_x", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + // 1. RO SCALARS // + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); + + // 2. RO ARRAYS // + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myX); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDx); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDxx); + + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myY); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); + + // 3. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); + + // 4. OUT ARRAY! + ciErr1 |= clSetKernelArg(ckAllX, counter++, sizeof(cl_mem), (void*)&ocl_arrs.res_arr ); + + oclCheckError(ciErr1, CL_SUCCESS); + + return ckAllX; +} + +void run_NordeaKernelX( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + size_t globalWorkSize = NUM_Y * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelX, 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL); + ciErr1 |= clFinish(cqCommandQueue); + + oclCheckError(ciErr1, CL_SUCCESS); +} + +/////////////////////////// +/// NORDEA_ALL_KERNEL_Y /// +/////////////////////////// + +cl_kernel make_NordeaKernelY( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs +) { + cl_kernel ckAllY = NULL; // OpenCL kernel + cl_int ciErr1, ciErr2; + + unsigned int counter = 0; // ro_scals + + ///// + ckAllY = clCreateKernel(cpProgram, "nordea_kernel_y", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + + unsigned long int cur_size; + + // 1. RO SCALARS // + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.ro_scals ); + + // 2. RO ARRAYS // + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDy); + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.myDyy); + + // 3. GPU-ONLY GLOBAL ARRAYS // + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.a); + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.b); + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.c); + + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.y); // y <- u^T + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.u); // u <- v^T + ciErr1 |= clSetKernelArg(ckAllY, counter++, sizeof(cl_mem), (void*)&ocl_arrs.v); + + oclCheckError(ciErr1, CL_SUCCESS); + + return ckAllY; +} + +void run_NordeaKernelY( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + cl_int ciErr1; + size_t globalWorkSize = NUM_X * OUTER_LOOP_COUNT; + size_t localWorkSize = WORKGROUP_SIZE; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernels.ckNordeaKernelY, 1, NULL, + &globalWorkSize, &localWorkSize, 0, NULL, NULL); + + ciErr1 |= clFinish(cqCommandQueue); + + oclCheckError(ciErr1, CL_SUCCESS); +} + +/***************************************************/ +/********* Segmented Matrix Transposition ********/ +/***************************************************/ + +cl_kernel make_transposeGPU( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + cl_mem inp_arr, + cl_mem out_arr, + size_t* size_x, + size_t* size_y, + size_t* size_z, + const char* kernel_name +// size_t* globalWorkSize, +// size_t* localWorkSize +) { + cl_kernel ckMatTransp = NULL; + cl_int ciErr1, ciErr2; + unsigned int counter = 0; + + ckMatTransp = clCreateKernel(cpProgram, kernel_name, &ciErr1); // "transposeUpdateScalars" + oclCheckError(ciErr1, CL_SUCCESS); + + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &out_arr); // input array + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(cl_mem), (void *) &inp_arr); // output array + //ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), &offset); + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_x); // size of 0 dim + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, sizeof(int), size_y); // size of 1 dim + + // shared memory space + ciErr1 |= clSetKernelArg(ckMatTransp, counter++, (BLOCK_DIM + 1) * BLOCK_DIM * sizeof(real_t), 0 ); + + oclCheckError(ciErr1, CL_SUCCESS); + + return ckMatTransp; +} + +void run_transposeGPU ( + cl_command_queue& cqCommandQueue, + cl_kernel kernel, + size_t* globalWorkSize + +) { + cl_int ciErr1; + size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernel, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +cl_kernel make_transposeGPU_WithUpdate( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + cl_mem inp_arr, + cl_mem out_arr, + size_t* size_x, + size_t* size_y, + size_t* size_z, + oclNordeaArrays& ocl_arrs +// size_t* globalWorkSize, +// size_t* localWorkSize +) { + cl_int ciErr1; + cl_kernel kernel = make_transposeGPU( + cqCommandQueue, cpProgram, inp_arr, + out_arr, size_x, size_y, size_z, "transposeUpdateScalars" + ); + + ciErr1 = clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *) &ocl_arrs.ro_scals); + ciErr1 = clSetKernelArg(kernel, 6, sizeof(cl_mem), (void *) &ocl_arrs.timeline); + oclCheckError(ciErr1, CL_SUCCESS); + + return kernel; +} + +void run_transposeGPU_WithUpdate ( + cl_command_queue& cqCommandQueue, + cl_kernel kernel, + size_t* globalWorkSize +) { + cl_int ciErr1; + size_t localWorkSize [3] = {BLOCK_DIM, BLOCK_DIM, 1}; + //size_t* localWorkSize = kernels.LWS_YXZ; + + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, kernel, 3, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + ciErr1 |= clFinish(cqCommandQueue); + oclCheckError(ciErr1, CL_SUCCESS); +} + +/**********************************************************/ +/**************** MAKE ALL KERNELS ************************/ +/**********************************************************/ + +void make_kernels ( + cl_command_queue& cqCommandQueue, + cl_program cpProgram, + RWScalars& ro_scal, + oclNordeaArrays& ocl_arrs, + GPUkernels& kernels +) { + initGPUgrid ( kernels ); + + // First Kernel + kernels.ckNordeaKernelX = make_NordeaKernelX ( + cqCommandQueue, cpProgram, ro_scal, ocl_arrs + ); + + // Second Kernel + kernels.ckNordeaKernelY = make_NordeaKernelY ( + cqCommandQueue, cpProgram, ro_scal, ocl_arrs + ); + + { // matrix transpose!!! + // transpose U into Y + kernels.ckMatTransposeU = make_transposeGPU ( + cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.y, + &kernels.FORM_32X[0], &kernels.FORM_32X[1], &kernels.FORM_32X[2], "transpose" + //&NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" + ); + + // transpose V into U + kernels.ckMatTransposeV = make_transposeGPU ( + cqCommandQueue, cpProgram, ocl_arrs.v, ocl_arrs.u, + &kernels.FORM_Y32[0], &kernels.FORM_Y32[1], &kernels.FORM_Y32[2], "transpose" + //&NUM_X, &NUM_Y, &OUTER_LOOP_COUNT, "transpose" + ); + + + // Transpose into res_arr and update induction variables! + kernels.ckMatTranspUpdate = make_transposeGPU_WithUpdate ( + cqCommandQueue, cpProgram, ocl_arrs.u, ocl_arrs.res_arr, // ocl_arrs.y + &kernels.FORM_32Y[0], &kernels.FORM_32Y[1], &kernels.FORM_32Y[2], ocl_arrs + //&NUM_Y, &NUM_X, &OUTER_LOOP_COUNT, ocl_arrs + ); + } +} + + +/**********************************************************/ +/********************* RUN KERNELS ************************/ +/**********************************************************/ + +void run_GPUkernels_one_time_iteration ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels +) { + size_t globalWorkSize[3]; + + run_NordeaKernelX( cqCommandQueue, kernels ); + run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeU, kernels.FORM_32X ); // y <- transpose(u) + run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeV, kernels.FORM_Y32 ); // u <- transpose(v) + run_NordeaKernelY( cqCommandQueue, kernels ); + run_transposeGPU_WithUpdate( cqCommandQueue, kernels.ckMatTranspUpdate, kernels.FORM_32Y); +} + +/**********************************************************/ +/******************* RELEASE KERNELS **********************/ +/**********************************************************/ + +void release_all_kernels ( GPUkernels& kernels ) { + clReleaseKernel(kernels.ckNordeaKernelX); + + clReleaseKernel(kernels.ckMatTransposeU); + clReleaseKernel(kernels.ckMatTransposeV); + + clReleaseKernel(kernels.ckNordeaKernelY); + + clReleaseKernel(kernels.ckMatTranspUpdate); +} + +void release_all_GPU_resources( + cl_command_queue& cqCommandQueue, + cl_context& cxGPUContext, + cl_program cpProgram, + cl_device_id* cdDevices, + oclNordeaArrays& ocl_arrs, + GPUkernels& kernels +) { + + shrLog(stdlog, "Release Kernels...\n"); + release_all_kernels( kernels ); + + shrLog(stdlog, "Release CPU buffers and OpenCL objects...\n"); + clReleaseProgram(cpProgram); + + clReleaseMemObject(ocl_arrs.ro_scals); + clReleaseMemObject(ocl_arrs.timeline); + + clReleaseMemObject(ocl_arrs.a); + clReleaseMemObject(ocl_arrs.b); + clReleaseMemObject(ocl_arrs.c); + + clReleaseMemObject(ocl_arrs.y); + clReleaseMemObject(ocl_arrs.u); + clReleaseMemObject(ocl_arrs.v); + + clReleaseMemObject(ocl_arrs.res_arr); + + clReleaseMemObject(ocl_arrs.myX); + clReleaseMemObject(ocl_arrs.myDx); + clReleaseMemObject(ocl_arrs.myDxx); + + clReleaseMemObject(ocl_arrs.myY); + clReleaseMemObject(ocl_arrs.myDy); + clReleaseMemObject(ocl_arrs.myDyy); + + clReleaseCommandQueue(cqCommandQueue); + free(cdDevices); + clReleaseContext(cxGPUContext); +} + + +/*****************************************************************/ +/************ DEBUGGING ******************************************/ +/*****************************************************************/ + + +void run_trimmed_GPUkernels_one_time_iteration ( + cl_command_queue& cqCommandQueue, + GPUkernels& kernels, + NordeaArrays& cpu_arrs, + oclNordeaArrays& ocl_arrs, + int time_ind, + const real_t alpha, + const real_t beta, + const real_t nu +) { + run_NordeaKernelX( cqCommandQueue, kernels ); + run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeU, kernels.FORM_32X ); // y <- transpose(u) + run_transposeGPU ( cqCommandQueue, kernels.ckMatTransposeV, kernels.FORM_Y32 ); // u <- transpose(v) + run_NordeaKernelY( cqCommandQueue, kernels ); + run_transposeGPU_WithUpdate( cqCommandQueue, kernels.ckMatTranspUpdate, kernels.FORM_32Y); + + cl_int ciErr; + const unsigned int ARR_SIZE = NUM_X * NUM_Y * OUTER_LOOP_COUNT * sizeof(real_t); +#if 1 + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.a, CL_TRUE, 0, ARR_SIZE, cpu_arrs.a, 0, NULL, NULL ); + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.b, CL_TRUE, 0, ARR_SIZE, cpu_arrs.b, 0, NULL, NULL ); + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.c, CL_TRUE, 0, ARR_SIZE, cpu_arrs.c, 0, NULL, NULL ); + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.u, CL_TRUE, 0, ARR_SIZE, cpu_arrs.u, 0, NULL, NULL ); + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.v, CL_TRUE, 0, ARR_SIZE, cpu_arrs.v, 0, NULL, NULL ); + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.y, CL_TRUE, 0, ARR_SIZE, cpu_arrs.y, 0, NULL, NULL ); + ciErr = clEnqueueReadBuffer( cqCommandQueue, ocl_arrs.res_arr, CL_TRUE, 0, ARR_SIZE, cpu_arrs.res_arr, 0, NULL, NULL ); +#endif + + oclCheckError(ciErr, CL_SUCCESS); + + // now the rest of the code! + unsigned int i, j, k; + + real_t dtInv = 1.0/(cpu_arrs.timeline[time_ind+1]-cpu_arrs.timeline[time_ind]); + + real_t *res_arr = cpu_arrs.res_arr, *a = cpu_arrs.a, + *b = cpu_arrs.b, *c = cpu_arrs.c, *u = cpu_arrs.u, + *v = cpu_arrs.v, *y = cpu_arrs.y; + + unsigned int cos_test_ind = 3*NUM_XY + 23*NUM_X + 211, cos_test_ind_rev = 3*NUM_XY + 211*NUM_Y + 23; + + + { // transpose u: u is in form: [i/32, j, i%32] + // and needs to be brought to form [i/32, i%32, j], a.k.a. [i,j] + const unsigned int ID = OUTER_LOOP_COUNT * NUM_X / 32; + for( k=0; k=0; --time_ind) { + + + unsigned int i, j, k; + + real_t dtInv = 1.0/(myTimeline[time_ind+1]-myTimeline[time_ind]); + + real_t *res_arr = &myResArr[0]; + +#pragma omp parallel for default(shared) schedule(static) private(k,j,i) if(OUTER_LOOP_COUNT>4) + for( k=0; k4) + for( k=0; k4) + for( k=0; k( USER_MEM * 101.0 / 100.0 ); + const size_t lb = static_cast( USER_MEM * 99.0 / 100.0 ); + if ( !(glob_mem_size >= lb && glob_mem_size <= ub) ) { + fprintf(stderr, "WARNING! Querried GPU global memory %lu DIFFERS from what user declared: [%ld,%ld]!\n", + glob_mem_size, lb, ub); + glob_mem_size = static_cast(USER_MEM); + fprintf(stderr, "Using user-declared size for global memory: %lu\n", glob_mem_size); + } + } + + cl_ulong glob_mem_required = 8 * OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(real_t); + assert( glob_mem_required <= glob_mem_size && "Not Enough Global Memory. A possible fix is to strip-mine all kernels.\n" ); + //fprintf(stderr, "GPU global memory: %lu, needed: %lu bytes\n", glob_mem_size, glob_mem_required); +} + +void makeOclBuffers ( + cl_context cxGPUContext, + cl_command_queue& cqCommandQueue, + RWScalars& ro_scal, + NordeaArrays& cpu_arrs, + oclNordeaArrays& ocl_arrs +) { + cl_int ciErr; + cl_int ciErr2; + unsigned long int cur_size; + + /*********************/ + /*** 1. RO scalars ***/ + /*********************/ + { + cur_size = sizeof(RWScalars); + ocl_arrs.ro_scals = clCreateBuffer( + cxGPUContext, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 + ); + + ciErr = ciErr2; + ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, + cur_size, &ro_scal, 0, NULL, NULL); + //oclCheckError(ciErr, CL_SUCCESS); + } + + /*********************/ + /*** 1. RO Arrays! ***/ + /*********************/ + { + cur_size = NUM_T*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(timeline); + + cur_size = NUM_X*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myX); + + cur_size *= REAL3_CT; + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDx); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDxx); + + cur_size = NUM_Y*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myY); + + cur_size *= REAL3_CT; + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDy); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(myDyy); + } + + //oclCheckError(ciErr, CL_SUCCESS); + + /*********************/ + /*** 1. RW Arrays! ***/ + /*********************/ + { + cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(real_t); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(a); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(b); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(c); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(y); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(u); + CREATE_AND_ENQUEUE_GPU_ONLY_CL_BUFFER(v); + } + + { // Finally the result array (i.e., Read-Write but needs to be brought back to CPU in the end) + cur_size = OUTER_LOOP_COUNT * NUM_X * NUM_Y * sizeof(real_t); + CREATE_AND_ENQUEUE_OUT_CL_BUFFER(res_arr); + } + + oclCheckError(ciErr, CL_SUCCESS); + + //shrLog("Before EXITING ALLOC ARRAYS!!! ...\n"); + +} + +//extern "C" +unsigned long int +runOnGPU ( RWScalars& ro_scal, NordeaArrays& cpu_arrs, oclNordeaArrays& ocl_arrs ) { + cl_context cxGPUContext; // OpenCL context + cl_command_queue cqCommandQueue[16]; // OpenCL command que + cl_uint nDevice; // OpenCL device count + cl_device_id* cdDevices; // OpenCL device list + cl_program cpProgram; // OpenCL program + GPUkernels kernels; // OpenCL kernel + unsigned int dev_id = GPU_DEV_ID; + + assert(GPU_DEV_ID >= 0 && "GPU DEVICE ID < 0 !\n"); + + { // initialize the loop-variant scalars! + ro_scal.t_ind = NUM_T - 2; + ro_scal.dtInv = 1.0/(cpu_arrs.timeline[ro_scal.t_ind+1]-cpu_arrs.timeline[ro_scal.t_ind]); + ro_scal.timeline_i = cpu_arrs.timeline[ro_scal.t_ind]; + } + + { // making command queue, building program, etc + char compile_opts[1024]; + sprintf(compile_opts, + "-D lgWARP=%d -D%s -I%s/include -I%s/include", + lgWARP, REAL_FLAG, HIPERMARK_BENCHMARK_LIB_DIR, HIPERMARK_LIB_DIR); + + build_for_GPU( + cxGPUContext, cqCommandQueue, + nDevice, cdDevices, cpProgram, dev_id, compile_opts, "", "CrankNicolson" + ); + + verifyEnoughResources(cdDevices[dev_id]); + } + + // allocate space for the RO and RW arrays on GPU! + makeOclBuffers ( + cxGPUContext, cqCommandQueue[dev_id], ro_scal, cpu_arrs, ocl_arrs + ); + + + // make all kernels! + make_kernels( cqCommandQueue[dev_id], cpProgram, ro_scal, ocl_arrs, kernels ); + + unsigned long int elapsed; + { // now execute kernels! + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + for(int t_ind = NUM_T-2; t_ind>=0; --t_ind) { + run_GPUkernels_one_time_iteration ( cqCommandQueue[dev_id], kernels ); + } // END TIME LOOP! + + + { // WRITE BACK THE RESULT ARRAY TO CPU !!! // + cl_int ciErr; + const unsigned int ARR_SIZE = NUM_X * NUM_Y * OUTER_LOOP_COUNT * sizeof(real_t); + ciErr = clEnqueueReadBuffer ( + cqCommandQueue[dev_id], ocl_arrs.res_arr, CL_TRUE, + 0, ARR_SIZE, cpu_arrs.res_arr, 0, NULL, NULL + ); + oclCheckError(ciErr, CL_SUCCESS); + + // RELEASE ALL GPU RESOURCES + release_all_GPU_resources ( + cqCommandQueue[dev_id], cxGPUContext, cpProgram, cdDevices, ocl_arrs, kernels + ); + } + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + } + + return elapsed; +} + +#endif // end include NORDEA_GPU diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h new file mode 100644 index 0000000..a19b589 --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h @@ -0,0 +1,137 @@ +#ifndef NORDEA_INIT +#define NORDEA_INIT + +#include "DataStructConst.h" + +/////////////////////////////////////////////////////// +//// INITIALISATION ! +/////////////////////////////////////////////////////// + +void initGrid( + const real_t s0, + const real_t alpha, + const real_t nu, + const real_t t, + const unsigned int numX, + const unsigned int numY, + const unsigned int numT +) { + unsigned int i; + + for( i=0; i(s0/dx); + + for( i=0; i 0) { + for(unsigned int i=0; ik|SG%E(YRU%rDe)Co@J6T0+VVj85i}oI#Z{sQkfml4^hO9IPLyqrcHAeRPBg z5Wyxo2^Mw?pVi`pobQ~A=(=YEXXx2rVi&>lJXK%t9F)5qa;$z_?0-G#RgN1g$`{@; z>Bfph6DrE9T+1dbOSxsjEt4kJRZqN$*-w1ryNs-SCK2)nAS!z#{-`a9KHN8Y!PXOv zSK8BGI{w+OZ**SSe8(=L&BR~G|JNi5Jvx0P;b!448-L@*tR7vKU!q@KX!Y zN0Tkly4$|ocK16VU+~{=V92Exphzh2LU<31y%4@;2>#E9z~6z2Tu9H4L)bGOHX1Hq z=dDBFzaFC8u|wb|4N#m;U zz#kaG&Tog{Hw;m3Ioj(&?N0r}fWN{2#3A(mdI^voQh-1S4~xnYQMCk#>Fg+uV)GX(#< zA@Hk*u-`p|oyUgYPZ^@Vz9H}z4`EN%5cq!$QEucA{C^t4{+1#1^bEm&*AV)D7{dSC zhtN|$M7a$^=zn4ezr8#}xj94NUmC)mj3LUk520rY_~V5ugrwcY&?q3!;{T3-pYT1q ziWwq^e+l*zUQqcBoLwkY^%w@}i3k6+;7J;7QaSl4PPNBy#Xx+a>Yp`(_yyz**)@); zbUWn=$wHBBc4pBcN3COVd7aZyJ3BMIqPog4yJTU7Lnta*Tv=UJROc+Ibrux~MKhNc z<*Iz?6(x0bjyf)WLE+Mh^jb%W(~(nKy|}id^3HPSlDukHZK*>jt;ldVEsmw-r4CzF zSvBBXM}?!L&N0hTTji+W^qh(kXIXV^rOIKgy2s^kIdUB(i>ABE${e-eQgK<9+>)xr zVPRfudUa)GN!6m;NlMko4N(=&D6cB7TLKDa4;8JNl3rcqbS!g%9zvX_FKD5qE~F+b zhAOJSz#80HTkdp(ssJw4Khs_16^m5XuzNJBLo%vCs$AH@Oh;w*!n+)$WHi$j=E!q6 zc?He2izxu=oQq0txPb!T7Bq5=a|v2%QPJIw*7tE{=R^3e2ivT&MIRt^?oC|bO1Sy7FnwywIWq@vupyl80>mzspAsYy;MqByH_ z)>bbk`4U^H734)FIZHWLdNNa6sTReAZb~Z3D{@rUKv}J$27y>zTe8?ea#?xKl=AAj zqJ;>XNw%tTC&ULT0#lyzrb$Ibs9kk^QMJoiR9#k7OQBL!R_R2g?!Ay63)fRsqS^ty zU=11!-&JzAIhNH371fJ{x_fG!~I!UxhlyL z__;2GQ~eGS(@`vmNqL1(URPIBLj5qvQdY(7#7Dc-6&>)~La&Rb}{RGtZ4A@8vZ^FUc3J2*WfSH@C%<5Gl+ac zdmzDoF&g}+AQET227kE*pP<42N`p6O@Ch1xq6YtK4L(VOM>ZJxm!iSb+Aa9cq`_Yq zMB*%I@MARi91Z>|4Zc8wzgmMY*5C~q{1OfR8V$ZigTGdTU#7udr@^n#;EfvmqZ<5J z4Zcx>|E&i9j0T^m!LQNa$7%4dYVg-<@ar`A8#MSP4W9Obg8y1H_z6KI&Yc?kL=C=6 zgTGOO-=o1NY4AN7e6j|wXz({_@O>Km%^G~a20uxI7u0nK#s6dtK1PGTMT6IC@W0dG z6Eye~4c?%^r)uzt8vGOuK1qY8y|v)K6b*iA5Q(!%gU{07B@I4JgU`|6Z`0rlH27&6 ze6a>^(%_e9@MaCZMuVTO!7tO`b2RuB8hpA2|ELCU(cl|3c&i5gj0QhLgI}Y;XK3)R zYVeWC%w+N;w&)>-4*9fMm&cA}e zFA_{)?5|<)vjo%B<}YUO;{+oI68t#~{yo7o#raJPewbjI+WbijzL#K{()2(Dr96$B>`T+HB038tyWpTpo01k)7b zH!(PZV46bwNen*K1ek8y_zes`N-#|&em#SKB$%cUzrf(H38tyT-*=YkzmH%8!95J_ zCYYuQe;0#y5KL2qzlFhV1k=>uU&r8$1k;q@U&G+H2&SpP-^k$C2>uPhD;WGD!89fK zYZ&}2!88^4iy8bl!88T!BYsPq1wNO z!8Z|1L$tqb7$ zNen*qAHX!!`V9;|N-zzjem#SKB$$R!zrf(H38tab-*=j|Kfxw~dl=kJFb$RdE(Y%) zn1)Dy3xnGTrXkS3j=>uVrlHTjhQV(UOhcZ(k-@JKOhcW21%qECn1(oi4TGO0n1(ig zG2omHjq6Rq#>Ie}qndNU?h2~ z@@ou!-cj#@;^`I}o`zA9yjN=dYO2)gpO(5)%-G>R6)iq8A7iZhluq6$bzNU&{*04sF~*jON4m?z zs(HrPnZDRhk^^O8^@NX~h0Dd7b{rDNb~7Mx%#ZARF8W2BkBQ&+gZ43)`@q<8*xjKk z6Wey^BzLQ!OgwiS3@v5i><`Ms0x%W6FOIYIK%kQ`sf1P#+Qo6^zSMI|he6Y}-d8QU zPHSqXGYdv-ms?T8=#ePxs3cy${is;jiCV_K?~`4!SF|Pn3|EcG=i5!mpE6&O_O9f%`*_TX$P2Q&b9gW>A{@n!O z4qNNtNTvOkKwxt`5H^IsDh*Zn2Po2pk5A@(^YU|B3^sX-UG9@ke${*}nCfjWj7X6tnRgBTZ^*bM$PT@lg0hprGkg8w7B zV)OkLTv2|p`Murf5^wdRue9t!Hz9B{ZDdoP;lCc$OFm?icP^0RuO;`leL1sj9W8y& zf!xu$f}J{w$Cw1=Ur_LK)5p+|FHPvgNpkmJBFWz^y|M}Avh*c>{$?Ts5EE(-pWjYd zOSs236FpyAd6+3^Jr@ZD68zb!Op|omq@CxSqe9v)4r&vx7Us7@B}T0kX)nBO5Cm6z zJ_MC242bi$MgIXP-7!|u=7cUXY?|PT?)?+wLdt$3fk4-M|Gkh2+mk2Br6{>W??ak+^K@UV-XiZnz07h43OG7l)JL5&%b!_vZK<7r z;-dntZ_Vyjos15**VSrvZ_!zF$5FOx4YhVKxXeYWKbz=A2W6g@H^DD~KCv}J?`e5( z)G?Lr&CvUD;2il*{X@O}=97WI!1k2NBTUmpK`Ot5og$~lNE`Q0dgrr;zqm48ip+|U z#n-p!=ObxCqY4C7Fy!SkAUf!7m~yOXy|^7os2 zt}zK6QATPOWeY6vMj2t-%2NSEdwn#jm(adpMHA+n6mT@J!*sK`i{_kXj+51V#&HL9 z&Z{0_EtM zAod4_t>oC;Aa*Ci&gIxiIEic1ZVwXw&4{;gVqhI35)Yf1o@T^rIB_2*{whekml2~l zaXlxV!ih=F2N9M%1=t(?Esnma9`YX}nmF+uM(h|wyp9v?jQGkR;xJD9EhEZ2r9C2j`@d8K8 zR1tA(bX^T3^%z!5M0S3je5}lZ850#vq5R@I4BwJ>vJq04;lA}v57;n6VxH?^!(tDz z4rN+un>eG5WgYJ!IRRe_WgcCa2{8#S*n-(`nAmX5MMO$$XQ>B6&OrKcWeAJZqaesW z11U&6C^Qwf{*lrZq#z+>Gmwguq9CIF6Vwen6$#S~FsR`MSZ$rUR^Rk9 z=2j)bjB&~A{v~3DZ!`-van(8moE&SUYJY;1WD>jDQf3uLc1ymf!$>p^3)bZAglIwC z0${8jbKT=qn{yK`X6MAo1Rt}A-+xzT78AG75GT1?49GhuLz%q|*n%xM6t>~8phX;K z>Ve*^hXI}ICAl74C2sjI{C(Ec*4n>VbbGC-`<%JtW4V*sp+)1EsBJ#8F12mx&8!Jp zBT{#q&$0A!A`%{1O2}nVA04%bx3{B?6I;lV7V-CA!mIG`gw#g3r{5C*xBn<=;Kzj$ z)Pd3$C?o)73${Y*_!c?(*z4#`4T+fU!S=1(g6#Nbpr}kl4aQkDYWl^D4tIcB_B-*B zT4W5&?0`=02Wsn4ao!e`S3t>>PHcFX(G#~Ko77Uwh#`8&36TX7#n1pjGXjZr6DU-c zJ%&JH#SLUZG|}Tt#4;Z&8`WqU$YeNBVI)jn>~bz4(+Iv0`!=*?=d4e(1;t8cn4wPWdRtm)b!Qa>AlZRu#@AYvQE z51Q~GBCg;=9O7el!n{!2rDM7T%c#9RIB*ZHx`L7vYyc?M;zt@4{ZV8#V9<{=?o>Sc z<>>m?DDFfacl!}_OMy5lUcW~hbbG{%cK7LM=-nqiatI9y?c3d_b*!izu_@Ea#7OhKfF%~fN*%=zX`@PDT$wl$ zv2bpzm0ce}pe9Z(#5G0A=M*XLV}+%L*@qNnA5mPrk3->h9OhwRRq(MmPU=AsAF#pf zYZBedL=j~FO$O_)`ll_r9klXVK#jmdjMh(DPsFkaYhQXRYbQk5J_@4qx$3SU2BJZ_ za3|X96SNG1Ek0@|X1A2Nl9n)PVYZa=r-jPf!1PZD z!%Y8}5WJDmyRec{^)Y%2gA*~E#?Lm!;23LE-Z~t>5UyviKGx{}GwpO>I;IY2F(%6Q z8;y)T0Y|%0PiQ-n9c@&WlB`A4gU`$Opay(;&W97q(2q9yKV)_t+0If_=Bh!BIov;% znRcXQ0Ly?OMd$zHDKbsvVIF~+U}`YTe>Ije!F)MC&sR;=8vCxyy4;Ky_gNj88vP;= zsNc^Bgke$#xk;d?MBpsw!ynG^wR#+8#z-C1s8~*#Y1^32dOCx)kepGHAg+oBhuxP& z)l9Sfo|QD=b`-#txj;^~12D5X@piEKa&(xy^zm}L#aE!Sxm#n{V(8OMnMSZ37GDkx zDQ)1HXTx4b;+`_`&M$G^iE%#>yABKXB6_<}6S8!{KG-pOAF(kCg!U2%kq#1;Rg8Av z=nS-UH<#ridm-{UA#nZxXXq-xFjn{xu6K}NEKxor3eGf#qr>P&RXvI-(rRrd?2L4` zM43|+f=70<<4(~t8jCS-MjiHLoU{0%HX)b@PMbuM;=HJBX5TU$hN}p>+~RJDoI9V) zZGrwCGBS#~rSX*15p|S2J+mXKmCk^FQO`fo8B9}&b80KPZUbScMX?ERFvdIT&A(&K zF!^;lroDzED9GLtSxuG6EZ2>j2)yJSbt5}Xu3@|n;;3w;tp{)1xtAC{z)q7TMxR5> zwDIr)cpAOYS%9(rEI|@XdfbW*tK-SIvioAUQotZmyOXMJ;x++uULV`NtS1FEGX2FH;US_{b0diypY3dxckBxrAo z!Kp9`t*y5sEXhDZx5i+g*V$9|xHj5KTacthQkgcNUDppzDtv(@0+;c+2lLE6=^PMx zi>_aCD|+eVPMfY((zV%iZPI%jFj5x+C$Z+ z`VQF7SmqtG>qWG0bq)-82$sg*Z!~!J1DM9HO=82H7+-C2K>7D~0nCwGl>2|++Z^&9 z^U0sJ+Z?{p@wz?oJYzv>J9fJ&ME4j-O1{yDD5|{Ci%^bTK8v!s zBOs?ZfMJ#G?}%$H#sUOD3iwfZ?2ELZscHXAY@la6EtI?J=NS#mf6X-PSd*dBVoaKj zZbF5@2d8Ot5DQPE{N042sE8m5V$AVE8yS%jB(usU5~|o&5I`e=YaXB_{)3mFmLoTI7wcYgi^jofx9J)+bLH08*H|I0p8J5aEMLurd5CsJO}XifyI{{ zu%`Z^4iUp~-r@WW1z!$&eW6jG?u&}Tm44)<;NA`L*Ek!u;o<|BTwwQ(+O~#i+h+I1 zy^Txqj&6^*wqNpEQ>ObyQme&w`J(=UDpODSHB}kse3Q*LHNvjzq_!=jX?v$L5%}MF z?ZzcIqvZ>~!(XRwa_w<8r}r+$P*{)qyQ zrZw8aB@H1_O69O?JrVAsc(v(v*mT=b+B}lDf)4SJIG}?f>No|ksSu?VjzqZyJ0x#r z5}d0?$FsS&Vl}xf%97enLt`wJ40H9rLX{IBKn0VlC?|>gog39AE^2}iRLV%B z74bSwWdmZOZ=d*+7ksgkZUYG3&u5d7Z{21j@%yZ853_6ap%ULRF*3f{|Dx zkYkfz8cZl?QLg$r5U_eMl8$=suT(5)!V!gw4R>Mq#5Ie``;EmG`77x0feq1lig6cy z&m&Ynl1HOu990b7Dntu2kHvljlaR_4?DpRZb;#c&`J^Ooqq_1+(pyRR?i8gtAj#i$IC##|-nV

&m`>6Msi0@!yYZ{zTcQ6HjJSt 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 literal 0 HcmV?d00001 diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp new file mode 100644 index 0000000..436e5ec --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp @@ -0,0 +1,168 @@ +#include "Util.h" +#include "Constants.h" +#include "DataStructConst.h" +#include "VolCalibInit.h" +#include "Vect_CPU.h" +#include "Vect_GPU.h" +#include "ParseInput.h" + +unsigned long int +whole_loop_nest ( + real_t* res, + const real_t* strikes, + const real_t s0, + const real_t t, + const real_t alpha, + const real_t nu, + const real_t beta +) { + unsigned int i; + unsigned long int elapsed; + + // arrays: + real_t *a = NULL, *b = NULL, *c = NULL, + *y = NULL, *u = NULL, *v = NULL; + + { // allocate arrays + a = new real_t __attribute__ ((aligned (32))) [OUTER_LOOP_COUNT*NUM_XY]; + b = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + c = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + + y = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + u = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + v = new real_t[OUTER_LOOP_COUNT*NUM_XY]; + } + + // init + whole_loop_nest_init ( s0, t, alpha, nu, beta ); + + // parallel! + for( i=0; i 0 ) { + RWScalars ro_scal; + NordeaArrays cpu_arrs; + oclNordeaArrays ocl_arrs; + + { // init arrays + cpu_arrs.myX = myX; cpu_arrs.myDx = myDx; cpu_arrs.myDxx = myDxx; + cpu_arrs.myY = myY; cpu_arrs.myDy = myDy; cpu_arrs.myDyy = myDyy; + cpu_arrs.timeline = myTimeline; + cpu_arrs.a = a; cpu_arrs.b = b; cpu_arrs.c = c; + cpu_arrs.y = y; cpu_arrs.u = u; cpu_arrs.v = v; + cpu_arrs.res_arr = &myResArr[0]; + } + + { // init scalars + ro_scal.NUM_X = NUM_X; ro_scal.NUM_Y = NUM_Y; ro_scal.NUM_XY = NUM_X * NUM_Y; + ro_scal.alpha = alpha; ro_scal.beta = beta; ro_scal.nu = nu; + } + + { // SAFETY CHECK! + bool is_safe = ( (OUTER_LOOP_COUNT*NUM_X) % NUM_Y == 0 ) && + ( (OUTER_LOOP_COUNT*NUM_Y) % NUM_X == 0 ) && + ( (OUTER_LOOP_COUNT*NUM_X) % WORKGROUP_SIZE == 0 ) && + ( (OUTER_LOOP_COUNT*NUM_Y) % WORKGROUP_SIZE == 0 ) && + ( is_pow2(NUM_X) && is_pow2(NUM_Y) ) && + ( NUM_X % 32 == 0 && NUM_Y % 32 == 0) ; + + assert(is_safe && "NOT SAFE TO PARALLELISE ON GPU!"); + } + + elapsed = runOnGPU ( ro_scal, cpu_arrs, ocl_arrs ); + + for( i=0; i=0; --t_ind) { + iteration_expanded_CPU ( + t_ind, alpha, beta, nu, + a, b, c, y, u, v + ); + } + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + + for( i=0; i datasets/$HIPERMARK_INPUT_NAME/input.data + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data run: cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/lib/include/Constants.h b/benchmarks/CalibVolDiff/lib/include/Constants.h index 8fd8365..c761a64 100644 --- a/benchmarks/CalibVolDiff/lib/include/Constants.h +++ b/benchmarks/CalibVolDiff/lib/include/Constants.h @@ -1,41 +1,61 @@ #ifndef CONSTANTS_H #define CONSTANTS_H -#define WITH_FLOATS 1 - #define REAL3_CT 4 #define TRANSPOSE_UV 1 -#if (WITH_FLOATS) - typedef float REAL; - typedef unsigned int ULONG; +#ifdef REAL_IS_DOUBLE + +/* Some OpenCL implementations require us to define a pragma if we + want to use double-precision numbers. */ +#ifdef __OPENCL_VERSION__ +#pragma OPENCL EXTENSION cl_khr_fp64 : enable +#endif + +typedef double real_t; +#define REAL_FLAG "REAL_IS_DOUBLE" + +#ifdef __OPENCL_VERSION__ +#define real4_t double4 +#define real3_t double3 +#define real2_t double2 +#endif + +#elif REAL_IS_FLOAT + +typedef float real_t; +#define REAL_FLAG "REAL_IS_FLOAT" + +#ifdef __OPENCL_VERSION__ +#define real4_t float4 +#define real3_t float3 +#define real2_t float2 +#endif + #else - #pragma OPENCL EXTENSION cl_khr_fp64: enable - typedef double REAL; - typedef unsigned long ULONG; + +#error "Must set REAL_IS_DOUBLE or REAL_IS_FLOAT." + #endif -#define WARP (1< #include #include @@ -799,14 +800,35 @@ void build_for_GPU( shrLog(stdlog, "Program built 1...\n"); // 7. check errors! + int failed = 0; + cl_build_status status; + if (ciErr1 != CL_SUCCESS) { + failed = 1; + } else { + /* clBuildProgram may return CL_SUCCESS just because the + build was started - it may yet not finish succesfully. */ + do { + sleep(1); + clGetProgramBuildInfo(cpProgram, cdDevices[dev_id], + CL_PROGRAM_BUILD_STATUS, sizeof(status), + &status, NULL); + fprintf(stderr, "status: %d (%d?)\n", status, CL_BUILD_SUCCESS); + } while (status == CL_BUILD_IN_PROGRESS); + + if (status != CL_BUILD_SUCCESS) { + failed = 1; + } + } + + if (true || failed) { // write out standard error, Build Log and PTX, then cleanup and exit shrLog(stdlog, "BUILDING ERROR: %d: %s\n", ciErr1, oclErrorString(ciErr1)); //oclLogBuildInfo(cpProgram, cdDevices[dev_id]); //oclLogPtx(cpProgram, cdDevices[dev_id], ptx_name.c_str()); - if (ciErr1 == CL_BUILD_PROGRAM_FAILURE) { + if (true || ciErr1 == CL_BUILD_PROGRAM_FAILURE) { // Determine the size of the log size_t log_size; clGetProgramBuildInfo(cpProgram, cdDevices[dev_id], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size); diff --git a/lib/include/Util.h b/lib/include/Util.h index 495ca75..9f15844 100644 --- a/lib/include/Util.h +++ b/lib/include/Util.h @@ -15,7 +15,7 @@ #include #endif - +#define STRINGIFY(x) #x #define TIME_RESOLUTION_MICROSECOND #ifdef TIME_RESOLUTION_MICROSECOND diff --git a/lib/platform.mk b/lib/platform.mk new file mode 100644 index 0000000..cb24d21 --- /dev/null +++ b/lib/platform.mk @@ -0,0 +1,28 @@ +# platform specification for benchmarks. Edit as appropriate for your +# platform before running + +# 1 = platform has a GPU +HAVE_GPU = 1 +GPU_DEVICE_ID = 0 + +# GPU warp size. Keep consistent if you use the non-log variant +#GPU_WARP = 32 +GPU_LG_WARP = 5 + +# GPU memory sizes in kilobyte +GPU_LOCAL_MEM = 48 +GPU_CONST_MEM = 64 +GPU_REG_MEM = 64 +# device memory in gigabyte +GPU_DEVICE_MEM= 2 +# ``Optimal'' Amount of Local/Fast Memory Per Thread +GPU_LOCAL_MEM_PER_TH=8 +# Number of GPU cores +GPU_NUM_CORES = 1536 + +# CPU and memory spec. +NCORES = 32 +# in gigabyte +MEMORY = 4 + +export diff --git a/lib/setup.mk b/lib/setup.mk index 096b916..d1a7026 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -23,3 +23,7 @@ else CXXFLAGS = -DENABLE_OPENMP -fopenmp -O3 INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include endif + +CXXFLAGS += -DIMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION_DIR)"' +CXXFLAGS += -DHIPERMARK_BENCHMARK_LIB_DIR='"$(HIPERMARK_BENCHMARK_LIB_DIR)"' +CXXFLAGS += -DHIPERMARK_LIB_DIR='"$(HIPERMARK_LIB_DIR)"' diff --git a/lib/setup_real_type.mk b/lib/setup_real_type.mk new file mode 100644 index 0000000..fef7d3c --- /dev/null +++ b/lib/setup_real_type.mk @@ -0,0 +1,16 @@ +# This makefile provides utility definitions for having either +# REAL_IS_FLOAT or REAL_IS_DOUBLE defined during compilation. This is +# based on the environment variable HIPERMARK_CONFIG_REAL_TYPE, which +# must be defined as a static configuration option. If +# HIPERMARK_CONFIG_REAL_TYPE is not set at all, it will be assumed to +# be 'double' +# +# This makefile fragment appends to CXXFLAGS. + +ifeq ($(HIPERMARK_CONFIG_REAL_TYPE),float) + CXXFLAGS += -DREAL_IS_FLOAT +else ifeq ($(HIPERMARK_CONFIG_REAL_TYPE),double) + CXXFLAGS += -DREAL_IS_DOUBLE +else + CXXFLAGS += -DREAL_IS_DOUBLE +endif From fe10eff4815739aac2ab753d66fd4663dbcf8eb0 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 08:03:10 +0200 Subject: [PATCH 068/122] Add large dataset. --- .../CalibVolDiff/datasets/large/input.json | 6 ++++ .../CalibVolDiff/datasets/large/output.json | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 benchmarks/CalibVolDiff/datasets/large/input.json create mode 100644 benchmarks/CalibVolDiff/datasets/large/output.json diff --git a/benchmarks/CalibVolDiff/datasets/large/input.json b/benchmarks/CalibVolDiff/datasets/large/input.json new file mode 100644 index 0000000..d0db1fc --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/large/input.json @@ -0,0 +1,6 @@ +{ + "outer" : 256, + "num_x" : 256, + "num_y" : 256, + "num_t" : 64 +} diff --git a/benchmarks/CalibVolDiff/datasets/large/output.json b/benchmarks/CalibVolDiff/datasets/large/output.json new file mode 100644 index 0000000..8ea53b5 --- /dev/null +++ b/benchmarks/CalibVolDiff/datasets/large/output.json @@ -0,0 +1,29 @@ +[ 0.029996 , 0.029204 , 0.028803 , 0.028405 , 0.028013 , 0.027626 , 0.027245 , 0.026870 , 0.026500 , + 0.026136 , 0.025778 , 0.025426 , 0.025080 , 0.024739 , 0.024404 , 0.024075 , 0.023751 , 0.023433 , + 0.023120 , 0.022813 , 0.022511 , 0.022214 , 0.021923 , 0.021636 , 0.021355 , 0.021078 , 0.020806 , + 0.020538 , 0.020273 , 0.020014 , 0.019791 , 0.019512 , 0.019270 , 0.019033 , 0.018799 , 0.018568 , + 0.018341 , 0.018117 , 0.017898 , 0.017682 , 0.017470 , 0.017261 , 0.017056 , 0.016855 , 0.016657 , + 0.016463 , 0.016271 , 0.016083 , 0.015898 , 0.015716 , 0.015537 , 0.015361 , 0.015188 , 0.015018 , + 0.014850 , 0.014686 , 0.014523 , 0.014364 , 0.014206 , 0.014052 , 0.013899 , 0.013749 , 0.013601 , + 0.013456 , 0.013312 , 0.013171 , 0.013032 , 0.012895 , 0.012760 , 0.012626 , 0.012495 , 0.012365 , + 0.012238 , 0.012112 , 0.011988 , 0.011865 , 0.011744 , 0.011625 , 0.011508 , 0.011392 , 0.011277 , + 0.011164 , 0.011053 , 0.010942 , 0.010834 , 0.010726 , 0.010620 , 0.010515 , 0.010412 , 0.010309 , + 0.010208 , 0.010108 , 0.010010 , 0.009912 , 0.009815 , 0.009720 , 0.009626 , 0.009533 , 0.009440 , + 0.009349 , 0.009259 , 0.009170 , 0.009081 , 0.008994 , 0.008908 , 0.008822 , 0.008737 , 0.008653 , + 0.008570 , 0.008488 , 0.008407 , 0.008326 , 0.008246 , 0.008167 , 0.008089 , 0.008011 , 0.007934 , + 0.007858 , 0.007782 , 0.007707 , 0.007633 , 0.007559 , 0.007487 , 0.007414 , 0.007342 , 0.007271 , + 0.007201 , 0.007131 , 0.007061 , 0.006993 , 0.006924 , 0.006856 , 0.006789 , 0.006722 , 0.006656 , + 0.006590 , 0.006525 , 0.006460 , 0.006396 , 0.006332 , 0.006268 , 0.006205 , 0.006143 , 0.006081 , + 0.006019 , 0.005958 , 0.005897 , 0.005836 , 0.005776 , 0.005716 , 0.005657 , 0.005598 , 0.005539 , + 0.005481 , 0.005423 , 0.005365 , 0.005308 , 0.005251 , 0.005194 , 0.005138 , 0.005081 , 0.005026 , + 0.004970 , 0.004915 , 0.004860 , 0.004806 , 0.004751 , 0.004697 , 0.004643 , 0.004590 , 0.004536 , + 0.004483 , 0.004431 , 0.004378 , 0.004326 , 0.004274 , 0.004222 , 0.004170 , 0.004119 , 0.004068 , + 0.004017 , 0.003966 , 0.003915 , 0.003865 , 0.003815 , 0.003765 , 0.003715 , 0.003665 , 0.003616 , + 0.003566 , 0.003517 , 0.003468 , 0.003420 , 0.003371 , 0.003323 , 0.003274 , 0.003226 , 0.003178 , + 0.003130 , 0.003083 , 0.003035 , 0.002988 , 0.002940 , 0.002893 , 0.002846 , 0.002799 , 0.002752 , + 0.002706 , 0.002659 , 0.002613 , 0.002566 , 0.002520 , 0.002474 , 0.002428 , 0.002382 , 0.002337 , + 0.002291 , 0.002245 , 0.002200 , 0.002154 , 0.002109 , 0.002064 , 0.002019 , 0.001973 , 0.001928 , + 0.001884 , 0.001839 , 0.001794 , 0.001749 , 0.001705 , 0.001660 , 0.001616 , 0.001571 , 0.001527 , + 0.001482 , 0.001438 , 0.001394 , 0.001350 , 0.001306 , 0.001262 , 0.001218 , 0.001174 , 0.001130 , + 0.001086 , 0.001042 , 0.000998 , 0.000954 , 0.000911 , 0.000867 , 0.000823 , 0.000780 , 0.000736 , + 0.000692 , 0.000649 , 0.000605 , 0.000562 ] From e2fa3f63534351a2d7c75d27f8ac2246ab96b607 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 08:05:48 +0200 Subject: [PATCH 069/122] Enable OpenMP thread count configuration on more implementations. --- .../CalibVolDiff/implementations/cpp_openclmp_all/Makefile | 3 ++- .../cpp_openclmp_all/dynamic_configuration_template.json | 1 + .../CalibVolDiff/implementations/cpp_openclmp_outer/Makefile | 3 ++- .../cpp_openclmp_outer/dynamic_configuration_template.json | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/dynamic_configuration_template.json create mode 100644 benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/dynamic_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile index d29cf70..d7c9dec 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile @@ -51,4 +51,5 @@ data: $(HIPERMARK_INPUT) $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/dynamic_configuration_template.json b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/dynamic_configuration_template.json new file mode 100644 index 0000000..14298aa --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/dynamic_configuration_template.json @@ -0,0 +1 @@ +{"NUM_THREADS": [1,2,3,4]} diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile index 51c9586..55cb40f 100644 --- a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile @@ -51,4 +51,5 @@ data: $(HIPERMARK_INPUT) $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/dynamic_configuration_template.json b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/dynamic_configuration_template.json new file mode 100644 index 0000000..14298aa --- /dev/null +++ b/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/dynamic_configuration_template.json @@ -0,0 +1 @@ +{"NUM_THREADS": [1,2,3,4]} From 58497321512dd323df232d689b7ada4bd44e2efc Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 09:36:52 +0200 Subject: [PATCH 070/122] Rename CppOpenMP to cpp_openmp --- .../{CppOpenMP => cpp_openmp}/GenAlgFlat.h | 0 .../{CppOpenMP => cpp_openmp}/Makefile | 0 .../{CppOpenMP => cpp_openmp}/SwapCalib | Bin .../{CppOpenMP => cpp_openmp}/SwapCalib.cpp | 0 .../{CppOpenMP => cpp_openmp}/UtilCPU.h | 0 .../{CppOpenMP => cpp_openmp}/instantiate | 0 .../{CppOpenMP => cpp_openmp}/instantiate_data | 0 .../implementations/{CppOpenMP => cpp_openmp}/run | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/GenAlgFlat.h (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/Makefile (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/SwapCalib (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/SwapCalib.cpp (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/UtilCPU.h (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/instantiate (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/instantiate_data (100%) rename benchmarks/InterestCalib/implementations/{CppOpenMP => cpp_openmp}/run (100%) diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/cpp_openmp/GenAlgFlat.h similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/GenAlgFlat.h rename to benchmarks/InterestCalib/implementations/cpp_openmp/GenAlgFlat.h diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/Makefile b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/Makefile rename to benchmarks/InterestCalib/implementations/cpp_openmp/Makefile diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib rename to benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/SwapCalib.cpp rename to benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/UtilCPU.h b/benchmarks/InterestCalib/implementations/cpp_openmp/UtilCPU.h similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/UtilCPU.h rename to benchmarks/InterestCalib/implementations/cpp_openmp/UtilCPU.h diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate b/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/instantiate rename to benchmarks/InterestCalib/implementations/cpp_openmp/instantiate diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data b/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate_data similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/instantiate_data rename to benchmarks/InterestCalib/implementations/cpp_openmp/instantiate_data diff --git a/benchmarks/InterestCalib/implementations/CppOpenMP/run b/benchmarks/InterestCalib/implementations/cpp_openmp/run similarity index 100% rename from benchmarks/InterestCalib/implementations/CppOpenMP/run rename to benchmarks/InterestCalib/implementations/cpp_openmp/run From 487499693cc2f3d6dbffd927b9ad3f9b0261bc05 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 09:37:55 +0200 Subject: [PATCH 071/122] Rename CalibVolDiff to LocVolCalib. --- benchmarks/{CalibVolDiff => LocVolCalib}/README.txt | 0 benchmarks/{CalibVolDiff => LocVolCalib}/ToDo.txt | 0 .../datasets/large/input.json | 0 .../datasets/large/output.json | 0 .../datasets/medium/input.json | 0 .../datasets/medium/output.json | 0 .../datasets/small/input.json | 0 .../datasets/small/output.json | 0 .../cpp_openclmp_all/CrankNicolson.cl | 0 .../implementations/cpp_openclmp_all/Makefile | 0 .../cpp_openclmp_all/PrepareKernels.h | 0 .../implementations/cpp_openclmp_all/Vect_CPU.h | 0 .../implementations/cpp_openclmp_all/Vect_GPU.h | 0 .../cpp_openclmp_all/VolCalibAll.cpp | 0 .../implementations/cpp_openclmp_all/VolCalibInit.h | 0 .../dynamic_configuration_template.json | 0 .../static_configuration_template.json | 0 .../cpp_openclmp_outer/CrankNicolson.cl | 0 .../implementations/cpp_openclmp_outer/Makefile | 0 .../cpp_openclmp_outer/PrepareKernels.h | 0 .../implementations/cpp_openclmp_outer/Vect_CPU.h | 0 .../implementations/cpp_openclmp_outer/Vect_GPU.h | 0 .../cpp_openclmp_outer/VolCalibInit.h | 0 .../cpp_openclmp_outer/VolCalibOuter | Bin .../cpp_openclmp_outer/VolCalibOuter.cpp | 0 .../dynamic_configuration_template.json | 0 .../static_configuration_template.json | 0 .../implementations/cpp_openmp_naive/Makefile | 0 .../cpp_openmp_naive/VolCalibOrig.cpp | 0 .../dynamic_configuration_template.json | 0 .../static_configuration_template.json | 0 .../implementations/cpp_sequential/Makefile | 0 .../implementations/cpp_sequential/VolCalibOrig.cpp | 0 .../static_configuration_template.json | 0 .../implementations/haskell_lh/Makefile | 0 .../implementations/haskell_lh/VolCalib.hs | 0 .../lib/include/Constants.h | 0 .../lib/include/DataStructConst.h | 0 .../lib/include/ParPrefixUtil.h | 0 .../lib/include/ParseInput.h | 0 40 files changed, 0 insertions(+), 0 deletions(-) rename benchmarks/{CalibVolDiff => LocVolCalib}/README.txt (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/ToDo.txt (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/datasets/large/input.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/datasets/large/output.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/datasets/medium/input.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/datasets/medium/output.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/datasets/small/input.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/datasets/small/output.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/CrankNicolson.cl (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/Makefile (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/PrepareKernels.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/Vect_CPU.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/Vect_GPU.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/VolCalibAll.cpp (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/VolCalibInit.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/dynamic_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_all/static_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/CrankNicolson.cl (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/Makefile (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/PrepareKernels.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/Vect_CPU.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/Vect_GPU.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/VolCalibInit.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/VolCalibOuter (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/VolCalibOuter.cpp (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/dynamic_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openclmp_outer/static_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openmp_naive/Makefile (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openmp_naive/VolCalibOrig.cpp (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openmp_naive/dynamic_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_openmp_naive/static_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_sequential/Makefile (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_sequential/VolCalibOrig.cpp (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/cpp_sequential/static_configuration_template.json (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/haskell_lh/Makefile (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/implementations/haskell_lh/VolCalib.hs (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/lib/include/Constants.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/lib/include/DataStructConst.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/lib/include/ParPrefixUtil.h (100%) rename benchmarks/{CalibVolDiff => LocVolCalib}/lib/include/ParseInput.h (100%) diff --git a/benchmarks/CalibVolDiff/README.txt b/benchmarks/LocVolCalib/README.txt similarity index 100% rename from benchmarks/CalibVolDiff/README.txt rename to benchmarks/LocVolCalib/README.txt diff --git a/benchmarks/CalibVolDiff/ToDo.txt b/benchmarks/LocVolCalib/ToDo.txt similarity index 100% rename from benchmarks/CalibVolDiff/ToDo.txt rename to benchmarks/LocVolCalib/ToDo.txt diff --git a/benchmarks/CalibVolDiff/datasets/large/input.json b/benchmarks/LocVolCalib/datasets/large/input.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/large/input.json rename to benchmarks/LocVolCalib/datasets/large/input.json diff --git a/benchmarks/CalibVolDiff/datasets/large/output.json b/benchmarks/LocVolCalib/datasets/large/output.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/large/output.json rename to benchmarks/LocVolCalib/datasets/large/output.json diff --git a/benchmarks/CalibVolDiff/datasets/medium/input.json b/benchmarks/LocVolCalib/datasets/medium/input.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/medium/input.json rename to benchmarks/LocVolCalib/datasets/medium/input.json diff --git a/benchmarks/CalibVolDiff/datasets/medium/output.json b/benchmarks/LocVolCalib/datasets/medium/output.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/medium/output.json rename to benchmarks/LocVolCalib/datasets/medium/output.json diff --git a/benchmarks/CalibVolDiff/datasets/small/input.json b/benchmarks/LocVolCalib/datasets/small/input.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/small/input.json rename to benchmarks/LocVolCalib/datasets/small/input.json diff --git a/benchmarks/CalibVolDiff/datasets/small/output.json b/benchmarks/LocVolCalib/datasets/small/output.json similarity index 100% rename from benchmarks/CalibVolDiff/datasets/small/output.json rename to benchmarks/LocVolCalib/datasets/small/output.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/CrankNicolson.cl similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/CrankNicolson.cl rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/CrankNicolson.cl diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Makefile rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/PrepareKernels.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/PrepareKernels.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/PrepareKernels.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_CPU.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Vect_CPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_CPU.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Vect_CPU.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_GPU.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Vect_GPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/Vect_GPU.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Vect_GPU.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibAll.cpp rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibInit.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibInit.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/VolCalibInit.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibInit.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/dynamic_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/dynamic_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/dynamic_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/dynamic_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/static_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/static_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_all/static_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_all/static_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/CrankNicolson.cl similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/CrankNicolson.cl rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/CrankNicolson.cl diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Makefile rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/PrepareKernels.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/PrepareKernels.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/PrepareKernels.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_CPU.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Vect_CPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_CPU.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Vect_CPU.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_GPU.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Vect_GPU.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/Vect_GPU.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Vect_GPU.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibInit.h similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibInit.h rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibInit.h diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/VolCalibOuter.cpp rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/dynamic_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/dynamic_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/dynamic_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/dynamic_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/static_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/static_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openclmp_outer/static_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/static_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/Makefile rename to benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/VolCalibOrig.cpp rename to benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/dynamic_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/dynamic_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_openmp_naive/dynamic_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/static_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_openmp_naive/static_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_openmp_naive/static_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_sequential/Makefile rename to benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_sequential/VolCalibOrig.cpp rename to benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp diff --git a/benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_sequential/static_configuration_template.json similarity index 100% rename from benchmarks/CalibVolDiff/implementations/cpp_sequential/static_configuration_template.json rename to benchmarks/LocVolCalib/implementations/cpp_sequential/static_configuration_template.json diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile similarity index 100% rename from benchmarks/CalibVolDiff/implementations/haskell_lh/Makefile rename to benchmarks/LocVolCalib/implementations/haskell_lh/Makefile diff --git a/benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs b/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs similarity index 100% rename from benchmarks/CalibVolDiff/implementations/haskell_lh/VolCalib.hs rename to benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs diff --git a/benchmarks/CalibVolDiff/lib/include/Constants.h b/benchmarks/LocVolCalib/lib/include/Constants.h similarity index 100% rename from benchmarks/CalibVolDiff/lib/include/Constants.h rename to benchmarks/LocVolCalib/lib/include/Constants.h diff --git a/benchmarks/CalibVolDiff/lib/include/DataStructConst.h b/benchmarks/LocVolCalib/lib/include/DataStructConst.h similarity index 100% rename from benchmarks/CalibVolDiff/lib/include/DataStructConst.h rename to benchmarks/LocVolCalib/lib/include/DataStructConst.h diff --git a/benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h b/benchmarks/LocVolCalib/lib/include/ParPrefixUtil.h similarity index 100% rename from benchmarks/CalibVolDiff/lib/include/ParPrefixUtil.h rename to benchmarks/LocVolCalib/lib/include/ParPrefixUtil.h diff --git a/benchmarks/CalibVolDiff/lib/include/ParseInput.h b/benchmarks/LocVolCalib/lib/include/ParseInput.h similarity index 100% rename from benchmarks/CalibVolDiff/lib/include/ParseInput.h rename to benchmarks/LocVolCalib/lib/include/ParseInput.h From ee6656dfc176934f4701d924406677c8a86fbc80 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 10:01:09 +0200 Subject: [PATCH 072/122] Move real_t stuff into its own header. --- .../LocVolCalib/lib/include/Constants.h | 36 +----------------- lib/include/real.h | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 lib/include/real.h diff --git a/benchmarks/LocVolCalib/lib/include/Constants.h b/benchmarks/LocVolCalib/lib/include/Constants.h index c761a64..3df4577 100644 --- a/benchmarks/LocVolCalib/lib/include/Constants.h +++ b/benchmarks/LocVolCalib/lib/include/Constants.h @@ -1,43 +1,11 @@ #ifndef CONSTANTS_H #define CONSTANTS_H +#include "real.h" + #define REAL3_CT 4 #define TRANSPOSE_UV 1 -#ifdef REAL_IS_DOUBLE - -/* Some OpenCL implementations require us to define a pragma if we - want to use double-precision numbers. */ -#ifdef __OPENCL_VERSION__ -#pragma OPENCL EXTENSION cl_khr_fp64 : enable -#endif - -typedef double real_t; -#define REAL_FLAG "REAL_IS_DOUBLE" - -#ifdef __OPENCL_VERSION__ -#define real4_t double4 -#define real3_t double3 -#define real2_t double2 -#endif - -#elif REAL_IS_FLOAT - -typedef float real_t; -#define REAL_FLAG "REAL_IS_FLOAT" - -#ifdef __OPENCL_VERSION__ -#define real4_t float4 -#define real3_t float3 -#define real2_t float2 -#endif - -#else - -#error "Must set REAL_IS_DOUBLE or REAL_IS_FLOAT." - -#endif - #define WARP (1< Date: Fri, 21 Aug 2015 10:01:20 +0200 Subject: [PATCH 073/122] Add cpp_sequential implementation of InterestCalib. --- .../implementations/cpp_openmp/GenAlgFlat.h | 50 +-- .../implementations/cpp_openmp/SwapCalib.cpp | 6 +- .../cpp_sequential/EvalGenomeOrig.h | 155 +++++++++ .../implementations/cpp_sequential/G2PPorig.h | 176 ++++++++++ .../cpp_sequential/GenAlgFlat.h | 280 +++++++++++++++ .../implementations/cpp_sequential/Genome.h | 238 +++++++++++++ .../implementations/cpp_sequential/Makefile | 31 ++ .../cpp_sequential/SwapCalib.cpp | 61 ++++ .../implementations/cpp_sequential/UtilCPU.h | 48 +++ .../static_configuration_template.json | 3 + .../InterestCalib/lib/include/Constants.h | 46 +-- .../InterestCalib/lib/include/KerConsts.h | 7 +- .../InterestCalib/lib/include/tmp/Constants.h | 42 --- .../lib/include/tmp/DataStructConst.h | 91 ----- .../InterestCalib/lib/include/tmp/G2PP.h | 326 ------------------ 15 files changed, 1045 insertions(+), 515 deletions(-) create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/EvalGenomeOrig.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/Makefile create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_sequential/static_configuration_template.json delete mode 100644 benchmarks/InterestCalib/lib/include/tmp/Constants.h delete mode 100644 benchmarks/InterestCalib/lib/include/tmp/DataStructConst.h delete mode 100644 benchmarks/InterestCalib/lib/include/tmp/G2PP.h diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/cpp_openmp/GenAlgFlat.h index 4dac1f3..257cd0d 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/GenAlgFlat.h +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/GenAlgFlat.h @@ -11,14 +11,14 @@ /** * Printing Swaption / Calibrated Price / Black Price / RMS - * The result is an array REAL[NUM_SWAP_QUOTES, 3] recording + * The result is an array real_t[NUM_SWAP_QUOTES, 3] recording * for each swaption the calibrated price, the black price * and the percentagewise difference between the two. */ -REAL* makeSummary(uint winner, CpuArrays& arrs) { - REAL* res = (REAL*) malloc( 3*NUM_SWAP_QUOTES*sizeof(REAL) ); +real_t* makeSummary(uint winner, CpuArrays& arrs) { + real_t* res = (real_t*) malloc( 3*NUM_SWAP_QUOTES*sizeof(real_t) ); - REAL rms = 0.0; + real_t rms = 0.0; fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", @@ -27,9 +27,9 @@ REAL* makeSummary(uint winner, CpuArrays& arrs) { fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { - REAL black_price = arrs.get_quote(winner)[i]; - REAL calib_price = arrs.get_price(winner)[i]; - REAL err_ratio = (calib_price - black_price) / black_price; + real_t black_price = arrs.get_quote(winner)[i]; + real_t calib_price = arrs.get_price(winner)[i]; + real_t err_ratio = (calib_price - black_price) / black_price; res[3*i + 0] = 10000.0*calib_price; res[3*i + 1] = 10000.0*black_price; @@ -54,7 +54,7 @@ REAL* makeSummary(uint winner, CpuArrays& arrs) { * scans the logLik array and fill in the index and likelihood * of the best genome. */ -void find_best(const REAL* logLik, int& best_ind, REAL& best_lik) { +void find_best(const real_t* logLik, int& best_ind, real_t& best_lik) { bool sanity = true; best_lik = -INFINITY; @@ -63,7 +63,7 @@ void find_best(const REAL* logLik, int& best_ind, REAL& best_lik) { // this is in fact a reduction, but POP_SIZE is // not big enough to warrant a parallel execution. for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX - REAL val = logLik[i]; + real_t val = logLik[i]; sanity = !( isnan(val) || isinf(val) ); assert( sanity && "val is NaN in find_best" ); @@ -72,10 +72,10 @@ void find_best(const REAL* logLik, int& best_ind, REAL& best_lik) { } } -Move_Type selectMoveType(REAL move_selected) { +Move_Type selectMoveType(real_t move_selected) { Move_Type move_type = NONE; - REAL prob; + real_t prob; Move_Type type; UINT k = 0; do { @@ -102,19 +102,19 @@ Move_Type selectMoveType(REAL move_selected) { * price, the black price and the percentage * difference between the two. */ -REAL* mainKernelCPU(REAL& wg_a, - REAL& wg_b, - REAL& wg_sigma, - REAL& wg_nu, - REAL& wg_rho, - REAL& wg_logLik +real_t* mainKernelCPU(real_t& wg_a, + real_t& wg_b, + real_t& wg_sigma, + real_t& wg_nu, + real_t& wg_rho, + real_t& wg_logLik ) { uint FLAT_SZ; short* shape = getIregShapeAdjusted( LWG_EG, FLAT_SZ ); int * start_inds = getStartInd( FLAT_SZ, shape, NUM_SWAP_QUOTES ); CpuArrays cpu_arrs(FLAT_SZ, shape); - REAL *g_a, *g_b, *g_rho, *g_nu, *g_sigma, *logLik, *bf_rat; + real_t *g_a, *g_b, *g_rho, *g_nu, *g_sigma, *logLik, *bf_rat; { // getting the cpu arrays g_a = cpu_arrs.get_a (); g_b = cpu_arrs.get_b (); @@ -131,7 +131,7 @@ REAL* mainKernelCPU(REAL& wg_a, // initialized the genomes with random numbers inside // their acceptable bounds => requires 5*POP_SIZE randoms for( int i = 0; i < POP_SIZE; i++ ) { - REAL r01, tmp; + real_t r01, tmp; r01 = getRandRandNorm(); tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; @@ -177,7 +177,7 @@ REAL* mainKernelCPU(REAL& wg_a, // select which move to perform. // Note: this block can also be a loop (in fixed order) // over the various move types - REAL move_selected = getRandUnifNorm(); + real_t move_selected = getRandUnifNorm(); Move_Type move_type = selectMoveType(move_selected); if ( move_type == DIMS_ALL ) { @@ -214,11 +214,11 @@ REAL* mainKernelCPU(REAL& wg_a, // obtained by mutating/crossover of the individual. for ( int i = 0; i < POP_SIZE; i++ ) { // parallel // Metropolis: get a random U[0,1) for each candidate - REAL rand = getRandUnifNorm(); + real_t rand = getRandUnifNorm(); // selection: dimensions considered independent // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) - REAL acceptance = std::min( 1.0, exp( logLik[i+POP_SIZE] - logLik[i] ) * bf_rat[i] ); + real_t acceptance = std::min( 1.0, exp( logLik[i+POP_SIZE] - logLik[i] ) * bf_rat[i] ); // if acceptance criterion is met then p->p' else does nothing if ( rand < acceptance ) accept( i, g_a, g_b, g_rho, g_nu, g_sigma, logLik ); @@ -226,16 +226,16 @@ REAL* mainKernelCPU(REAL& wg_a, // print best candidate for the current iteration: if ( (j % 16) == 0 ){ - int best_ind; REAL best_lik; + int best_ind; real_t best_lik; find_best(logLik, best_ind, best_lik); fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", j, best_lik, best_ind ); } } - REAL* result; + real_t* result; { // print best candidate for the current iteration: - int best_ind; REAL best_lik; + int best_ind; real_t best_lik; find_best(logLik, best_ind, best_lik); // recompute the calibrated price and the black price! diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp index 948bb78..192c7e2 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp @@ -16,9 +16,9 @@ int main() { - REAL wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, - wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; - REAL* calib_arr = NULL; + real_t wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, + wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; + real_t* calib_arr = NULL; printf("\n// Running Original (CPU Parallel) Swaption-Calibration Benchmark\n"); diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/EvalGenomeOrig.h b/benchmarks/InterestCalib/implementations/cpp_sequential/EvalGenomeOrig.h new file mode 100644 index 0000000..a315ca4 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/EvalGenomeOrig.h @@ -0,0 +1,155 @@ +#ifndef EVAL_GENOME_INLINED +#define EVAL_GENOME_INLINED + +#include "Constants.h" +#include "GenAlgUtil.h" +#include "G2PP.h" +#include "G2PPorig.h" + + +/** + * MOST IMPORTANTLY: GENOME EVALUATION By Pricer of Swaption & BLACK PRICE + */ +void eval_genome_new ( + const real_t& a, + const real_t& b, + const real_t& rho, + const real_t& nu, + const real_t& sigma, + const real_t* swaption, + IntermElem* tmp_arrs, + real_t& new_quote, // output + real_t& new_price // output +) { + bool sanity = true; + + const real_t swap_freq = swaption[1]; + const real_t maturity = add_years( TODAY, swaption[0] ); + const UINT n_schedi = static_cast(12.0 * swaption[2] / swap_freq); + const real_t tmat0 = date_act_365( maturity, TODAY ); + + real_t strike; + { // BLACK PRICE computation + real_t lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; + + for(UINT i = 0; i < n_schedi; i++) { // reduce o map + // Map computes a1 and a2 (depends on i) + const real_t a1 = add_months( maturity, swap_freq*i ); + const real_t a2 = add_months( a1, swap_freq ); + + // Reduction( lvl: +, t0 : min, tn : max ) + lvl += zc(a2) * date_act_365(a2, a1); + t0 = std::min(t0, a1); + tn = std::max(tn, a2); + } + + strike = ( zc(t0) - zc(tn) ) / lvl; + const real_t d1 = 0.5 * swaption[3] * tmat0; + new_quote = lvl * strike * ( uGaussian_P(d1) - uGaussian_P(-d1) ); + } // END BLACK PRICE + + { // PRICER OF SWAPTION COMPUTATION + real_t v0_mat, dummy1, dummy2; + bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); +// + const real_t mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); + const real_t muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); +// + const real_t zc_mat = zc(maturity); +// + const real_t sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); + const real_t sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); + const real_t rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); + const real_t sigmax = sigma * sqrt_bfun_a; + const real_t sigmay = nu * sqrt_bfun_b; + + const real_t rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel + const real_t rhoxycs = sqrt( rhoxyc ); // used in reduction kernel + const real_t sigmay_rhoxycs = sigmay * rhoxycs; + const real_t t4 = (rhoxy * sigmay) / sigmax; + + for( UINT i = 0; i < n_schedi; i++ ) { + const real_t beg_date = add_months( maturity, swap_freq*i ); //scheduleix[i]; + const real_t end_date = add_months( beg_date, swap_freq ); //scheduleiy[i]; + const real_t res = date_act_365( end_date, beg_date ) * strike; + + const real_t cii = ( i == n_schedi-1 ) ? 1.0 + res : res; + + real_t v0_end, vt_end, baii, bbii, date_tod1, date_tod2; + date_tod1 = date_act_365(end_date, TODAY); + bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); + date_tod2 = date_act_365(end_date, maturity); + bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); + + const real_t expo_aici = 0.5 * (vt_end - v0_end + v0_mat); + const real_t fact_aici = cii * zc(end_date) / zc_mat; + tmp_arrs[i].ci = fact_aici; // reuse the space to hold the factor of t1_cs + tmp_arrs[i].t1_cs = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; + // hold only the exponent of the original t1_cs; + + tmp_arrs[i].bai = baii; + tmp_arrs[i].bbi = bbii; + tmp_arrs[i].aici = fact_aici * exp( expo_aici ); + tmp_arrs[i].log_aici = log( fact_aici ) + expo_aici; + tmp_arrs[i].scale = - ( baii + bbii * t4 ); + + sanity = ! ( isinf(tmp_arrs[i].aici) || isnan(tmp_arrs[i].aici) ); + assert(sanity && "Nan aici in pricer of swaption. Exiting!\n"); + } + + const real_t eps = 0.5 * sigmax; + + const real_t f = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + mux, muy, tmp_arrs, mux ); + + const real_t g = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + mux, muy, tmp_arrs, mux + eps ); + + const real_t h = exactYhatOrig( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + mux, muy, tmp_arrs, mux - eps ); + + const real_t df = 0.5 * ( g - h ) / eps; + + const real_t sqrt2sigmax = sqrt(2.0) * sigmax;; + const real_t t2 = rhoxy / (sigmax*rhoxycs);; + + real_t accum = 0.0; + + for( UINT j = 0; j < NUM_HERMITE; j++ ) { + const real_t x_quad = HermiteCoeffs [j]; + const real_t w_quad = HermiteWeights[j]; + + const real_t x = sqrt2sigmax * x_quad + mux; + const real_t yhat_x = f + df*(x - mux); + const real_t h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); + + real_t accum1 = 0.0; + for( UINT i = 0; i < n_schedi; i++ ) { + const real_t h2 = h1 + tmp_arrs[i].bbi * sigmay_rhoxycs; + + const real_t expo_aici = tmp_arrs[i].t1_cs + tmp_arrs[i].scale*x; + const real_t fact_aici = tmp_arrs[i].ci; + const real_t expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); + accum1 += fact_aici * expo_part; + } + + sanity = ! ( isnan(accum1) || isinf(accum1) ); + assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); + + real_t tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; + const real_t t1 = exp( - 0.5 * tmp * tmp ); + + accum += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); + } + + sanity = ! ( isnan(accum) || isinf(accum) ); + assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); + + new_price = zc_mat * ( accum / sqrt( PI ) ); + } +} + + + +#endif // end ifndef EVAL_GENOME_INLINED + diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h b/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h new file mode 100644 index 0000000..5f324a4 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h @@ -0,0 +1,176 @@ +#ifndef G2PPORIG +#define G2PPORIG + +#include "Constants.h" +#include "Date.h" +#include "MathModule.h" +#include "G2ppUtil.h" + +#include "GenAlgUtil.h" + +REAL to_solve_orig( const UINT& N, + const IntermElem* tmp_arrs, + const REAL& yhat ) { + REAL accum = 0.0; + for( UINT i = 0; i < N; i++ ) { + accum += tmp_arrs[i].hat_scale * exp( - tmp_arrs[i].bbi * yhat ); + } + return accum - 1.0; +} + +////////////////////////// +// Root finder +////////////////////////// + +void rootFinding_Brent_orig ( + const UINT& N, + IntermElem* tmp_arrs, + const REAL& lb, + const REAL& ub, + const REAL& toll, + const UINT& it_mx, + REAL& root, // result + UINT& it, + REAL& fb +) { + const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; + const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; + + REAL a = lb, b = ub; + + REAL fa = to_solve_orig(N, tmp_arrs, a); + fb = to_solve_orig(N, tmp_arrs, b); + + if( fa*fb >= 0.0 ) { + root = 0.0; it = 0; + if ( a >= 0.0 ) fb = INFTY; + else fb = -INFTY; + return; + } + + if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } + + REAL c = a, fc = fa; + bool mflag = true; + REAL d = 0.0; + it = 0; + + for( UINT i = 0; i < iter_max; i++ ) { + if ( fb != 0.0 && fabs(b-a) >= tol ) { + REAL s; + if( fa == fc || fb == fc ) { + s = b - fb * (b - a) / (fb - fa); + } else { + REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); + REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); + REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); + s = s1 + s2 + s3; + } + + if ( ( (3.0 * a + b) /4.0 > s || s > b) || + ( mflag && fabs(b-c)/2.0 <= fabs(s-b) ) || + ( !mflag && fabs(c-d)/2.0 <= fabs(s-b) ) || + ( mflag && fabs(b-c) <= fabs(tol) ) || + ( !mflag && fabs(c-d) <= fabs(tol) ) ) { + mflag = true; + s = (a + b) / 2.0; + } else { + mflag = false; + } + + REAL fs = to_solve_orig(N, tmp_arrs, s); + + // d is assigned for the first time here: + // it's not used above because mflag is set + d = c; + c = b; fc = fb; + + if( fa*fs < 0.0 ) { b = s; fb = fs; } + else { a = s; fa = fs; } + + if( fabs(fa) < fabs(fb) ) { + REAL tmp; + tmp = a; a = b; b = tmp; + tmp = fa; fa = fb; fb = tmp; + } + + // reporting non-convergence! + if(i == iter_max-1) { + printf("# ERROR: Brent method not converged, error: %f %f %d\n\n", b, fb, i); + } + + it = i; + } + } + + root = b; + + //return BrentRes(b, it, fb); +} + +REAL exactYhatOrig( + const UINT& n_schedi, + + const REAL& b, // scals begins + const REAL& sigmax, + const REAL& sigmay, + const REAL& rhoxy, + const REAL& rhoxyc, + const REAL& rhoxycs, + const REAL& mux, + const REAL& muy, // scals ends + IntermElem* tmp_arrs, + + const REAL& x // output +) { + // ugaussian_Pinv(k)=1.0e~4 + const REAL k = - 3.71901648545568; + + REAL up = 0.0, lo = -INFTY; + for( UINT i = 0; i < n_schedi; i++ ) { + REAL baix = tmp_arrs[i].bai * x; + + REAL up_term = tmp_arrs[i].aici * exp( -baix ); + tmp_arrs[i].hat_scale = up_term; + up += up_term; + lo = std::max( lo, ( tmp_arrs[i].log_aici - baix ) / tmp_arrs[i].bbi ); + } + +// CHECKING uplo!!!! + + const REAL log_s = log(up); + REAL tmp = log_s / tmp_arrs[n_schedi-1].bbi; + + if ( tmp <= 0.0 ) { + up = tmp; + } else { + tmp = log_s / tmp_arrs[0].bbi; + if ( 0.0 <= tmp ) up = tmp; + else up = - INFTY; + } + + const REAL yl = lo - EPS; + const REAL yu = up + EPS; + + const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; + const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; + + REAL res; + if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS + else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) + else { + const REAL root_lb = std::max( yl, y0 ); + const REAL root_ub = std::min( yu, y1 ); + + REAL root, error; UINT iter; + rootFinding_Brent_orig(n_schedi, tmp_arrs, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); + //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); + + res = ( error == -INFTY ) ? y0 - 1.0 : ( error == INFTY ) ? y1 + 1.0 : root; + } + + return res; +} + + +#endif // ifndef G2PP diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h new file mode 100644 index 0000000..b8d3bde --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/GenAlgFlat.h @@ -0,0 +1,280 @@ +#ifndef GEN_ALG_FLAT +#define GEN_ALG_FLAT + +using namespace std; + +#include "Constants.h" +#include "GenAlgUtil.h" +#include "Genome.h" +#include "UtilCPU.h" +#include "EvalGenomeOrig.h" + + +/** + * Printing Swaption / Calibrated Price / Black Price / RMS + * The result is an array real_t[NUM_SWAP_QUOTES, 3] recording + * for each swaption the calibrated price, the black price + * and the percentagewise difference between the two. + */ +void makeSummary( const int winner, + const Genome& wgene, + const real_t* new_quote, + const real_t* new_price, + real_t* result // output + ) { + real_t rms = 0.0; + + fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); + fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", + wgene.a, wgene.b, wgene.sigma, wgene.nu, wgene.rho, wgene.logLik ); + fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); + + for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { + real_t black_price = new_quote[i]; + real_t calib_price = new_price[i]; + real_t err_ratio = (calib_price - black_price) / black_price; + + result[3*i + 0] = 10000.0*calib_price; + result[3*i + 1] = 10000.0*black_price; + result[3*i + 2] = 100.0*fabs(err_ratio); + + rms += err_ratio * err_ratio; + + fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", + i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], + result[3*i + 0], result[3*i + 1], result[3*i + 2] ); + } + + rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); + fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); +} + + +/** + * Utility function: find the genome with the best likelihood: + * scans the logLik array and fill in the index and likelihood + * of the best genome. + */ +void find_best(const Genome* genomes, int& best_ind, real_t& best_lik) { + bool sanity = true; + + best_lik = -INFINITY; + best_ind = 0; + + // this is in fact a reduction, but POP_SIZE is + // not big enough to warrant a parallel execution. + for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX + real_t val = genomes[i].logLik; + + sanity = !( isnan(val) || isinf(val) ); + assert( sanity && "val is NaN in find_best" ); + + if( val > best_lik ) { best_ind = i; best_lik = val; } + } +} + +Move_Type selectMoveType(real_t move_selected) { + Move_Type move_type = NONE; + + real_t prob; + Move_Type type; + UINT k = 0; + do { + prob = mcmc_moves_selection_cumdensfct[k].fst; + type = mcmc_moves_selection_cumdensfct[k].snd; + + if( move_selected <= prob ) { + move_type = type; + } + k ++; + } while ( move_selected > prob && k < CUMDENSFCT_CARD ); + + assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); + + return move_type; +} + +/** + * Main Entry Point for Swaption Calibration + * The (out) arguments are in fact the resulted + * winning genome result & its likelihood. + * The array result has size 3*NUM_SWAP_QUOTES + * and records for each swaption the calibrated + * price, the black price and the percentage + * difference between the two. + */ +real_t* mainKernelSeqCPU( Genome& winner ) { + + UINT n_schedi_max = 0; + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + const UINT n_schedi = static_cast(12.0 * SwaptionQuotes[4*ttt+2] / SwaptionQuotes[4*ttt+1]); + n_schedi_max = max(n_schedi_max, n_schedi); + } + + SeqArrays cpu_arrs(n_schedi_max); + Genome* genomes = cpu_arrs.genomes; + + srand ( SEED ); + srand48 ( SEED ); + + // initialized the genomes with random numbers inside + // their acceptable bounds => requires 5*POP_SIZE randoms + for( int i = 0; i < POP_SIZE; i++ ) { + real_t r01, tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; + genomes[i].a = genomes[i+POP_SIZE].a = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; + genomes[i].b = genomes[i+POP_SIZE].b = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; + genomes[i].rho = genomes[i+POP_SIZE].rho = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; + genomes[i].nu = genomes[i+POP_SIZE].nu = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; + genomes[i].sigma = genomes[i+POP_SIZE].sigma = tmp; + + // genomes[i].fbRat = genomes[i+POP_SIZE].fbRat = 1.0; + } + + // Initial evaluation of the genomes! + real_t quote, price; + for( int i = 0; i < POP_SIZE; i++ ) { + Genome& gene = genomes[i]; + real_t rms = 0.0; + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + eval_genome_new ( + gene.a, gene.b, gene.rho, gene.nu, gene.sigma, + SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price + ); + rms += logLikelihood( quote, price ); + } + gene.logLik = rms; + } + + // convergence loop that runs the genetic algorithms + // (takes a population and returns a population) + for( int j = 0; j < MCMC_LOOPS; j++ ) { + + // select which move to perform. + // Note: this block can also be a loop (in fixed order) + // over the various move types + real_t move_selected = getRandUnifNorm(); + Move_Type move_type = selectMoveType(move_selected); + + if ( move_type == DIMS_ALL ) { + for( int i = 0; i < POP_SIZE; i++ ) { + genomes[i+POP_SIZE].mutate_dims_all( genomes[i] ); + } + + } else if ( move_type == DIMS_ONE ) { + + UINT dim_j = getRandIntNorm(GENOME_DIM); + + for( int i = 0; i < POP_SIZE; i++ ) { + genomes[i+POP_SIZE].mutate_dims_one( genomes[i], dim_j ); + } + } else /* if ( move_type == DEMCMC ) */ { + + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums + // compute the k^th and the l^th genes + UINT cand_UB = POP_SIZE - 1; + UINT k = getRandIntNorm(cand_UB); // random in [0,pop_size-1) + if ( k == i ) { + k = cand_UB; + cand_UB -= 1; + } + UINT l = getRandIntNorm(cand_UB); + if ( l == i || l == k ) { + l = cand_UB; + } + + // do DEMCMC base on k^th and l^th genomes + genomes[i+POP_SIZE].mcmc_DE( genomes[i], genomes[k], genomes[l] ); + } + } + + // evaluate the proposals + for( int i = 0; i < POP_SIZE; i++ ) { + Genome& gene = genomes[i+POP_SIZE]; + + real_t rms = 0.0; + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + eval_genome_new ( + gene.a, gene.b, gene.rho, gene.nu, gene.sigma, + SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price + ); + rms += logLikelihood( quote, price ); + } + gene.logLik = rms; + } + + // mcmc_acceptance_rejection(); + // Deciding whether to accept or reject the proposal, + // obtained by mutating/crossover of the individual. + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel + // Metropolis: get a random U[0,1) for each candidate + real_t rand = getRandUnifNorm(); + + Genome& orig = genomes[i]; + Genome& muta = genomes[i+POP_SIZE]; + // selection: dimensions considered independent + // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) + real_t acceptance = std::min( 1.0, exp( muta.logLik - orig.logLik ) * muta.fbRat ); + + // if acceptance criterion is met then p->p' else does nothing + if ( rand < acceptance ) + orig = muta; + } + + // print best candidate for the current iteration: + if ( (j % 16) == 0 ){ + int best_ind; real_t best_lik; + find_best(genomes, best_ind, best_lik); + fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", + j, best_lik, best_ind ); + } + } + + real_t* result = new real_t[3*NUM_SWAP_QUOTES]; + { // print best candidate for the current iteration: + int best_ind; real_t best_lik; + find_best(genomes, best_ind, best_lik); + //winner = genomes[best_ind]; + winner.a = genomes[best_ind].a; winner.b = genomes[best_ind].b; + winner.rho = genomes[best_ind].rho; winner.nu = genomes[best_ind].nu; + winner.sigma = genomes[best_ind].sigma; winner.logLik = genomes[best_ind].logLik; + + // recompute the calibrated price and the black price! + real_t* quotes = cpu_arrs.get_quote(); + real_t* prices = cpu_arrs.get_price(); + for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { + eval_genome_new ( + winner.a, winner.b, winner.rho, winner.nu, winner.sigma, + SwaptionQuotes+4*ttt, cpu_arrs.tmp_arrs, quote, price + ); + quotes[ttt] = quote; + prices[ttt] = price; + } + + + + // write summary + makeSummary( best_ind, winner, quotes, prices, result ); + } + + // Releasing the CPU resources: + cpu_arrs.releaseResources(); + + return result; +} + +#endif // end ifndef GEN_ALG_FLAT diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h b/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h new file mode 100644 index 0000000..a99d977 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h @@ -0,0 +1,238 @@ +#ifndef CANDIDATE_CLASS +#define CANDIDATE_CLASS + +#include "Constants.h" +#include "GenAlgUtil.h" + + +//========================================================================= +/** + * Candidate: + * - identified by parameters (target, and nuisance) + * - holds one proposal, to be accepted or rejected + * - holds fitness results + * - holds MCMC selection regions + * Population: + * - container of candidates + * - container of proposals + * - caller of mutation functions + * - select if to keep/update candidates and proposals + * MCMC: moves: + * - TODO: Gibbs sampling: single dimension update + * - all dimensions update + * - crossover + */ +//========================================================================= + +/** + * Genome min/max ranges and proposed initial values (not used) + * { g_a, g_b, g_rho, g_nu, g_sigma } + */ +const REAL g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; +const REAL g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; +const REAL g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; +//const REAL Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; + + +/** + * perturbing a genome; requires one random uniform number in [0,1) + */ +inline +REAL perturbation( + const REAL gene, + const REAL gene_k, + const REAL gene_l, + const UINT i, + const REAL gamma1, + const REAL amplitude_ratio +) { + REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + REAL semiamplitude = amplitude / 2.0; + REAL r01 = getRandRandNorm(); + REAL perturb = ( amplitude * r01 - semiamplitude ); + + return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); +} + +/* + * contraining gene i to be within accepted bounds! + */ +inline +REAL constrain_dim1( const int i, const REAL gene ) { + return std::max( g_mins[i], std::min( g_maxs[i], gene ) ); +} + + +/** + * Helper mutate function: requires one uniform random number + */ +Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int i, const REAL amplitude_ratio ) { + REAL forward_range, backward_range; + REAL tmp_min_max, tmp_max_min; + + const REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + const REAL semiamplitude = amplitude / 2.0; + + tmp_min_max = std::min( g_maxs[i], gene + semiamplitude ); + tmp_max_min = std::max( g_mins[i], gene - semiamplitude ); + forward_range = tmp_min_max - tmp_max_min; + + tmp_min_max = std::min( g_maxs[i], gene_prop + semiamplitude ); + tmp_max_min = std::max( g_mins[i], gene_prop - semiamplitude ); + backward_range = tmp_min_max - tmp_max_min; + + const REAL bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; + + // assign p' + REAL r01 = getRandRandNorm(); + REAL diff = amplitude * r01 - semiamplitude; + return Tuple(gene + diff, bf_fact); +} + + +struct Genome { + REAL a; + REAL b; + REAL rho; + REAL nu; + REAL sigma; + REAL logLik; + REAL fbRat; + REAL padding; + + Genome() { + this->a = 0.0; this->b = 0.0; this->rho = 0.0; + this->nu = 0.0; this->sigma = 0.0; this->logLik = 0.0; + this->fbRat = 0.0; + } + Genome( const REAL a, const REAL b, const REAL rho, const REAL nu, + const REAL sigma, const REAL logLik, const REAL fbRat) { + this->a = a; this->b = b; this->rho = rho; + this->nu = nu; this->sigma = sigma; this->logLik = logLik; + this->fbRat = fbRat; + } + Genome(const Genome& gene) { + this->a = gene.a; this->b = gene.b; this->rho = gene.rho; + this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; + this->fbRat = gene.fbRat; + } + Genome& operator=(const Genome& gene) { + this->a = gene.a; this->b = gene.b; this->rho = gene.rho; + this->nu = gene.nu; this->sigma = gene.sigma; this->logLik = gene.logLik; + this->fbRat = gene.fbRat; + return (*this); + } + + + /** + * mutate all dimensions. martingale with uniform prior. + * requires 5 * POP_SIZE uniform random numbers! + * I took out the evaluation of the proposal, since it should be + * done for all types of crossover/mutation/etc + */ + void mutate_dims_all( const Genome& orig, + const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { + REAL fb_rat = 1.0; + Tuple tmp(EPS0, 1.0); + + tmp = mutate_helper( orig.a, this->a, 0, amplitude_ratio ); + this->a = constrain_dim1(0, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.b, this->b, 1, amplitude_ratio ); + this->b = constrain_dim1(1, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.rho, this->rho, 2, amplitude_ratio ); + this->rho = constrain_dim1(2, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.nu, this->nu, 3, amplitude_ratio ); + this->nu = constrain_dim1(3, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.sigma, this->sigma, 4, amplitude_ratio ); + this->sigma = constrain_dim1(4, tmp.fst); + fb_rat *= tmp.snd; + + this->fbRat = fb_rat; + } + + /** + * mutate ONE dimension (Gibbs sampling). martingale with uniform prior + * dimension to be changed is given as input: has to be the same for + * all population. Memory coalescence? + * Requires POP_SIZE random uniform numbers! + */ + void mutate_dims_one( const Genome& orig, + const int dim_j, + const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO + ) { + REAL fb_rat = 1.0; + + Tuple tmp(EPS0, 1.0); + tmp = mutate_helper( orig.a, this->a, 0, (dim_j == 0) ? amplitude_ratio : 0.0 ); + this->a = constrain_dim1(0, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.b, this->b, 1, (dim_j == 1) ? amplitude_ratio : 0.0 ); + this->b = constrain_dim1(1, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.rho, this->rho, 2, (dim_j == 2) ? amplitude_ratio : 0.0 ); + this->rho = constrain_dim1(2, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.nu, this->nu, 3, (dim_j == 3) ? amplitude_ratio : 0.0 ); + this->nu = constrain_dim1(3, tmp.fst); + fb_rat *= tmp.snd; + + tmp = mutate_helper( orig.sigma, this->sigma, 4, (dim_j == 4) ? amplitude_ratio : 0.0 ); + this->sigma = constrain_dim1(4, tmp.fst); + fb_rat *= tmp.snd; + + this->fbRat = fb_rat; + } + + /** + * Crossover + */ + void mcmc_DE( const Genome& orig, + const Genome& gene_k, + const Genome& gene_l, + const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), + const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO + ) { + // proposal + // gamma: integrated out from the adviced + // Multivariate Gaussian with Gaussian target (Braak, 2006) + REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); + + this->a = constrain_dim1( 0, perturbation( orig.a, gene_k.a, gene_l.a, 0, gamma1, ampl_ratio ) ); + this->b = constrain_dim1( 1, perturbation( orig.b, gene_k.b, gene_l.b, 1, gamma1, ampl_ratio ) ); + this->rho = constrain_dim1( 2, perturbation( orig.rho, gene_k.rho, gene_l.rho, 2, gamma1, ampl_ratio ) ); + this->nu = constrain_dim1( 3, perturbation( orig.nu, gene_k.nu, gene_l.nu, 3, gamma1, ampl_ratio ) ); + this->sigma = constrain_dim1( 4, perturbation( orig.sigma, gene_k.sigma, gene_l.sigma, 4, gamma1, ampl_ratio ) ); + + this->fbRat = 1.0; // TODO: fix + } + + /** + * accepting the proposal + */ + void accept( const Genome& mutated ) { + this->a = mutated.a; + this->b = mutated.b; + this->rho = mutated.rho; + this->nu = mutated.nu; + this->sigma = mutated.sigma; + this->logLik = mutated.logLik; + this->fbRat = mutated.fbRat; + } +}; + +#endif // #ifndef CANDIDATE_CLASS + + + + diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile new file mode 100644 index 0000000..14669d4 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile @@ -0,0 +1,31 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h +OBJECTS =SwapCalib.o +EXECUTABLE =SwapCalib + +default: $(EXECUTABLE) + +%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + ./$(EXECUTABLE) diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp new file mode 100644 index 0000000..84d002b --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp @@ -0,0 +1,61 @@ +/****************************************/ +/*** Translated to C++ Cosmin Oancea ***/ +/*** from an original OCaml code ***/ +/*** (sequential) by LexiFi ***/ +/*** and a sequential Python implem ***/ +/*** using a different genetic alg.***/ +/*** by Christian Andreetta ***/ +/****************************************/ + +#include "Util.h" +#include "Constants.h" +#include "ParseInput.h" +#include "GenAlgFlat.h" + +int main() +{ + Genome gene; + real_t* calib_arr = NULL; + + printf("\n// Running Original Sequential Swaption-Calibration Benchmark\n"); + + readDataSet( POP_SIZE, MCMC_LOOPS, + NUM_SWAP_QUOTES, SwaptionQuotes, + NUM_HERMITE, HermiteCoeffs, HermiteWeights, + NUM_SOBOL_BITS, SobolDirVct + ); + + unsigned long int elapsed_usec = 0; + { // Main Computational Kernel + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + calib_arr = mainKernelSeqCPU(gene); + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; + } + + { // writeback of the result + FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); + FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); + const int Ps = get_CPU_num_threads(); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + + writeResult(result, + wg_a, + wg_b, + wg_sigma, + wg_nu, + wg_rho, + wg_logLik, + calib_arr); + + fclose(result); + } + + return 1; +} + diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h b/benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h new file mode 100644 index 0000000..b21da96 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/UtilCPU.h @@ -0,0 +1,48 @@ +#ifndef CPU_UTILITIES +#define CPU_UTILITIES + +struct IntermElem { + real_t ci; + real_t t1_cs; + real_t bai; + real_t bbi; + real_t aici; + real_t log_aici; + real_t scale; + real_t hat_scale; + + IntermElem() { } +}; + +struct SeqArrays { + + // max size of temp arrays + const uint MaxSzTmpArrs; + + // [ MaxSzTmpArrs ] + IntermElem* tmp_arrs; + + // [ 2 * POP_SIZE ] + Genome* genomes; + + // [ 2 * NUM_SWAP_QUOTES ] + real_t* new_quote_price; + + SeqArrays (const uint m) : MaxSzTmpArrs(m) { + genomes = new Genome[ 2 * POP_SIZE ]; + tmp_arrs = new IntermElem[MaxSzTmpArrs]; + + new_quote_price = new real_t [ 2 * NUM_SWAP_QUOTES ]; + } + + void releaseResources() { + delete[] genomes; + delete[] tmp_arrs; + delete[] new_quote_price; + } + + // get the quotes prices for genome i + real_t* get_quote () { return new_quote_price; } + real_t* get_price () { return new_quote_price + NUM_SWAP_QUOTES; } +}; +#endif // CPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/static_configuration_template.json b/benchmarks/InterestCalib/implementations/cpp_sequential/static_configuration_template.json new file mode 100644 index 0000000..5087e27 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/static_configuration_template.json @@ -0,0 +1,3 @@ +{ + "REAL_TYPE": ["float", "double"] +} diff --git a/benchmarks/InterestCalib/lib/include/Constants.h b/benchmarks/InterestCalib/lib/include/Constants.h index 357f6ba..5d22d72 100644 --- a/benchmarks/InterestCalib/lib/include/Constants.h +++ b/benchmarks/InterestCalib/lib/include/Constants.h @@ -3,6 +3,8 @@ #include #include + +#include "real.h" #include "KerConsts.h" #ifdef __APPLE__ @@ -15,13 +17,13 @@ typedef uint UINT; /******** DATE RELATED STUFF *********/ /*************************************/ -#if WITH_FLOAT - const REAL INFTY = 1.0e38; +#if REAL_IS_FLOAT + const real_t INFTY = 1.0e38; #else - const REAL INFTY = 1.0e49; + const real_t INFTY = 1.0e49; #endif -bool equalEps(REAL x1, REAL x2) { +bool equalEps(real_t x1, real_t x2) { return ( fabs(x1-x2) <= 1.0e-8 ); } @@ -37,16 +39,16 @@ struct Date { }; //"2299-12-31T23:59:59" -REAL MAX_DATE = 168307199.0; +real_t MAX_DATE = 168307199.0; //"1980-01-01T12:00:00" -REAL MIN_DATE = 3600.0; +real_t MIN_DATE = 3600.0; #include "Date.h" // Date.of_string("2012-01-01") -const REAL TODAY = static_cast( date_of_gregorian( Date(2012, 1, 1, 12, 0) ) ); +const real_t TODAY = static_cast( date_of_gregorian( Date(2012, 1, 1, 12, 0) ) ); /*************************************/ @@ -60,7 +62,7 @@ const uint LWG_FB = 256; /*************************************/ /******** MATH RELATED STUFF *********/ /*************************************/ -//const REAL R = 0.03; +//const real_t R = 0.03; const uint IT_MAX= 10000; // a.k.a. itMax template @@ -71,14 +73,14 @@ struct Triple { struct SwapOfSwap { const UINT n; // size of swap_sched - REAL* swap_sched1; - REAL* swap_sched2; - REAL maturity; - REAL strike; + real_t* swap_sched1; + real_t* swap_sched2; + real_t maturity; + real_t strike; SwapOfSwap(const UINT len) : n(len) { - swap_sched1 = new REAL[n]; - swap_sched2 = new REAL[n]; + swap_sched1 = new real_t[n]; + swap_sched2 = new real_t[n]; } void cleanUp() { delete[] swap_sched1; @@ -90,13 +92,13 @@ struct SwapOfSwap { // Gaussian Quadrature with Hermite linear expansion: cmulative distribution function of Normal distribution UINT NUM_HERMITE; // 11 -REAL* HermiteCoeffs; // [NUM_HERMITE] -REAL* HermiteWeights;// [NUM_HERMITE] +real_t* HermiteCoeffs; // [NUM_HERMITE] +real_t* HermiteWeights;// [NUM_HERMITE] //========================================================================= UINT NUM_SWAP_QUOTES; //196 // 196 x { maturity_in_year * swap_frequency * swap_term_in_year * volatility } -REAL* SwaptionQuotes; //[NUM_SWAP_QUOTES,4] +real_t* SwaptionQuotes; //[NUM_SWAP_QUOTES,4] UINT NUM_SOBOL_BITS; // 30 int* SobolDirVct; // [SOBOL_BITS_NUM] @@ -109,14 +111,14 @@ int PROCS; const UINT SEED = 12345; const UINT GENOME_DIM = 5; -const REAL GENOME_SCALE = 1.0; +const real_t GENOME_SCALE = 1.0; // Likelihood Parameters enum Likelihood_Type { CAUCHY, NORMAL }; const Likelihood_Type LLHOOD_TYPE = CAUCHY; //NORMAL; -const REAL LLHOOD_CAUCHY_OFFS = 5.0; -const REAL LLHOOD_NORMAL_OFFS = 1.0; +const real_t LLHOOD_CAUCHY_OFFS = 5.0; +const real_t LLHOOD_NORMAL_OFFS = 1.0; // population @@ -127,7 +129,7 @@ UINT POP_SIZE; //const UINT MCMC_LOOPS = (UINT) ( 100.0 * (1.0 + log(GENOME_SCALE)) * // (2.0 + log(GENOME_DIM )) + 64);//was 2.0+... UINT MCMC_LOOPS; -const REAL MOVES_UNIF_AMPL_RATIO = 0.005 / GENOME_SCALE; +const real_t MOVES_UNIF_AMPL_RATIO = 0.005 / GENOME_SCALE; // Generic Tuple template @@ -138,7 +140,7 @@ struct Tuple { }; enum Move_Type { DIMS_ALL, DIMS_ONE, DEMCMC, NONE }; -typedef Tuple MV_EL_TYPE; +typedef Tuple MV_EL_TYPE; const UINT CUMDENSFCT_CARD = 3; MV_EL_TYPE mcmc_moves_selection_cumdensfct[3] = //{ MV_EL_TYPE(0.0,DIMS_ALL), MV_EL_TYPE(0.0,DIMS_ONE), MV_EL_TYPE(1.0,DEMCMC) }; diff --git a/benchmarks/InterestCalib/lib/include/KerConsts.h b/benchmarks/InterestCalib/lib/include/KerConsts.h index 52e05b6..ca3256c 100644 --- a/benchmarks/InterestCalib/lib/include/KerConsts.h +++ b/benchmarks/InterestCalib/lib/include/KerConsts.h @@ -31,16 +31,12 @@ /*********************************************/ /*********************************************/ -#if WITH_FLOAT - typedef float REAL; +#if REAL_IS_FLOAT #define EPS0 (0.3e-2) #define EPS (0.2e-4) #define PI (3.14159265358) #else - #pragma OPENCL EXTENSION cl_khr_fp64: enable - - typedef double REAL; #define EPS0 (1.0e-3) #define EPS (1.0e-5) #define PI (3.1415926535897932384626433832795) @@ -57,4 +53,3 @@ #define R 0.03 #endif // KERNEL_CONSTANTS - diff --git a/benchmarks/InterestCalib/lib/include/tmp/Constants.h b/benchmarks/InterestCalib/lib/include/tmp/Constants.h deleted file mode 100644 index 8fd8365..0000000 --- a/benchmarks/InterestCalib/lib/include/tmp/Constants.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -#define WITH_FLOATS 1 - -#define REAL3_CT 4 -#define TRANSPOSE_UV 1 - -#if (WITH_FLOATS) - typedef float REAL; - typedef unsigned int ULONG; -#else - #pragma OPENCL EXTENSION cl_khr_fp64: enable - typedef double REAL; - typedef unsigned long ULONG; -#endif - -#define WARP (1< -#include - -#include -#include -#include -#include - -#include - -using namespace std; - -/////////////////////////////////////////////////////// -//// FLAGS and CONSTANT SCALARS! -/////////////////////////////////////////////////////// - -#define TRIDAG_ALL_OPT_ON -#define MOST_OPTIMISED_ON - -//#define IS_GPU -//#define DEBUG_PRINT_GPU_INFO - -unsigned int OUTER_LOOP_COUNT; //128; //1024; //100; -unsigned int NUM_X ; //256; //256; //64; //256; -unsigned int NUM_Y ; //32; //32; //32; -unsigned int NUM_T ; //64; //64; //64; -unsigned int NUM_XY ; //NUM_X*NUM_Y; - -/////////////////////////////////////////////////////// -//// GLOBAL ARRAYS ! -/////////////////////////////////////////////////////// - -/// grid /// -REAL* myX ; // 1-dim, size: NUM_X -REAL* myY ; // 1-dim, size: NUM_Y -REAL* myTimeline; // 1-dim, size: NUM_T - -unsigned int myXindex, myYindex; - -/// variable /// -REAL* myResArr; //[OUTER_LOOP_COUNT * NUM_Y * NUM_X]; // 3-dim, size: OUTER_LOOP_COUNT x NUM_Y x NUM_X - - -/// coeffs /// -REAL *myMuX, *myVarX; // 2-dim, size: NUM_X x NUM_Y -REAL *myMuY, *myVarY; // 2-dim, size: NUM_X x NUM_Y - -// operators -REAL *myDx, *myDxx; // 2-dim, size: NUM_X x REAL3_CT -REAL *myDy, *myDyy; // 2-dim, size: NUM_Y x REAL3_CT - -void allocGlobArrs() { - myX = new REAL[NUM_X]; - myY = new REAL[NUM_Y]; - myTimeline = new REAL[NUM_T]; - - myMuX = new REAL[NUM_X * NUM_Y]; - myVarX= new REAL[NUM_X * NUM_Y]; - myMuY = new REAL[NUM_X * NUM_Y]; - myVarY= new REAL[NUM_X * NUM_Y]; - - myDx = new REAL[NUM_X * REAL3_CT]; - myDxx = new REAL[NUM_X * REAL3_CT]; - myDy = new REAL[NUM_Y * REAL3_CT]; - myDyy = new REAL[NUM_Y * REAL3_CT]; - - myResArr = new REAL[OUTER_LOOP_COUNT * NUM_Y * NUM_X]; -} - -void deallocGlobArrs() { - delete[] myX; - delete[] myY; - delete[] myTimeline; - - delete[] myMuX; - delete[] myVarX; - delete[] myMuY; - delete[] myVarY; - - delete[] myDx; - delete[] myDxx; - delete[] myDy; - delete[] myDyy; - - delete[] myResArr; -} - -#endif // end include NORDEA_DATA_STRUCT diff --git a/benchmarks/InterestCalib/lib/include/tmp/G2PP.h b/benchmarks/InterestCalib/lib/include/tmp/G2PP.h deleted file mode 100644 index 9788da6..0000000 --- a/benchmarks/InterestCalib/lib/include/tmp/G2PP.h +++ /dev/null @@ -1,326 +0,0 @@ -#ifndef G2PP -#define G2PP - -#include "Constants.h" -#include "Date.h" -#include "MathModule.h" -#include "G2ppUtil.h" - -#include "GenAlgUtil.h" - -////////////////////////// -// Root finder -////////////////////////// - -REAL exactYhat( const UINT& n_schedi, - - const REAL& b, // scals begins - const REAL& sigmax, - const REAL& sigmay, - const REAL& rhoxy, - const REAL& rhoxyc, - const REAL& rhoxycs, - const REAL& mux, - const REAL& muy, // scals ends - - const REAL* bai, // babaicis begins - const REAL* bbi, - const REAL* aici, - const REAL* log_aici, // babaicis ends - - REAL* scales, - const REAL& x -) { - // ugaussian_Pinv(k)=1.0e~4 - const REAL k = - 3.71901648545568; - - REAL up = 0.0, lo = -INFTY; - for( UINT i = 0; i < n_schedi; i++ ) { - REAL baix = bai[i] * x; - - REAL up_term = aici[i] * exp( -baix ); - scales[i] = up_term; - up += up_term; - lo = std::max( lo, ( log_aici[i] - baix ) / bbi[i] ); - } - -// if ( n_schedi == 1 ) { return lo; } // delete[] scales; - - // CHECKING uplo!!!! - const REAL log_s = log(up); - REAL tmp = log_s / bbi[n_schedi-1]; - - if ( tmp <= 0.0 ) { - up = tmp; - } else { - tmp = log_s / bbi[0]; - if ( 0.0 <= tmp ) up = tmp; - else up = - INFTY; - } - - const REAL yl = lo - EPS; - const REAL yu = up + EPS; - - const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; - const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; - - REAL res; - if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS - else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) - else { - const REAL root_lb = std::max( yl, y0 ); - const REAL root_ub = std::min( yu, y1 ); - - REAL root, error; UINT iter; - rootFinding_Brent(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); - //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); - - res = ( error == -INFTY ) ? y0 - 1.0 : ( error == INFTY ) ? y1 + 1.0 : root; - } - - return res; -} - - - -/////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////// -/// Main function of Module G2PP: pricer_of_swaption /// -/////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////// - -REAL pricer_of_swaption( const REAL& today, - - const REAL& sw_mat, // swaptionQuote begins ... - const REAL& sw_freq, - const REAL& sw_ty, // swaptionQuote ends. - - const REAL& a, // genome begins ... - const REAL& b, - const REAL& rho, - const REAL& nu, - const REAL& sigma // genome ends. -) { - //SwapOfSwap sos = extended_swaption_of_swaption(sw_mat, sw_freq, sw_ty); - const REAL maturity = add_years( TODAY, sw_mat ); - const UINT n_schedi = static_cast(12.0 * sw_ty / sw_freq); -// - const REAL tmat0 = date_act_365( maturity, today ); // BIG BUG -- was TODAY - REAL v0_mat, dummy1, dummy2; - bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); -// - const REAL mux = - bigmx( a, b, rho, nu, sigma, today, maturity, today, maturity ); - const REAL muy = - bigmy( a, b, rho, nu, sigma, today, maturity, today, maturity ); -// - const REAL zc_mat = zc(maturity); -// - const REAL sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); - const REAL sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); - const REAL rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); - const REAL sigmax = sigma * sqrt_bfun_a; - const REAL sigmay = nu * sqrt_bfun_b; - - const REAL rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel - const REAL rhoxycs = sqrt( rhoxyc ); // used in reduction kernel - const REAL sigmay_rhoxycs = sigmay * rhoxycs; - const REAL t4 = (rhoxy * sigmay) / sigmax; -// - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; - for( UINT i = 0; i < n_schedi; i++ ) { - REAL a1 = add_months( maturity, sw_freq*i ); - //sos.swap_sched1[i] = a1; - REAL a2 = add_months( a1, sw_freq ); - //sos.swap_sched2[i] = a2; - - // Reduction( lvl: +, t0 : min, tn : max ) - lvl += zc(a2) * date_act_365(a2, a1); - t0 = std::min(t0, a1); - tn = std::max(tn, a2); - } - - const REAL strike = ( zc(t0) - zc(tn) ) / lvl; -// - REAL* ci = new REAL[n_schedi]; - REAL* bai = new REAL[n_schedi]; - REAL* bbi = new REAL[n_schedi]; - REAL* aici = new REAL[n_schedi]; - REAL* log_aici = new REAL[n_schedi]; - REAL* t1_cs = new REAL[n_schedi]; - REAL* scale = new REAL[n_schedi]; - REAL* hat_scale= new REAL[n_schedi]; - - for( UINT i = 0; i < n_schedi; i++ ) { - const REAL beg_date = add_months( maturity, sw_freq*i ); //scheduleix[i]; - const REAL end_date = add_months( beg_date, sw_freq ); //scheduleiy[i]; - const REAL res = date_act_365( end_date, beg_date ) * strike; - - const REAL cii = ( i == n_schedi-1 ) ? 1.0 + res : res; - - REAL v0_end, vt_end, baii, bbii, date_tod1, date_tod2; - date_tod1 = date_act_365(end_date, today); - bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); - date_tod2 = date_act_365(end_date, maturity); - bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); - - const REAL expo_aici = 0.5 * (vt_end - v0_end + v0_mat); - const REAL fact_aici = cii * zc(end_date) / zc_mat; - ci [i] = fact_aici; // reuse the space to hold the factor of t1_cs - t1_cs [i] = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; // hold only the exponent of the original t1_cs; - - bai [i] = baii; - bbi [i] = bbii; - aici [i] = fact_aici * exp( expo_aici ); - log_aici[i] = log( fact_aici ) + expo_aici; - scale [i] = - ( baii + bbii * t4 ); - - if( isinf(aici[i]) || isnan(aici[i]) ) { - printf("NaN aici in pricer of swaption. Exiting!\n"); exit(0); - } - } -// - - const REAL eps = 0.5 * sigmax; - - const REAL f = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux ); - const REAL g = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux + eps ); - const REAL h = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux - eps ); - const REAL df = 0.5 * ( g - h ) / eps; - - // AT this point we need: - // scalars: sqrt2sigmax, t2, f, df, mux, muy, sigmay_rhoxycs, zc_mat - // arrays : t1_cs, bbi, scale, ci - - const REAL sqrt2sigmax = sqrt(2.0) * sigmax; - const REAL t2 = rhoxy / (sigmax*rhoxycs); - // t2 * (sqrt2sigmax * x_quad) -> sqrt(2.0) * rhoxy / rhoxycs * xquad - - REAL accum0 = 0.0; - for( UINT j = 0; j < Gauss_DIM; j++ ) { - const REAL x_quad = GaussHermiteCoefs::coefs [j]; - const REAL w_quad = GaussHermiteCoefs::weights[j]; - - const REAL x = sqrt2sigmax * x_quad + mux; - - const REAL yhat_x = f + df*(x - mux); - const REAL h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); - - REAL accum1 = 0.0; - for( UINT i = 0; i < n_schedi; i++ ) { - const REAL h2 = h1 + bbi[i] * sigmay_rhoxycs; - - const REAL expo_aici = t1_cs[i] + scale[i]*x; - const REAL fact_aici = ci[i]; -// accum1 += fact_aici * exp(expo_aici) * uGaussian_P(-h2); - const REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); - accum1 += fact_aici * expo_part; - - if( isnan(accum1) || isinf(accum1) ) { - printf( "accum is Nan -- expo_aici: %f, fact_aici: %f, h2: %f, t1_cs: %f, scale: %f, x: %f, bbi: %f, mux: %f, muy: %f\n", - expo_aici, fact_aici, h2, t1_cs[i], scale[i], x, bbi[i], mux, muy ); - printf( "accum is Nan -- t4: %f, rhoxyc: %f, v0mat: %f, b: %f, aici: %f\n", - t4, rhoxyc, v0_mat, b, aici[i] ); - exit(0); - } - } - - REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; - const REAL t1 = exp( - 0.5 * tmp * tmp ); - - accum0 += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); - } - - if( isnan(accum0) || isinf(accum0) ) { - printf("Numerically Instable Implem: end of pricer_of_swaption: accum0 in NaN or Inf!\n"); - exit(0); - } - - delete[] ci; delete[] hat_scale; - delete[] bai; delete[] aici; delete[] log_aici; - delete[] bbi; delete[] t1_cs; delete[] scale; - - return zc_mat * ( accum0 / sqrt( PI ) ); -} - - -//////////////////////////////// -//// Pricer for one genome: //// -//////////////////////////////// - -REAL pricer (const REAL a = 0.02453, const REAL b = 0.98376, const REAL rho = -0.82400, const REAL nu = 0.11830, const REAL sigma = 0.02398) { - //let genome = {0.02453, 0.98376, ~0.82400, 0.11830, 0.02398} in - - REAL rms = 0.0, logLik = 0.0; - for( UINT i = 0; i < NUM_SWAP_QUOTES; i++ ) { - const REAL mat_year = SwaptionQuotes[i][0]; - const REAL swap_freq = SwaptionQuotes[i][1]; - const REAL term_year = SwaptionQuotes[i][2]; - const REAL quote = SwaptionQuotes[i][3]; - - const REAL g2pp_price = pricer_of_swaption( TODAY, mat_year, swap_freq, term_year, a, b, rho, nu, sigma); - const REAL market_price = black_price ( TODAY, mat_year, swap_freq, term_year, quote ); - - const REAL tmp = (g2pp_price - market_price) / market_price; - rms += tmp * tmp; - logLik += logLikelihood( market_price, g2pp_price ); - } - - rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); - - printf("\n\n!!!!!!!!!!!!!Computed RMS is: %f, Computed LogLik is: %f\n\n", rms, logLik); - - return rms; -} - - -////////////////////////////////////////////////////// -//// Test pricer_of_swaption: -//// -//// params=params2dict(a = 0.02453, b = 0.98376, sigma = 0.02398, nu = 0.11830, rho = -0.82400) -//// swaption=['swaption_maturity_in_year': 10, 'swap_term_in_year': 4, 'swap_frequency': 6] -//// assert "%.3f" % (1e4*pricer_of_swaption(today=today,zc=zc,swaption=swaption,params=params)) == "657.822" -//// swaption=['swaption_maturity_in_year': 30, 'swap_term_in_year': 30, 'swap_frequency': 6] -//// assert "%.3f" % (1e4*pricer_of_swaption(today=today,zc=zc,swaption=swaption,params=params)) == "1902.976" -//// -////////////////////////////////////////////////////// - - -void test_pricer_of_swaption() { - const REAL a = 0.02453; - const REAL b = 0.98376; - const REAL rho = -0.82400; - const REAL nu = 0.11830; - const REAL sigma = 0.02398; - - // (maturity, frequency, term) = swaption - REAL maturity = 10.0; - REAL freq = 6.0; - REAL term = 4.0; - - const REAL price1 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma); - printf("Pricer_of_swaption test I = 657.82158867845 : "); - if( equalEps(price1, 657.82158867845) ) printf(" SUCCESS!\n\n"); - else printf("%f FAILS!\n\n", price1); - - // let swaption = {30.0, 6.0, 30.0} - maturity = 30.0; - freq = 6.0; - term = 30.0; - - const REAL price2 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma ); - printf("Pricer_of_swaption test II = 1902.97628191498 : "); - if( equalEps(price2, 1902.97628191498) ) printf(" SUCCESS!\n\n"); - else printf("%f FAILS!\n\n", price2); - - - //let swaption = {30.0, 6.0, 25.0} in - maturity = 30.0; - freq = 6.0; - term = 25.0; - - const REAL price3 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma ); - printf("Pricer_of_swaption test III = 1840.859126408099 : "); - if( equalEps(price3, 1840.859126408099) ) printf(" SUCCESS!\n\n"); - else printf("%f FAILS!\n\n", price3); -} - -#endif // ifndef G2PP From ec2f52c0ccdd0b34770d788123e6c91cdc287817 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 10:02:04 +0200 Subject: [PATCH 074/122] Dynamic thread count configuration. --- .../cpp_openmp/dynamic_configuration_template.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json b/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json new file mode 100644 index 0000000..14298aa --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json @@ -0,0 +1 @@ +{"NUM_THREADS": [1,2,3,4]} From 884f6ba7470f7fcc7b631e4d172a3e59a1e3c7da Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 12:35:40 +0200 Subject: [PATCH 075/122] Port Haskell implementation. --- .../implementations/haskell_lh/Constants.hs | 103 +++++ .../implementations/haskell_lh/Date.hs | 155 +++++++ .../implementations/haskell_lh/EvalGenome.hs | 214 ++++++++++ .../implementations/haskell_lh/Genome.hs | 128 ++++++ .../implementations/haskell_lh/Makefile | 26 ++ .../implementations/haskell_lh/MathMod.hs | 390 ++++++++++++++++++ .../implementations/haskell_lh/SwapCalib | Bin 0 -> 5575328 bytes .../implementations/haskell_lh/SwapCalib.hs | 277 +++++++++++++ 8 files changed, 1293 insertions(+) create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Constants.hs create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Date.hs create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/Makefile create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs create mode 100755 benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib create mode 100644 benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Constants.hs b/benchmarks/InterestCalib/implementations/haskell_lh/Constants.hs new file mode 100644 index 0000000..e9502fc --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Constants.hs @@ -0,0 +1,103 @@ +module Constants + ( + eps + , eps0 + , infty +-- , rrr + , sobolNum +-- , pop_size +-- , num_mcmc_its + , genome_dim + , genome_scale + , MOVE_TYPE(DIMS_ALL,DIMS_ONE,DEMCMC) + , selectMoveType + , equalEps + , reduce + , Swaption + , Genome + ) where + + +import Data.Bits +import Data.Vector.Unboxed(Vector) +import qualified Data.Vector.Unboxed as V + +import Debug.Trace + +data MOVE_TYPE = DIMS_ALL + | DIMS_ONE + | DEMCMC + deriving(Show) + +type Swaption = (Double, Double, Double, Double) +type Genome = (Double, Double, Double, Double, Double) + +equalEps :: Double -> Double -> Bool +equalEps x1 x2 = abs (x1 - x2) <= 1.0e-8 + +selectMoveType :: Double -> MOVE_TYPE +selectMoveType move_selected = + if move_selected <= 0.2 then DIMS_ALL + else if move_selected <= 0.5 then DIMS_ONE + else {- move_selected <= 1.0 -} DEMCMC + + +eps0 :: Double +eps0 = 1.0e-3 + +eps :: Double +eps = 1.0e-5 + +infty :: Double +infty = 1.0e49 + +--pop_size :: Int +--pop_size = 128 +-- +--num_mcmc_its :: Int +--num_mcmc_its = truncate $ (2.0 + (log (fromIntegral genome_dim))) * +-- (1.0 + (log genome_scale)) * 100.0 + +genome_scale :: Double +genome_scale = 1.0 + +genome_dim :: Int +genome_dim = 5 + +--------------------------------------------- +--- Definition of lish-homomorphic reduce --- +--- requires a binary associative op --- +--------------------------------------------- + +reduce :: (a -> a -> a) -> a -> [a] -> a +reduce bop ne lst = foldl bop ne lst + +--------------------------------- +--- Sobol Numbers Computation --- +--------------------------------- + +num_sobol_bits :: Int +num_sobol_bits = 30 + +sobol_norm :: Double +sobol_norm = 1.0 / (1.0 + (2.0 ** (fromIntegral num_sobol_bits))) + +grayCode :: Int -> Int +grayCode x = (x `shiftR` 1) `xor` x + +sobolNum :: Vector Int -> Int -> Double +sobolNum dir_vct n = + let n_gray = grayCode n + ires = V.ifoldl (\res i dir -> + if testBit n_gray i + then res `xor` dir + else res + ) 0 dir_vct + rres = sobol_norm * (fromIntegral ires) + in rres -- trace ("Sobol Num "++show n++" is: "++show rres) rres + +--sobolNums :: Vector int -> Int -> Int -> Vector Double +--sobolNums dir_vct beg_offs end_offs = + + +-- ifoldl :: Unbox b => (a -> Int -> b -> a) -> a -> Vector b -> a diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Date.hs b/benchmarks/InterestCalib/implementations/haskell_lh/Date.hs new file mode 100644 index 0000000..fe3be36 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Date.hs @@ -0,0 +1,155 @@ +module Date ( + today + , max_date + , min_date + , dateAct365 + , addMonths + , addYears + , test_dates + ) where + +import Constants +import Debug.Trace + +type GregDate = (Int,Int,Int,Int,Int) -- (year,month,day,hour,min) + +today :: Double +today = fromIntegral $ date_of_gregorian (2012, 1, 1, 12, 0) + +--"2299-12-31T23:59:59" +max_date :: Double +max_date = 168307199.0 + +--"1980-01-01T12:00:00" +min_date :: Double +min_date = 3600.0 + +hours_in_day :: Int +hours_in_day = 24 +minutes_in_day = hours_in_day * 60 +minutes_to_noon = (hours_in_day `div` 2) * 60 + + +date_of_gregorian :: GregDate -> Int +date_of_gregorian (year,month,day,hour,min) = + let ym = if month == 1 || month == 2 + then ( 1461 * ( year + 4800 - 1 ) ) `div` 4 + + ( 367 * ( month + 10 ) ) `div` 12 - + ( 3 * ( ( year + 4900 - 1 ) `div` 100 ) ) `div` 4 + + else ( 1461 * ( year + 4800 ) ) `div` 4 + + ( 367 * ( month - 2 ) ) `div` 12 - + ( 3 * ( ( year + 4900 ) `div` 100 ) ) `div` 4 + + tmp = ym + day - 32075 - 2444238 + + in tmp * minutes_in_day + hour * 60 + min + + +gregorian_of_date :: Int -> GregDate +gregorian_of_date minutes_since_epoch = + let jul = minutes_since_epoch `div` minutes_in_day + l1 = jul + 68569 + 2444238 + n = ( 4 * l1 ) `div` 146097 + l2 = l1 - ( 146097 * n + 3 ) `div` 4 + i = ( 4000 * ( l2 + 1 ) ) `div` 1461001 + + l3 = l2 - ( 1461 * i ) `div` 4 + 31 + j = ( 80 * l3 ) `div` 2447 + d = l3 - ( 2447 * j ) `div` 80 + l = j `div` 11 + + m = j + 2 - ( 12 * l ) + y = 100 * ( n - 49 ) + i + l + + daytime = mod minutes_since_epoch minutes_in_day + + in if ( daytime == minutes_to_noon ) + then (y, m, d, 12, 0) + else (y, m, d, daytime `div` 60, mod daytime 60) + +check_date :: Int -> Int -> Int -> Bool +check_date year month day = + let tmp1 = (1 <= day) && (1 <= month) && (month <= 12) && (1980 <= year) && (year <= 2299) + tmp2 = (day <= 28) + tmp3 = if (month == 2) + then (day == 29) && ((mod year 4) == 0) && ( year == 2000 || (not ((mod year 100) == 0)) ) + else if ( month == 4 || month == 6 || month == 9 || month == 11 ) + then ( day <= 30 ) + else ( day <= 31 ) + in tmp1 && (tmp2 || tmp3) + + +days_between :: Double -> Double -> Double +days_between t1 t2 = (t1 - t2) / (fromIntegral minutes_in_day) + +dateAct365 :: Double -> Double -> Double +dateAct365 t1 t2 = (days_between t1 t2) / 365.0 + +leap :: Int -> Bool +leap y = ( (mod y 4) == 0 ) && ( not ( (mod y 100) == 0 ) || ( (mod y 400) == 0 ) ) + +end_of_month :: Int -> Int -> Int +end_of_month year month = + let leap_year = leap year + in if ( month == 2 && leap_year ) then 29 + else if ( month == 2 ) then 28 + else if ( month == 4 || month == 6 || month == 9 || month == 11 ) then 30 + else 31 + +addMonths :: Double -> Double -> Double +addMonths time rnbmonths = + let nbmonths = truncate rnbmonths + (year,month,day,hour,min) = gregorian_of_date (truncate time) + + month1 = month + nbmonths + year'' = year + (month1 - 1) `div` 12 + month'' = (mod (month1 - 1) 12) + 1 + + (year''', month''') = if (month'' <= 0) + then (year''-1, month'' + 12) + else (year'', month'') + month_end = end_of_month year''' month''' + day''' = if ( day < month_end ) + then day + else month_end + in fromIntegral $ date_of_gregorian (year''', month''', day''', 12, 0) + + +addYears :: Double -> Double -> Double +addYears date nbyears = addMonths date (nbyears * 12.0) + +test_dates :: Int -> Int +test_dates arg = + let tmp1 = trace ("addMonths(min_date,1)==48240 : ") $ addMonths min_date 1.0 + arg1 = if equalEps tmp1 48240.0 + then trace ("... SUCCESS !") arg + else trace ("... FAILS !") arg + + tmp2 = trace ("addMonths(min_date,2)==90000 : ") $ addMonths min_date 2.0 + arg2 = if equalEps tmp2 90000.0 + then trace ("... SUCCESS !") arg1 + else trace ("... FAILS !") arg1 + + tmp3 = trace ("addYears(min_date,1)==530640 : ") $ addYears min_date 1.0 + arg3 = if equalEps tmp3 530640.0 + then trace ("... SUCCESS !") arg2 + else trace ("... FAILS !") arg2 + + tmp4 = trace ("addYears(min_date,5)==2634480 : ") $ addYears min_date 5.0 + arg4 = if equalEps tmp4 2634480.0 + then trace ("... SUCCESS !") arg3 + else trace ("... FAILS !") arg3 + + tmp5 = trace ("days_between(max_date(),min_date()) == 116877.499306 : ") $ days_between max_date min_date + arg5 = if equalEps tmp5 116877.499305555 + then trace ("... SUCCESS !") arg4 + else trace ("... FAILS !") arg4 + + tmp6 = trace ("act_365(max_date,min_date) == 320.212327 : ") $ dateAct365 max_date min_date + arg6 = if equalEps tmp6 320.2123268645 + then trace ("... SUCCESS !") arg5 + else trace ("... FAILS !") arg5 + + in arg6 + diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs b/benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs new file mode 100644 index 0000000..847b008 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/EvalGenome.hs @@ -0,0 +1,214 @@ +module EvalGenome + ( + evalGenome + , testSwaptionPricer + ) where + +import Data.List +import Data.Vector.Unboxed(Vector) +import qualified Data.Vector.Unboxed as V +import Control.DeepSeq + +import Constants +import Date +import MathMod + +import Debug.Trace + + + +---------------------------------- +--- Main Export of this Module --- +---------------------------------- +evalGenome :: [Double] -> [Double] -> [Swaption] -> Vector Double + -> ( Double, Vector Double, Vector Double ) -- (logLik,calib_prices, black_prices) [NUM_SWAP_QUOTES] +evalGenome hermite_coeffs hermite_weights swaption_quotes genome = + let genome_tup = -- (a, b, rho, nu, sigma) = + (genome V.! 0, genome V.! 1, genome V.! 2, genome V.! 3, genome V.! 4) + + (black_prices, swap_prices, swap_logLiks) = unzip3 $ + map (pricerOfSwaption hermite_coeffs hermite_weights genome_tup) swaption_quotes + + swap_logLik = reduce (+) 0.0 swap_logLiks + swap_price_vct = V.fromList swap_prices + black_price_vct= V.fromList black_prices + + in swap_logLik `deepseq` swap_price_vct `deepseq` black_price_vct `deepseq` + ( swap_logLik, swap_price_vct, black_price_vct ) + -- ( swap_logLik, V.fromList swap_prices, V.fromList black_prices ) + + +pricerOfSwaption :: [Double] -> [Double] -> Genome -> Swaption + -> (Double, Double, Double) -- (Black Price, Swapt Price, LogLikelihood) +pricerOfSwaption hermite_coeffs hermite_weights -- Hermite coefficients & weights + genome (sw_mat, sw_freq, sw_ty, sw_quote) = -- swaption + + let (a, b, rho, nu, sigma) = genome + maturity = addYears today sw_mat + n_schedi = truncate $ 12.0 * sw_ty / sw_freq + tmat0 = dateAct365 maturity today + + -- 1. compute quote, i.e., black price inlined + (lvl,t0,tn) = swapSchedule n_schedi maturity sw_freq + strike = ( (zc t0) - (zc tn) ) / lvl + d1 = 0.5 * sw_quote * tmat0 + d2 = 0.0 - d1 + black_price = ( lvl * ( strike * (uGaussianP d1) - strike * (uGaussianP d2) ) ) + + -- 2. estimate the swaption price for this particular genome, + -- and also compute its likelihood + (v0_mat,_,_) = bigV genome tmat0 + mux = 0.0 - (bigmX genome today maturity today maturity) + muy = 0.0 - (bigmY genome today maturity today maturity) + zc_mat = zc maturity + sqrt_bfun_a = sqrt $ bFun (2.0*a) tmat0 + sqrt_bfun_b = sqrt $ bFun (2.0*b) tmat0 + rhoxy = rho * (bFun (a+b) tmat0) / (sqrt_bfun_a * sqrt_bfun_b) + sigmax = sigma * sqrt_bfun_a + sigmay = nu * sqrt_bfun_b + rhoxyc = 1.0 - rhoxy * rhoxy + rhoxycs = sqrt rhoxyc + sigmay_rhoxycs = sigmay * rhoxycs + t4 = (rhoxy * sigmay) / sigmax + + (cs, t1_cs, bas, bbs, aics, log_aics, scales) = unzip7 $ + map (\ i -> + let beg_date = addMonths maturity (sw_freq*(fromIntegral i)) + end_date = addMonths beg_date sw_freq + res = (dateAct365 end_date beg_date) * strike + + cii = if i == n_schedi-1 then 1.0 + res else res + + date_tod1 = dateAct365 end_date today + (v0_end,_,_) = bigV genome date_tod1 + + date_tod2 = dateAct365 end_date maturity + (vt_end,bai,bbi) = bigV genome date_tod2 + + expo_aici = 0.5 * (vt_end - v0_end + v0_mat) + fact_aici = cii * zc(end_date) / zc_mat + + t1_c = bbi * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbi) ) + expo_aici + -- sanity = ! ( isinf(aici[i]) || isnan(aici[i]) ); + in ( fact_aici, t1_c, bai, bbi, fact_aici * (exp expo_aici), + expo_aici + (log fact_aici), 0.0 - (bai + bbi * t4) ) + ) [0..n_schedi-1] + + exactYhatSpec = exactYhat n_schedi b sigmax sigmay + rhoxy rhoxyc rhoxycs mux muy + bas bbs aics log_aics + eps = 0.5 * sigmax; + f = exactYhatSpec mux + g = exactYhatSpec (mux + eps) + h = exactYhatSpec (mux - eps) + df = 0.5 * ( g - h ) / eps; + + sqrt2sigmax = (sqrt 2.0) * sigmax + t2 = rhoxy / (sigmax*rhoxycs) + + accums = + zipWith (\x_quad w_quad -> + let x = sqrt2sigmax * x_quad + mux + yhat_x = f + df*(x - mux) + h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ) + + accs1= zipWith4 (\bbi t1_csi ci scalei -> + let h2 = h1 + bbi * sigmay_rhoxycs + expo_aici = t1_csi + scalei*x + fact_aici = ci + --fact_aici * (exp expo_aici) * (uGaussianP (-h2)) + expo_part = uGaussianPwithExpFactor (-h2) expo_aici + in fact_aici * expo_part + ) bbs t1_cs cs scales + accum= reduce (+) 0.0 accs1 + + tmp = (sqrt 2.0) * x_quad; --(x - mux) / sigmax; + t1 = exp $ 0.0 - 0.5*tmp*tmp + + in w_quad * t1 * ( (uGaussianP (-h1)) - accum ) + + ) hermite_coeffs hermite_weights + + accum = reduce (+) 0.0 accums + + swap_price = zc_mat * ( accum / (sqrt pi) ) + logLik = logLikelihood black_price swap_price + in (black_price, swap_price, logLik) +-- tmp = (swap_price - black_price) / black_price +-- in (black_price, swap_price, tmp * tmp) + + +--kkk :: Double +--kkk = -3.71901648545568 + +exactYhat :: Int -> Double -> Double -> Double -> Double + -> Double -> Double -> Double -> Double + -> [Double] -> [Double] -> [Double] -> [Double] + -> Double -> Double +exactYhat n_schedi b sigmax sigmay rhoxy rhoxyc rhoxycs mux muy + bai bbi aici log_aici x = + let kkk = -3.71901648545568 + (scales, los) = unzip $ zipWith4 + (\ baii bbii aicii log_aicii -> + let baix = baii * x + up_term = aicii * (exp (-baix)) + lo_term = ( log_aicii - baix ) / bbii + in (up_term, lo_term) + ) bai bbi aici log_aici + (up0,lo) = reduce (\(u,l) (cu,cl) -> (u+cu, max l cl) ) + (0.0, -infty) (zip scales los) + + in if n_schedi == 1 then lo + else + let log_s = log up0 + tmp = log_s / (last bbi) -- [n_schedi-1]; + up = if tmp <= 0.0 + then tmp + else let tmp2 = log_s / (head bbi) + in if 0.0 <= tmp2 + then tmp2 + else (-infty) + yl = lo - eps + yu = up + eps + + y0 = sigmay * ( rhoxy * (x-mux) / sigmax + kkk * rhoxycs ) - rhoxyc/b + muy + y1 = sigmay * ( rhoxy * (x-mux) / sigmax - kkk * rhoxycs ) + muy + in if ( y1 <= yl ) then y1 + 1.0 + else if ( yu <= y0 ) then y0 - 1.0 + else let root_lb = max yl y0 + root_ub = min yu y1 + (root,_,err) = rootFindBrent scales bbi root_lb root_ub 1.0e-4 + in if err == (-infty) then y0 - 1.0 + else if err == infty then y1 + 1.0 + else root + + +testSwaptionPricer :: [Double] -> [Double] -> Int -> Int +testSwaptionPricer hermite_coeffs hermite_weights arg0 = + let genome = (0.02453, 0.98376, -0.82400, 0.11830, 0.02398) + + swaption1 = (10.0, 6.0, 4.0, 0.2454) + (_,price1,_) = pricerOfSwaption hermite_coeffs hermite_weights genome swaption1 + price1' = trace ("# Pricer_of_swaption test I = 657.8215929143189 => ") $ + 1.0e4 * price1 + arg1 = if equalEps price1' 657.8215929143189 -- 657.82158867845 + then trace ("... SUCCESS !") arg0 + else trace ("... FAILS !"++show price1') arg0 + + swaption2 = (30.0, 6.0, 30.0, 0.16355) + (_,price2,_) = pricerOfSwaption hermite_coeffs hermite_weights genome swaption2 + price2' = trace ("# Pricer_of_swaption test II = 1902.97628191498 => ") $ + 1.0e4 * price2 + arg2 = if equalEps price2' 1902.97628191498 + then trace ("... SUCCESS !") arg1 + else trace ("... FAILS !") arg1 + + swaption3 = (30.0, 6.0, 25.0, 0.1686) + (_,price3,_) = pricerOfSwaption hermite_coeffs hermite_weights genome swaption3 + price3' = trace ("# Pricer_of_swaption test III = 1840.859126408099 => ") $ + 1.0e4 * price3 + arg3 = if equalEps price3' 1840.859126408099 + then trace ("... SUCCESS !") arg2 + else trace ("... FAILS !") arg2 + in arg3 + diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs b/benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs new file mode 100644 index 0000000..ee5d8fd --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Genome.hs @@ -0,0 +1,128 @@ +module Genome ( + g_mins + , g_maxs + , mutateDimsALL + , mutateDimsONE + , mcmcDE + ) where + +import Constants + +import Data.Vector.Unboxed(Vector) +import qualified Data.Vector.Unboxed as V + +import Debug.Trace + +g_mins :: Vector Double +g_mins = V.fromList [ eps0, eps0, -1.0+eps0, eps0, eps0 ] + +g_maxs :: Vector Double +g_maxs = V.fromList [ 1.0-eps0, 1.0-eps0, 1.0-eps0, 0.2, 0.2 ] + +g_inis :: Vector Double +g_inis = V.fromList [ 0.02, 0.02, 0.0, 0.01, 0.04 ] +-- [ g_a, g_b, g_rho, g_nu, g_sigma ] + +unif_ampl_ratio :: Double +unif_ampl_ratio = 0.005 / genome_scale + + + +-- rand_vct[5], i.e., needs 5 random numbers +mutateDimsALL :: Vector Double -> Vector Double -> Vector Double + -> (Vector Double, Double) +mutateDimsALL genome genome_prop rand_vct = -- 5 rand nums + let (genome_res, bf_facts) = V.unzip $ + V.zipWith5 (mutateHelper unif_ampl_ratio) + rand_vct g_mins g_maxs genome genome_prop + bf_res = V.foldl (*) 1.0 bf_facts + in (genome_res, bf_res) + + +-- needs one random number +mutateDimsONE :: Int -> Vector Double -> Vector Double -> Vector Double + -> (Vector Double, Double) +mutateDimsONE dim_j genome genome_prop rand_vct = -- r01 1 rand num + let (gene, gene_prop) = (genome V.! dim_j, genome_prop V.! dim_j) + (gene_min, gene_max) = (g_mins V.! dim_j, g_maxs V.! dim_j) + r01 = rand_vct V.! dim_j + + (gene_new, bf_res) = mutateHelper unif_ampl_ratio r01 + gene_min gene_max gene gene_prop + genome_res = V.imap (\i g -> if i == dim_j then gene_new else g) genome + in (genome_res, bf_res) + + +-- rand_vct[8], i.e., needs 8 random numbers +mcmcDE :: Int -> [Vector Double] -> Vector Double -> Int + -> (Vector Double, Double) +mcmcDE pop_size genomes rand_vct j = -- 8 rand nums + let gamma_avg = 2.38 / (sqrt (2.0*(fromIntegral genome_dim))) + ampl_ratio = 0.1 * unif_ampl_ratio + + k0 = truncate $ (fromIntegral (pop_size-1))*(rand_vct V.! 0) + (k, cand_UB) = if ( k0 == j ) + then (pop_size - 1, pop_size - 2) + else (k0, pop_size - 1) + + l0 = truncate $ (fromIntegral cand_UB)*(rand_vct V.! 1) + l = -- trace ("(k,j,l0,cand_UB) is: "++show k++" "++show j++" "++show l0++" "++show cand_UB) $ + if l0 == j || l0 == k + then cand_UB + else l0 + + -- proposal gamma: integrated out from the adviced + -- Multivariate Gaussian with Gaussian target (Braak, 2006) + gamma1 = gamma_avg - 0.5 + (rand_vct V.! 2) -- * instead of + ? + + gene_rands = V.drop 3 rand_vct + (genome_j, genome_k, genome_l) = (genomes !! j, genomes !! k, genomes !! l) + -- g_a [j + POP_SIZE] = constrain_dim1( 0, perturbation( g_a [j], g_a [k], g_a [l], 0, gamma1, ampl_ratio ) ); + genome_res = V.zipWith6 (perturbation gamma1 ampl_ratio) + gene_rands g_mins g_maxs genome_j genome_k genome_l + in (genome_res, 1.0) + +--perturbation gamma1 amplitude_ratio r01 gene_min gene_max gene gene_k gene_l + +---------------------------------------- +---------------------------------------- +---------- Helper Functions ------------ +---------------------------------------- +---------------------------------------- + +mutateHelper :: Double -> Double -> Double -> Double -> Double -> Double + -> (Double, Double) +mutateHelper amplitude_ratio r01 gene_min gene_max gene gene_prop = + let amplitude = abs $ (gene_max - gene_min) * amplitude_ratio + semiamplitude = amplitude / 2.0 + + tmp_min_max_f = min gene_max (gene + semiamplitude) + tmp_max_min_f = max gene_min (gene - semiamplitude) + forward_range = tmp_min_max_f - tmp_max_min_f + + bf_fact = if forward_range > 0.0 && amplitude > 0.0 + then let tmp_min_max_b = min gene_max (gene_prop + semiamplitude) + tmp_max_min_b = max gene_min (gene_prop - semiamplitude) + backward_range = tmp_min_max_b - tmp_max_min_b + in backward_range / forward_range + else 1.0 + diff = amplitude * r01 - semiamplitude + new_gene = constrainDim gene_min gene_max (gene+diff) + in (new_gene, bf_fact) + +constrainDim :: Double -> Double -> Double -> Double +constrainDim gene_min gene_max gene = + max gene_min $ min gene_max gene + + +perturbation :: Double -> Double -> Double -> Double + -> Double -> Double -> Double -> Double + -> Double +perturbation gamma1 amplitude_ratio r01 gene_min gene_max gene gene_k gene_l = + let amplitude = abs $ (gene_max - gene_min) * amplitude_ratio + semiamplitude = amplitude / 2.0 + perturb = amplitude * r01 - semiamplitude + new_gene = constrainDim gene_min gene_max $ + gene + perturb + gamma1 * ( gene_k - gene_l ) + in new_gene + diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile new file mode 100644 index 0000000..df75451 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile @@ -0,0 +1,26 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +include $(HIPERMARK_LIB_DIR)/setup.mk + +SOURCES = SwapCalib.hs +EXECUTABLE = SwapCalib +OBJECTS = SwapCalib.hi SwapCalib.o + +GHC_FLAGS = -Wall -O2 -msse2 -rtsopts -i$(HIPERMARK_IMPLEMENTATION) + +default: $(EXECUTABLE) + +$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) + ghc $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + ./$(EXECUTABLE) diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs b/benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs new file mode 100644 index 0000000..bc90ded --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/MathMod.hs @@ -0,0 +1,390 @@ +module MathMod + ( + uGaussianP + , uGaussianPwithExpFactor + , zc + , bigV + , bigmX + , bigmY + , bFun + , rootFindBrent + , swapSchedule + , blackPrice + , logLikelihood + , testMathMod + , testG2ppUtil + ) where + +import Constants +import Date + +import Debug.Trace + +--let (p, a1, a2, a3, a4, a5) = +-- (0.3275911, 0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429) + +--------------------------------------------------------------------------- +--- polynomial expansion of the erf() function, with error<=1.5e-7 +--- formula 7.1.26 (page 300), Handbook of Mathematical Functions, Abramowitz and Stegun +--- http://people.math.sfu.ca/~cbm/aands/frameindex.htm +--------------------------------------------------------------------------- +erffPolyOnly :: Double -> Double +erffPolyOnly x = + let (p, a1, a2, a3, a4, a5) = + (0.3275911, 0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429) + t = 1.0/(1.0+p*x) + t2 = t * t + t3 = t * t2 + t4 = t2 * t2 + t5 = t2 * t3 + in (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5) + +erff1 :: Double -> Double +erff1 x = + let poly = erffPolyOnly x + in ( 1.0 - poly * exp(0.0-(x*x)) ) + +-- Cumulative Distribution Function for a standard normal distribution +uGaussianP :: Double -> Double +uGaussianP x = + let u = x / sqrt(2.0) + e = if u < 0.0 + then 0.0 - (erff1 (0.0-u)) + else erff1 u + in ( 0.5 * (1.0 + e) ) + +uGaussianPwithExpFactor :: Double -> Double -> Double +uGaussianPwithExpFactor x exp_factor = + let u = abs ( x / (sqrt 2.0) ) + e = erffPolyOnly u + res = 0.5 * e * ( exp (exp_factor - u*u) ) + in if x >= 0.0 + then (exp exp_factor) - res + else res + +--------------------------------------------------------------------------- +-- THE FUNction-PARAMeter to rootFinding_Brent +-- if fid = 33 then for testing to_solve(real x) = (x+3.0)*(x-1.0)*(x-1.0) +-- Otherwise follows the real implementation +-- N is the size of scales (bbi) +--------------------------------------------------------------------------- +toSolve :: [Double] -> [Double] -> Double -> Double +toSolve scales bbs yhat = + let res_map = zipWith ( \scale bb -> scale * (exp (0.0 - bb * yhat)) ) scales bbs + res_red = reduce (+) 0.0 res_map + in res_red - 1.0 + +toSolveTest :: [Double] -> [Double] -> Double -> Double +toSolveTest _ _ yhat = + (yhat+3.0)*(yhat-1.0)*(yhat-1.0) + +max_num_brent_iters :: Int +max_num_brent_iters = 10000 + +rootFindBrentGen :: ([Double] -> [Double] -> Double -> Double) -- toSolve function + -> [Double] -> [Double] -> Double -> Double -> Double -- scales bbs lb ub tolerance + -> (Double, Int, Double) -- Result: (root, # needed iter, fb) +rootFindBrentGen toSolveFun scales bbs lb ub toll = + let tol = if toll <= 0.0 then 1.0e-9 else toll + (a, b) = (lb, ub) + fa = toSolveFun scales bbs a + fb = toSolveFun scales bbs b + + in if fa*fb >= 0.0 + then (0.0, 0, if a >= 0.0 then infty else 0.0-infty) + else + let (a', fa', b', fb') = if (abs fa) < (abs fb) + then (b, fb, a, fa) + else (a, fa, b, fb) + in brentWhileLoop (toSolveFun scales bbs) + tol 0 True 0.0 a' fa' b' fb' a' fa' + +rootFindBrent :: [Double] -> [Double] -- scales bbs + -> Double -> Double -> Double -- lb ub tolerance + -> (Double, Int, Double) +rootFindBrent = rootFindBrentGen toSolve + +brentWhileLoop :: (Double -> Double) -- toSolve function + -> Double -> Int -> Bool -> Double + -> Double -> Double -> Double -> Double -> Double -> Double + -> (Double, Int, Double) +brentWhileLoop toSolveFun tol i mflag d a fa b fb c fc = + if (fb == 0.0) || (abs (b-a)) < tol || i >= max_num_brent_iters + then (b, i, fb) + else let s = if (fa == fc) || (fb == fc) + then b - fb * (b - a) / (fb - fa) + else let s1 = ( a*fb*fc ) / ( (fa-fb)*(fa-fc) ) + s2 = ( b*fa*fc ) / ( (fb-fa)*(fb-fc) ) + s3 = ( c*fa*fb ) / ( (fc-fa)*(fc-fb) ) + in s1 + s2 + s3 + cond = ( (3.0 * a + b) / 4.0 > s || s > b ) || + ( mflag && (abs (b-c)) / 2.0 <= (abs (s-b)) ) || + ( not mflag && (abs (c-d)) / 2.0 <= (abs (s-b)) ) || + ( mflag && (abs (b-c)) <= (abs tol) ) || + ( not mflag && (abs (c-d)) <= (abs tol) ) + (mflag', s') = if cond + then ( True , (a+b)/2.0 ) + else ( False, s ) + + fs' = toSolveFun s' + + (d', c', fc') = (c, b, fb) + (a', fa', b', fb') = if fa*fs' < 0.0 + then (a, fa, s', fs') + else (s', fs', b, fb) + (a'', fa'', b'', fb'') = + if (abs fa') < (abs fb') + then (b', fb', a', fa') + else (a', fa', b', fb') + + in brentWhileLoop toSolveFun tol (i+1) mflag' d' a'' fa'' b'' fb'' c' fc' + +testMathMod :: Int -> Int +testMathMod arg0 = + let (scales, bbs) = ([ 0.0 ], [ 0.0 ]) + + -- Rootfinder.brent (fun x -> (x+.3.)*.(x-.1.)**2.) (-4.) (4./.3.) 1e-4 == -3 + (tmp1,_,_) = trace ("# Brent test: -3.0 => ") $ + rootFindBrentGen toSolveTest scales bbs (0.0-4.0) (4.0/3.0) 0.0 + arg1 = if equalEps tmp1 (0.0 - 3.0) + then trace ("... SUCCESS !") arg0 + else trace ("... FAILS !") arg0 + + -- erff 0. == 0. ;; 100. *. erff (1./.sqrt 2.) + tmp2 = trace ("# Erf test => ") $ + 100.0 * ( erff1 (1.0 / (sqrt 2.0)) ) + arg2 = if (equalEps (erff1 0.0) 0.0) && (equalEps tmp2 68.26894723352726) + then trace ("... SUCCESS !") arg1 + else trace ("... FAILS !") arg1 + + -- ugaussian_P 0. ;; ugaussian_P 1. +. ugaussian_P (-1.) + tmp3 = trace ("# Gaussian test => ") $ + (uGaussianP (0.0-1.0)) + (uGaussianP 1.0) + arg3 = if (equalEps (uGaussianP 0.0) 0.5) && (equalEps tmp3 1.0) + then trace ("... SUCCESS !") arg2 + else trace ("... FAILS !") arg3 + in arg3 + +-------------------------------------- +-------------------------------------- +rrr :: Double +rrr = 0.03 + +zc :: Double -> Double +zc t = exp (0.0 - rrr * (dateAct365 t today) ) + +bFun :: Double -> Double -> Double +bFun z0 tau = ( 1.0 - (exp (0.0 - z0*tau)) ) / z0 + +tFun :: Double -> Double -> Double -> Double +tFun sigma x0 tau = + let expxtau = exp ( 0.0 - x0*tau ) + exp2xtau = expxtau*expxtau + in sigma*sigma/(x0*x0) * ( tau + 2.0/x0*expxtau-1.0/(2.0*x0)*exp2xtau-3.0/(2.0*x0) ) + +-- the first parameter `genome' is the five-genes genome used in +-- the genetic algorithms that models the interest rate +-- the second parameter is the time +-- the result is V in Brigo and Mercurio's book page 148. +-- \var(\int_t^T [x(u)+y(u)]du) +bigV :: Genome -> Double + -> (Double,Double,Double) +bigV (a,b,rho,nu,sigma) tau = + let bai = bFun a tau + bbi = bFun b tau + v = tFun sigma a tau + o1 = tFun nu b tau + o2 = 2.0 * rho * nu * sigma / (a * b)* + ( tau - bai - bbi + (bFun (a+b) tau) ) + in (v + o1 + o2, bai, bbi) + + +-- the first parameter `genome' is the five-genes genome used in +-- the genetic algorithms that models the interest rate +-- the other parameter are times: today, maturity, and the +-- lower and upper bound of the considered time interval +-- +-- the result is: x drift term in tmat-forward measure + +bigmX :: Genome -> Double -> Double -> Double -> Double + -> Double +bigmX (a,b,rho,nu,sigma) iday tmat s t = + let ts = dateAct365 t s + tmatt = dateAct365 tmat t + + tmat0 = dateAct365 tmat iday + tmats = dateAct365 tmat s + + t0 = dateAct365 t iday + s0 = dateAct365 s iday + + tmp0 = (sigma*sigma)/(a*a)+(sigma*rho*nu)/(a*b) + tmp1 = 1.0 - (exp (0.0 - a*ts)) + + tmp2 = sigma * sigma / (2.0 * a * a) + tmp3 = (exp (0.0 - a*tmatt)) - (exp (0.0 - a*(tmats+ts))) + + tmp4 = rho * sigma * nu / (b * (a + b)) + tmp5 = (exp (0.0 - b*tmatt)) - (exp (0.0 -b*tmat0 - a*t0 + (a+b)*s0)) + + in tmp0*tmp1 - tmp2*tmp3 - tmp4*tmp5 + + +-- the first parameter `genome' is the five-genes genome used in +-- the genetic algorithms that models the interest rate +-- the other parameter are times: today, maturity, and the +-- lower and upper bound of the considered time interval +-- +-- the result is: y drift term in tmat-forward measure +bigmY :: Genome -> Double -> Double -> Double -> Double + -> Double +bigmY (a,b,rho,nu,sigma) iday tmat s t = + let ts = dateAct365 t s + tmatt = dateAct365 tmat t + tmat0 = dateAct365 tmat iday + tmats = dateAct365 tmat s + t0 = dateAct365 t iday + s0 = dateAct365 s iday + + tmp0 = nu*nu/(b*b)+sigma*rho*nu/(a*b) + tmp1 = 1.0 - (exp (0.0 - b*ts)) + + tmp2 = nu * nu / (2.0 * b * b) + tmp3 = (exp (0.0 -b*tmatt)) - (exp (0.0 - b*(tmats + ts))) + + tmp4 = sigma * rho * nu / (a * (a + b)) + tmp5 = (exp (0.0 - a*tmatt)) - (exp (0.0 - a*tmat0 - b*t0 + (a+b)*s0)) + + in tmp0*tmp1 - tmp2*tmp3 - tmp4*tmp5 + + + +swapSchedule :: Int -> Double -> Double + -> (Double, Double, Double) +swapSchedule nschedule maturity freq = + let lvlt0tns = + map (\j -> let i = fromIntegral j + a1 = addMonths maturity (freq*i) + a2 = addMonths a1 freq + lvl = (zc a2) * (dateAct365 a2 a1) + in (lvl, a1, a2) + ) [0..nschedule-1] + -- Reduction( lvl: +, t0 : min, tn : max ) + in reduce (\ (l,ti,tf) (lvl,tini, tfin) -> + (l+lvl, min ti tini, max tf tfin) + ) (0.0, max_date, min_date) lvlt0tns + + +blackPrice :: Double -> Swaption -> Double +blackPrice iday (sw_mat, sw_freq, sw_ty, sw_vol) = + let maturity = addYears iday sw_mat + sqrtt = dateAct365 maturity iday + n_schedule = truncate $ 12.0 * sw_ty / sw_freq + (lvl,t0,tn) = swapSchedule n_schedule maturity sw_freq + + strike = ( (zc t0) - (zc tn) ) / lvl + d1 = 0.5 * sw_vol * sqrtt + d2 = 0.0 - d1 + in ( lvl * ( strike * (uGaussianP d1) - strike * (uGaussianP d2) ) ) + + +testG2ppUtil :: Int -> Int +testG2ppUtil arg0 = + let (iday, tmat, s, t) = (9000.0, 18000.0, 400000.0, 9000000.0) + + res_b_fun = trace ("# bFun test = 0.30490117 => ") $ + bFun 3.24 1.362 + arg1 = if equalEps res_b_fun 0.30490117 + then trace ("... SUCCESS !") arg0 + else trace ("... FAILS !") arg0 + + res_bigmX = trace ("# bigmX test = -0.2356067470979 => ") $ + bigmX (0.02, 0.02, 0.0, 0.01, 0.04) iday tmat s t + arg2 = if equalEps res_bigmX (-0.2356067470979) + then trace ("... SUCCESS !") arg1 + else trace ("... FAILS !") arg1 + + res_bigmY = trace ("# bigmY test = -0.01472542169362 => ") $ + bigmY (0.02, 0.02, 0.0, 0.01, 0.04) iday tmat s t + arg3 = if equalEps res_bigmY (-0.01472542169362) + then trace ("... SUCCESS !") arg2 + else trace ("... FAILS !") arg2 + + (res_bigv1, res_bigv2, res_bigv3) = + trace ("# bigv test = { 7.8288965347e-4, 1.107549139, 1.107549139 } => ") $ + bigV (0.02, 0.02, 0.0, 0.01, 0.04) 1.12 + arg4 = if (equalEps res_bigv1 7.8288965347e-4) && + (equalEps res_bigv2 1.107549139) && + (equalEps res_bigv3 1.107549139) + then trace ("... SUCCESS !") arg3 + else trace ("... FAILS !") arg3 + + (sw_mat,freq,sw_ty) = (10.0, 6.0, 4.0) + + (maturity, strike) = (22094640.0, 0.030226283149239714) + swap_schedule1 = [ 22094640.0, 22355280.0, 22620240.0, 22880880.0, + 23145840.0, 23407920.0, 23672880.0, 23933520.0 ] + swap_schedule2 = [ 22355280.0, 22620240.0, 22880880.0, 23145840.0, + 23407920.0, 23672880.0, 23933520.0, 24198480.0 ] + + vol = 0.2454 + black_price_res = + trace ("# Testing Black Price = 654.1429648454 => ") $ + (blackPrice today (sw_mat, freq, sw_ty, vol)) * 10000.0 + arg5 = if (equalEps black_price_res 654.1429648454) + then trace ("... SUCCESS !") arg4 + else trace ("... FAILS !") arg4 + in arg5 + + +-------------------------------------- +------- Likelihood Measures ---------- +-------------------------------------- + +sqrtTwoPi :: Double +sqrtTwoPi = sqrt (2*pi) + +data Likelihood_Type = CAUCHY | NORMAL + +llhood_type :: Likelihood_Type +llhood_type = CAUCHY -- NORMAL; + +llhood_cauchy_offs :: Double +llhood_cauchy_offs = 5.0 + +llhood_normal_offs :: Double +llhood_normal_offs = 1.0 + + + +normalPdf :: Double -> Double -> Double -> Double +normalPdf z mu sigma = + let sigmap = abs sigma + res = 1.0 / (sigmap * sqrtTwoPi) + ecf = (z - mu) * (z - mu) / (2.0 * sigmap * sigmap) + in res * (exp (0.0 - ecf)) + +cauchyPdf :: Double -> Double -> Double -> Double +cauchyPdf z mu gamma = + let x = (z - mu) / gamma + in 1.0 / ( pi * gamma * ( 1.0 + x*x ) ) + +logLikelihoodNormal :: Double -> Double -> Double +logLikelihoodNormal y_ref y = + let sigma = (y_ref / 50.0) * llhood_normal_offs + pdfs = normalPdf y y_ref sigma + in log (1.0e-20 + pdfs) + +logLikelihoodCauchy :: Double -> Double -> Double +logLikelihoodCauchy y_ref y = + let gamma = ( (abs y_ref) / 50.0 ) * llhood_cauchy_offs + 0.01 + pdfs = cauchyPdf y y_ref gamma + in log (1.0e-20 + pdfs) + + +logLikelihood :: Double -> Double -> Double +logLikelihood y_ref y = + case llhood_type of + NORMAL -> logLikelihoodNormal y_ref y + CAUCHY -> logLikelihoodCauchy y_ref y + diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib b/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib new file mode 100755 index 0000000000000000000000000000000000000000..fd74e7921ff86bb9fbe8869628c5bebcf054689e GIT binary patch literal 5575328 zcmdpf4SZC^)&30-Sry#%16@AURbz=CU;wc}v~DEPySTw9pi#jDNJ1hZ#AE|eu|`6K zb&al8ZK}47+FG<+T=yxp?FhBf8uHnMx zWFyPi2XLmq@d~f`Q@*bbEstfknsXEtZ(bS^KhSNpS--= zPmd~bQgzkRQ%*jqx@<~yRZTTJ@Nr!(GjHbiSL?hGTyBzS}b)f$klr|lmNe*=U4&_T7 z%9o(?)6p+?C_l~tKixqNuQ-%n=fLN;9OMvppmV1~e?9F$|7Hh1-*BM69~3a1eC~26 z|Dpr^E(bctgMVKdeVgTg|A|ArXE@+5bf|Z&1D{?8`8PS}$pa2_Haf_Ef4)`?={CwmfpQjz<`45Nk=QzmcK8N;>b-*umz#r=%pQ#S~Y;!38v4eaX z9r!PHkVAz-`R_XLKhHt_|8ywta-jc)105Q5AO43P_dArI=OCZO4)vBgl)v3UJ|{TP z8R1aA5RChVG7tC=2Rc_e@bi%a{hbbSSnHrauRGv>fP6&z2hC|uX2!Ql>`059Lk3s%D>}K@0$+t ze8@qcFLjVZl>r>?>Mw~twZ^J z9NKk+1HQ|FezODqdFnrklRtl1SAG-5=bk5(gwT-c-I-x zWMQ1Gawy*-%8xgCu90-Cn{GmX9SAy}A@pldp7^2lE>LpFndY}hi0>N|KSSwz&@ZIp z8bbdP(O>%;eJ7^U*)HUBfbp{_m!;4*kcU~mvX+ULX*otoU_oI?S$SRg@~Zk!dEJ7- zIn}Fb$`>qIT3v3Glq_Gls-~nqw4^RnQeu?MU0rg%DmSNkNqv2Jy}aG==GrSus%ol2 zf)LKj8*5k9DF|d6mX=JDmugCu)RdLf*g#pCeOgmiV_hJz)#XV7OUlZU1gcimCCe?V zE?-h-kyzPKZJk!vS5{Tn?9|q+TDoLuNo`%#%JPz0s|<=;RIe;qzD#i5_UWH8gg4d8ov02IyF2Yf3`6x#V)ipDI`~9m0_;Tv<}PYRyXP zyatsD4lVv5HtV!bYfeqc%2iq&jZz#H5WiJ=*~(gW{YrNHDMt0G#c@4hG>*`k32^CzntfXGnQL?aRO%)X2{POw+R06fbwc7H!`c*Ycs;fd* zl&sF-9m^!=<+ZD-t4kCQ6&2MD^_50_sBT&96-GTIRTHW(z%F=O0u`tE+iS4J)ZwRkwmg zp+3u2E~#HZ8WnZrm)G^-Dq_ zw7xvF671K2{>mk_#xizGNu5zqzN*5g0Qq_YB4LG~P>s$&8$d5~1@1FemapU&*s56~ zx&TtBSw*IogsN867@=jjj9NghzPx+|%Tu6addc!~YQIsw8dX=68Q^@nQM;r8LxDZT zYA{ksJyjr(k`PI#Y*hnfT-y*@MtXG(^`I!=dZXH|jDm;4f#^yIJ|v_lTT{2B3Rv8^ z9OA2~E~#EpgKn%?WmGPyhdfrHFH1_6g|4VAFImb4v1obCYIfVQRYIOHe|2ON$}42i zP(%5lSOX}sG%1&qRLI^fDXG7resu}TLpz7GNmx52h>|sRRnW8w^+i=Ms+O&)SzRLA z0mAH|RTX7R(033LIt-Fl>K&>UHIoDClg5J8?m!0GRxU}a3WU;!mf@1< zGVsfuHWDdVGTjlxvHiDlp*V?Iy4NO(72=ogRhYup}cHKXbEsj>+9wH zK-H8PX9ojk&MBEbb^6qq_W6vdGmNw6%qf{MHAj8Vm^#hAI_+fp6vfo--?YzWOx3Pq zr9mDeuu3ojs|oTu^;51O=q2D_aS*c){^c1V>(K8XE%0#RI7VRYO21}NwkSw=UzFJ| zrJSroa>p{6;;Md^&INhW|0Gpn$oEhlSQD{&jk+8p-@JQ&V~kjD8DWf7_YgZ$lN#4$ zMi?3DpI7BM0uLM+_$xzYT-Wj8zhOevz6R?3z7&oqdyKlCV_zR5uJfMy@hrcOalcl6 zy;i>H8&~XafXm;Ac*!u9lzao_M;X7f%V!v0fR)txM{4!&WBgXpLv_ZjH{Xss#~R&= z-oaH>V+~_p<3$A@CSaHGCk2NDf1{1RD!5L-nZ^zU%l3}2>&sm#*8y?an8*sPL&bCK zEv`>lhZW}$-(ex~ZN-O6KJs+9S@CR$<2Q)m_LhWOj)GNw( zoQ=fdr-naN!+SLRVH)16;k_E(r{UF-u(+D7;W4|hj~orJ>v^t*Kin>D7=8_ZgoZaY z{E-^INW=Rye6fZ^;=h~ljY|`*2SV(+#Xn47@FE4g#_$gZXE)73b!}nZ~# z3yJS+4L@7M=VdxKV8H7HT)SG-qi4Z4PT_;^E7<1hCfromumPq8opA)|3bsp zYWRE&->BgWG<=hWKU>3Z)bOT;k81dUhHumGb2WUshCfHcZ_@BV4d0>R3pISFhM%Y5 zyEOc{8oo!v7isuj4S$}7@6+(-YxsT*KVQSgH2eY$pV08holu4`py4mj${XcL{l8Gd zyEJ^UhWBXri!{7f!(Xi7eH#7}4WF&y7ist$4Zm2!=W6&%HN0QLmuPrX!?@KqYVO~dOMyLJt~ zLMy*X!&htg4h_Fj!*^=<8V%p2;a6$+9t~fs;d?dw z!}~S-H5%U3@J$-NNW)*N;fpo=It^c{;hQylrG{Ux;cGQ~i-vF1@YiYhCJnzq!*A5^ z8#R1X!-q9|n})w$!?$brh=$*!;cw9J9U5M0hP>FR;cwK+cWL;WG<=VSk81c{4S%zS z@6+(NX!w2&{~Zk<)9|-y_=JYPO~Vgp_}ewSu{^2&-_`Ig4d15WJsSRd8s4kn@6hl* z4S%PG&(`pFY4{us|9uUgtKom3;r$x^hZ^40@a-DDNWeL& zG<>aw|FMQ|)bRIdc(eKME;Ew3aAu)lwseIuV=rYGhS~gtYnxUGr-L)kM3KQ`^YQ6E z(vLI3!ZXDC2XP#GDq-Ag#Cruio$v_4T>?Iy@JPZP0zR7XD8lUmoVgvS#u5^x>i355LuzKrlh!Z`w7N_Y}s zpMWnWd^ll`fX^q)DQ(;k@La-25>9-{_Mb`EN4Q_WrxHGjaIb);6F!=7mw=Bad<@|Z z0Uu2`i*UPuClEfCa8$qt5&j0@CIRn9crxKy0goV@O}JFRJ7)ksj&PBHcMv|FuwTIM z5k7%%j)31Ld?I0=fL|j#g|J7!FA|fba~$9Rj|G@X3VR1$+nLnS`SPzJ>59gqs9>J>hQ>t`+b)!nuS?1$-spS%ixO zTu1m+!hQi?MtC;i904ySd>Ub&fG;L|I$@81&nNsX!iIq757|AUvONhk)-Pynt}KfbSr@kZ@GMw-CO7aFc+qCww8{ zS^=*kTuiuBz*iE!h;WgB>j+;=*e~GA2wy@tN5D%7FCy#{@Wq4|6ZQ!Be8QI!HUvDE za0%hWXQKZJmlEz5@Tr8C5bhQ5bizvscM14-!pjJE2>58iWrW)WJb`dI;i!NQB3wbZ zNx=INUQW1Hz#|CL0mVxNymK1hD#Aqq-a+^>!hQk2M|cI{909*gxSFs}z^@TrN!TOc z7YWx8HU#_(;Z=ka1ET*4*Ang*@S}t;C)_LG2MN~^?h^0=gzE`+2>2etA;RqfzJqWB z;i!ObA-tM!lYp-$yoPYCfY%XjBwQ-sD+ymgxJbZtgs&v*7w~0-uOgfy;H8Au67~uB zV!~Gw_6YcV!rvxr2zV~xYX~Pk75z`RiEzJwPbGXU;a&kxC%leumw=Ba+)TJbz(*5a zPqi36~0ZXAa;n;UWR=AbdSxzkuH(93h+| z;I|3iK-eeX*9f-~_6Ybz!Z#8&1pEx)n+PX95&cg%O1NLZj}pF_aIb(LBzz0uE&)G4 z_&bC<1bh$STM4%d_zuFi5snJ@7Q(j^ZW8eIguhF;R>12Bw-GKC@RfwWN4QA9b%gIA z>=*E5gzqGrBjBZk?;`9I@Wq6`PuL^i^9lceup!{Ngnvjl@lVnJgxd-C3;0yRcN6Xv z@N~lW5bhH2@r3Us+#%qj3IB+2J76<%`u*m)#{A8t1veS7=TO0R&tt#-%L-#!m)X3{ z6$>6V*)StB%$83YVvl9uuGnQqOg7Fp!#i>3a@;wsYm0ehHS)3uR?Nt_FTOk%0qu*S zaky;a@|KHmaava_AD6dJG$UhY0Qu-75ZXd&kA-;e!*KMH_*f9HnCd=~`e`8GHS#XZ zyC832-hzc@_{;eSn!RTD^tSWQHQW!Mo!y=J1Dx>)XWojlNapSMG$SS6aDLVpGjg^s zKjI5)eRp)=+9&*xn?(FCXXjbQlG*bjd*8AO}Nf!TVMD|XTtP-wl% z1HSVkGc&+F?eDTxNKJ+5ET*90kG)UGewPD`f1IhphIY9Uk%$TL#|Zr$8Tg{kOxf&%t%k z=u=s6tSC4bYehjJr@Y7o3D9u`TdQAk70&u{^<*i(V0bXl-0g~u!d*bG`5VzHkip&RdkXIPcQD zl5LW&?#v6U%aJ+Yno_9V<{{_Da^7X}9o$dnyWj(JYm9tv^G2X@k+BDY$fK35mC(rj zaN6>8XB2?x&Ij)!qTQL_R&}6RX5=c5 z*&5pBjUD^j$rvuna49@zjA*cGLKs?$n@`8hq94uhpCOFK*aE0-e6qkcQHb4{-%xai z^>m87CV|6U_A?m|XTC8HmAXKlD%G9&3_u?2huEtw!(gfW$k+#gf7Ep&#rsp77C^o^ zfGqiLK)`ItH~i;V`>)Z+ncqgiK)Cx+FFK;rkB^p5tnwG8l<&@*ud0nz@Xpio)tx;z z;LZd-S_ajflId(*kIxr0pm`8)bJu7~A3X7$h+d(;qCGnc?e_R$`=UJ@W-)B^5DkmW zd=1whZ49$rFX6Q1lg@Sk7MmTQWSK-s?*X0OBcm0)4te5@{RAguF>?B~B%Cb>UrEA) zokbeq3kBgON}3FHXP%#=n;lzXkt>!bzSz0)#1%VBRgfRaJd!muZ6NDjoEEfnb#4M= z@%}MlSdJgi_r~13KQae8c$JTO=!<8P&``*~=`|zH6Pkv;@7&DwO zoBIdMh!H7@HSf%Duiqb6-RoW-Wf;vnN4VE>*K#m&^2@F@)ka|J`}-8O{395Cui>!x zNv!Yr*6wE>Vt8s3=Kx^}xaJ{7l1JHd8< zFJEkqvc2eEMv^8OdyEf0?rSEV#&S~Z`DllUM4S2YeJnd@YI>kmdXfn^uO3L-UM z1TtR9YyNW3y`GP^7PS1MVO;!UaS!_EDOcVL|8TE=7jWJuPiBPBKcB{4M!D_pz^_I! zrz?8rr=xcgkdodEoT0o;?-;;IdMy^c{K&YsE@OMqBJKfK){NHwC0c*?bt`aVG9+xrCIWPAUDa;m@2RP^phM{hNdlHOHA=&eYhcbi2o zKXUkomF(}=-Rq0lIBFw$h3bf~<52hdnX1VL#dC4SaVhli1g*V;u>y-8?LNJf9W4xr zbNGIRq@L*U!nnVjeXh~jPlxp4qn%omuoYo>FjCt`0~UV~CfWw308k9ak_`UPsKie0D(&lu4y;@4LBC?#TO2{$;X?X;!U%}O`padxgP)v(h&WOfL8%OB+v=p zz$>=^sEEd&RbVqf=y&{80T0IN6?`Y!lQbt$&TazXFEPQHZ$?fs!`lPl_XFX-o6YYG z?^|VK==Z0p8Mhatm7k7PAWLpm=&w{MoyoCGrEYYaA$YsVSrG*fpVd&sd?eY z3#*>#1RNYWcFbSTHS)rVyyl*a=D&`rD8S5YYGI_RxG)^d^5sRwSLB5kWo73@3JshE zvyOMK&jiUpI5P6V^m=t;*^F1j9xL`E9*KdSB9L)Md6gX8Mg4BKU(d1cM-5WZ{ z?biO$W@`thpJwDNILjh$aP|ehAf&o_zsF!Tjac|D&e(jx$TG~!N?k#QLt($i3_lgv z_bIdaxePNrqcGfHXif8@tH<6wN7S?08yWWloYI3`3SPT2Hv(dJ45`~}#jJ34jn53% zc-MSWt8x3SNrjAzJ73WnA!wbZXvJq>h6jCq4ED^3y>jPdWBc#eenf!dQ6z6x7xXhG9S2j+K0ub7^TMBL-8`>#R8MgBS!m)}-qoWq1^w|Ila1ytQIT(TB)@g>zrc_y z?@`46#@yDE-{5y%^E;#2^uVkg?)7C5b|FXRO}G+h{yZa8htCnAOYu1}G#8(vLZ{#} zGjudQ_X!<9f#p5wL1~I@Ze;DjuDRj09#;U9{kf59Le&-&Bowru1%wtzXkG-@=2_R~ zMe+&d%WHzK-(v*Li!35~k;er~F~Ku09P+?sluhu?3zvDkfymkkK344uM5-rbv)b%H zBsd|5Rp!8=Ovq(*xrM;_S(P6w`a!(mC-EANPx#Zw%%}XAvtc$B!0Z~|BW68S5PoX) z1lYHSa76@bT;l7_{60Xd3kt&9v@V$2dRm`3``b{PZ+lm}@?oHl`rc$n`Cse=_jMys zS3zsVzo1#Jyhmh5ocI^n5%0q6n&^nQd;RP1o`o&%S{?C)=!h>wM|>eV;tSCcUx<$Q z0v!R(^yEFlj(~o8Aj17ALKiw>t7~2)L?|SoxrF9g(7eb3URz+5TtsM*RdOv$u9cAB zYYzCD7b#<*GN2>D@g4}+1sl0wycYs?c?%=?<9)2!hi)35&1%sRq4DU5kSnJU<#Jga zI%3gybi^VTI$|q2B94yui#9KgtZ?~1d2)2aSwYz7yic}fgj|8vs=>lYU@&m)X9Jk( zxz~SiAhh(_&w2&$wgfmObgzF|0-O=L*Y^+zuQcN0L~Py!A;Eg*XMJ1%^O}gv?ETic z#<{Hvax!K;l^=eY-F^6zKrvQpxf~+x&inZkl5j;`K`@I=hd!*4!zxpZw;;KgZ}RIY~@APDq-{A>&s+rQO&BBy`jbdJxb zM$PKZ5C0Q}aqQthKz1$H9l&lH4an-I{O}H~n}V&QdQ%MJ4Ywt`sRq2{x0a)yU>wDm zoY#7YHYRJ)Q7^dHpN(RBH74N&)R=@XKu4vH!fKAK>U1LwQs=dxbqynwLraZiePj#1 zehIDC$7G0OGUP%>EgFxGTEsCK;+PD%*iqxzQ5=(NIVRV-U>t+vVH|_5T#jNts}f@p z#L-clrNjT`N9HpT_T$;?fX7E7&L{}K!l9CR2T;hqxLbB23*DXB4AAO>g78aPAIxn% z5tdQL0n###zE!h~F--KNWxUE|c_^(D8j(JShk6{PL?>{iCeRGScsV{tgcjp-WGH~o zQK6am%nTic&wWB;VQ4+VLBY1dufy#G>2^dmIuarjvLHC2Af1rB1}7Ax6Os^oPmsQc zkV(g8(y@hiLa=!gY4ao`_<8`- zZVUpV%e;sXf)f!T1iiFY6KSoyh!7S`M1-)w%Rw+Po7K`~ zq(o;TG}z~6Z24$8avfXs*X#uEqas#_jRZ zJM3`@y$GWk>IB@ThLlUYb^*Rp-B>gvhuz~*0mt71tnBC3w(VSy#uXfA)+G- zyzq+)448y6FHAz2LBHswUo>bEyxFXle$h+6Xuu?dyf6tN0|Cq;F9MiF224U1OhPXd za+c_Ogr8qz`<5G=KDgI^irhR9u_Koo?v@u5$l|q{9t3SZ_l73`<+WmV-G*7|C^Iv0 z;Y~(x--PJSt`8vR$hg4Cuq(5AndUePr!?q%t5$br4j{{-Xnkk4M!D=}!lIjUT0es- z{NN2jg$kxUos9Gul*1n8Gf=N)pkB?OU=f3YMS7qP(TvAvEYpJmhU{oOg93yMCPd>h z87LGnP$)w1UW5=l3Pu`kif2JFrJc-+tj+qE>5BwHgjF-R(7foI8JMo;hu;uZa~W{L zYQBYm*PR&zXtgmv{HoT>VCxuot$FaBN=09YBvtfWicW-Xu$jVZVO~4LX2NS_qu5^B z%&U~w!n7YYQ}3k9FX^Ni$L^mY7UD7?#_XX%pqwh1uwp}885L9%nm%TKR zz2rqNoUkH8Ne|_gSAD5fq@xPLHQo!f{4U%~I zPa3wza>aT!Vi7a^Byy6lKbOE^{5{b8dt~j9x_v*0O$z7;G@=3j$8h=^>wFli%jW>S z0?k^8)zG!iV#mUl?&dSL!&F5U!i78uDhK7GkVxRPhFIXAb??LvM+v#V0=dc1mF|Zd zvuB^)b`ti(G>^cg?#vr-PNw4@y~mOu_4kazegDe*A(oD6a5Zn%lkV$Y#?@drT`JW5 zaB+6ttT)`(J%}RPe~};ViRX$+<$RFvj{xU2zdOR+@*7lT!b+Tg#?*Sn79Ml!XCw2% z&o;kxM&8!#`;6Gx0nKpc zJfPeyxnwSq82}K7_>rQSNxH3WL@7ubT}UcVuZW^vnwyJam;BQxKa!nV~T zS~&bgoW{$6&X1gp;%G~;Ebc<_LQ#CmFGTSb7#WA(%i^bq;w2yFk1R>dZC?92iyjSJ zFfy|l*WoH(XW2C@yC3k${B7Q~1B2*(_l7SZlfW|Umw9KDdF{5u*>rOs1;UH5A`!!t z@Sn_U-(ea&57}@e!UJ3XzE5D^KjnRb{CoyHZkDgW{cv?wHc~i$1M9P=%s^f4=I`U) z`0YqOMW!4L1me6yBB%Rs)-u>o)17$$&V~#bX1z_iUn{!VPo|K+)1pOqkDDS3iwI9< zV&gMWPht3_z}9z07e;>F6uHSL40Bl`d@s-AhvITLw!IDgw-M~Y5NAQu^L+6$0L3;n zgLGuvz9*s&y8U7S0je_sAacH*K=@2={8wngw0{J`FI;Md-!_}yO%yE%bayr3rB`P6 zR*(4Vb{{&&h%I_yaPZ@#c%z-q;{{#|%_)4(mf1XTfEoVF>WQ6@xOj}?z{QX8!eGCh zKUs{02*0+aZ40k2G_QSM5ZL;!ks!eB16yNfVByJp;a{O~HnsgNY8c0h)jp-B(=(1b z7e4+#Y>4|ytOmNc_^HhIeGvOcqNc|@cmcfGe1_4Gx&1r1&nEUEZy4-d9KRCxR7A-! zk3;1b*7*w(!C3=!SQo(Xe3Or-VAtL+u4;DJh;#zExt*gt0(FC{si059Qby%-6;8f z?ZZhL-^FR@Bj|IWf4ejN*mo8ED^uuu($H7@_fzh{6uFhx}&=w_Li))KYrU|hue*60{ce$K~ipP3rD7Pz}_1Cx8!#=$PBbE@neX5lD8!X z8*SI&)%HCLsF>DHF!+aP~|ONSr5;#I$~l4q<)GS!LC27j-tG0@ECIKTIxrda?UStv+eSD1e(;#h9@!9-RQ%K)xHo$AiwAeFN4I>S>yal7eP=zI=S<($qvta^J!-e~sNrCxN9GXz*}s+^`O2go zxu!yox>EHBYfLDaJbXA6_vw06DyyR&#oV&|Ug%K~s&~?(rlES2P7dTw44)-yZZzU^ zZ=Qtp=vu`Gvl2SMxff z7&njIe?zOWNP zou8hu&hj~XC_gr zN{e|G9k{maO24tg?U@6Dmw0x#4=jj*T0iaj zA%n+MMDx`BKK0F_qw!Jb+TmW*v%`JS*ax3H4g@aksc>J|RpFl6(~y1TH#T>!6W$sA zKn5)8ZaJ<9Pe-R!K5$G{pmkB! zXSmffSdL9AEgNws1%)=bYS9i{am6RRgDp2UiD9=X|3umFz*4C=AfFiRL-i2(#QasD zD`gy`R1T$!^Q*g(?a|wEq7u?YnfE<$Tq-Z4>?XL-1jYSsyR<%bvR^ z^TBP<3sFOi_=I)STP!-jo1O`Tr95_^;}Xd(W!t3M_>HkRx5fm&vCUl^=&wHZ*Ye=( z`a`d#HSKe)Ku_Vxg~&N7M0w3b?l-)!-wYSV5U?bW8(=uo$8J1~-H7p@Pog+{;uB&_ z`Z*4(?9CK`>?-POt);IGmIq_o+S(veGg9acU~APTimwCVlaD8zyx!F=l&BDMq9Ei& zQSk{1p7gU&s(`v|0k!D@%1#QX7R<)q`!n~!QIGkrjdL--IAW+i=(b|}QBu5UKP{O> zLzgewYFcf*6f!>S>g8zhXb9IG%=nNB)dPh>(|RCvwxO33M@<8E+4E?k>iJ}&OmG6W zDCJH|>au;fppR4GKP%C`fxc>rUD&^Y_-ntXJXn^8PkdsiG(X|9+L3Fu0QVe5=3^cZ zptKY0n1MieQWjzY8kx8-C7&Wkp^Z_}jMu*@_8Tg-F|a{N9Lm1B*L??IitM`!`Zum5 zpVGua5ru_~A20Z&?0NXar{Fi&;`iL4{PuQSCi(3nzx_$o*(3x(jiOkQgjUUX5zX+3 z=e4zFKgZve#_#6_K@e6J**hgmRNC(E%R8s;#skU0eY09=%{9h_K*(b zZ`=4I(4NCE6&ZC69s+m*GRLkv80_yMgQBtL!CmpOU{ALG5;vZY8%2fd6AC9i1GFpE zly1u0%XauyY3=yIGgdoF6`eh4$H>%ngS1N@>T)-L|7|)LynDrnlpjr>%BG z6`eh4$B5K+#F54u+K#JVPie=9-L}KEx9#Yt)%xQAyB%F4r9Aee9T}X4%e8i#)noNXV#J=e!$@sM9(RL^(eS?fBD$&h^q+iT|un6_CWS{SF#vlwbgk!`Rd?~CnaZzce zTV)7C03n2AfkqFhy+G?jf?KX5!-Bt>^ek-H=4?C4ZUSgDWyt1X`) z=+kCQKVE@DknuHX@bHOGVdrc=b0S+4b4@~P;20BZAbiWoBJ>lE1*~n(Rs5*rGQy1!&y@Gl}x zIXuO`U|z#T9LPEmKl6F7hyta&6N5oP$KuzbHwIYJ1HZQX1;6m|ZqX05A!_fUtO1K( z#Dd%6)yr*ueYoA`H>&Ef=+nRN8NatYr}OJqbU5dyK3Vjf_{{{rV+Fsy2E}h6d>T|{ zZI0tcI2b1@x#U>=Se%R}<{ySR?Qn0sxmh3bPd+0(iyiKXY^CtFvh2K;fv7~yKMpQ&|6<>QV-&3E}*2(TV^xsgP3f6*r@8+dw#EfM&~zI(Xsl&qNnMvgFa+mvA6orSz))u)`!lWsrq2~ z{&f0)C!?s3QXilThYMZk5pr9=>4v43je<2XV^X@H6yc94icp-iS(a&tW-ERsK-iY8 z!l}s9ihS9%PqYKH5AAdhiZ))fL+q$aWhXs5J>pbI}v$A@48IpJWqi%tGD zH_b8h2xYy4xMOoM+@hG%EUvPDo_w9se8#3hRjj1F{@Y;@FM< z$0HZ%{r~rd`2RPD`2VP?XFO`LYy~T1TsRH?D$n9x_frB`0xMn194LH11M(?_%%_O7 z*pVuqVk&x;p8Iec=ah8w?YLFBAh;h)?0COiNJ=m#GZE_vE_J`9r`G-0rt5}@f_cB% zv*o~fT$~d@4PQio*}Qm1MYw>GgDal%$MMGI9wl*=PXi0$pd5Kv@ki=9>^ItyavZV_ z>zS(7VfTyb>#$Zl!oK5S#ZO=g3u*5RAcrdAAg6MOTTiBeWq)_6 ztxudE(@gD}?!Q-m@6h^BcdEbW6RD@^^k*wLg`DMjhaRBiaXiKvMI}tW02&wo#2`5s z?xA;y2f_&O*Jgbt7J5WiV>uk%I}pG8)A3fQ=|c^h2kf3kylL!$A2Gg~p^X?{d)FVn z(-+(Qv6KBVWwAql6#Y}m!_xmfk0Z{1LiZbnqGR!C(Hny%vK_iOQ{&yzYoy;ujd#~B zvKjW_cH7UjfBaSXy=R-wZ;_(23qNPaq1cp^jC=Y#O_JXjjknYVOWag|K88C&=C796 zO|aZaMYQiD$v^ECWyDyU2mML>K1-F5bnd{$6Ll;#tGGz&^b;^VFwFf{`0e5#R=6j5r1&5t)3Q}(6=1LrzIcV zUI;$1HzoWproaq3Bul`yeNtgM^VIZo9-yTWs0$-W^iDY04*>M0uGMMpZDvuZdj);e{~kg-E5t zHbWvL=d32JfI%-eD`RoM8bFWMWCqWjm#)~$eS^B z$Jl|Iip3|=iNA^@Pqh6*DW^Rduh?5bp{aRF$F<}fdPak<=6g@&ZK-O)+V)@5joK#i zo2%-x^qpQo$g#CxlhBJBp)o`BqR+S9(hEH1D|JIIjx@_f5$H#MBGn%FEV|H-B5`}F zesnmOPqfSG(A0C-r+cIyrHbAYsF#Ni|Ds*pNcT&6Y4syp-PgjxIDGh5_a(AhM6-wR zk&UGxOHZ?h>1p2wQV#sRAs#;bD|!Q^l3rRq+SPp<$MP=iKBcFfxEHa^=s>uOp^O=6 zK*poN&*dN?rf{JZ&v4{=g}ydD;x$Y~_X%YPe4wrP!BgD~$r^n6xb<4)$pj7`{zZAk zNA7jxgDY0xBW1jx{>7*pyMGu@>EmXg^J^V9cRz`7Q~7@CxUuwEo1bJ``HNX{+(>2O z813(AmSYEN3HCr;n+2U#1IP?N8^7lw+ihe+2-5Qz1OG_XbIq=HiShGoNNdRW=`Y@3 zjh|t5b(5k;8T0VrpXVSk5S6#3)tA~Kd}#M2`sIB?^cH<%>#fL?rPx=WqL*&`csC06 z)AAAfyOhVU@e?V?MjNs#aWC~21{S76Dz5NWa}dTuPq?x}eWf0UQH1MGJ-_{0_2u$y z&=BSn7rWnv`^8E{FI~U& zN_uJgEl1rqtlu!-@?9^QJ%o>4+r9qxq#V-Oy<$l(EgzfIeNJ|-1NZK&-P`z(*C;V!0}ImGy^dI_o@;h*H~IJnAJ*gjQbos#XRY{j3}i!j>*024yl>n<-nr>v zH}QUazTE&TkgkZv{wDdi>ZSa6hf+){HFM?UsbOz{*A6zE=9*07isj$VV$S= zM%jg_^WOD^wi5YlZu9Z`gn#*}{5}9{z$t*7pA{=QmOkqIa$W}&wE1P+Z|D1CuA3CU zOsHe05|fDNl{cAQI15kI3|pmW0{=$r-BkV8?Z$Z%ZGEX5Hs4ixf5|v1ci$!bCoShFGOiBJ)9)R$`E;-Q5C|+jZ^D;7 zR9_@cEik*p%={sd049zL&3#Q2-9u`#+S;rp=5d#(Jnlv|Fxqr2iXfp|rxLnt#I~0< z%Y^PGDt-r1oo%fWh0%hMPkgT&^{x3?-{Dz5i^Y0`beN!Eq$#t&pD_izok@W{F=&{j zqMg`m4Vt^{LDSl43yCe=>}3{# zi_f#0>QhaHoNM2b{hcoVzZJ!-e5t7mG>4TAc)ufs$qXrnCnm3-Zkd9vW`^ubr2zx+ z>AAM5QN)`~r3_Ne*}JG;=)+Y~A1paAchAGp!z1-MQQnqcF{dJT;3eW-Gh0|j?l<`= z_xGKhyx&RBP}%7C2YAukZuC)<>rR&2^yk!ZX7NWo&+sSPcf2*uAYhI&B$7s|rG{`} za+v+@q49G37Ad;v`ZL475AA=c<+7Kt8#noGWj6-Z4wzCvNf*6|5VUAh((v>u6zr3w zZ^mubsKP2NGe&Wt0pfRPl-DRlvo=@SX25Uc?ut(oj?b6<-t=awoN!4TwA%;bMas|v z?z>H{2i4xrAlz|1C|A+5{Gw0LfxIz4>ABwD;0{`)Rp_tRh;f?oT(q zNC*0A=Rvt&Q||le`mUvM*jp;rKk{wkMh~B~vx7xOF25NSGhzb)*##j$Z@^u4|*RS_f|?Ux4F;mPQ;;YyW$7IoyE^^J$XZ~ z<4L@=YIDpc>^C;5tax>*=w+)bTH=OS?(?Buu19&hELB z&;8}7@|J(m@)^$SW4`bE>3GtukM;ji)^FKYALFt?qMLAM^cy{kv!DW1hP?#^m8s-}*S+%k{BGevW)s(<@T0 z);!sguZX`8SLphA9Qr1cu~Mw}E^;ll&#JwUSQta+(*-?~9J*wZN{RT|r|Q`&eaQKt zqdxS$?5q!^;83=#bUyl|B?Hdg=5bCh4Ws2d}!%Ngs0B_go*0AAYU+a6eup z9%yuI4r}!Olg>1Y(gDO17M984k#+*B< z+QqfW0E61Mxl!50_LpS4(&%5Oh?_rw=Ib#U&igy=cGSNjMb8>9tjw}U{o=M%{qs4O zPvqPqs@W_3>wQtSC!PLPN_uJauT9;TM*p}N@9M(6Sby{lUw`C!eFE!9Sm#0z4701& z?Gy3FyS#>f7yKkh6EEPw;?n>Z#kg<4zadp-^Z?)+NE!QGoM4k}-e^0nfP zk%m09bpYFMPgRp83S2(FRtgOekFIHZ2cE;ST>R&!4I2z{{%@%I(&(qNzbyKZqkeYu zO8(R7XOp-sRX>}Y%O`qeHG8F>If`C7{dE0Uu$@*v2cDOFr_oQL7e%;tPyJ>8_r6xW z2qW7S)%%AUVZ~R@&r95L%OpBMm6!IY_F4YcqBjP#*jKQ7ek(6=8vQMFN<4qiW1tu4 zbFuD$rF7wj+l4UfaGZHkCadFTpK5EFA2exl+nAPR6ejSIb*jLc6=}}$3 zI({$ZviJH`ie4L{U&bb)hU?egzBx?4a#X$P{P{>#mbZZm*ZsP?I~`VD7o2 zyNetkjmpQdf$vK|!-?-FN-gn$DWZ_<$0qmiR<*_b(=D9b=WRJ14xg#IG%I8sN81_L zB5<*Jqlyif7tMLraeVA%{dM{s`nps9GrN_)?KdXt<2%-LKZPw8F|_B4)}CUE+NXxH z*tguc>w22>dBO2|J&9gX4?5L)U<7YP!-`UO{G#L|IMi!ejf$vO)sx0<>_#pVV11Kz zujgqg7t5bo^v0kjW%p9#0%M@|;k7-W|+s{6uYhuo+3f%t#U_;ct!Jad=(@CI)78eQE=E~AFfMW9+sn&F0QeIH)bDldyC z<)QXfbtyiuuL|jitFieG@2`wB_|#@VY^>tG$;Awc<)*57FoAilb@5;<;Zc)=Y-^Pa=!`9WE^U(j!MIVeR$jA$4s{eP&RnwXr~>l z9a5hXr+QA!mohK=X0pEd_`O^CTvE*U3)YEE47M@ja|8HYryd%akC717@>a6ie60IF zDcfn;2c=fB-cdPC7{AQ_y4SUUSv^Qv2_{tJF#O@ko|rHmd^istL%szgD)_T@T8J!$ zv@AhBE7U7qTZ(OpO!w1|U<--L`Omu4-eBQZ62rci&64kQeh-;k{GO+Hp4PptS@LcB zy%oamQ>ijNbKNRmZzn_#k@|$Dv`&zNiZ%5az_-)E? zmT#rb?~nVz??#PZ?+`gyiaN+8>j0NV{*qXg>n3 z$Bt8vrwNbsKP2t7%uD9{2E!O`1Mk)yCEmjDWqj)!spGZH77xa&N3|z?eHd2}xgN-H z$%;L3D%Pv{4f*v7zsR4k478qw_b?9_?i;=j2=5=s{O6kEjLmQ1wTRQ6M$p^meHalZ zo(AH+fC7X8eE-(M1m7-4)4~^Uxm)f5)xl$0=!kLn#HX<1*1Da0!vK&X6Nm>DPz!dV zOBa?WVJXl@OHq{TiHzW})Y&nO6qB|tpK9Ndbx6T}s1WTOL6LqH9pHBI*WxhyLX}OU|1)Z^`XsFw1=%V)H6v+Jli#wZ?%Dba;q> z8Ts5w6vty1;+ZQxgZq2D_?dB@b@8$!t@i_Xzo(6nm}Ldd_NdZ>nhMu;bMb z1?i^KV^#q@m3hpY!6{YI^9ULH9C11Hupt%{?|~D~EvLK(PN|`-hwM62+}Z~nVdS?M zDtI9JPd=3+63hn;9&?szmrs53zNXas@cKP@AD=R^?&}_YpV5K)tjcnEQ!b@Gj!#w_ z-Bbh|KJh8E-IAkw!!LkDM_>X`h%vDc!=xbxgbF|eV+9|*gfMaz@d@d_yATO=vLnR{ z8x~}lc%y$-5h`4eRgBMIR%xuTo^M)zf`cu{OBZpZj6E#GmoZN5xpE)(by3_et`-Z- zh`Q5Kd(({MXZb}0sUDs4L;p7SrRmb6@S{NXy&~hnd(ENu?m-dolb=O?G8^iTGp-y_ z_pE)Bm?Wg-N#@157NO=~m~%DYJ^NxEA$$8N@_GjbD@FgLK6r@0FQL|4LwKWucrya#=h?p_qj-v!UMYuTYZ~5cJ>-V@ ztK|*b{~+cC8#p1x;S-;Nk6iG9c{+YjLJl*&5B0$Or##q04^A>b5dKHLTi74}7-llNSR9OJ)Me;WIx#N>2xzJJWx zvMD$FEaKZk7Rk4L${cck6h%==4lsL55XTng*fKhJocHi`r+kAgn;S!O(}oA!kBRUg zmTE8?!Ero+9|Zc3+bgr{|5tlev=t(EwpZ(5el{oe!d@-GZvuU7_G%R3R?A-X2}XBg zukOA4|CqhXew^ZmC;0d5RWHc=XYAF!;k~g}rQ7}&?Nu9P`9Er}+R)rx*{gvx_R7EE zf52W1Jn{dly)vHKrM-F)=4Z39a?j(dU*Q*lzBYTc0MBDt_G+VGbT{_uqw4=-_Nq^| z>fg0jP2K+~dv($Jy|GuGp8rLAg`bJ~AGTK}n!77|m5qU;O+Z9^63MAkDXr@dAQxYuUP9;l89$D$vj-o{Zd}m z{EmIf!|GRzhd!aVH=xJCYhUN@F(AdSG$5xopL+l$0}|=U%*f#) z|5d5#VW05u;h#E`%+I=;zXU9%fvJ;0<}#w$>V8X(*8O<&xC6J@Q^Gg^K4#2!Tz5c} zoSz56^8J%I$IMVZg3K~}*L9beAF6j^L&r9<@*FeM6L3d`z5mT8N+-+b3@iWMH&~v!#=|E*SziBn zG&P8Mkpl&C?6^JTb1zc0x-#LgcYHiYs5Fjv&`nFs*Ca zC)N+CE#G1Lvtrawmr6c(_{1kTM;>+~ZnoBw6k5MN(2474Vaoop_~#YEK2cUYeBx8k z8yJw~#a2Ehb~rSd3gx@hU}0F5*LwdTqa_|b@d*KFe()rURW#Z=J|IRo#gG6!xB%;| z4{+SHTQs-YsE;qglWszoyj8qPf>1AO;Ypu3X{8vOpFr+o8*UeVdE-4veHs#Pv`+c3>#APbCd)q2 zheMA=Tp@nNF!_69h<9es@rC&7Sh3>&X7}Jt{mEY+i*3I~**&(ChfjP8`C98#YmOk# z&g*?joL<}+Z&`y$?Y@Z3A!>%j(c-(MoW|lR`Q^B=#*5;+L-?ncp&{V1!+aTBiZ}yq za6Xn_uR0Vi@d)hs`$jM_ACFR8a!MeK&AV6&DD1>aOc&l}+=KX|7t0fv!Y=H`FG?d8 zv41tHgKBgXW059QZS=NFe!>?KlI<0IXnARNdTJ;xA656~voSb)_~-pYf7)vT znq$QpE+O~=xO2oAGB81`A)^uo$k^J*OYIc1N?a#@F5};eH&Q|k22@bvTuVP0uZxu; zR@@tXiR!^8d+<6{oM7xgH*o^Ku|p6ixjY%bi7A%jBZcA(a~siNcp8XCtCuTqVsUbD zE)*a;{)-VQ0ZT3f6@M?p5hs=zqJ+@;34b0K>@rupo+({=rf})! zqZu58UA5?QN0;t-6&G8Fx^(|*>0J7|e;MY|)6OU9*GoZRSAIQ;>u71JUq7bA(XaQ) z^8c%TeSPg$^XnaVB<%&qfCvB7F)L2wBEIe5&xQ1oi?JzlDb3lJvfFm$?CC4xGb++J ze81sU{OIG6=T^K4cC2;LHFd+)@hTBsM*CkO3;cCRY!}|diE9Vdt+Vp=H0mavrWu-u z>0}GUJT{sp5z`2c7&YSee7~1oe!AGs0iW6CU=O#Vtu4g(@xap~;I8-C0g~}2GA7>Z zJtPe?%KE9lSK~%94P(VfsHQiWhRMf%*R~`-Y3=m=U>$c^$ujo_Oqcd9FW2!#T08yB zHM_IZGua0s#fObLW7ieocQ;MF$ZE5KZ|^t(y< ze^tL8gTfE>>#nbXZaTl-aeI>AwE9A`pQ118fN-`0Y4W)Je@?3}cU-+Yeff%c+^s9n z552d^cIkG6?bGbYZt}Puu$|7YR|@>s<=1l*pZ~63@4r>H*BT3?r`t_6UvjVe8s_QB zuP2@QsMLA7*-yzi%+q7MILxVg-cIM#OI{u3)X^+)_|!N3dCuFr_UEOzKFpubztGX2 zx6AVXtN#3<%CF|n`)^5(XZHWs;Lmg4lHJ)aCP--}@4}xiyELsoHx)nnIMnqLrezQO zd8aVo!~J>gJ83lS-}2|}H>Z~$__V{IJ@Dtfg0Zi`pC{gt`#B>`=u8{~QOO_A_veQ? zxKHg2{EK`tUyLvJAo_yXhZt;Kys2>3=k-Tz&e_fKdm%RSA!70e!+$IcKNE}uxiuDv z?N@@~9l=>oxz~T}62`x;=&xLzMOuRS2V`QfnG(4Ov1va3*?idFV#Vi}qiK<3-T+zq zR98}pr`qh80GyYaBMVR=Qg@MpT;w!z@$JR8AE_-9PZyeKl?yu%i;xQ`!rZ&q9DEAP zFvXmUW0mmgQoi*aJI=Dv>YN~@(EMa>d=A2aq5Uifn#={LR(yU1EMwtLQ%GqE>5kBL%hC;5+t5XJdmewjp=p zGU2-v{7Z<1wyP-)+Z5i0>4>|f9RY)t|MS{($E47O9#+~ZRu3{UWSTN;_dN?rDtpmE zL2g zpNH^^^0vH*O*FVKn;A?l47KCLgZ@JQEG}g<7yr#6N67r4d83rS=a`dI+9P_JiBRxq zMs91uMRUcAc*{dWrJ3=H*?IwXlfD8$d5ph-Sw5-(4P6N3D6BNYzY)copY#avy@jo- zcHXP6^{dpk{kHbKxR2X=C7s)TY zCv*afNeQ(aB$C8Jn+M_}$8sUb7`Q>UZ|L}9Jw?1f(qPKF<1dVvWJG&*QNHUhqP$Bk zUB&Na`8HMlITtgTsqN?#^u@CV==y?M&ZVv2;VE^v4|?mj^|ld;E(TkxIf&t0YYskc zHh+f4bS7g|P?>wWL<+H?hzruaXp5I8eGJF?nKtJMG*;%j6GB@9VYzPC{&zGc{2WvL z+}Ry2fOW{vdWL+8sQ-jAA-~Rul;3l%F~i!o={?FLwS6aH2R1}o%1dInHoPp>dutu& zXnxJTVIK~5HBO_OFx3O=Xc7Dw)Lx9!P28tV*V@71iBa1Cp*+P#cL{mqzCqRD@BLw9 z_OoD2uGMo!l}+#1%8kDGVR&-s|A&mYqgYriX6hKDm6_4cF)jfY)W%zmIb4p*j_aM} z(6QZ74wby5%c0VN4&-3vU)>w-Q~k~+^)|knltX{IPDRUrh8*xJY1yurY8NyD?Gh&F zJ54Y_R;zw_v>k&~qF3Xqkh4*#SH?l{k|gXWe6GmpG~v|P6qa%rW}hI=MvPn3W{r<) z_r>^VROO#Pa6jIjGR}L23cg7dj4W=9?;C^vG41kvB1kJwdrGecYl*H))XIC|Z>_P< zmmk3GgbPK_pC*(NSZ+PC9d^YtC z4!WGnC5lkakqEKoR<~KVYLilF#9!K8T{*Td$%kwNUC6J&!O} zBq8k>qNf5=zpwu~DUbd9D2&60e{mnm%kv*8;Hen|reVZD929d`y~WuzcI6S42Bi zzdykWha8C3Qq}``8GLk#^}tpD5Q>$TThn09u0O`z8X>Q#%|&cP^@K!}Ra zWBx=lV+Wrld%*+5{y>~yX6)p{Za{PwbhUlxhYIockI@@F=$&5u(Iz~yQ;@)ic*d}c zx-on37|mLyc>=6o3GnzpS4xji0XWDw=y};>B5x>tX@_vlxt#m5WeSFqVt1`aj zB0InLElJp>pXRYazt}f~Z31X=A)X;z)Pua@{yW^oJ+QkTG%ffneCmMN`fWU}U6&DT zy&Sh*A`AKzvwDzO!yo)@Op*G)V4$t85;wXHo?ZV`y@JeCb&n4_)gdpLw{AhY$ax ztM}J6(r6@qzfASrLWC+J$Z~a}g5=gr@q^lo_PeWS`##qQ?bkKp zXGqiN@Vg>y<2Mr5%64$pMgFb-vFaT4m0Ih*7h3IMmu~9V;TNG)Cqt<&xv7ouhzo6E z@Rep)W-sw#F<_IWz1ptKQdG%-A>)6=m&K3OU*N~iD}M|8c=>4Jil;OA6gZa2%x3)0 z+Ir1&b{W}BWPdE#91u0)aXJKeAI6V`c~RnE&RIyS`H7gd1W*y}Ym#!IPazNdrrp_B z!M44bh^v-dU^(z&`}!lX`Cu|OADo2E2Y8pwC1)_LcO&1B6u`u*yP&i8pXBNFARdVk zPf!+gVfGEfay1M~K_3hZk^zNC2Jm-2L^7Z={-=wXW`jB^zBWz-BRG8cCx2Q$xi@@H z1pBBrK?N?zrrbMl;uldd1K=)cLNG3EWsuoRc#4=u3u-beUHfD6Nq#~al1nFHTW+8gpnJyU*7 zKF@mqutV%ZU(=@)3AaFA0{we+bIvskp4E#FnxE{8f9p)k{p+)>5C7NVA0%VF zl8jmj7QdId*(2ich3I(fh~g%Kaza;P2gK{`SUX#yY{bLtYaR#6FZxBXf2(px8)B}VtWoX>C+~-Hn(bG2 zNxli73OiKF7JSo+4t9ybB_A=DPl;QriW;9{E;t{2g0If2q+E14lUIwsVf)rMfj@1( zO_MC@i&r|oU*M1K9?ft&>jw_Snfb@O%7jn?zx-Wrq+P7Y- z?ziM<-M_1S>y@Ib{}1k4?|_VVwQv2fjVar}Iv}_Bo#zUDGp|UMGj&nvTd$Z0oCpZY zZ8;J51`iM^gCu3&g|+faOW z``FhHOcegy(nI@xwU52$|B?4D@Nreu{`jP&5TIoSq!OT|2S_0xk12Q|71V?_GNB0u z+Dd9mi3%m4XrPn^C=i;KCbWTws8JCkJ_rgLU)*4@3@y+B6odFkL16@yIf62P;#83S zzTdU?KC{o6GkJmDd;kCQ`OM6jbM{_)z4qE`ul*7j_B{48k)!xL_FO^wLnJ+U!po6w zaDXx5_UAal5c9eze93x^dYoCU_=*t)xyaYAk#nYh)f{9aI!L{5f?&l?2R;z&$jUf; zAlN~+kE+WAPX?Zi+6@AQOGgRzv{jdfx6EI<4Pu~Kav8Z{OB%%ZR3a5hVhes`~)-(1nMlR2@i6JmvM#4regtruRw zLIQ{#%`lo`#z5h?BNNDwWfx^+5FaG*zyVD;_aV%l3fBwJJ=ajMZ(=A&oak%Ff zc+QM;&3{wp`31&auzlkNd8zj8ZvF}MYjErq`B~7uVSgL2UM@%f0&lNflX*gvLAJN2 z82~5)2`HAf0w9;DpxSV=iclHXg(6Z}Qq2K=U_rmrh+ z;iqp#>eNiBLBwJ77B^-0#EHZ3Cgar7TsUQ&-nk(ci5 zlI@mNAvCu(fqImJMq-L|f;uX8u`ztDFqwO>KzT$9O4BSH|0QXOO z6~(vJztp`89yJcD-O5Mz`bw+ zaE~btcfi2iX9944J+&wwQU>micNsq)t}YHYW8i+&2RAV0;_dI|KDU>QD>Yr@Z?D;( zmUdp(OOF3~vEcjUNE&RGRlWJ9by$?zj&Zxmr<=C9jdd_q1fK2h984csj9uC8Y(cG229F>E396eBcv>cxt;Q_M_G=V2+KnS6H*Zu-;E1SVaoXIK~^FGX<{b zPQ3NA4;sq3@4rzUbwNL?2tGEO^K$G3GL{@8$3l(=ydEaU zNC@0<$}zsDudp^F$IhcdFmy5v1|u;4@}9uI}>W*sbB%^z%Mkj?F;El4Fc=Jab0@nb42Q5V-8Sn)ZAQ^)cr! ztjWmn{v$)=m})MpALA^qVVaM)G9$-}a|Hyh=xz)tk9-4t;q|d~uTVM0G#q4=%fa`U z<@nu=o*Yx>7t&u`j&UGk$&F&$nk>NA#!Ya>*e+N%S#wJ?q5jYitg-36@8{}&A94L2td;pU3&}upp)(3$BT zFT=B(wD$L^SPGuSt-O5Cyb@OdtV#O6#8;4(@s*^sGMi*09l~UM#gr}a7vyhdKIA`6 z=a;An(zfD%hgA7R_J%r0$v2Fv^f22;^`Bn)(0vV}TV_`%Rg~VJRd#Bg35#BupZMiI9dwZUY;B>M5<<{YxeL8kgsDB2&d{79jm;%)Kz*fTw}K4zN~9AuTt z!8hTI$zQ#3omU_GG#uvTW%@DU^|1lS7+TTqXkdN3FdJ4M8$#e-3;5%xk7<8lX~Wp< z2Zz+h^f`rm9cOu!@AMJZXzF9}@QXka$SpXV8oBuB`i;$)4&p0u8EO(Jg-0I842M$$eptU^;U!W&-_liOm3mbx9MfOPRrc6{0g$1pz)Y z9pqV0e^yDZOUD8gnPHiZ^l(jeoX1%)E-Xp;Z&a}!s-|gz}{0_CDSS60$eRq>Rt(ZI~W7akRH}I_byiW z><=7Bo4G_@uxrpeiBlGypYs=-mg5C1fAu9mbu?7Q+uN2E)*GQy$1x7F)pj#`fWVj- zX5HOiHdbVQBvLspIOK{4=l-k(C%be!_z+VM&gC|ozER*vbkxk%o5RJ(il}#MAWb@d zm>!j2MQ0$M-9nXaOG7bKJRARdDh^Qp`uMKDMgL3kUur=A8|FVXl-GsFs*%B6Kku@v z6$p##R;Eo^UQELc1hf;DJd4Gx-nMfI;xkxZ{?DFE&<&MQ=Mr#$-*+xSsi2$MVXlw?oqT(%_^dMd#!`c#70L1aFL z#(led-{GwzYi=CbF3hs+6bvgut+kMq7^;T-jDe~0+64MJykIwF{PRLz{%tjx(pi4L ztN8pUZ+x5QnMPTmv(BkYBC6hQ+ofE*WX>9;T}Rbrb8Phs-7}7Yp3t(=n(@QStRv9) zMb{pOH}EISWUJ@~?3%z4wbT zWRpo(Nan+FGF)JvHM(SMJT~cByChnV;K)X4)gucRA2h0|&LO-~Fk*X&~pG<#I%~P8}eOK!oPC^Qln{o~jp;Dkj z;?!^k@y2;rd5ig|bW}KRedD~t@tei(vH0cWpOkwcrg9?Qugf##DE#1{=jVMyH#`9@ zNWB;mjo>t4Sz9docy$8-b+R=K$5rT?%7LabQ--rx9e71?6zI73;LN%1W?i0+`M5{ zlNnee+&#Qd@w=2jaXI)1Ts;q~QDAeigG~2u%(~)UozM8*!F=6C@-^#xHoxuiQbqE` zbw1-e2Fr_-lLv)(=FU{~nRz2#KG=&m^I!#~Z(fQ?uLWeMZbl+4T1{Q+uapX<=B6iUCsKSoREp(Irjr7Z zt2xWibWVRXJ^aGMj{1%7Wez*C3=0Rp+)amhlZ)8pa@XKL?W}W#;@^IFNIVVyO??F3 z4W^%UHtH8vT=SgVh11bVmO{51>XdT(@QX~w3G9rrrgjs|tC$Wk#4oD9PM<2pH2gB zDqs;F==A18pk|TIrPD}TCOwN)LbkKf}jW0i*Ve=(5BEBQ>B^SgOMrfeWH9x z93IA(bK#d+PKw8u=2KNUrXQ-Sx%eyShI;+bz7z$=DtzTPz+5sn6&-1NOK1SE1pIU*0`OhRJ*W_rm#?S};+3FD$e1ZPjp$ z9L6s1#Jj@e{lg!Isjc$UWtamYKnn^Q} zqsZhndn7{A#+b#;Sov9m1T|e)lO7DPJ5@VAB`H$`1QH@XssVU z`*rDe!u2DUm?*wqoNnXWr{RoWpUaNX_|kBY!D7GuP^A9Fs{Q&Lv|sRdB!2oy+mL-I zuh@QvY0n)*EU_TaRAZGJXt zI1`Znv7z$6vxxjZFk$(>!^XEy!+P@Xx2un zL!y+$P1oo0rfW#(C}z4iir{{}-7{SrlA-C!&Y!3r+_bl?2fZ53`1RH~E=+Ily(3%? zswRx@voRarY@mHK^>!-wGID=s$l&X1cYADyjix9Aa~d@om~xdQu&N9tXkT zor!MhzTu$m8@{0WhW6;@Kd$!dQ-iio4OJ7>&sV0}@{VXY)v|cMForS%?o?9Hu-vJT ze&Oc}EmD(iPYu0e=ij6~ZF$Euobk)MzcNhTM|~}vfBo;BsD7TghmCKOhBJOYs%dVR zyl?qtIKC|>_~jk6N4C5R`-KrH%jZ7z%OlHu3X$`73oTGY<6-1duqKER=pJ|TO7YEd3m`SN|A!+P8`zx)O! zQXRtz5p{9z%IX-Fy@$|?c~{agoYUx8FQQKG3iEJJny7vpS8D4=m4-8ZeQrC6m?J*x z>lZHT4cCvfZWoL^#$Nx{?q=iL9ccFqJj!=u|0;g6#@A=Rep;md4IS^-=b-&E?dur* zt0B#-bl$&e13o$$;I*@%{#9+EHG}-;PFViC+Wf52a3&!C_lC;<)*|xP?SYZkIOIRY z#Tn7n`bg>e2g=yJx7?<)}---w1Ye*Y?I@b$_2i{#9%q*)?weDz5P`{#9_C4|wF`QrBwdihfdeuXs9$N9Dun zZSMyTaGfODq+F*CQNJ;{POU=0h_2IXr+bFU1g7-(cEfRspA(S(oBPoR)8}tSG@SA4 zYjS>=zRvi35&3JoKYn~q@!{JLXx9w9siXQ&Ej1cnpT2JTVmQ9eyZrhZv`?n}9AjKP zhQb4eDk=C_hAK3^`iVm4N#d&w@d?ZS4WIlqoC(PP1EKQ&Y&buAwY@j;8oPZx#fNW0 zpxrR=#vuPwL*?HSj&J1=e)$LOm687_arKxK>N8wPd1M)`P`O`P=sbzs2Pza^#(qKV z?efkbXLYZVH!oWWxB~w!_A^|0uuS82U%o&)8{U`uSp! z`jiNiV~-zGSB-vNXg929=HsUerz2t@8z&F%!#zx6g#*+b}{ow%k8z%l$MZ zcQr9>xKA_4l6Rxv;I~PLnFq#rdkbw+cSE_N+w|we7~#vpOI{D|XEmN7szT|5-4`oE#F+?kjl93m3EK|C%-YcX zg__KAxdZN-jni}JIob2fM~3_KLq*}X8n|0F+i<(JeYf$}at+xR>FVO}_r3(|;Uw1pMK=6_!<9Zvp#J~Ou20Px&IIcJ2Se-srttbyI$?aj^{S2U zz+n@v{|%w_|Hg298v^CncAvbmt9?VLx$o2bv8%tJV3~U>R*e~J-0aak9t$k=#K}0y zVJpvikeWSFd0+U7&A(O+XZ-R`oDnAPo39V&U)hB5{qf5-zA0_@#@}zw8GL>HkX>#F z$G2&Oa)R--p*!iSr zR}nkkFDT{hJQh>QJjuGwe{7xx3tzqYUl(v0?XvPmF|nQtC%8%@>n>_7i)b{fppJtX zm?P>W?&TWUE`Q+uqIS94*ySVdvF&pIA&PzzFEH!L(Y^`Y``hbYyt(8n9#9)tV?D)$ z^53nOqT-y9gH-u!3k(h<)M{tdzMkKQBa$$ZJwsK;9ZP0LpN%(T` z;kXjAL@F0kJ+@a5l&$QF-1oitIQ!=>Wb5Y2lWvH(dmK`RbusZ``K^7N4^k*Zdd}ij zn=5y7uX%bu6yAoSBFzUYI(W~^!KWlWizr8WQNCGcTva?>HiL9fb(x~fZRTU^L8NR( zTT`$;Cg-T~OnW5d^-6g;=R+Ef9ALt%Id{`FYJEde=Oe#)Irx;Qe33@vyYCmDyCJf9 z0B#12?{Pn|zjtX6loo_nwQcelvGjv3X zrL*Yx4Dt=86dh&mlP{s}0ZOY#ap|t^{y=lE5-P{~Tc+V5i(C%ANvc^AcJn_E^sR;9 z+QeOHX0mZ8JXh`Ly>}x6;Dp(G*ZtXn-b%JIKy!ce>R~=Ghk0OH6d2jU*JOugl)2Xj zKwJV4*cVFM#jtuwyxot{V}twVU{Sce2JW*z7(d)^7Kht!;9l>8OFL-lIC1BHUfMoK*S7Hw z7Sok}xLWo_z!su_pjRTis^%oz>cCM9>6h}XjNKn60DwsJkuI}RlzLxBg>RJ+($o`jDBgW zvo(76*2Mj39K_T!kcYuU`;D5Y+xR6KJ&zymqj$=AWya46zBm0fuH($bmnvStFd9CY z^p3s}{t%}x{jwr*#iYxQ=Kbf@{q(^FmrEx^&erPCv=5$QJ)E1r_wP3w(C6sdPoqHi z7G|CB>dWgoU&5hmiS`#u=Oi<$?#V0S*%b4@SFx8NoCV-FB?ffJXZ|w%02L*3=C9w} z$vz*AhdL}M+BoI!PpG8ocX{fS>ge86F$)`~Gf`V0LvM5V7=W-hsPGOuugl#JHC4BJ zOl@oge>u;eSKZuyt=xl#FR^nQPn$hy<@BrGn`qxzb=6-7SkJlV`V(o)`k$FN`2NKD zhjBuhBz)ml%GtxBx{{acj=wY&)6ai`O+SFyBghg=t#)9V6rS#)jI><0SsQEe{+(FlWJnot~V5{NEWcr6gaH2 z4mEdwZ@v8k+DJH(8%4_=B|IB;F_!3Z{rA&}$KOoM!S432wm(;rSpU?jR;ZoXqdvN! z6=hIm(&=UNmgJyJ8Euvkaja3qX|^5bpkbx-HuFm#Y4V)3B3ze8KkPwPKwOS|3m(A1 z+h;(|YxI>nfP{&S+-`t{w-hhD%2znrO=_#y6N+bz-l`lOZb94rL_BxUEJgQ?Z#7Vjpn zd}%P_Js2F)cpAH>;fC>@ZIs9NHT(m<_iNm&_L=w%?WgFo`EJ&S8yvAd7zcxBJY#O> zuMdQp;fY2!=C0-wVvHp=&TZ zhta9h|3l{WK8sS^Xa2@ExD6CX+J44bk-yA(dz?xO&BZftBdXT6FmR)L9@|-K>)wnw8|68gO}Id ze3^gR-<%ZPw3c@iLk!PG;l8HWP62HwD#JE?%M}bEiZWOM}Uav10v!)%glFJ z>X3WNcV<&@hx*R*vSyJrX=laO6P;J3%}MqEMc;GC-Hlld1|_TRaWALA&A=zJ57I=o zEY7`SmSGxQ83#0UJHV9}FoKRG$<21d*$CD=~Cf7i@?tlJ-CwC@} z*v|f1qU2FDe5HvJ{)_S71yA*o;U(O)frsHrd#UB@5E)#gH_h@jy%nJM%{;vo?zitO zN^jW;KfUFK-qn()jqt5z_NKQAMxgqgN>O=&dM5Z?lT#XR5Rz{>H(@j-sP&^{9EXYSgFbAe~0Y* zW7B7~yW+i|@y*i_W}x>!p5@Hri=e0l6SI*&pXzk=a++ zIe`%X1wGABD(brq8fM&=@0gvp+m6m(h_BewuJ+r{LL>v*&WvPIpLy29mpJjV_6Jh! zK_?ytaf@F-KRUmsJkCLq%=mKj4YEXN0sMK zQ9yu>bP5Q9*X*dpARsw+nBBXO^SLO`oJtNyJby0LNb;=sgqA0R*1FkuKlV*&M@Euk zMc%(ra>Qx7vqqEUf@dg8u@PkDnCfE^2#%pXW=Y45utY+~$6sr3Z~eyGTOV(DdQ|zP zLgd$R(YWL{ppuVSei@|S+<t3jEOiQ5ovJ1xJ0VuiH!F z?O`8~wspMt{)ApAuw3Zcnex!JF$!zH|NE(l$*-~HEy=G#WgoNrl1LvezsJ7%AC%u$ zpB#_;nlJwM%kLi&i)mvGX?RV=9k;0J5*gm3PTv)d2l(QSd%%%LrOL!F0h8%}A#!!p z{pipmXsC~wZbv8g6VjAdMLINGQ;vgDsM7$EYXS)Dvp3ksV7A^r(!|RP>esaoB$3Tq zzxPETMfK&{J#Giz2zQXxjN8g%-JEPm&n@G#c+S1v&6e@@7V-UXbGVYNg9(_Jf4W&4 zdIr$)*LH2v`^DGcWIjCYZ$rb#CDKVA#@E9;sXIe$XgF%S7IBx}MS2ow6>O?nPJ!n` zwVnII(ZsRSh_{wT*Y$t{WI*#uVSsFMim+ZMdULQcaEN8tU|;ShxJ#jZ%Jm}K<~_+o zG5{xJn!Pt)y4CYHYG_<>Ir1&VMTT^7vbA(gjI1s*`wu=CNKdJv=eZFP-j6>#^~Zdh zIO35+$rdqUB}25U6_@IICN>g|pSF{Z`$;tZ%I^%qg`G6#ibps65yX+P$ttnX>fmth zr2{d}FXwK2F_~7&GI^6hhpL1QdlCoQMQ=D7SOH!JxRh00MpmMaj3Gx57G3{sz()Ti zjDL|;MfmsKFV7aa^noz5`D~$F?xkG9_!|dY**B6~cfSq%?I50PhYI++m* zg%tiq#Db2Ozwbp~(D1i^O@P0HfQ^u5*%e*r(e7QJW%ZYlL95@I1n%zIU!kLA9q)cU z{;%lXf>*p8`KBsUeK3wdjcebrYjo2IG&Joyc8_lQrMlZQy6K~gZ?x~&GrGP5`LJ*E zLD5Zr;zj{x38N^UJf%Xeillg0nf5x|DVAMT}Xa;o-x0 z{G(7NHiL|#n9I>O_IuzlYt3xpFa#~k;

`VQ^_Rkg@paQ`yavzk8pAP&VLfx3XBRa36Qfhk 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 z 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 >Sa0fjfj{S>}a42T8fRjFc0&A=VoOGR0 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
?Qo6fKyPKc;2r=k zIQYNBeF>afRrUWX6dKkUl_j!1rOGHO0Tl-kNo}h^S{w>6vh{rUqb{W1A z6Y4i1g&R4SbYGq6Asoi;xh@CqKM?1!RbFQLY!y?4Qf~zRK8@cZ{n)XQYv-xoa)2k1 zfnBI;cI;FH>s079mX;_!@*vNyaNerFRlA6OOWT{KTx1QG~j=WIcOI7}D&!1$9l=5~q2Pq+)_pO7Xou3Elzxt8M%3^JQ#`8d% zkqfRB;c*0WIRf!ZXWLzexKll9E!fkvPT&Yz$i;>+?ZJGpLn<*2hSg+(eS zXJ1@95&NS1^4_iEurhQr_0icE+7;?9fK}{^<~)vmc4$|6BlVMRA8*to>j;XdD#2=C zw8z&G41(HDtH;?tR}aQ-!#>I4AKIr;s5l3KK(K92i=co_2crJn?P4oQ|=yCcumS~IHgf{2&zvNj{ZNi@~3J04EzF*?I z`eD_VDE*1&szB){`h z?Z?c&c6#|3>Hnug{a>JRi~8;4F{1zU+dI~8$Bz*qc5M6#eh~ltay$?9he0~+fZR!I z59_%2e*S6mvbn@ITWBi_yPt=XpK;DiZp)g<+@?EFn~MZGHa-EBgivV5#+HX~vj{+r zjkPJ4$g#1D=n*fTz_d#ddRj7%7*j2}wt4&-_`&42na^w<)NQYpB?U14EKnC z3G?4w4g9lqT>VbY5LN@Xo`*Kr`L&!3nucFpL!$`@In}RTex>=<)fX#YNq%)#iSjGE zd5D-_U1(KK^ntpd*REgAGovAo`Y0;1y(6ZWx_5-reMpMm*LwxTC9AZm_+B&JWZJqI zY!_;Wpl)8bwfj+dIz`IB0HJB;KbBQ!N%&io>RAc!lhM;`~Y19vI6XE zv~sE$vHNOzb%o#wBRB^1v9-g${iw6UT`yF5J2|_5Bl1>1bPIZ)BzFE{=6L+^r-pc3 zJW<ktMjD-Ve^-LGeCjez0f!MsbOBM8=7(Yq=CZqO(Ixd}r>G2Rkm8 zT~AE_5<`pOGST88O~kfF3n*F>P=xm!6@u!ALwA$zy5ysKPSAd8fpaj6ahwZ~nnXMv z!7@f`ydYcSkjEB>Uh_eRL!-}EIvxJFb|Ugs9CG(#=YPfib$%iJ!Kv}^!AFGnlZ({P ze)I9RaoO+(m*W@mUh5I%Y50TQoep+lCpJ&@2N#1O$+MQ9r~EYgpBPqNH)?C;5017d z7sJW#gLpT#s%4?IU7mGR+PleetoH;x0IF`+PE%Yk6{kwjOlV2#{AwGVdhoCqPDy_C zlLH}6u@iz1G``D7e;>ZD%#S>`p$~X!%K0wKBLZ1-GNjt%cW@)&nZ6j4ZfFVt9XK92 zVw5KZ)`EAe4E-k(gCS${Yn|49GEVL`$E{l-9U-uvtVZOn<^Uh$C9YP1YhqJt`$1D9 zaJO~b`Ed?kBj;dnozD#NPiS+_YZ(lL>nlsapSQU2mN~v5UycLU4)KlO!Jpz;H@?vp z)PEfvZ!lOg-squJgRdPDjfTCc0mcl9B3$^IsB6tVMUAA*~#@GgI3a>VL!I1s7F z8$~^~cC9Iyx1vH)Ee7J`Gbi-y_9)q~SqiR4ABGXNd-He98-PLAAIH=G-5;e=#6LMa$^6Q+-vOLB_PBB)0*c|L`i;iZ4AUovduZy z%!=27kG&~WYmPapwYA%A?Ixa6>+QCi)9aq7Ai6~m{%=*UF}LzOE>mn$>D96Tivplh zRDu^C8mhDp8nzZ=`K*a!m4C*|@OI&tyQCN>%SX6wrN-T=|FakwMV{d z!4K28FRIR8-AIR0522n$Ir*p_$qHb4BV=)KJ|t9RS; zTGm@|^?oi^Z}mCaFT?>ihS?V7z&GSwr+&VQ@~&4P?+rL1{?7~Uv;A8IE6*}~`FL|F z{;8XOwP3ufzQw!lOP6i&wmli27Hq3SN)&!@`N{W9Zq4yG+0MVn^9HS+B>ZK4prc4S z2H4-jzXu&t&#I=M+HLhXUPuoyg%*vDD5AM}xl3;E*m47Z+`c$fMO~UusB5?K#9-WU zM>hX*5W2S4$W(u*{A`ui0u<-V$D8`h=^w$U4L5cM+mTbV@i%7AgGG7y_B3TXDR*kQ%JXav9Di-cdWmwsCUUG34ADy+9~%jMw6MBx`-Sun~EEv=M4)Gznzy{4?ZGIWxe7tD#s-Hk8050v7VEkI>jG3^DZFgDt(2xl8W4;I+9EuU{uS7bL!j#FL54(1m3(TNV5! zG`e-zWDuQ|`_oD|Z5wVt7WDPhR0s zM@nwmotMdS+I{PITur*sSg`HQq9(v=8bJuOjR zU~_EbRf0pn`_`fnksoeTFXiC$#mPP5PYbS`Pnm}<7W%RB7s_AvD+$P`A6)@g<>0rS zPVT5$UcUVs9hX>Qg-)H6^?)`Q8%w+BaZtsgqwJzLh5q5t(XHh)2MjqmCHQH1P|k$$ z6hF-kJN9S8PrDtw7!hP*Yt=-mdez;I4m=*L0&D`O+^fBx^PFe3^hd^>Kk~%+Q9q~m z=_-dLe`NPQkwe2D84k=JdCiH=AMvfcqtC~O-SI#1N7Dax{>WbV6!AwMeID#nH-B^f zNY?5}%G-Wr)fgp!p@= zIU&R_|?Eo(`7nk71BAQdj0jt=2)4A}FF`7mBS-ugWK zqh^03)9^>k4^f}Q{19G@u!*1LeuBbkB9O`|e zzX$K3oI`)4?*;cwW~@AU;mgN+`u^Vkx#;iSXn*%vJxO-W`di{~`XiO}y`+P&W=Z>I z9Wwfy3l96f6ntf087G}q@6>*e`y;;kBmG8`SpqL~0qKWuwGk~hmbeiWgA~L#a+Jz1 ziEgePfc!{z$NJCm3urITfcAgv6ZTKm>Tjk$ihFvjt@$I%>5uf#-Zc9oiOe{EBptjE z0^2%h{6|spwP!c^B7X2-xc@h4e1g*uFApcrBE|T1qLtugFu8Tu+RG=&FIrE-pRsyS zZ^JfS$hz`TeVVb|>HT{fyR&ld$HnfG)<|!cEw$c^@s1cvHw;z9hT1)#e;q1rlhez#4+Sl`w6|1(BMl71SVXnyK zfZC9CxR6xSDsDYg)#!3OkuJe)z-<9Vfeq_Y zUdI+Yz0LFPBXz&h)$v^<>gkh5ZLNeHdpWD`Mh1g;`FIO`o7Z(kV&hD(R$^l>?b^42 z(s*9tbkHF7@PfsNKyq__nLF{ei(UvGk>wQt?9?GmK4E_tb6+`6Y>$_TQYw2oubDh5 zx9KNx2`ppmOi)KYymq+ubE2Q&U=0-dfowtL-PIws|W1L%g6tx*O$wm z1%0W7(t{Jt=_}xKSiRzLW5Yf^_jl zYy0_3wwJN?lGZCQU)QmINaYocwaU4Fp+9wNGQoykO+{i|#9G7_oZ}spm(bIczq{P} z!5c+g>L*)T78f~hS`J@XcC6HbqjuNO-tu2BVP$yv@_+EjdJ!UDxOZ;D-Aw4Fffihs z7k*PY+2dh3TooBDl>!=Cq{=`K3es5)2@4(g;A6WvxldI7FDKtfTr7E;XQ0louPh$6d_*{}R0(dIHO-B_2dI$8gxmkHIzqw>_OG_QJ#-B#-9o`{KS=46Z}@}M;{UY@|+Em>-7rUYf<4J zt36;WoF$`R=q)(U6g%8dJ~m2TKl!K|C4(SmYc{kD;hf0Mjgv1v`l#gY zNo)NnOWV4PZ~AdkPw#mA^(R69iBrkre1rrsZ#T1XUew3`3*-D_ubgh2bB=;9!UA6w zx1aYejEykXuK*!$gQ-B1FFXkr=+%Iz!p-C;;ZMRf}C!fKhu3 z_^AbZ{+f6q=Zw*<(?L7Lc0H31`J>I@a(n(8SywkA_-X5Wis?D06Eo!;k?o5Mb_$lR zTi$#c&f;1+0lX;T5w5p`vk;!s^#U;wQ_txt1h0JPQ8(W_*rENsrvbTd^gsgMAeu%@ z&xGdGbvXtte5TBu+#~Xi#X-gX-5_r|UA)h7 z8CI9CJrKQq_^F$)%?9^zaL3JZd?Z4zBT~bcmv!OA;8iccz205c-kxj#FCTCAZ_`oe zPX^tY+)0bm7aR%28v@zgI{)PMln$XxFqu=cG^~3l=}iF~M?8-zp{sYt+^yXXA74Fx z6LoTePZsldlB?{X9; zWp`5lTc}6u@HdE#5h=n*SwdC~`p$V|ve2fUuDPPe)U$X+?$rL@JrItE{ucE_;b9?V zTk)tUwhj}iyv81!v{)Sc0*TL^f82v$fnmel)Xm^BgqmGP6aGE;YM4#A+ zrh6k=($_f4tvn3rt6w6cO_Kw<^``6$#xH&m8jOq)qIr$dUh#28Ka_Mu@JsE*-|!>E zRm{z!63xV397~y)-GH)*-GH(!q}@QA7@mh-2#&lj93MHO=TbAIKAIJLi>!Z!cxFdavj0b$=?w1pN62TN)swJJzcUxJH~u}yJa}F9{EY2P z3B>H2oe46qGZXWa&nb2$5~?2t`K2NE4APZiXNITR8OGDW$6um$Cf~Iul}GQ$8HK6n zq^TIAsepOGg>tkdYFQ@mByC1Z%Yuz%d6upT8nWB<#MFpofhCGrmXX?{ljS|*`aV0m za`wMm{%+LjY2M#N-Rs_aW_Bg@2Atd9rk)|xWAi%6c4gz=LVfCNQBM?S)vokYF=lO7 zK9yisCbDW*YJ0K9>Fvtky^l`z?xFHevMc*QS76s0c4c56>Tsf6Nn1U{D!zQY*_Tm% z8+N526wbh|EIk2srI=t>ett^BuAmt&k`H1&Mb?2dObHx;%)acr7VC*Fha{5o%Ah}7 z=Qr#1M8^t|L!>Wh9)rKTI5S}#Q3cXYTu0z1Pa&t0qIqe1>qH?OlkPeEIT!smdEiaXdQfd{kJt7&|E>Rfl zBp-H=cU}UX?TbfrL-5kkr98-c$)@FFi1o(t?*w=%y7&*gfyWh99Oex^CH~6?pExtz z?&pIxdig8!Y2$CNKKz82k2m|CcBlXX7~eFGA_#81g}t)K^D2`k;VJleeezFOZo}PJ zCcR^~jtzUE7MO_~oDnWa&m#KmhI#J^ZkGAmQCEH-UY?c(ZKrylAhxRupPP@F^TjC1@;|!r2b=r4!)}bP$QS09&V! zV1V*D1uF#IBwDjd9Kuwv{P=%VPJ1-xSFE2qpJY15E&i$C9X~St8nSY84d8rKD0-VVvqcO$8Llg=9IFO}{-bWRs|OGLA@mn3I~sI@>~Q>p z#Ci?oEH5I<8&$DEr5r9;4Km9gnH;t94o@9@Q2L%QiJuh=(LLegqa9>i_pMGaTBEaH zbkRVG7b@H>DJ1rEr3<=jDI_^JokxEl$+4AY2Q;RJ4;0rBtAn^LpQ?w;OJMg>jxTlw zUOwLZ=y0ioa*zoDp=L3f0tUfC6F#-z*oK^<@<%l^5&dqe@_bS{I)D+t+8Kuw9AAiJ z&az0RAR}ZECMm&hMR`KG8c({TF)L~SgHNMw%{@2uarrz)pbf|#v>m(>+s5pBKfj-X z?}n49hqXVG{A%i=^Q%`=2a5+$csn#-Bi1F{=U@D{))VEM@{5?pH7}$SLEfvLD6<~* zh>(5-`ZTh|pIdIz!NbplOI?e*)IOn?9^eC7-EmVk$==28Z^O}M2~ z@}t1s@q;Pv9$bgY6N$pXBNO_ka+ZFG<#)FVeSX0UJ%lwK*TeV089Tf016m2~{ykr9 z^?Z1K;VM3i`TQGw^a!Nq4TAs~R!|`w9}7VYa%YJO?tyxqiS7Y} zX%|(4y#W?H%r4P{<2H>|3T?h2&;ah?POk5Rms8j>^=Z!dt|@<6^;Pe0 z$Q7-5q=WK>zK7GZdd_eSIvqBF4*(mWsO_($)~C#W=%l8*u#|=(75x2IF=$~U!H1q5 z8t*K>uWx*3*czON?<@0Jqc15haU324o#8P7hfyB2UUYnzj^KG)_XQh|iX8{A)!X5A zHem&P17q+}@GM0x|v@_mT%UKbig1%olm;^qcs{lg-by=3iCDo!h|a1?r`vpZ0(+ z=f|ysA~;8T&07f0GM%@1*}<@LM^Z7ybKr(Uqe$&2@uzZLe&P}q3@3~mc-0b4=_IJT zmLB{r25hqm?fGi3{Lt`%>mE=+1JW|jH;aC{^bWUf!pSMpPt2=!tp6CA1FsI8)?66t zw6L@6?3Wt4fV{~##gpa2Q~1MeG(ym22ECFdD+l-df|wZMs*h&)(zwT?C^-1Vz-^Lc zpq)YQsbPHV<538qHvRg>FXBlMQt5swOeFS`SMO}IFN@e_cF*RZ3f6(GBXWgvqIf|He;jB>6Q54?H>;3b6E$j8pej6RET5xj^ ztvB;G#d$|K=_aOP{78JibjhZF;Mj%ShI>=TO;j(9)Gs#}j=S?XzSBdYjA!tFU0L)L zes?>6YQYT;*Kqd%xzX`Zx>wsx!ddn)+Shdpck>Grv~RxX#i^SfL}#F9xP>&_{!MCA*4auN(E>9{88>dP5G=4E~?n#Lr@#?0!FvPRcBuq z#|Zs)e!x3WzFL>^gw!*!=;>FoFeeN&B~%XMm+`-5Lyue7UDnUAQc?Y94S+JYYu1z0vLQKO1s&!DDe~>pGDBnqbitSfd z{Qf0Mps8B-(d=Z-a1U|p_K7B@IO z@7Op@(%Z#}ea{GcbQW=O6xMcQ5ST4{3>xgK`l$bW`FK+% zC|b|4Xe&HldyB}S-^x$%b0ornNvEEp9w@XQoPsvDP8fG;H@mF-Vyhr*pT=*)jj4OK z>2scI#{}-4i$L+3gQ#^_SGsx`eyyQ&S8(e-p%RI~{{G?QdXeW9{-AQ4;unG5VbY74 zLrgz$?%fZLF0hs+>kI*T&k+GJKrS0>SJX7~@Q?W2T#$e`IOSjtB$pqw_7nRN@(-R1 zOoX1fS9?GHJ%4WLZ+AL>`*pvK`r9+B_lVZ@cDs6ai`85By~;IOf7FkES21RJ0 zn$A!eV{<9N|LjGr7$VIhR$p{n&%s|%wBC!NEyu&TMHvshRz5bKP(G@sx=sjs`X=h> z)(rRqXMW&=jIBN778X2`>JR1}8q!z)o$?D6mY0wJ%XsB@;l@DdZ{Kk;-crF&QptKd zu8bt;EhFa@ShJxiU`D?rtsE>B?$GFqnJmJ3*e^?Gpmp3ukv(@4S1L96ek z6l;sthlLw3Y$yg%$_);1Sbvq6_%!mQR<0T6qxx_N^r4IU0xsErnmIO5TPD~G zL_|l!zYoSdWbN0=*G)o2gN{gj9UDJ@KQ{Zfow-S*on=zm>n7K{$9>aHcJTp|pqgbZ9^HMwEx=g9nl4nDLRUFVL%7RIkc+DZlhF*q3`4-w}T`FM9Q5 z{2?ZU%ke|o_+&0Jk+`I1*#Vd*J8a43)8^3RXV#EhD;8`BtNdBMdf;}}In zq@OVhvlOw)iV9|9s?3idPr@*AG?;rsOc0uB;P^KF=Gg@nK7KNPsu8dJh^#clD_xQP z^iPn!A+E(YC~*=QIbpY?hAtR79c#6q`XxynNeY~ORSFiIfcqQ?5CKlzqBEM~$Of-y3V5D=V5s8a?Hz>gjl2TKYvf)J z$=42m^k^=;QU&jjO&Uf315lEtGIM(nr`WS?_rdSfdcjpl(^wvq^fkw4=Rya=9PqLj zv0)B)nGa%Rvb#D8>TSzW{6c%gyi_hIQDmFOb;nOh?2ebUzlf8hhjX+1H!?mHcRz+- zLC!=^x5%qQ)-s(2EL;k_l6`Yr;sYGO7A1}Ij>f;xn1$RQ!Ff9FhoCY~1ZP}Fj2%KV zUe?;5XM*tY8}$WEc_U~lInIL;N}QKLb=6=DY}M~jKAP)+I5XkA8*?<&z4G|;$b_aw zpk*3-fmXc<2*gqe7lqmNlz$?hUkAD4)+!zqidYu%J!}52K?t=!6ye#dj#_hkyk7%>p`9j*)Tad@9Oi9*$ZSp|p_YGOS zQ9Eh!3W62P~FFW*QHc07eL!dCLrpF+ZRu zmqMINIAxj?D*gx^l?hIthfpye_ZG8gHTYF0-wzuUQNI$kP9dU9jBk@^)M#l1t2s>cz;NFXFJ`?LAF-Q2~48MfGB2aK(JeimZ&W zi@zUJG>+C_tm7bW=;tc0jS;`5iQbNlKf%+k58b+oOvL_-f+F(`n(dF@Y=1ERV)h3Q z$XF-^KR6clr}i_W#~eQ=KZs0n>SZ)#W(6Rki#dlri#)HDyNL^c@bd8{AGuAx!{c1u z0t+F5Xt$iJ6?IBR_diH569_rIz3Dxf1pN2x&F&!Xv9mXwpnm4|=9SNyVsCP{YyZsH z-b}n$1nqMiuOcWeypO%+H;4Wv=2;DaRl z+Sr>sD4E9ItWta986DHxn}R4_b9->g)2G;j?jNhX9X->=AEiaRZV&GGMraQvZZZ8d zLHLk`^f&B5dhyKcK^NE>Y*A0LJ?LF9J9{t+N~W;~KT~^9yIJ{}-X2Vd;_ae6_}kZ~ z+Jg`75syFKkMH>&qbu1ScsvI)9)ILt+S(o*`#@+9JgYa!9+X%`D|_$&D2HD(@gtSj z%#*6nj&=QTu(y_9lCp z$ZMD4k8`dG?M;uhpA>%#qp6wXyT-v*szp7?_NJd8F^l-4a|xesoA0vtW9SBz=k)d_ z^KzkK*YaKKzB1L`JO$aPXuj(S_@1v^uXMGrH@punZg0G$t?kWq_lEW+Z}leGn=Gqn zWp6fsa@d<5D?c-PQxuu)n!S1BKVfes66{UzAINF^hbpHw_U3VoKMJpSY~qhUemOb* zsQf_rOPC*dY~zo zdnLErSZnZEWM}e&R{y4jQ|fPwvprC4`#3+#fIk-J=UkkR7{7SB2(t@vijOgN<8*O8 zRA5C;a@iwKeq^%veU-d6@2>6f>l1jDI z_q5-f|3*7X*+p(v>6>XnB$m`92MrA2bMcMDcf{jMW^$0wuM+(hr;NxpO zh@G3{Te~?5052bJi&F-}dCeoN-Fz7y2>d)rFORs{uu<%t!Q{}Z=Z^vPI(hU!fs4S$ zN$ErZW{YDEximT6QZsF3K3?IYRX!@4q&~vO>Zm7C^n+T)S#Dl-&3UAxToc9CCAa7fHbW>t^K3N5Mh!?aCcy6Kd?=@> zGQo<^#{5G8&N=@I{lh`D9NhQM@Oy^ee~<6^!grL;7XISg&|myDia@W*nKOVzE#^nB z_(N!i`>ft1e{q0SwDK31ffI~7-^wTWiw;-U;Qm9MA1w`wvg`2#Wf(Uo0#^Goe&h#8 zbp_mS^d~+*pphdCek#&?!C&DjdjE+nq!WzVhJ=f*s~8?vIsO0g7c0GwjlcNK(GZ2H zBw@a~@NMPqarYPVua(ZibLsrjYRl{te+*q+*N@Rk`UgWh? z{^CU=p}*K~?e4U{I0`ycPiEjRei4kTeXbRh-c6G+!x+1 z{l&gF0E=Y3dZn?RPLHVxUSAIV#f;UP;4gZ4R3Rppp(VBjb)lHo`uTc^O}6qcANZK~ zmlOZ1e9X+h92c4Iw10WW@8Dl{Cis_U2hP8wFTz**eLLH}aUcSv8@LJL{6it##{QRW zIk&&&b6<|`+vzbrwRWw4o{z4vee&`BHD^caPugFT0T0`rLPi?D3%uc}=C zfBDI&H$OIh@?{?ltxwEP9==BTd))oxaWDcU-W5N2Y~CZ2<*z8cJLM-|hwWUmUDuI) zi`bDgoYGE=)+z$5$8}x#p+e(hm8Ypg>NB^y=gggAcl*Aq@^*HYc*eNj@-#li-LTAK zzZ?r~FoH`XD@9(mPZ+_goa=OsE3tw-+I_({vR6fMZ z*3s6g=Y;<5ge9Ac%#nZ~aJsbQlFenXU4dk(mTZOy7L$;PU>!st>j1{aRGv9A42~Xp z3n-cH>L=$o`)$)rVq!MSI^lFMUzVX{y?!fyNu)o>S|sn&vGGUzfw`X%87#U4p1B`M zV1>CKnD}rleA;q9el+*P#A-Tt!xb@Go<-%s9(U80yH#Ub&O=^a4lS}J!018T6-u(!*>BN8cF7R~=L#Kfk`!F%#CR1B^{!Y4Wfc{#qTKi2y{D#xUKmgwI; zj03K_>R7)Wk}y2(%$b5=^&p}`eI{TqQ$U$ zq+izLoQ{<ac#t;5^2Tc4x+{BC5wD$KB7Zk01w#^sqd}}-W z%P%+Vd`mn0{gUc+r|#Z*VAOqrTj65PurFC{9A4#w~Nrh*8bzTo~8nd zXT6^0n_FUoMKT8E-yP@`KCkj>wVo#Zc8+^)%WABr$)0zRH)!Q{dOgi3DmFX6lj~`I zFu4Qk|F2g1XB4M5ucx`=x8XP=R`EUUd`#CnD3JeNeEnRZ@v*Y=6-a&NcK)JAcDVIN zK4ioAdhl}%JfXar?EFw@=g%`cKlDzK*R1UP(VId$-)ZeN+4&*hpI1cHGqLl7V59h1 zrMtPFn4SM2IHL6^j=zmW+fh1zKUgH)cLYNv`;HRr{D)bbc0S**^F7vXvz;gX1Mgxh zXU+>=d2^_Tev9W(Z^JKmztQQ|M#Cp4x_PHMD#f^B4s1G~0H?-wSV zs=QkH1Kk6peX2k3DNLPmA7!tVpP4@}B!g-f{ef3)j6qx$+8O-o&KCYa7Gm0Ye_-Ws z+#k4Hnvp4TF@6`~yZQrzm#G|+`~kV*so5XMzZ-&W@&}GBhWg=sM(b>N#s~RN9ln%VFT46>lHq&`oObCoXl7SzuSFyHTbLNy%)9Ay3VI=HqJWx_>G}n4p===Iw*JO zRd~+Ni;1n3Ug=cDRt=QIVeeenE2oqFoIF$UY<+wJ<#_z-LV9W5gYM*N8Guw7N zMD&U0c&k2nt7oQ9+eJ7-sLmU)`dz&~ev9c75A<{Tbnpj4ed>$Q#d=td^f`SR0x4>{ zlJ)6^f2lsD6WW)0pig6{BY4scqEEFer{aQpu8!vn7veX3aHX=Hj%Uh*b3281Z?r{y zR!{66xZsZW%lU-$Zr700va|6A#lf7_m!xNQKbGhj$9*mTp17VJdwr;9DXWLP@#W)f zdX{$Q;ys%RRU4zSnhmdWd6t|Z%rOz1atlDJ8ds|{Dhh7;xx?*|Psa6%ZSci>hV;L# zCp~Wf^j7-TMD@z9FggwEO?bG2tTh2J8Zc8~l8R}OBB(>A8H$R~IHU5bPpD5m_2l|y7gnnK71JSR1o9BA*TpRsL zgLh;cux$$|v0$_C?q%E5H>~v`mA0ZY_}QCfJ$a`+zkx*J<>O6$t=*KR3FORbw37-J zUZgrX0zt?_PA6}^kms9^k0{?sc9~~0!wyx68}CN{R{i%xj=KeTqhEBrmz-Gxr=Uz)B!1r$ z`|e36h|nbd+rD^u zY&`7(@l*XsJE+$4@s|1>F4oYx!^O|6XV5W(N4)AstY7&BFCXs(csr@pK~6hdT=I9t z#Zjxr@fX$uY5MDci&uV6$A6pW2JoEWQQ#g6y*nnyt-PsSD6c4f4Z8ebb&!M2R+j<8B8$q<)v4Tt!Y^{C zXU+dBT1W-BBtfnsS()##b~d0d`10|dgSW|NDt>QxZx~|n+2EL40cjXS1$3Yka(Mpm zAo0BVA(cZCo?nmhF+8ttuLV-V%hMVvQiO6^JD zQju6J>KCC~4WUZGJ@;?`dcM_vF)PK($D1Fe>-AucF1aVgjr)9qPd?|yLzBPOvHlVK zm2&KSzc4vtT)K9R;L>oU9W*0!v8^z^tfGF0OY<%aajD13O_7(ydwG!44wt?eC@!TE z+9$tY$s0!P&jz`cvC(t z@#ul`Lp+jD;Y#FWAoO|;LXY9m+wkDZe6Q7?gh#v+Duzcx8#tz8_W=hdeM|Z=ZS_R) zi261aj|wts+vCwow*ila6Y%KP?S@CyEh-nvo$_!m`hk3d?uH+jxfpbBfFJnI&pAJ^ zVC7voA0L=U5I=Ajx25TA1MlU%Y1?}7f9aUld=h@(NYoE><=gwYU(BNulGlawIzRUV z!%;ssW%MQaxz9(VG5$I)G5&7*wBxU2`8-FTj}KUtqx_A71Lf~a{H5{cr_<0bm%!{04! z)_$d1#+Q$`w3A>5GUo64m!e5t{?^9d9khC*eyh}rq0y`56aC$+m75pYUm@jqu_^A{ zhQHf!88>{v=k3_StHp?L6Q~h`jmhn}N5un;CBo))T(ZZj5-j)=^4R4MDBsjUzI?pd z4#tnmOEva=SL}?!_;fU8`xQ`nHioS?dEC-EC$cl7f^)~{3Sa|BHp5m9o(OVQ=5t2R zrACmW$Ltz+r*#LBc`C_v9g7@K=!a*6UTj{gZ&JQ?CqH;QoD}`(5&aoQyw!`0uKYLam^`9>v?>W%Nh@94(BJvr*Nw^oQYK(zl!pnJ--9bZc-ps_ z88o0ahh5maM$$c5Z|G8$Qxvz^zKlEk3qIociNVd}!~FG`=O=t?$H~e^-5lphe!I(0 zl-SfXcwM}tK|iWfxv^fPT{D+S*ZKHdvPp-sE+>+}u_9w#Fhb^FFjgc7QVQ<)9S7+U z>+84rV|a_-BmFWJZ~duDdC@;y0@yjBG-ap~u^SlW{9)dkqBpx#gc#_#;cX@O9Ee(( zFI!$Jn&+S#4R1Bi@v_FbPSV-eZKIA2;W007aWQ7 z8*1}hKb{l$Hd|?(Z}4L{yH@$mw5e~z>I*vF8setcEyR!ARD_K?` zxO6mfRPLHBCTkGK4i0JmGd82l+>77Yhpl)_in3)GU3a| zo1dwAT^|aiG4;NxD_06`)h|*y91X5K^rpwn%e~#nVSGS3PuCSpxaEad!m@tC+)1mR*0JS8JPbB)X2xmzVZPzO+~&27Q+eG*Rl^_VV*DE2;hnmu zY93^2^keABLX!K#;qxkS?Aojq=IHW zYDs&`2&C4j+@kkXv3-vB+?D~{W4yR?iTo?;4*cNShD{|8!MWd#ti+MaIpK)@8%nJ6 z!wzrwEMMpcj`y9szv`x6?BKAh;U1(5ly26~es=#x`dj_Af3af`Cv|0t=sY&=LOV9(5@P-DK`(}mT68NOV+*;d>Op0 z%zM^ebUmBtLnb^Y;Q7{Gxr`C)Ai9DNPzrU15!(WRWNSEvAxzu8ypG+=evHIWd*caQ zF1*>kxO!hN=Ed0YqzeEcJ{JNfj>x<4BfY9p@RVOdZF<+L{CN}zUq0TVH)v%LtsM8@ zf^Ga01DD_;EMVr#FmVS zqW&tria5OCX=(V&Si#)HsQrk_+ciQ|h{gCsPM;(ciIT$Kwu*Iu< zp@!#kLR_viubA1b_P_sf*sIl%qzcS>@C9%ip<`>>P(NQ8R5~2KJAWcF-do{2PCr7& zJPkPi?2av5VhMZ)&aZ7;Sm^M*{}YDqzeKk*T|~HU;?ym#=Ed;5W_@uP-HR?>fz#hP zgym?YLU43nNWH`NjM2So_+ABJ&hw5%OKtIe@b(>(g*7U-oyPagntxfq!GM=9|Bstc zKZo4NxcsNU zPSMxL*5174C(hpVy{9q$h-(SWqR%mZLYp1QfIT>w)@*^}x z>`m%ZGqg7^1aB+z`PIr-g1vF)l5}kR4H#y7rSXx5y+P_jLxPF}XC_KxhKDhggi>A} zR2}zV%=aUR>kS^L7Vvt33j1dlyZi4;l8V<+J$vrHM`LH25omI>_P@?O=lO@HQ9wN=(wm| z$T_=EJWuIxcHwdH`-eWWYkq$R`YM8f3@p<|_paFmZ#2}9S@`{ZKi)Ap@@|#ePTPf5 z$QOkeG}Z6VSpBYFW?`?zPR}SFOMiCP`ejY;lztf+P`T_{zl?ye+1u;l%{wMNYk#Nv zrK2v<+EpW9uhQ9wWC$&Xw;5^sJI=S za$OZ{mt4`~2iulSwWDuD!pT6c9}NblH@=GRexd41 zwfK3E*|dh@p^wlC4WSjU^mgSp$$qB35RSsBan)9^fVe7e<=y!3QKySzvnbDyiUAZ@ zPX`w@+U<4aKqg;4-d3(Yr0p_Bo!ag~Z8vS@6Z||E=dW49#;GOc9vL)^W8gZe9}Mi^ zZfRf#^@tn;$347VLFQ9jr54YdWk6@}?JtD#8$MU%N4rTGx_>!-7cdXx@@AXy1C%Jt zo2^=M(yFI-Y~g{IAQNlWPQ!YFWmvng>IlSE&mq~84l(z>RQ%#BuzEFAZ5W>i{gN^ zL+@MHHC!;rb-b(4>;5Qe0{(NQT+QOOy3M$CLX$uhR#j@gSuz=tXxV_g^Nlxfx`uK0 zTa~Z%5IbK!-qv0;AD0f`7)96eKI?Wl&9)|MoRNhavw9ppNByIP(f)lddLQJL`o>i0 zHBB^O>j}8$LE~PB*Gz9{&Mb=66TzE$WL$MyyV1Bp+H><=X|$*73NpdBUlZnsJS!JH zZ^`&hfxJ`&T%2BK0NAcU_AmMjZcbp6kVP&WhW-X;per z=evjrb@U=<46y$}`OdbfZ`kS!j>P?!hF_hnpRX73e0;u(O}dO>HRzq#FO1OpX{zURxQdx+qePre;2rvfZ%u!RO$ zFK2XI!i!(<^6>^VsQhSwoAPyFgxSP&uxe>It|k0B^t13^kQ5t1M~m>?df>k<;k;Pc z@=;0iVhg>OH0;L?G>&>Isjonv6V@ACd%5<%)fdHo(No|@w-lv}DED+Qgd%;dpRW(% zd61lp`=^0V=$milO)W)EY!CgFfcrH;B#qbDMUuy37fD}X;6+wya~qW6e)q??8ZZI( zulr1h`}w!1-Z=l9-9{Nia6d10_#5~!g8LmCKZYNG{m<{%;uA8O=1g$bIL;YA4d;w6 zI~iwiuruPIsu^;91^D}c*#}te|)27-XWx>K@U{bE1-T3Q+6w>irTH}o0N|!31})eIzjx5ui^d^_!^!hPyr(&`mhJPm;OmAPdm!h~7SUd( ztzKu3Xttq7qIYJGbl#>`=Vol5?oqx++tk-p(E5UluyDrg(?ILz>-~7XoqZbr z&W_29m2Z|8^r9z>pS}knqO)Ywji&$*7y;tqPT+%J9{O1gRS6%uX_g4ff`aI7MM3oU z3b9zkMZinMbaj5+VkR1|tzx_m4UN|jTK9(gR3A1T!Ef5Hzyc@VF58EgiL9IIMm=4@ zwJ!~Urw7jmXMR%cSGVgNXTP3_2NC~RJ4xpaF7(#ZerXk(O>tCcge-5#|SlL(nHu7Iq|9TRGmyfs56JLjr4sZ<*ukDB!mmxgrji06bIQtUqhuz7Si)Wt+ zhS7Sd=l@h$cQ)QxwNS=G&f1N}JJOzucRJCYi+8r48rqXiD;L#g<5%LH63A<3PtN~8 zwI{_hmG5Z#t{>~DBe;Hp*ptyV&*i=~3wv^<^4-&>zCo)mICep3PyE);*T?aEJA2Z9 z?T*RH>!yx>@(ERN{&UC1k3bPPc*?!kvU3~LR5DitJE03DU?+6G3hK!F5_HvH_qW3^ z=T5N{3y@k1*Hiad`?HR7HfO`}CpnnsB9{dHs}G}dVsXxHco6IVUaNd2#W~O`-m|EA zvK`1z$eiqMsP&{y2*^?869(47Ps0-iPN~+J`rReAtI> zE6?%Amyb8wi}X_@zf}>WnQffYvk9m?7Dr`~?HwNq?c!Lk$}t+}5b7ehJR)(<)%Y=j z%N-lJP)y^T@5~Wwj;#%g#yQP6JwEXr=DHrx2xr7_dekDEF&E(!0E833XWS^i9M>&j zJzuz{fVeGd3PysTof7Iz6t~M~C|{}LKqg*3-Zl=x6dmK5tj0C>h&vnK_OmyfsMn8f}Cw4o5&bmI?}gNr?2_asEkn!Nw`JbWoVPa@&)IRKb{IT$4 z86Rn*BkI>n`_5i;h4vyFe0*VOFDlEe-y`vd$wBOe_dSQ9$>+~3`kLB{5vwQKzSILe z=t3RAht~;i477P}5YNpx{y10p_S@7qX7vS=FAVKP?bXU}0-g10$g8H=nP!US$GX3Y z^)FUF8h?;as6{S}KdynYau83{h=lMoI2D4BLk$NUM_pt9gj|f+gPXw2g3y#81;2xZ`~xods9U2qi9Axq8=iZQ8vO;)5L?rTb8~3pUvcK5$3&KrSc$Kv}aKqo0AnkSMw+z#vdbgZOvNP zwC8ke$q?R};tkB(JRNpTjzNgd-4ur>XwU9b{2nuVRxo=u?&1#EGVVECU4~7oKyRvy zKTLPVf_)&*DG9o)*J*r2=T(G$^y@g9ZH_-GJ<4~&^YxlMk9-jCkI_9$b>`4`4$GL8 zi{S|6)HsKw<1#tppZijGr^N>ay+05Q@#$d2W&j#cQwNvKWLJVOeHnSPtZRqH8ZRGj z@`EmL>v0h3-{?7VGrfWaE3Ap0Uh{*=u`(ZrX>alvGb`(NWzp6*{ zPtUhlL`B=axH$1c9i*y61~ID!ga8fMrwVpteu-y<16#wp+{T05Pmpn0 zeue2l3XS6B<2{G%I{WFPU5&T8gCl30^-2iIPz zcC!w>jM>fg$J1^OSUX8}6MELTN6y^~GI%5EX>l*e%gzt&k#F^yIcn%F^kxiIXdK3V z@PkeitDUC&COluSvdLESO?QC}*sp?>kJ?R+6ZD^(AB@~Pmy(;_-72{@0CiPx=31S4XTT5_+{Su-l&zRMF(YZ;wD_DyeD9~Gfx$^7c zH7;Wz#z?$IJ$LsF+=d?`cCBM0C#qoEPVU%JR@>GpUVA?0rE+lEve4P3&B5E)$aZ$* z`SW{nI1)G~_u*<0ZPwVGS2oFr*;7 zMXZzKOG3NhpnhDak}kB%d&d9X+-HE7kGI*6Fs?fb#-Rsso!_w~fbJ*7b%JG?Vi@3X1mLw0TD*dgE;PL*xh2z=<5^mqH=54UCx8Ezn$Gx*PW_e zhe(kn7Q354tC_wZg%o&ZcT;9}K>-eEg}HThm!Ko}{RVr26xH)?qbC-xQhzD@#CWyI z{yu4a#QydKFWM^MY%f$klJd-Y#g{4H&JJ_DK>ee3Sm$xyt9H21cXQMZkD48Zon1Nx zp2pFSJTGDb|8gB(5&v>dt%Sb=5X25w@b4-34H~_W^J=uuFT=l_lNb%&^c=yRZli0j zo=AU0?K5Oy_PHmx=sTf(_N?6AqmgndH__<|$ZwYqeeBtfAP`e+-87PMpuwUF~9Zm^>H@Y%AW57{$U?0 z3zZMYm#_3odo{MFad0;p><)f%Zb;{tD;JGRl+JqQHffhIHg&z?hapb1+i&GlY!ELW zZ}TI1LOmPCk513VOF&TQ2T)ZOy{ev3y~Kr}dWl0w^%D1w>eb1Ifh!HqQ1nbZL(ay1 z2da<@dRM{CD8tRbo%ArTt1AdNV-urPH}mxfKf(43LOG1QMCC_+ia1HX2t6Ln2W#A% zwB8YM^RK8L32}3?8&MknN$d5F%dwYC=jw`rtHuHbHsWQ$(L!+7GeUiL&H?A^DhrhU zqNMY;@vW6(h#vJ+?Au4QqJU(=0>P{MT4G+tjcFSiNnjs+w!CF zb(2qO>|>UA_iE&f;>L9dMZJEj&)L_QzI0-oyK@{*Qu|sQ`>77XU5#@OJzBQ^ zVJqJ(FQ|lzlR7p!|FPuBNYnH%08FP7F{853E{Bm#T6g(8bc3l~!%Qvm zyzY~=$BX=%XOECV|f!_%Q&_U(iKjtGmB$C^VAqo!S+V}W%Pwg*Kj6I zm*CkQqHnFEP79pPF7lF&N^tE*2$WvV>W$tHX7fx9JNS9D$&PV$Fdl!x`Dxg}DrjkA z2LUW;z-Eio??pn>5IHQIsQkv_P~vE-ICO1O9J+ZGaAe9tPOr!6b#^fpcdA`fJswcI zSSXjHcJZ-~JMTGC@L;0b^p1`nUOwJ2d)Zjm*%QqBN@y>Ktz0aQQaOpe?ERIqA<6dg z-Vdt1%qF#Oc54WA1Sj>0y-c@xu7u~>*h>Zzw3j;T@FZXOF1{dvZ)?}PQ|k-<=kU;8 zjAomZtP z&GDBCJ|H@Xo@Ihxvizlv4?WJ5Rza!kg=?(q+-l*b`KN^wR4%iQH}5(u#1N`duwg*$ zX{YNP7jK@92eB`qDc;OjyC@pQp!_WHX6J7Hlz4OeF5>eo2x)+{tE&iUTr5xy=A9kd z*UIyipIE$U_O*&CqVZ;F1?~ZC{d~Ra*P<86`xUMPTfnseD<6wDt-U^!7c4{s2c7H= zUXKP%?%l2&tpZ*?-ZBoc`x#u?Mpe>+Y zk{q+77WgxAbbA|rCiG?OoR)F_cdge~t!rLi#oZ%q)>o}MBpl~dRb?#e z4IXd$7hhjBBz^*#Z;rEbt)8cyb>|+>rI*7z_YSm#n$qK_$&kKou8n6YdPd+Wpgg^d zdT{HLIU3!jO|0up@HDe{%{|RXBmP_Oa~k@CR-^q_A3{+Z)l>7S3qdmM zYTC-rWnsL0yg829|Kn_0^SC~w>Id_r%^^JERi3TwHtic{xq4mOWo~S0ySE%5?T%Xc zru-rCBV5n)IyTO}DW*i}^}1+yX-lC7dS5CONA6423#6;2CYsts-_4av*|>Ki6MT6E ztmmNFjOYyfamXCyQ$~-AhY4%clSn+Q`Ph%+#|X%+xd^rcdk{at?rLE>n(f9!&!1>F z?$_zuQ3KpDo6aq`>0Cs=nD?4uGk6P&Ox%tJr$ClXL2vF^HV&y^c=>p{yd(Ofa}-UR zPE1*2D}7D0=eEJSk(h*j)Q{2nns7cUf*Ihv|L3sPS>Sy3(jAk7)_xPtbEGEY{IW(q zRd9Y8k~?7sM1fuNB#$kw|L+Ee>sg~ait7!1l5=wllGn2RRmGma=wMS^hmyL~!%ee#HB^l{;RpT&z3z*9UmjcGMp9YPdORd9Huaj_m z5W0p2#efjU#ehU{Jhm>!;W#asAH1_8hT~cA7d-JzaU9vB2kIEnP1bCW5(Uv&A79?Ywmb;XmIF3tsZ;(x6f;D)V zv^4~-yfOE@Iqi}5ym4)h_+68Ed0pk;3oh)V?e)9ztPC$7?>YDn`r-1_YhFb_p?;Jq z(kD}|xi;8#h+Y%5aInp_JYB&9X8^WG<@ddT{ZKwy`Q}(B?|e6nGxeXQ%%cIf z=XY#*FS}>+!nyE`_rA1^SPB^TFw_HKC60tLH29$ko zW5I{_pMuq#*YJ)0J@*IUc=>oY$+2VO4frvXrJeB%wZ@z{Nv)KQI0yT_&zk>J{sbGy zIW7Dio&qal3{DpDzW`QDmzt1R?-k+3Jz0_SdwihwHMYfleTe4}JzeE}acmqy&oIPu zTLyVfZxSwd1*;mkEZw*D_5Vd&KIlS+%VSSd`W-GO=!?$3ucl&PLb7r%2hYL|;xgkW zu0K&cCN9&zCN2YLBIiVH-#f(PthE>Sb97vG{jC)q)7@ffjYF;)q(OaszS7-X55`+2 z^sjG(p0MZ3xxWeq3LaP3B~%KculUb8%37@T+Q zUyLUB^6`d*INqE5=uQ!sHc9+dmp$S~cUmx!=GqE}zvQ$t`1@Wl{LP?&;6q5}n3E%Z z^m=?>nXeqB@<=|vX%82lb*$fxI?#{R;lDflb^cQ|c)@95o@m7Cb2$tj#W)U8v|dEf zmiW5^Bm;kYt$Z_nNBU;CLeBo z_zL_HM1_+dYxF$YH&ERZ{MQgj92TZ(t+8-<6brcqe;sCQ;JaYP26*V?J{D|*%$oex zw9y~mwNWO!eQ&Mi(+8iT`WE*?1^1Hh&JQ*>@J{;ame>6k@$TvGb$B=K$MG&fFVqjcMDeaz zzONbY(2qE0cqV@6Pxc6LFK6w>{ZPd{|Nd6E7xzPbaN)J62P*9RjE;@BQm5%>^!%fN zd$VyrQ)3`03V%EomM&o`xLz^|Uj0awBgMp*k2gO~#XnC3Xh^Fd8_y%OIWPS0b7S}? zhVnzbP56iJz`rAuo@D=XuZI6w0+G<@%J2gi12S(O^-C(jb6+a>F=F*KZbM1V+QII(!Uk?bqm`c*{^=^C*VQ-P=4IMU1+`F=Ydt$DCw*0?{d(S!F;oiid zaokJL1NHOXfl&XVF7D@L zKz(P6dZ4NeJNSL-F8#dTe+u4pQV&4tbbg*U3`(LfCzmM%RX|+Y+MOQX>d-3Z*3rL% zrJXUp?GJ%P7Db9-{Km34zI_hgSLRcPH2M$R+Bw(a$7p`^4*Uq=#_vCSe zbH@H$Gp_AGE+sS!k9S`2HScn`Rz0XOF6e(ui)*7hW{+$09{CT@e+bokL)Kmru2oTW zay~JRYrUYpyG1>banrFe#I+0*5zsPYTlUS&4X!K*eB3M>$m*InpbnYji!Opyve0->ZS|kk1vJsnc(lm z8gzii`Iq^7g}+z%drh-rctGvc7F5Bs2NP!Z;b2qk~W=1%&N>)vj7+ii61G~RATu7>?NWrF_kn8*3^TOHmG zKA|yQXN0$%bCv-{koT7PdB)At`;i}iFvQzVYcC0Jdr|dF@U{x-i=CziG!S_Ccw0P{ z;75)=Iy<~Afs$lDvSjT}kGENmg4($_`KEtO#oM=?8pqq$;rq(`L`S3lD2Ey0?f7oe zhsl2AZdfCQeO*>>65iHPyd~b=0@8smT}^Z)^iRZ(91~g125-Oj;;DF>%N^*A?XU89 zTyd>y?y_BqkI#XOn*7N6ex}c{^+vlEA5VbHoy4^-oMX7wXLRi}u3d}#%YO~m_J51R zwb6YW<6=g*R^4OvxOUxrA+B{>dr7#K*>h&N)(Prs`i{iMp9^Y5yt9v*4Z^pQmpVtQ0o_Rd$&0D=mxK={(mbmr+ zNC&Rw^v%$4Lo;VfP1{NOZmG)A3Jg&Ir?X_#Tb_HbAgloRhJ#&9;`uKPR zWbP!c-TFquwc(V?bEk3bE~H!jYq)kopTo7{yvDeg5w1<_J$qdH%e^74^;vsKxR%;y zX1LZ3>eDUiNsfbG(nVFN57bIzWbdFGjC zzVpm?=FHUN+Q@sR2g*Atxjo;H3>+4ibH&3W(32S=UovO?iq>8%B<+R|%7Ji#1L1)V ztddN!HIB3a!#R2$<^448XLvswf(|%(&hdVp_Y1sV3?9U_B^+bpKGtL-2|bQh`Iw=! zT^UMKp0x!%ly1}VZ&h3#*>m%7`Cosj!{vb;l-`@i<>+-2@s`n+DdX~Si!?5mwpVgZ z8JA~*E@I7YlX3JdA2PTc)pE1_G=U&na?}8Jhq*#zZyT0^D!wT-OM;T1?dw$ z>3HLEagWL2a(FL4TprN*PK?U~u&Sxz@@3D}jA!OxM!sdf{>m(S32bAELwGER3JPZbJ6v;;)5o4bR~kN0&rblfmVs$JFC;U&3~`YnA#Vel&$^`F$JU+OuzFx^bPZ7p{f(Yk+It zg6P1tV2xajacxX=H5pvH>8N^Ki@a-kU|^%t$5zF)czE-0?R4m<2G{bh>UOaO`N0Cj zoZ>io_N*Di`ywwr{(^ zwb7R=?V>4MD;zR;Tw9-aa4n|u^TM^rq0Ql17}A$tQgYX(T#{_sOf=xN$KMNC_}qGREyf*1t&s+9~{G_^NLUg7vuv~`CJcv6L5Fu4Bp$?C(pIFCddE|u<<6l z0Qsa7Q)CQBc|XnjnJ837I&qBmbG)x!RZD3)F~eI$(uqliKrE`Pc!Af?lzfI;e1;40 zEBqqMv$mx9Mc;kA&&P@))Jx{?Nh)0YVn%^g!V++W^-} zM{FLheHqnTlZJUQ{>wj8@YhC|O>AQJcn|NNO``@OFYdf8+ zaV`62CD)YwwS7SQY%^TD;3R`<0WEja{@TFXCy#4~KH}io$e(om)$oS&*K$a@8C>gy z^qoHGc;i|ahBz5qiyz~MYh60uiE%9htC}jVy?3l0*IqiX8rPo1HReB_Rr)me(bT+3 zG}-{yuHKdDmYz}Rdf{3xqWj|7Jcy3*U|PpFay7;^ON?qVxHfCAdR)sLFg*~}`EFHQ zOC7s;xc2w;b-0!&=ytIM=T+L?F=br)w-Yq375}K@nli4P2-;_x;o9eqH@FtjayN}@ z-S3<{uATm{gKOERb^UqZ+9;B42G>R)eVMTx0&@4@#c~Kbpd|;BgIb?fW}2-LOvA3)kX^?u%;|Lv-L;{`b{# zHO95F=xQ>!_Nh13<63$8^gx%+cdO!B-@7*t*Y<;sYQ~|XztioaXN}xxXIQPTjj2*WQ6^%zxx7_1E+`v@oLq zu01tA4e7>ox?Z?uozMW+ZiDE+wLpzrjd3j}x|$5G-LOkNu339c5A;1>eQsOtZyq_LG zWpPR-%Q+Uj41G4{WpF=l9jsP(r+L4?DVYI=Fgc@Vfp8)7GZfF6pJBPo{LGWwyR9-m zLp`hwY))OoUBztXAmow#4g!m6g)ubh^t?^ph^dv(9^ z6t02)zo^t7aG|+*o3>bke&xzn*{>9TuG01DSNag$*I%9s(b2Dr>iEWww;-GUyiG)m zYBK%GN!!);D`UG&4@7jnTNT$vPuVkT zAFbG5Q#?Q{K6zX_@4F7J6&}&`=YeYjNV*wZ%Ru@OpLD!&Ehi1Rd0Y$3@x!&0&Ua#5 z>xETK71ut0M?J2cuzfYI9ffP`|1egmKeX-U{Iw#AhmDTB_sjXk--&B&I$bYZi=5E_ z*KUO9z_s%FYPlNYT3&QD8C+ZauX9Y@OJE*}&Z(JKiOPtI&G!IF<`OPt%@5HzkZ=X7@-T%#c zTs!x58i;r&vH|f~xW@hu4^`@~XG%b*NQ0Zf<;##zG^Kk7P=%@zQNJgs>T#{-U(*6(_bGjBRa^@$*gRZY z1s&DkT3E~7Jij*ad~^z8P7&AE?W=Juaj(+nlyU8s|J;VS_V#H8*RpFX?V>4M8+-rc zaqW*O2iLlEeqOj1`apBI7KQX7pLD$awXXS-!?giO;*D!zo$tiBR)$qgbsV}U6jr+~ z`ui_eU~zTy2E<65^E z)nssON4p-^k}ttudsfXy2dNBv3K>-nhRr>O)qM1J+hIOB0=swSqj|yk;{uN7C}8#o zHHb09iq;aY5ym|9iq^7(7hx9arq%%Gckz4>zZtNyoWBmsobL*m$L2Gf!{#%bzfOVz z;JkHAKcnWaZ&LHuc!u-WJ#eQvZ{4GxQS;X~$$Nzy(j{W(SU7bp?*wB0`s~&e?~jI2 zF`T-Vw+6GkKgRpHf_|HDl+)6APF*MTB(}=Xna8GtypVZp7Ks<~o+0&N=COI;V7M}m zO_i+;O)!s5J0iZ2|K$hgY?XK}^!w0Yoiny(V8mQGsKP~*uoN<(%Hz@EgO7I%FKxwP zR1ZOrl0Bo}A!wL7Sy#+^-L2}Kcj)?foady@sh!CRugK7{>ImGxSzm8!8NQUEnllgE zhvv4rqM9!8LQtvpYmgn5moKw3XO?~s^ESyu@fwRqV9=4o~$FmO?xX&0$*nG4M*EhEc>AswqbvG$R4IYOy8yC zH}g#%c2j*0SYeT1sq5Us=Fb6J|3#<1V>(~2bHE}W_Ujj`&jAag6y-aW{I%)8#4C2= zoCDSd!&RsTT%b|VTnY$S#(-chgabfH8MmWiJU9R;4Uwu3Li`mhM4be7D~`!Ymb4rb z_me?U;1vD;k*a=D4Cm^}80I_?Pa2& z-S8Z+-#xQiV66pocKH*cr*k(@FTU%G`l*~l1+xKzfob^iV{rR06tn`>{TGL~yKHY9 zB@~MH|A}WUm&Ok#4zK;J9zsi@DPgx4hENhicEB^Yo-Eb}xe zBNk*tN&DB8?d+P@$1R;-?YIy9@h-EE&Bli=4aSF-S!i})bb_JyxSYxwv9a>ZbSqS; z{i&krRsN9feY$}COm(4Yo@eiZwPHha52HGz?$p6GNY*sv z>F#cwaP_p zA6mky%xT!j4-)N$W?HDS0)E-pi%2(T-@l{rFX#vJvyb{Ao;H~-TJVcq*E0P|x{IB3 z%imJk_pc7+wXIZzmnAXd5q)Bc_gjoT?+aLV`bUs zF+@Y^sJMdN1L@;B9S?t{%fY>8P$E`*x&U~Cc>qJOcZ%r;vw%Wt&fxskF=8SEIY2>> z10?j7m%?YkIY;sS@j%NpV@wF}e-BKt04)TP=Q)i~S7MRa4`ZRFmbJJMz$JZ~g8fg? z0NP#hcBSvDbUj+4_wCq4Rq$^Hva7{ENNVs8`3HKWi*SyRH{e%BUGS*qlKoIp`~}M= zKNcb`i5MKTj(r7<9DT#0D2qU2Ktg5v`(>U_-DT3LI!9ehBG8L;UU_JjWe1KQo{aiD zhw_;&c=>;@Z0Ph`q*3;KoORt|cq5F+lgtf^AVe)F|eK3o^%wSV%g zYi&H`yCrq_2=Uc?&$b~k5PYU zd#O)&`-2DOq(4aL^bBrLY{w5^R6l?4Pa;zwrsI3~gXSEfYRPP5s`Domyx$v`>`f>cd{h5$p z0hUJ3JYCoiZ42~yO2(mh5jG%xsr}mHy8=sO+LLupubBRf$=B51u9BNH`FWND1afR@kTr%PYz{Nm3*$|^O% z&Jq_^*%{Qe5M4codlfsgPk5B$Ix^^4P2r&2aGqAoHKlb zrjY03B`0V+HE@A?X4JS&Y13h6<_xda?@+bl%_q1>S1_?L+OK;3sqeirk-kBp9-_qX ztkzrk02aBz%IPcd){|!RWTUboux1*OMqC!vw!xqzS$2M!>t}AcN;SvD5|44W6dw`0 zRn_Zsq-ok3<=PEjso&w*ihuYBu28}G%%@QygK#Vt?ie3@GCug4G8S0>;4+x#GMZ?f z;B@f#;b_Ojly1kmL$ge}!UdRqpr!xkxbMQ2mR0}c4d~Tii&X&@IjPeVSg3B*UVC-E z)qb_)QSnc2MIJIR9O?i}EQmUM!i^{_GcN{ET4szsRjBSjXbEpL!6yv8wsD;8Eqajy zxvJl1PdPMmPqec#es{*N@&Qix*GBi8mjL7ad8c2oAgg@`u2uPxUsigp<{zYdrc-NK zwOZ@YjK47y0PR4xAEnTqX-*Hm^NJQ(RG?cmvsEb)`7fJKQ#r@ zh*n!BmM4Jnv}rl^Kso5Mxcx6F*YIq`dvC%&*$&2*>UJ=9C$xn<;0DF%2I*{MP+e&Y zhp{ar5Hpa!*|$AdXivs3Itp!}Qjb|gq&ey-AVto+s^O*TN%1Cz=I#uU_NZDE7 zuf~!zhb9s8oj1H|RW!dKFPVT2He+~u*akWIn>#=d|YM$4hIz`vMyy29M? z+7OR|lE>)rd9JFj%_CFj!x?uKx|cI&HQxeHSsSY!IfQh>2)nrqf_%t+|7BHNhFIFh zpVNOVjHq%}&x?X*SG+(~nwsSe*}EV)jhm^d#9x1@vwlj9{6dI=nhoYrv%32$>B5u+ z1)+4Iyf_qiw1f_v1I3>)O5n3nf9S3`=^nK2eNEM0P|IcPz~y(#IORMj+8L*uiIf}? z0SXW40iIPgP8oypsq+FoP>c&m9~+9tkQpU=hxNMwQ=FHp=w#BKdcRP?J=&3x%hk?A zu1`WPGw@!1ma2UBIA!4xY#g}}6uV}OBJNNJ+#v;%4#ki|8=>=8vPbT(AD>Vbeq8?U z#QeyMv%vR~A2|&vvV@D1EDzH%xHt)ZBqS4H@Z~&&X9HKl|L#6Vc$zP9lX^9H;_9dJ z9PhDyjYGM-LH#a_P@lqHP@f8)rJu>0K^`Ct{IeR~=j}W1b>y&=98$lg{067B`^A2f z^0Zvp3hltm^4*sbz2K*lPMN2vnx}=TF+K|Ybt$#@>(j+wH|1oW{0N?rJs5nd|5_JSZ;T71~-~r9EADUJRQ0%xGYK|v|@nEMw=|Lj7c9sAP8y7_SrvDElC%( z3!>OvKb;oHT&Hlu`~1l5f|}oGx$;p8f5pS2_;GCDTfB#XIS1$#$bgQ)yY!|bcj?XG zXSF7{!@JrHeyo?}xkNA8>gEs&HJ)VY(kxRZ3Ki%rNG`z`eE23c^v5{Ns9;v>w-rRP zQT0OY4s(J!acC2kUnUcOhya^+(LVc!PP1YW*2Xj)Z0g5_PlA))yzkveMd6W0yoqtm z;e9V~(lPDY*xMv{j;ck~LeZM5@k!21>w3PbW0#-(QZycyoN z_Z|m1EPKg4o5}k=h}2x5(FW_W4|&7^4H?+%iEGV2T&voX@poN*f%0>`c;8UJ!H)@f z-;haP8=wVo7!)X}<9&OOu=cbX^S;wRvn_ewKd!IiecP^4dSgGt^0@RS?QsgcZ~97Q zOse;(a-|&JcY2o(@0%K~_opbA%b%Jo?^{G=5Y7ve<$Y6kIoL((qcJ9fT0YZnyY!V2 zf540P?OQpqo!O_}MZbM?b;XX6XTZW&>}>t)at6u3s=RsM-IoaO+oR(f`AqzYc;7A{ zfEs~R^S((z1{d$!1ze&w2O99ci52RZQKT5=!)XMhgWZg;&$Z=w-#(r1X7aw}t7tJU-ZwbN8%^-O*Z)7o z`$h&F$ZgE~p88BZ@B5PnoqmOiv+u^W>Q_bvm0qXD`wpNKdf;0_k2b^m=AYd-9@hCc z&DYlQz8iilesyj@m80o&Cg6Q@PW{vrtO4&EM0sLbj;49v?A5v*Opf<0tnzISR;4{G z*=oG+z>u-uDe%63EI7PxSeIi;yzk#1*h;+bho3e)WA9Z;&-7~vJ#K$m`YpBItit;y zS4&?w8QwRI+(J4ZlRld%)5o~ZgZJ&G(bV$3Mag-}yzdxl)TD_qb(6gBr|x%_iaIP zn)e-@O8h6ztLA-|lQjZ~n?ub`$ou}{DL3z1R`plM`-Ze!#tvM5_f&b`ER;Vn@4Nf= zJbB-~D=N50J2G;)+Sz1y-(-@qRE<$4=6zG6_2U!D!jFqrnV27Oc;ELTMa8qQJWR{r z?Iie-=6K&feZvvn&5sy7apB_D<$c$F-I2pWd0Bemvnjv9Xw2Qse*y0sxK5ex zScUiP)wk5h8^B`Grd-^&!_9i|zTf|v!`?*fAAD^~@V@6DNf(79yzfHrLT=u7F0Lob z`=)OoY;Gp+oBo_&uMA5S?;Ai>QelSl+#KHbV_#J*$<6zA-#smmy+q-L5APdln)eNZ z448oT&B~z4@V;FbP}cCi5vX7iyl)TG-YoC?vD=(xCA@Fvlz89!k&42jDdC#K`+mkr z$F%Dy;97IM@9vd?yK${SzT~r7u6zdILoR*f3u4QD9hv0+f@171hh&&N%bn;eD3U1efZqm z@_Ijsa=HAZ$?~}wR7Q=js7=3_Uy?M&8+7tnM#|CqNwdkg*W!e>;u-R)HD3p{QD(S3Q`nTv$SP3ibXE(-!P zK6uu5aE-=}A-;~zuas@g;UU!u&o_*YR=@raUWyTG+KPz_Z zJx}=Dhqe}fJFraEXVd&`@6D))=K0&GPJc&jFc!)z_Og}v+ssl`uFd3cGdIy{T>S0W zExgeLfBVZP6n|TUzR)OS6H9g;Xt_lgcKy2DD<7-pZ+HHV(~nSb_AB2u{YZX^E}tI2 z7`>u@tgQE3jW{&mx^=tpFFOO+8k(~i{xXj=!~ZJ|6ACa``!1jlYfGYV*BUPno|RK#iI-o9A!8J?bEf@V7VNddu^-d#*S2VO^;0 zMeB$4!jH>es^)JCw@H0WmcPwjpz<+%i-kPIzwqU6OQJsy{x<$qNZ`lccIkXfIZQs) zrW-z-QfV{y%g%wIk)^k9Z}-GyHAZ=efrGZCI2)dH(j6 zv+DWVQ@>8XF{0&|6n}drlG8X*{FEy1q~fk9XdyqAep38x_?twp z{{sFt`weBj7(bbHyU|f~OO3QA$=|+ot&6|?=e1jczx^_j&f!By|+uBwR!7yd!aw5D5yrG@EXRlqP{J|-+uKP)sl2kyI9mz3U7g)r*MNdZ)_bw zv%jO|@V5`*CI;&%{5XU4+jvjEP+P<}oBVB`45%;RdR?CIhjJtnGMHLwHd(~LsD`&K z0&O&JyHu^$Ra-autk;b|-3~)Sj?ukdxn{lYw}+kPMA6rFPl>nPS!++dKZ|rGhiBh2 z?;+d|X%wDK2^TB;uanMZ;9`^fZ$*J_Tr~L_K8O7bKd=|h&sFw&NPS1z#L}aiP4xRKKP7n$rC?+V;xT%J6GwA7*?aVsq)05 zcer~mZ=U$zxB2kI>5nLRczi&OJnH?AEAbCF)!3UIEsz<+VEmXjF6fu zpkiwLGvcjl{=<1Kh@5eOJ9P=0d((h}hqOfHUd##v%H2v{)2@x&F8@)@>m-!i<^`VR zJz_bssK2sD1!O%2vK~)av%P7hM@&Pub0-$Qd4l)R;1pcqzhgy~OgHuxQ*T{7x5|;4 zoi>}39v{SN=|nclyG1UhQkl7iGfs%vAT5lWv-y3(()k1^oqMO9mpV1K?7XId@8 z*Xc3@?vz0#7fz4qZCG-$4U5{_ERXwYue1JjWA>G&X%1QVXQUt>OaHp~isf%r#5?#3 zb`2bgz*E|>b-NE5na>EB1={8S4jv;@<1*Z<{IeGXWjn$YSEd zlLD8D4x^Uu5~nSV`*pY{FK}VE7W6BX&~2o7L-Q zJL^!!Q1fBHmU{K@nEqV@YkR9V45K#fx2`e$J?n@c*Z5f4iT8ZaWk`@lzPWzryEiW# z#}9qsN+XYHX9h1PF+Ok35A8=*F62>NK*M!S)qZFsV{m^PynohxkAf|jjoI;M3h$ql z5-vaV<%H=^fLvy(XEOVaoq9#RA9~Am)qdzTxK@5>smm9~{r%A751aNwlO}!L04%ft z2EF~zA`))O4_$New)8{K`CO&<)BBEPKA`lr1^v({3Qy2NpX0ml*qXzfj?n32q`!}7 zd5k|-(+{>>xp{tQ&yOfu6*M;Ihfcf9Y0g!CXz%-#{tTWNxwn8HS{7M3w-15QGN<5& ze)v*H>KZ>Zv!GgTHx7zjtNqc>1A1 zSNfFGWgip!p#%3#!Vlee;#TxSe?44jiQeHr+{Ox@Iyxt6)5iQhaNaX{Lnrff3kjP@@_V#dOvgw_vv5C$t>_8=~ITJcfP6B z?T6;|y)OK}89y|=R;9Zo{Lmgi!32J2-~G&Ps($D<`rwBqJp9mGt~UKW+de9HR6S)@j7xSVwRJpzZp z@A&(drH4d!m}i-g=Zu>4wP9OOKZD->W&GhL{mbKy+m`<2_*Io&P5YN!9ZGLo(7#MV zs}uQ`$L;5Ia8BPL{^eM^lE?UIHT~P>`j=y02fkuPa`$Cth3liv7dC3_jYxzg+uv@h`(VzLCYm2hUkXQV!2~ z6vfdzX9zxF7(J@-FUc2@=ZxUDQ+nE)6jzCRG29!`_sDOWb?n{f_UVUq^B!nMK3B_a zhJK=+@%JeyiNkGvP%eD9%`v1!pOP~AaGQCl;|YDrpqX7Kw;2Mr$vx15_Ph(=Qzol@ zN@~zP14Pwg*>{v}p7zKO>RHBJ+!@oog`tI+jffn5g=F1FUx9MRdp71yGJl$?cc#a_ zk7r#meTCcGGyMUvBiUc9!jQGBx&u$)Ji?P&hR;O=)aj0JAKrvL?WSRt>L8v+*giDx zZS6w~-xUYR62k+tNd4-)a%I=%(dTjAl`NT##!YT!i_7MTPj#ET)H5;j;0yywfpY|LSed(lr)U zxtFtW4(DuD{@tF%U3@Hjw}S@U&f3{ngxHBq`!Q4WAu->Dc#Xm-N#($(uAkA)xR$-B z#V@JZBW|rSyUfKI+`|{mQ1)If+9y{FWuJGM(;nkmuEAbPRVA01+H6^MFaDt#6WEvT zTd)}3oU@2PnByAY3@3Svv?xfM>@|%Om>^~(@VK;W3*oZfb~vE+o5qQvTHFu=Impe! zU@X~pxE~wVee{-%SW6g4%~JZSUPlPK!C8Ir;Xdp&jCiu=Fl=1yJv?GupFs;&%+cN8mSy-(&EL^<*aABxW*=EjyOm+IaR^hi&w!4w|J13v-HcF* zDmgkGuzwx@pd6VoB}b6CLKSLH4Cq3gt_WrD2r|fv0O}oEtRf(?7HPy#M!mqHRIc`@ z$9o}XCu9uSr(qXZH699RIR|*KEdbG^4V8>v`BuYe2_89r^NO;cN2mLVV;; z)G4Z0covmlUf4hs=5@ZxKd$2sFfu+CzS_>6{W+JRkq8o}3sQILHTDc>CRh_*JwpJN zk2lW{fWc$I9|Blpm;DVeWu?V4)fWqV&NUs#*g8OZq0_x#Jp&_knsm?pn2 z+!H_GT~Mmq4+sH-BIuN(*vhyKXEI*a8lUl^_yw3sHC_NICs}M^Zp3H&{IVC|DY$$G z?I*Sq&xbBWvde;~L)MwK;T?;U8TdmGC-5+Z!YA<_Wj_ql2I)`mUlqS%C8wXov=4x3 zyZYOfRd3)yxE6C;hF2pFYIz5gVt15cAGj3o$rWuG{v=EQ_U7$Z zrG4d!)XEhVxt@P>wOlO~xk@K0xmG`@4Ap{cT3<1z-})(T8f+O$x%?_robs!H8;bxk zUJh1VJ6LUKiEZ7#6{w3M9Mle0NIO_zqfd(gn1;AyQSD#_?d{jFpN(mGS1L6+IEX6M zXJ|I`v!eF(m9sQsD3-m$(rQ0T8~`pu;<**QZa)iIbh(|dKKDP}PS}=z&*`n#89%J; z1XW+GE!aq4cYJGbgsoI?7t?TXP$>&RK2)nMf`pM*CqU3h+n#D1NQ1e*nP$V12c5H zw1{|B_Fu8Hn+bgIJ;r)}S@AuP54|$w1obe0oRl|$tXL(=bL%ypTN=gn@!V)t^xS%+ zStLKValF)~67GF!UI2&YRv+N~HI$(j@`vrQSI5VrTK=KSMXkC$c=>aI zyvQ!9tYk;xUi&_A?ay_({kbmW6t~}caFst7Ltgfyy^cTE!|NYauEn3b9oLJK;j-!n zgG#(W-|nw&VfZYz|J;rpZa0u6Vd5vSkQV< z{#^!1po|>h)%#bwqiFCSitko(8JR4|Wc;%-MR5CfZQ8$Ug8*gw$BW?Kjq3PwSQvaP zd`}tC_#u5xJNO>{gVrs*QnE+vsRQ=Z-Z}!eG0H#+fi?!vI+RC= z*3p430IS{*h%kWG(E(dmerT8hw2lt64&{fUamhN5nu9V!Y%gWwhkgzv@3Ft}G5Dcb zxQQ?Z49e;b3eLOciTWVBz3&CaKlSw|--+j74{3lX^(ho=Eq#ea8CB zto9i{xoofa;A1uZuH*g2XS{J4HnPE5W5@jkN5-gowa<9)vh6px|1)FbWiM{{h5z~V z8{Vz_GNaFRTA{t~tl$90RP4uCK9@fnH~kogdR6{#H*UZm{!q*Cj}QkIxjjm~8ywxe z;o2SmU--?&7e31P!tXG?@CkH*;S0|@m5y#V9zKH)_aK$C_;4?hI+uYy1U?xbyrDG# zv5@vfH7>Jqj0^Od?`lo*87v_kkY^2Tw~|HBzH=vniv4OwW`o0BxYi`zFv(iY;|;U- zW*BXJnEo}xU1;wK2D%X#U;xf?N0Na)1kn0cwTDi0|HAA2qLDoqYTi1IfRJm0YTV)abV+kGOFdiN)7iMeZrrLwhzb2 zw>C2_XtRevk!gA=j$+yyz}h%19;u*zGW_cm>)6cQ-aq~ir>^pU!a>ddd)@yhN$CE+ zd-S02QjNx{@ID8>Xo@`Ub1TjGq5N;Ep3V4y$BWnCE|E%HuuJifCIANhAHA@dM>sw1%UCzB@e3_-HomKeQ z6q-EiIMewwi>F+1WUpLt0Fvp4)^Tsv_vFCip zAsNVCjt|}}-38%dCsdH|T-|Tec-nm<#dho&^M(mrIY;`i*5WG zsD(qDqJ11HQS{Myw9>~loD#0OE+IOO}O4G+VQOB|)k^LKhYrhco+!w#fiAB|S% za$h^~to?zHIzz4muTQUBM{o^oTb<8ytgwdFfn+SZ6_2n#4C;LMYEvT=3lFeA{A7+$`e4}HW0>9Vc7anl4oXVr z@f6*u^|SMB8;DOlvc1~Zgi{%Wrt|id@8$TtN2g2wpC1cfXZ(vKFn;$Qzs}u5#?KKQ z-^k>SpP>lu@p}wC6z<4mRoUJS0wjxXRppwCeEG5PHTjoS{@&yF$KE9QkLviV85ti7 zUlYIWuQmC@yd{4&ow9vJ2lDUH@jF;8_*nRw_U=W9Nf)2yWjL>%g+xDG)Til5*1Ow3hQfmvg?F?UyR1$&|N`-56I%8kHv}+y$>3*7F8Y05~$uRr+_Mz*q;15=Q(d62PZXCo9eIVERqLuXQ zb1wo+z*vmR<2SUX|CWo``#`kSL#ruuW4tzC=UAsa>ZMQPi!RD zh_76+TDjKK0nyGTe{neDxLmho8RUwQ_M7P_#c* zBiHH=D1G%FqV#p$QJW}Mz`|GCS7n@9#7*O0W};uNtZPH3rg#_hXlnj7k3gI0)zE=@ z5imV6Ld7T-Sl(4aN#I;`A{@~KOjHvvZH9n}F@R<^n=U}7CSW3V@A8e~>4TO0s}ybI z$d92=^Zd&=Jl+0vZT7Vr9Urt4MYhj-e>De#KEA@Sr0|5BLqU#x?*9`7s{g+-fm`lJ z()EuF)I5@@dBkCAATT$nP@~eSesVK-n)fUQ{icd`RJ9%(-5c;+z&y;IFqUwCQRe*5eO2cQ&LRJ52`bPY9e!x7fdN?H!@L$>;vXKh5n`>Z7D8|sI~Bn=BAuC_Aafjc(TEgodA zRR;CLOavKrTf%h>JqPIWWbdvnPmTW^2U>EiH>)c1cPSM-*%iijhSw_lR4AW!0Di8; zJ4pm042&QEcu>A`jDb-w6h|&8P3|P(RSonv@hw(L+i#+;5Vo-IltvSy1|em7gh zLcuUo__4QpV-uPU*`nbA-iBV0SHU5SuEsyZ_@@Xzw4j>>*zgQ)TDU3x19&*xEN%EH zZbopE$+A{(v%KM+3X$|}*ne1;_wsY_km)!0IC(K$UZJ4!_MT9hi%ROoX>{rzti0^d@3u5GN4}LuX)!i zSC6w1RP#up5Bnr2k$gs%&SzSg7GIN3Z_DsH7r&GC&8OQVA8NB`|LS#>PibFOo_#Jk zj4&Ip@Fk9r7h9RYMKzUVZSpG;#?-Y%lK7I_V&tZH{e;eM@B3FE@tXW-87;#Z%oiIK zCjIhLY1d~d#>E1@yom)2gmiv;owIjUerN%ebvFh43*amK)tL4#fF#nw6@OKLTLF|% zbMin5A+m(NX1Hu{FaA26i611GUOk<~S})+fLubKbuc5OJzEJbvUDJ(yFGOM$J<(`- zfEN?+S!C11(PPuGkAKPWD`H5?ZUN(?*KdxM6u)KO-_1```7%#)k6}9hu#4?54o(Qa zbqo3yWRefRK@eUPsvT@#R1revdHX9TlHVH8=_+=vsyyW`BmozUvs?B2%K00m9^*Q` zk;zi>P=xXbMR4<5@Ii&&p-Wu04}$>7ppM^xc>GxS(#{z_uk!ciw>G>g`H$_R^l}X& z<744#;)lm;@<+3i{Mn?j{`mytKcM5ExgBFy$L~UXUw-R+m495vmlu9&;*Zqk->35@ zm5cH-|DcZlJ~~k~@$)KwZ+>e-S(SfpRsQR0_$}(s3e2z4|IN|}MFna)fl}N!gEkjP z=yc}sK#UqWx{(g_(CujlA60V1bo?8Rs*VqyErUCb>tjLBs!6YCr3={k3e8md1yXIw z6(q5yw!wm1faa~Xz(Tm2Vetm5sX4TKTGPu1G=yJQb8^u?n{$sUe@ql-*Hgz4#C z>doFXM~%mPd9fOv&a~s6y()NN?jgN8o^F32I*deh5jPvY?hZ^kuWg$^%!a&{-H)9V zU{_p2!*7V0<74=`55t(6=j(@pOS4-;^T4Lvq$#|G zz$(2UXQ+Pwg78u~gZ&CdR;=lXIV)eP`^|tV@`%qUSSs*Mv+%4 ze4#D|SE{k5Ebx~#Q(S?R5NYIv0$!@3>4E18Q4QKkg8xd%lN^9L>y`jFS_^m)l3`JS zj6`+$I2x6;PaX2A0Z76zLk?zDdimP^8puIi*lS8GaOr0nm2)KPp( zBVgf6yPH$7GvNnC#1m)7z$^vVZ=r#4)M({9%3~F*w44oU+KUIrsziYO_ zv9OkF|M>LFn~)1U+!!4iKe?=3{N#$&%B6U?r7u;f(Y|Sxk}I*h(pUI~t50r1F7R-B zG?FXhD;F%aT3?-_uiw8|E!U1(uHtS=uKkW$C&)5EJz~cEEP{uhzB+?``l1tDRgWAb z7VTLza(!y1(pRUJYu^RWHsqhReRa1Ce?fYFpI1kUzH*@jSIecwW8W@S>+4siD!DSd zDt)cFy#(B>vU~GBTFWX@nr2*)PPll>EIj5gdvSF4inq)m&}O=PI2CH{96pH`feG(J zR*=!l@5$`ycuj4Zz>H}EGj7^TCj)7ekd$Y)CNSIV@1D!iMuPGegQ`3OVwIKhpxd4t zk2x;0%58Q(7UydRqYLTVH=e=)ww{jx$;4b)4E3tX73+x0HFPDr1NS4@`bUyAkBrqn zLTq)XlB<6tRr5%`<`FmP8G?}TH_#~M6Vku%H#UR!JnbCAdv@)j>VfIQkOMe5pte5` z0j8xt&nn)N{nW^t;DUp)tni*u>7|7CWH+dJPt|t`?@2OI^PY5&5j@6lq^8dz^{Klo zvY)!UBI~KUDnnf+kT*F{^io26qK7iPB|0eKKvVd=5RZ)FU-zI;2&QpsIey^?3-O6o z(f@$@7utp4K+!S`<(fxuy?UU4pk`Z(2!2`JEg|@X3X(6SX6)TIfO|*=cUF2mATUQ3 z#94Ss_fx&jpkWELP8%KR-Ja@H&IEZMB>X7;?x@h`o~VW2jWxAj1$`Eu@3k zY9Sqjmi1QrFQi_X(oaI{m9&3DrP4&DiDR%oum_RUlS&+VR~88dp2d$nSaf*T6mKiSG+)QNQp>CX2vTr(S1F8I_Q*1Acm#q+AUO3` zA&g5KzK8o!+|R1}N&aA1zu}7&R`wcM|F*r+$7`^xfVVz`=FQnJfWvh0vb}iRUJ9~C zcN-MV{#fNYf@@S-w6rJbhBY}}@@4x|$nQjSzWW#6JqQ2L`Bv85{kzzz;$;gywaytq zwy0`emij8%UxkuczU+3YeBsjdt#$ce-Q9gIUN*j$w{`LDTfclx()o1heD*8P6ynlC zW^BL0%hKpuhEH&1mGRB0uRbfmASu=3&l_I07*OTfchjyMI#%gVkgjF;2QFSVvbRss zRN8f=lO!a|g~$^9XP?e*`Wvn2#cJ}SrM3)XlMD1ps>()u^JC-mD54lUD{jMcl3!5g zH|_Ge_0W~|{Vy{u%>!q(zXk*p>{-;w0I)~#zy$;VLP7{TJTQRg<`mN4{jve@u6^jA z{Xpcb=Y(kq1z4QJ31@MmdWqw%AH+KU`1lMY90=Sn{ySH@68;h(F@FL+_~rznB9{^% zhrfmzF4@2TyW^(C@jv??$1DG~`vnDPTp!O*_6?Ok!{#2tbjo3uJI05_I}pF*Lh(zm z^l=*dlSSd$p(e(ZVc0_6UiB7cmS8$PI(@D`;>W_5_D*5@kPdjk7}Zp_Kg8TWOZ`T4 zd?TAXeui?m`C*JfgrDV*2mOT@e~*s;KGqOE7QQBaAL9G+!*f;s5gq?Jv5xBa*_!;7H7I^I zfqX=Y*A8c01PYs!9_D%Q#DRT94sV|Lp=U)8DINa?51u%V`0jd;j#a6`;6vG7qU7k( z=`8Tzi3gM%-JbSvqLL%5ls-PN0MFoK;cMz8 zw4dms&r^;&pAmf|b^MXr8M_i6e03g|j_Y|g>Rmz43fV(9zB}8F=8Dx34e+PnMy-}D z%@FQkSUK?>K%&(`bK^cdEW>X*bho0QG)HY%Zp}_RJ{_DZkjhkTx;4h2oz;G5fgA5qAt^%zwB4+`Z5!KMT$YKDv zTElf8%kKP&bz{ifzV%3O-SG)XWbIQ>=XU6w)6kweERVfQB6bbWZSW|$QP~0F%Nj}k z@Kv<){!`uf+7Ih zXB1GcSi_kCq+}KKig&s6E-y$F{eAUDO$qz7r;Q)h{V!Gi-JeBq@UieE-c%JeDqsO` zRra8}My`AauQ3$Hn@~l!TupdcsHUR5_78$v`B#)2SC=S7l^m6Mb9u$d%$uk8Ct@u^ z%T{g@+CAE`9_p&4NB$enr4JG)wV>t38_$hFYIekxjpzPy=0-y_(XQZJ)aqBZ$I$@5 zN9>kk9KWOVPgTy9!s1oRiRRnPdy`RHotM6H01YU{wC{X7&D`O+_)eW6x%$_2yBRKr zRl?0Jyl>qr?S@YZ>hhWP9fXWE?Mc0_vJ)E(_N|K?!fKqkRramB{7KqY0wM(Z{-N~V z+`e@&v8|@|txH3GAHF0{i$_CL4E=S`(c)z3Wi1E&b9^j(b$hFo+;M52DgL4cWV6iWE2**K$t0 zZ(a0Ykr5rVtkF|~lwJFrG}yQ9J^4-U5qT8lwx2!P!R=07|Dtjo;q`;KUYtz5r1W?I zZgKw6eDwGrg#Ifng9Ec~U8hBq_1?Gc!u_50*{Rdj?x<5g1d1e+@Y}cUohS4;<;l3aj1392i;t0RQQGSeHvi0|w^YPd2gbG_FFb#4VblR`wV!{T%AN$ zD;wcbzKU`--f_V;b$Zh~4jA;bcn^Z=H5j$&T`#WnrgyRd9%Eqvz#_c9qV~O$4e;;+ zjM@MX^ZsfBJWTp88ih-g2DD}1BEdB>udK*?yXX5Vl*5kv8U*JHN}ny$4y8&R9H`RU zI#>Xpw-D(|D&YgN? zejE9B`_44}U1WpO1F;3Q-EcoVnXz9#dms{_CH&Xyhj+;nY(_D>^{v~HC3JJZ68UAE zQyE`;4JBe-jOEeOLfzui(78gTDCerjn60>5;0fw?kqcx|Tpy2+qX~M1B;ty8;?#}f z1zXG2Xg|DzwOpyt;Ubs#gBbg5?fviuj-;#jNZporUq>-|QG~GlHO#sTe-PH?n0Q~j z&=FDwQE5eiE`PDXzIb~+Uga;wP>J^U4|CdU53j#cxsLGqI$Yy@kAJED5?+OTx{FHh zyfF6|*8ZafKO-fbrP&uRc@)KNurJKtY z&B*vz_?r01+Wf&hxOnX&nSV&f_u3aPr}FpSSK#HJs`5Xl%HRCHczt3||E2rlT{|6q zZr=nno9wGbNea~uWqs*``Q%aL0CUbKh? zesblUX8m$C&%Szf&Y+jOeAnF$8dTinS%CnTWet4gDyacs{v@Db<97Bit zf7^a|-*|*rkU(_=vd^k|+Go`FJ>r&C?-$QoO$E!Icl*gO#?J+gvVZnk^XcOPhapaz zmSgX;>fRd;Ig=_+!_wnw$&Gq9{lZ2=f|9Qs(OOp=%ShlaB*(D+;~Axoz20&e)#KoE zm3=O*k^^gC*UJqbee@mcrw{Zm)kBk*$Pt7b5iLh@x07q-sPI@Z$ySXAG9&*c9VmPk zwG1)L00#yU2H<7s_o$7BC9YN#gNva;Wh1-fJESw?6hY&S>@p|>hZ2>I>>?*jX<#r1 zERlO)Fr()BNL(jF1yw&=Oj87&#&EZE9Ppf*Mys$!9Lr{b7T!kq3J|CIuefI*#(MbPC z?7R1s2f5BL^#@hXhWqXBFP)=%MIYe;GunK@z9(x|^lh7-{p?GH4^Qwd%EWU83Z!A8#7()9L%|leZthz~qti&7;dB4>gwm2UJL& zA*A#1+b3_0YY|=9H=iDleAK$Y)jFTiCzZY$?vodG^}o3+Yy_Qbh`ntAffxf|;QaQ< zE6$J(wg+0D!ajKqzeAASoJiD3GYjrL4dyCSmtuD1y_{=~)RB=j_HGF2+D`G;ctqMq zCa>Fv$9{VwXn7O7pUmx6%p$b1eQ3?zdlyPBlqnFytIPb=%ZUPQI$!rahBZ$R15cpl zGtK^cnG;0K!CI;j^Ta_|W8U6=d>`-x#owy(C^o9%$5GBQlJH%B_1JwfP9D|qjhq%_ zGUN2N6RAXaR12|RB+o~R>2W&UH?049V;`*l((&iAF!)&bn)rQ)@5>X+RryDBe6RiY zGPU`m*$7X-=7{xg%)j^>Ren;}{8;#!{L3nTZ=T?>dsX>$e6RiY+D@t|f3MD;n2Yki z&hqQ{Uiw{5gmWB`|nxrqIvv}+JEnRJA&O9XpY^WlWAKZf_&FI z9S#pq^8)nwYW=%+x= zaEej<
=!_CH)1=Z=!~IB^NK1u4;W-Zn4sV$RU)!*_iGlDf9y8<0z9E50NyU7F+6 zqr5EJb_&|{|G&55>&R$-v*+ik{`c$jegCp$l{z|LWeWOKe8$s_c$F;F>&>h9@EO^A zHjNi@N{)TM>ifQB%PK{q7&*Xayt9!U@l*ZeXro)@o@!NmMjPbl(sE2c<3*wFEtHx4 zQI*~Q3oRS`P742nKJX6jP$PaP=PL*L<7zqL(t6W(ZyL`%q4Y6rO_@Vir(dj+2piAL25*_0cJEL?B08%W?ftn~-*u9A+I!%c{yEV!Z7+@E+y((5=kE z=@5Qr3<2SHNc3PjO%XkD@j(sI)5ky+(IdPCyzwsJWY@qf>5b{ZHQq2U4Xv`zu56fh za%4(GPxmfWC~9}sT*qpzqqq(~uIg=zz0Z1aWp6%NGV|EZ6soe$uZp`FMGe((JJ4!{ z`$^aRe`Nx<+>d1HA0e!|AIa7{;%11{YpSs={GRG9t%e^m>#1t{)#Ke=sUJTiooNW> zp?b;gRD~z%`l+fnHZ~eMcK7h@2QP*Ydf&h9(`oE8|2OaZcWRpaQtUB}&yDu|TMRFN zwmF*qcdBLE?fVyv6WTmqRvjhAy7&Ft`*5zm?0r<1XM%nIZWGE(?fVxySxN=!>3{aV zf5|hvJA!J4s&CG)DmGp{r6(m_!gLsejKiakDE&=g-@k6OF05Sa6`j_NmSX=9Jc_2%WZ3=9%5?<)r@z!Y2Qs_1l)MU$sCk^8b;hn2 z;@OIS$C~PfZBD?akrk|expV!C&dZ%Kq-pPm?94na-uq-eWy-NKayjlphl(%o+Kwd4W)8%|VKNh}*SL#F(;B`0|SkLP$xn1m{Q^z-Qy5lD) zf}2-^|17)~-S@J6Bm_u?bo>tF%a4Vx$v>y^4}0eS@;4>_+(Sw)UiqLBCUU7-azf;He+V?M6n}46qpVTzU&-_C=zSq8gIhDURulDk& zD*uD3{9gP1g*&Uu@44^aZ8mK#Frd@%+V`&u=|B(Np7n6Pk|VC;Pj=tG_-QoL;RLF^ z@?PZs-hKbply(iQ9chjm%e?6OLDbE2U#G!EWeh(;SRxcw??du^f{Qsh-iAR?4BTPd87vBS zIE(|fM|W9z%ACOm=kz~Y?ikv8_Rxp^I;a1&U6%b@$KYdFPt`uSUbw|Kf0DRY+0}vAFOcob!ncmsyIAN%*%Ar79{9yONpSnU z$}x(X@a8#v_{IEJHjS6pDme~_PZzuQlw*e~IlwOl8_5y>=lPcBeDnI8txY>+b!|6~sFsIKM{PCRrXW+o>I(z7Sa9}p>vh1CHK8ao*h&2$( zjnVU@bYnbyn40GuPe#Yf+i$&EF~^IO*4@g!0E_{&%0Q!i6Td)@WWDU~n_I+2`+xf; z#_RV@{KXf^H|OqBdTqFG;u-J^>E4dy-bZ!*x7ar^`(gGzo>cS*Vc)%P;;J_}`z99d z)a9LE-^BBTVpn?t=H^MMg^yM{?fh@wH?ij<-d%eYbM3otVizo{@B2#6Q`k3g6WX}& z*71duqMoH?ik?Mjy@Xo7kqG_ulXD(m}&(kNMP8qrDC@ zP)t6pgAStUYnkPWVr-cf=@_(SLw0AK8Jm-eGU`8`ANd{`Hh5nNH>(dnFa(o3y4r??|LItcZ~`y38@jK1k+>~nZnu!>Xf zMak@sKkvAoX?DAXX^G%L=zg1d+eLo`*Ep}aP3gq z**EdbUoo=;(~N#crO)+Z{8;!JemjkHz^lekfO>v?pX3Hp%*mj=i z!JB6v`kd&YN5}WtH!*?uZasMJn|Pv4C$Hhs}N0*L2*?kieXG6yS+c&Y9eG@;C$6Uc^ zb8`h8(AxQD_VJ%5_~=2xpKpf;`Qf@9elTw+^91`7MGaMsGj=#fShDxc1%-ZIoSa;| zr=MsLufX-aN7m)1S#TQN%U>L3Cta{V@1z3)Nj{kEkPqZ$IxSc32FcuMAzUbbl14_l ze<46xRxuS`d1#kqdygM(%3+ywWE;pQ`=8k*-v8?MOD+IUUfJK``*;Xb2D>1g7J9T} z*1s=IH_6deZO?8&M*z`dX_?$1w8TVaW@~GpaeO z>HO|zK{JVAA$7#tg7?J`xVK{f8i3kQwUDBg=Bcko2RAg2*H+4Po|b*+`?5JO#1&vE(lX zI{nU$@yk!5npk&*;-Tju55ynG`g1IH;LXw~D-HG`O!G6wEMC-Rp=*s^lil+4K8~4K z!ZihYzozsCf?M?E(wns3kGqYiqe_8w^ImEnt$YGn6>3wD(Ux*g?1NglDJV4iOI7X* zrkPr#{m{JBdWdH1C+ulIqK6J_Y9+a;i2=ucUUcl|#>X7{39FpNeoVfc>*9y=UHrg) z#>9S>qT*5fvB-sDGca46u`x7nKfM2XD5m_5fbC!vV!j=xgbi}r&kmGz0jy{lO!v}K zJ3aXRbz`)qY2$}4PMUly$%U4K_v$bg8y|eC|5;$h#_e0=a0{rv!aM(i0u9Y`n#`y| z3hcK_Ysk%v7zo;|wJt{palOD; zfaYwX7&nn%z7f;bH|p#n_TP~m8@RUNZWQ01`@3r7IT6?N!@e?=_TSrl`#0$~*Zx1< zZ2KSBrtSZ!`u2b8mT&*i>V)n8lRoV~pHlLe_Q-a~K3dH`OM6U8d%Qrk$5i{$}I~m8>;TW4)tuX-UnXpeBStEPbz1%*uv^9p|)hOC)8tpZM_L@a|9b+3t zo5gT=7B~2XPk>i@Fp-Xij2Zv_btyLF1IG_fMzy@V6JYVN@TG|mDchE~MO(NZGASc1 zx*#PJzw~8Q-aS%?gpY-<#FsOZ(VGk{2*wAW?tc!L@CGnp2>(ZOGkZHMzkqEz6V#BK z<;f~zyp_wK3qn)1*!T(vw3$}e#XyPJT*mEKr2%%Ch7a_@mIi3}KSY3It}c7sx~i7g z2`TI!{}wH=|KVO|T8w)Y0S?8@7|Ck*N#WEMK+GlFA6y-loo3z{N&#_~8gbELAdWx; z#g(Zta1V>RwYc*|+|EYge$f$kUx=$gqnD!Y3sF`7LR;dO{Tx5WFPZB8+RA3`vq!{EdypHA!T7)kXM2{3VW4uWmW{N*G@~d3tgi!gumC-X+9nTGkhRZxnEXao z^9pPq{8;!(e(PtKN0BVXSM)&Y$NdNP%lImx;~RP1@rxA8J?@7vGVUk%m+hZFgmHIF z$3GqU@?+s^@{fE*@{f4tf8&*se?Z3{U}StOd>J46;s^2T*wS&hP;SqP)&TgD@+YV= z?vT2=HH2%PUBvYTQE?hqw{l-0-s8)1J^Efu-{S^Coq!3(tpaZqd!(CO(K<)cg|ElEX@JA#%GUTuDT^PK4V`Yt9b5gre#EuhNdW$se6c5Gswv zhkLg}v7y#Q7A&I8z7y=aE($T(-be9Mfyt($_IXEJWSQ7@q4)W%HtLmv21ZdbRX;Ta z(<4ai4OvyD{&hJ!`r@nOy(3DWoz&a2VS{0?7nIIvpnMf-rM*`@DWmG4 zxjRFoJ*#5Kcn14~bYEihlh=n-7Q}v)UW%sj(URdCL7%$fNfYJmU9^d!UB|zm^tA(( zgO7!;=!vF|Ce@DmN8K}?Wj}zK9CzLC_XNiX2}Ie#@5Np9H)%s9?Emw5B_I1`)}=>% z=A=IVgny!-#hy#q9n9RheegwXKWgf7c3!t{f?UaIxwM-+a*OGFO!^j*qaIKzW?0;^ zs-HK2Wu-P6jo!DuOxKAj&PvY9LbH#31-(5-ha9qo>_M~`v)o+ti&Wegx%_0NSxBKq zO`4ET?R_eVGpPb9fXi51!!{1H?HhjPAd4W)3S5)7q3!eI^2eyBi)KJl$7d4WaQ*C@ zrc&~Q>{W(l!hmNN@C#rUE-q)kvf=;Z?rq>Bo6bM*S(Y8DGW9yGx2qeBQif^;?XR=l z-J0$05@joDk(O>#iqvA$vcv{Sy25yEyp*USN{N?hh?nuUJ7{%O%b*yvHMdl!{K}v| z`G3F9Ip@y3GxsKwNp}DL&;R<2%*@U`=Q+=Lp6~N=o^!65kI1E3UeGrAWBeso9HH_; z_v2sDSFUu1%m?Fo#PkOvreDgKzCrrnzJ56WZgaCORSeHTzC`syTgJ=6i~V`#;|TV_ zXDe_{!oq(2TpPlbo|jVVnV8LPC=+MWXiVBY4^|iLFQhjxu0b5rNAFJZt`{mkksivuq06ObLf5gN ztI5!XWHcw=oj^N$Cn`s_?JUwFIio{J%gKyX{ZqnONP)PTcILNEwAZ9aEBUP}jK4nc z?>QHQFxb3(Dq7?Sm!!6u`0`E2`P`B6Csn$E3I;)_V?5FJS+yVO?@AXEvdu+hVVh~WW3?72~5%0qagK;VVD zoE&G&e(5e(j?>}${urHPIsEwRv`zj-1*W>uq{|>CF$BA7m17VseqM^t@NbKO5y+b|VA6OJ7uhLY)OitLh0L(qRIH#uTKXl9JV7<$P*?@pyj+8t}*P#>64XSM2fO?#GUPXZQ`KUlgAd@Hzyw9QdFf#e0;B?^4hzIlj<0WpO0Ug z>rK}@She01(&I9@KNsJ`Ppo6Tx%gAJwWrT0-i~Lz`OgP#R_VQ}xW@Q5M&Bpk-*MgD zfp-Z$b@@q$aqL@P?Kc-)khj;l^-u34GK7(6sclrN=>&?UGscD$X_2vU^c6_lW z`=Fa$zL*o^Oyzp>ndpuaq@9&k%$NP*eO}~w5})CxHJx3L{$EhL{&!7C|Iu)5`u~Hq zs{bR^`me_|mHK~v4f;PnK>yoUC_Z!jff(SzqfW8QX8?6QVf5;`srCy!^JpPggv4`s z+c(ynlUQ?Zh6m7U)}7nnq_^;S63OJs1z3shUD(ezNxT_A5H^V1(hydjhmpojW92ym z1B4amg(xU-wtc7Ir8JzwCoPW796n3Y?YHhcq{!0|w*R_whra)l185GHg_p7~vOIy1 zqLy{%4h_9&#s_NMIR+R|S*@v9cV2j-CwyoImG-=Qppk*=&T-%+UGRb0)}3Q1AvZ=x zAP>5ed{e-iR=z26Tv#??alENhsa__(9CM|X$*;b_0sD56diAhbKM8fJ`7*d~5Uo2H`#?~C$|v)kY7li(A0q+I*v}R#4`i+J}VXeEpF^bA`Kq3I8FuoqU$}p zP=+s5Iz#cn|9PR)>9-Gy-ZelQp?A5?O8{*F&kOzP^~B;%Feo&r+a-T_S$K&&BRoyB ziJ*1yb&rvC={9}8vB$3aLnYj=W`Iu$og24T|I+CCa>b7s1Rh)#Uc4V6ZXSP}5O)K7Ng5dDa;>|qTjVx6ulK6PCWg59 zp6lHM_@3V}6y|p=_?y$;Nhpl(7z$emhbZBl6p)?{e!}`Sf6XaQ&FfpxcrD-c^WO(z z7pq@GY*a-Fq(;?h4C76l4W;oW!Z#VbK~T+@7y&YAdm_0N1&by-$K&3HvX2T;E6@L9xp|lR@@=zY%*paJu3n{WtpLM$eRf zO`}{5idJ^D0RouB~mn^4uv)zksv#?MgZ6>nb@IfVb`Gg&2e+aq{k0dUy3oKoT8?i>ZbQ=9svqW0J zGFiL6zl%bL%fd_g^dwJXHxzS;eY*bFK`xVu? z*4&ce5yuvh^*-vuR)6{c0xO5olPC7kchc|D%y%|PJL~P7V_sTqIKPuvH+tY{vu@P# z6EzPet}}j$OO6yiEvLX>O{(eg^5jUt*le|AgykMg6fDW??eG_(J$onoWlWj1Pdw6D zXDI$y^|zi*gjyJrnfFdK?X#5?Jhr4MwQNza)1ZDZpdCz=NxL_6{~nE#r`ev%NVLj* zA!V!9@ba8Inoba{9&8P`hce<5%%fV!4_|ReXpi^GD~Hd3keGc9lvCsIfTrUdk35OW znf0G#hmnSSTffj?u}82+JwY3q@2vYo^-_uDUiXQCfl>SXBRuOqO&FKG=k1Q8E{iXp z#pfldo({#|E%6g0GkB}>iW?ZYX;`ruUt&HB1&k0?Ca&s|g8kgp4&EnpdnR7AaGRd5 zQtV0*dX`>PAny`7Ml8a=!|JF@IVco8GJrVd$W$x=hJHB`uvyZC@ zZ>^tC6mM^S%8R$}{(3Fq?E$|tcw0DG&121YJ9sr=1C9_3S*>_G+T!4Cr|!=WZ;NQU z7QAf+^-Tfo_~Y#mkO4Ccw+Kp&H*l1=j6FWyc3cCz9d#q_p9FCi3F6MdK2S}^_;{Ox zh@i*1@OE1;(B*gu-ad?UjFxi2+dJ?X`)`+yg}0xo#@m(ws-hQfzkj)dx7m|adwzJ^ zk6U%tqZ)5_kvR{g^!>HrZ9;@=B6z#?wZPlZx*oq&@bCmOo?@EwNM>;!UG%a7C|IfphZd+rcrr}-&kp?iWumaZ3q zrp1l-@?D<)D67rnvyPEA(mQ9u?)BFQO)J-5qo6ZvZ*-ZHLAC6L%gox8GRqMimGY+% z`z-v_rR2>Z)PCtkN-=OId7>AmDNmG9_}yvYpWk{%;+JljIyk1~DhEztzF_F#40GiT z`|AoP==QbXTc&+VLe>7del%QDzVmN~tj&DqZ8ucqJ0p5r^tCuN7vJh#@5o=LM5Le< z!f(CfZ(rKXfO8zZVp{e7x{l)&pN-#V{#N9nPCChD$d-M(tdA8N-XN9P==DlB^GqUv zD5QxhmPHCiKoJrn6zUb%u3)!c>}V=23S}>q|DmFf{Nm-}mx{YiReI{iuI%6q9yzlh zXK>c$dgRRBg7$O6+-2Y(irQc>hq)d^VFZ~H3(|-oFPOq#?k-^AFNH`O zeC8zWhpxkZ5RRQ!ZFLBz9;noD>h~2`$0@m~d0#<(5Hcg1U257_kU3V%r8a;T#w>C} zzkLnvD`?jJu3wQ~gnF8Cq+0eB#4uWIHPpU>reE=k8uk?&{ixbk&~lRlxnu7u*d#5! zy;(#P-|(_)9bb`*v(Lq6wf@@v1I1Tw-pdnuHgunddqg%X_Z19d6wuf@_Z192^ucJc zP4!>*zJief@$&{J+Rixp3PLxV`Kf(hK@OacYC3A(S5QPps%~#W`wE7?AE*yjSs&Ki zzJlRf41em_S8&^dN<@(lDK1gtsB2%rgXO%Cu_v@wye5~A-0gl7A15_^w9|wh<9{Jc*^!^dcO(fr}O@N)T2 z${#lS3Yu?|`CvRTk$nX%x*y{QS?ELj4EKC^_7$|s#QW?k7$yZl`wEIjtMQm|n0_kb z7_+aSFhsc1_U`KV zgtYK-`McxiW&UmIV7En!5{s?*eFb-(>kv=zWpMTX%D#e?=Qwm&ijIlxE9kk4=!K-| z+TK?Xzf*}XVkfh&U_gHbVV?NDf)!^wnV6V;&e^V7Hsi=I+aH1JMD`WzjwU&=8XJ<} zue}R$Jo+>FZEuCo@Ns zwkET$V6QHvNqVR)9BTa1O+)>Q6^>EnjV;1kz23Jy{W4W&^8~&`&_0MiPHygIeuu!E zdk2z825=vNDpR;iZT?4XOebq&)P8~DjU3O(dcQyqLoCG2DUMF<7ia+smqTd@2syc{HbSXI%R~^KEXR11g!JzxR>vk+JHl-g8 z-M7em!^>2AyUlYtyB=$D>I|B7yEWHGTv^k4T@FJrsixZMBR;yryIwc@BI>!OeNER# zTs>s`-=@RV{Lo#aEu@a|ud>USCsV&=>LXh2El*ml>vacy#qpQ2Evi4i^|}ExUCVmi z0I2T?Xb1A(Qy-D~Es3sUy)HK5S0B+`u8-){bd0}V*K?21U=dCj55@SV#`=g8zU=W| zn=nE4CMm}-NTjq5J}*hN9jf^2Umr2c#Ifc2i12+Nt75(Gx65f`I?+qW((M_0W8phf zACbhZ+E1=tuR9GS!%pSDRhBPlPv4Ju@~Mv~3XdkTUiZUuuwG~Rtk=DJzSzkY-Tx-& zm$L06-~D1YH-glAz@&&@1D%2^BdDZ6^-SmeL{3yjJd02LTKflBukC7xzS?4>!n3LSJVcG#*gK#38j|_y=7`JSzwAWRv+U5&Hx1KR zY42Q&kr~UzALNW7dSSkFNV8^G*RmkXuGo^{3}IIE3~`}D>ivf7qxP+0Rq0?w_j7e^qM}lKz%z7+}_kIlKo)RX}YH2oZf0ZYW_x(s00dmzZ zZolZ}^_sRL-};rYBgJo)^_=#@XWmr3W&%h8u4f0*Wv0|>M`rBp*pVLHpPwBmpy^ud zNDHV>1hfOuYIXcbu8L5I2D1c9ZAZ99BlTOuW@QI5E#uwqtqi%n$JQ?B@SYIr1Eq^#296J z&wcT~qxbx~1)JL{qK5 z|0;g(iji7DzCEMYV+z5g(C|YvYl~v`n?1@7G%LP%>%o;D8h)fKiaZPxJhe~$w9-#2 z;69_5+px2C%-DmJdMId=#gr%_vwwky8u1?!_{RtMkLn*RdmkMAkV+q@=<&DHXI0zj zAre_(ryEXn>~x22&(BU5aciKRer7MR(@pw*lV`O+u(mfocDhNFcOrKB(dDqyaUVN9 zzgy;K=m5nJ+8Sa9^Fw5s%MTq8+`kH6LV(LoUMIdt?swX*4SjJ!OMu1Bs*vDx?0|ql zei|+0FgfYOW3&YCDs`)>YJ^!Hh7qVJXv8BM-35)`1Ov69q+g~IGoivlHJ-|PMoL5n zI<2$^)3?<1-$C~&y@7C+&y#&#v7#LRY^QNb;vWiOauiRXloH8kWR*dcf;T`}=u^Pm zi(46$e(Q!0^m#E+O_w)M3jJ~F9Z!i$0HpR!$L#sAL-hX^C_apJA2Gq@FU0JIikRyg z1Sm5ofU6o&av~$*XnL;qhFn=BZP>Dw4IF1IKuAep*k0hLq8t|2H>dGc<*wu1)5dlA zH=;_)C||Dg^dx`Sj)`{HH00Y>%cQdwD*}XJt&CJ1={l@gXoHs}|M$8!v1A|1r?69C zmndn{;jLOo;W1u3A{=sOR`bPQd$&vUDmP#8-}qAoANZMcBfjf_UY+!LXoL}@Wt-32 z=e>sWF2ld$+v3RWNOz(Kmp4cuSL?liEBphK(Qk4aK+c9u@7g4IFOVQtqRq^(iD9BJ_q1w9Qp)OYes$*`JWML(RHf zum4Qkl6qmBW$Doc%RXHEx$-`WtyUn@s1rI4PfaKiBR@@%_MqnIklLuR5Va(y)8Aj7 z#tY$xsiz^HIcH%F+Uvk@ElC+WKw087$@R|x<0od4imzkj8@;IHA+vLzgY7&0T1%Do3O%u@wi9W45td4}QX^?AxwNfrov3gg>0-@U>>TV%arM*WP8iqO+C! zaGi^gr(w@spOKQd;BAZmJj|3p-vZ`#@Vxcsv7-t3yVGP>6PURX3>^%g*~Q62Af2pE z#y;y4*e^8nHPzqxmH675>&l}vzJxQ|k5pZinx7^s)YcU_SrYwmJLf_Ous$y9^Jr7_ zphdSkBdjLQ!XNS+8VQ$B;&Ql!<#XYGjDPfC-6s5kdfY66!Hu>#yB z@F{{8W#E}wxE8yXyWr_8zk(<`ClpH0QseEeh|@iN-vC0T?}GF_7kzVU=yGHbQ5+1F zi(}w~q=fxL<+_(KbSq7_oWsogg0EZ6r&VY;;#!T)5FiLCt-BP7meWw*@a(+ar_c>6 zFq&*W+s}nrf;rQE>|mCB{&xrJS@Q}1@sWB&>rLQ4o?9$u&8h+1%yWiaN_7ASZekBO zu6o1SAID@mv#Qlh4`1$$Kbk?H23Y~o1U?&Fni{|B?#qndW$@CqUd%Y9VFlyq3hc>8 z{v?78!Su!|e$PdM-;q#1S0M@{pFYTz++G6tnuX?hS@M68X$Phlyc&u|_w!JJqM*lK+$ZSN6S(B{_J@|lW=4=!~kkmF&-{ap$ycpn9YK5_(7036dr_hnAq@($T8tIq`Ixy&@ zlN`T6x0yB>Ht|1nPUR4tQyGv)pb`9`R7jw}E-^#5tY5~*aEJ2BFK9YcZf4MC)my8oV?(FZOIFZK^SfnA!L zSkRZiau3E19spCo3$c7j`!uXQyD~BMCuBsS(mrZD6K-!8X%C{QrjJE^NRT?`;SXV? z0p0}^yZ}<+w!n#UI~UeP9+EZbMm}VFf&8{!oH)OSQnIBZ)L#W- zF$cyLobSv@60EoXbRvf_)pgZhM=!LBQ=LD0yU(;6-doKh?Gok3#P2Tqr1D33h3&c0 z%gSh|?WbnD+u=OC1172J9QcNFHUW5!&K&%b>c_Ni>Ha9_$(J}s%p2u(sIQ*k!6h~c zDC9_>yj=p-t-2lWx|85c*+)JDv{EMWDG9Dro`JfB^a79)Z^Dj~LVJ}40T5V#qq{o) zujo8(zxj^j-3wn-^slcwcF`Xy;C7QIN(cN7I9R6dZE#y+OPwdmx5I6Mj}EF--6RxM z&XH2u+76a$Z7ulcLR12yU|;rWlMiV!bb$N3EW9*6n7F*5`&4aea{c0Qsx1ZNldy+; z0wLbSOl8eC{6U zWbZ3{+Q2FXb8ll1Vf)Gdh&;CFe%GtccZE7|zmdmy!0$Zr_%dch$)h<#^YHCNfAT<2 zdg1gfidtn<5;LsCfO)h)nS?07>0qAj<1LI_4(zFMfI@)F!i#S`^e`bH{WtxE{g=hj z;g_W?nH76Y=8SZx+@8+sQ5=CsuH@cNKm&diN{F*Cqn)Oh^X#Z&0iiSP8eXm7o*{FMHn`{;n85U1{S zaqDl!;i_R>oY?TSZmy4oH9f)W+G;%y_ze0m80G{HMAk~rYv%Kc55f1t+r`-GSQl@d z=!n|Sb$mmLnLYeH0sxk=R7g@*AMvC_yF2K3%*3Fk1z4&QG!d& zx_@%X#5Q=V_fdty;D@Tuwecl{Ja4^)LG?a@#2T`;d@`q0r|0b}7fO3!-|@(;rB>dm z;*#op0Y`5n{K)L6_+eeUTEk$3_qkO={3&H zSfx-L{HL+w&ST|t)vUXU2&X-%C@pJW0YXOFHOEp-nx47ngqMYvrUxcOKerk2jIMNj zM#^06#mJtkI;hePYCNlWGcF4+-tXj^`|*Kz1ZSY!;ON8f3y?rt%yYw^l=H*wFxqq_ zoG`Xh5e(&?$zC4M$>oKTz3Y*jhD4|{pkLxt94x^+uwF^Fo}v3V8i1Z-nb>SRd-rpj zghrlF8(O*a29_5`K2V=|N{seb3c8;F`3c!0h({pjg~sx{a{OMq0~VP5M30jnz1RWq zu4j_3<=6YQ?9|Z56C9E&lUP-1#<^kb*lgb+L7r3nhGFHJ{>546vdyrrl}@W!U!LJ% zIar6|0>q-cT72MQFG^Lq9vil=+K^(H2qiSVE6^`53op`b>U&QH(;$o}P8n4XhdIDI zJ+y1Rj}W$$9295j@oS(k?TK6?)+@a2=!QIINhVay2Ytknee}-d`QYJe&V0yRgnD%Q z0rL<6e>1W^^8y9|w&V-oke?nuGf(t5q1!Y5nnN$dE>?7Ct=8i!!=lF_GhTGZ%fgHN z1KDM}b2`2d$DXz)0S=I%Tn5Qg8~6rBNLB7YIMr#>B@;0ZfC^o@!?4M+?}4O^q_pCq zWw|W<*Ua12My6T!pw&q%#*5#^nO<7H`EOdjao4TfxVlU;?V}G4sv@@$n}hWMshL zV^q@v(<+yR|8t%p*JU^x10Qpi;>WqX373VJ-0xcF>%n(uFGg9Am<|DSQXmpeh8rT+ z^XeePycEIkDj;%$!;lwf)%`w(ws~22Nx!(KnfI9b4LC6dTRUtx9c9b2Y#U*w^%bP| z#Me|Cmp+6r3Shbpxjv&s?ktY{p!0mV)vP9`o3FTSmiA3!(a zZzNmzxCGePcakel=HJD5c7igv&GsxvQ>rPry@)&S+bexQSX9jpWFPt0(N)sLXj(lS zL|JM+n!)~?w|bWoHUO?y46k7S^B~R`lxt|4fN{Z|7iGS|&AH#fk0nGa*{ zpTrkb3Cb>7^T^;%5t&+(-&H7ki&_!%dbxwq9+r z%!09y9ac2+Y)@IjAGU|q`R{0prqj3X+BxrS=`l1v;_r<7Jte)~%x->2=fg4TJF?a)|Ao@?3<56z-D%U#iC@m#~~y#M)^_H86)GkToH&ODyIV6is zyRQA0D)0Kf5|YBev_)b|VQBE+p~~kP+gmqj{L}54_AK2#U_B(-g#W^8op& z_Tcs+lZfa3Ssl-{uY(EmhN}g8n>m~&#B+s6z_<|4rE#a&HpX-7J};6#`FQTb{auDi z`#MWfEt(ELoYVMX*4LKp$*IkjLY&T%dBh@5t)T1D48c+dn!#(yI$ldTGHHSYjYPGc z%lKOw)cEPIGZ$?1K*fja5MKu*UwJY95t?t({d8COe4;cY4X!12@r?6)qR4urZSv12 z>iS>D_K;>1=k;%_#^J470R2o4uf_}AyZw~Co>O|-s_$EWV>E`#!fP5(0QXsNmg42Q zg{6n7BVLeOaGvYN0_P?>2ce7VcD(fhx}C9}H>A%mbL8r~oJpN0;PW@iTFfmyaI%r4 zPRU?YVVU0CtSTI_ctD4hDHd`&aeaqu7pZkV@ zMxOh|HI&`S1x!%JKCwtl?Iiu}x?k`4?wBX&dndZ^Uk7LIv7{GL@%%T8A{NjNRK)11 z>-lfZ(@A`JzcIoPwGM9a4T#p2q_Xt@pW@VA&RaOV$me-PtcMKS-$7+~YTy%!kCo@i zxcm|Q{I}Nig$C&n?3vK{X6OG)SpgmR5Jv1hXH#-yb^9791cl{$Sc0R4+Z6k*kZWH~49gS@;h8?{UBqJ{C)b|tHcv*Pye%CxLI|#yp z2YmuEGr}Xat_#sp=LbQyR3!lBNte{hJaLZrM6;(c8!@}92@AY2uL~u7+VE@Si}3^M z^H<*9*!U~Z2Dx1OQ^&{~o%&DXN4IaVmT5 z%h}U+QF>UMuEuTJSK}7@TPmT+z_{p13Tr0*x4yezylo+tE{w`GeAo@a)HcM8w5 z2G0rXu!2bX;SDOl1E28uIDkEF|7y<-#LLvSE`bj1FMSz26aP7?>G8LBpQW8?HFOS79x4#GPEcQ3EZdreEyXLouKxvS-2GtR5Rgn4W(f51j8~2-h zvBa@hrL({(6I?WO$A|{3B{~#u$RkfJQO~DLBs*R$(J2W1WMf{|{sstIk}9pE#`EukhBa`{otFgylKg}EZtP=4h zarnG6VBJ#6kC@ekLg^FyRxZG@Wfl>~NYd+U&_jn}7Ms8vwKVGtzG#2`i(aKaWgmP- zwlvxMu6Qrs+ljM1Clo48Q~dFlXNbP8BO>p3ZK3{9uEY=7dqMBN00YUcx59g*3s5Bz|9dLaK%pXzVl4c;Ct_m>Z;@%qKx(~tym^kpjmHF_xY zZ%X!hpP#wYj^th^Y3|qU8Gp~hcheyJxV4nSt%3UT=3hl$TJ-%Mf0y^O2C1urV<`VZ z)j(@an@MX72)*Y}${80}VgT{wPn-rqhNO_fIJl!ii>YPl@@9}Q9;qkzK* zWIrsYA+o^Fqmna4C7*5RJHV@wl3XfAHm^k`VGK-p--sG-o2KXMBm$R(7vC~KfpS;` zZLdCx9-z?f36|p}>=tMt*TDkX@#x{%(y;RNjUFP@TFfncUOja8?Wc$DVvn;!!k?*) z!~WWs!7L&BWX6s2llJgx;+xb=Y9fP(muI5*sUI!jlVxY|ssCd&U%v8*;n;_(b^fUS zov+>k8XP(PC3%3jt91*1+&>(hf}h#{Q~i46P~BP@;H^QpKl3$_g1~~^4)BsIohhffs`BhKw zVz0lK@fSM&tN4nig~;U^hvcb>;4O~>kTeHUO{3_7!TvF;95IR8zun%!n@-)H@4TZ2 zdtC@8<}>n7)vuo%L4&w%t^9(AaT5kw=!|kgyg2vOa=$%qsrKABC+%QX)3`NIKGw~P ze6;EN-SQ>(J2-b5#6@J})6!b)IQJd&FjCUe6aGliIY+o%#+P9wjB0~u54ylaQtL|g zw=Md^*$>ryk5$|!qJjx|bG4Go!GPcS$yX#mzM`Lz5mF;6y(S^e_HjF_@M;51&$&Zr4wK$V%fE^nalE#_#yz zJ|JPW_7AqjAf5Ua7`3R{KqcpB72n)hxdE80q;7}m&il<@SKX3|M_$H1x|pptQ7qVR zDJqno!#|1LR3S>aI$0mbnD5yNjPK=sSWuPL#cml@?6xRt)H;XQ5(P^*i&C90p0-C{ zq6~MU`OsiVjhEHXyez!<79=?--LDznuh5T~c1#W4AgJRhp*+i!X-(ONX4xGNJ0^lo z9aG#o_+abyJ-f>ZlUt$-ko1Us(>9o&sHP)|UyxVkqVF^<0X~?#+f(=gqs_N&&9PVS zA2=MX5&z%UiUsw2uw{nf`&p!1&GMN7UY=`k@@A#M7 zpH07~_~>qb1{jI?5P#Y0&z|6F-_M^N#7G~woWm{qv&Vk?PnSO%)%_8dIbReYnK#|v zXDjs2!pV!%urLBAOY7hc)WKBdKZ+7L=vUgEoz zvr)=29~FZKyGvQbY0QPUqYS>U^sl05a1p9m)JjHH<#t#!xZLRAuzlJKB4;s8=X7m| zEc8h_L6TXIUzRj-mXB^**1w|E_W;k43t&u*AWMwA(!!Yi&I3VODCzDm?5Y402@iXx z&p7rt^}mX5{y4cV=Uwq_H&BVWz)BBokJrvV_i3lSq;Ah`XU%zvF>4GxyfP>J3G4ga zc2@3p?Cb-aC1`bzYOQuV`vH1L4Zf?!I|r@svhb?pzoX~*HpPFyUWIx`^vVbK7Hr)p z0SKf*m7dWt?xUU;ym~IvaLealsxtTo*lx?dI%@1-O4H>(577IiO7D$aQ%`sqy=-yG z^s+>S(jZEj4~03{g3`oX?jp{f>wQj&u%rl;8&Zn)KdR&ifo`bn9mTgO`ZO5H{sph` z4d_tot~%VyM?UM1*Eeq|cx~zSyz{JPwwbpE;q}sIMNabnR`eKJEYQMvgnnSOX1^DY z&R=f1SkurwmvYRSgATlL@j}%cBxahhu$G#G< z4v0X2xjyR@o`Wb5!g zGtn*Nx?i{FCx zu>@K%Zqi+&e}6TYq34+LV6WQ2;98TWr&})oTKH#;w6#gP3m5>}#OBu)Qk(-G63FFq~uY~tj~`dN@<>I9Y@Y33_Cw4-1Q=F4~Q zokO4s8%}S8YqW|>&>vt5)e#n_4}0d#6+2Ll?d1Ru^tOdeC1Qu;KgF4x6AINvI{M)-m}4j_UZK{~wBf{{DtV{;73Nn?eV_FTXPZ z%vLo9@4Baie-V9u75_c<+@l!xkut8i%z`4hL~S$Kzn$2{ zSn~1KTqFmUwO;@sBW;?osZLw*2cjmIh5w8GyYkKi9-YH;?cb({jtPW?*Soy^Hf4VS zxg!@~g2AOBaH(R);m?rT(Q$jRpy;W}@1PE-9YfW1e=++LxAUG*I^g%t{_#bi!0cO% zb8!wP+3ay;t-9_vs`=nACy*z~Bl=6~{``NJsFtVruGR8%!6%*ZhID&=^3;x71NHIX z--$e>-%$LTfIPj9DHeI!$4{PyK0iTu`Y8w*=`r#Y*Yr$Wo|IiL{@s86&Hm)mYZAMS zs>LpZaaD+&we6;%&Vc?Psi6dJapdjFTj9Ov{r-*|>HW|yIm+qw{N)33^rDiZkp3Ox z3N!b3tK*DL%8`mkU*&AU2Dk4<`rpO560Dso+Vel5=oT1^kZBiSWwN zFo|}_(YhOm9Che+I5u7uUV5CR5^f2UqbFC395w0tCm=@-4(*4Is_a_Ro)eU#b+9dC zBxB@g@U?p7Na0YMzQ1zb4Gx`AFAnwWQ6+BuNGp|IRrFT&M;yxV7A0p5=bXmXn3)EN z90}4$q$CL7+p6ggkPG-n3Wv;m*H*WX63R=K#rmehQDF9hs%=6Vl6#jI5gzmQuIp2* z6QKd!zG>Gj*I6_bDA(^kDstVb@1KtDd0BXgUVw!1dTH}soYboI(i_*?R2RaBqPm^h z*GX>_|3CkV;!ov$E)Q|sb<#Yj!#F3fPI@;6?{eGhm$xu+ZnLH*Xq_}lPB`mW<#p08 z-{i!par=Vl4!)LNR^tnh({(V;W>cp%mmo1bD8O(sO0MuJo7bQ6{8VVdjIu;as_loJ zjiOnVNnYG&6L3{+bTcM$q@>}(SDs}Zz<=NO+b^fFOb>3w;N5!gED|irJ|s0gL3&`36Fz#d*9|T`=$_{2LGi^g^i;ywH=ee{8S$p%=CM^vs9S=25R zI~+fX)2yO;R?;)5;@d2FBE%{3b@bDo&?oJ#P<{a zTcE$jyy=n$yn1wg#OP5-(-Tw|(MJ9_dQ`59cA9803;vhrVxyCeQ*~L`D&JDW7-RDW7D%4&oU_Qu@u`;)7b% z!G~X^n)LmZ@;DK>>iNn<HCA_*5GLTtI}HSa(mFdz|qj3{pHmkM?)N}FOC+_yAO`;@F8X}9QLf_ zMLA6yZKV97&OfRCE9KVfk5uDmGT^?6$a_a(qVm2iCdDo9Uq=#1`6I*6sBu)uyRI)A zB7b~v^p`(($@}{yx4hfjmn%i}}nVWdOLO4}dRxW~lN#Me01xr}K`_PwYP!nqjwzF-_(cT5~D zKJ71$6OpSd$O0cHV4qjr?Uk#y!$z)JH9b{w1sn}=_yIV&;7XTVUGtt>t}eu{+yGe;Td0fC}d#&FckSe~{7u7B_-8&tvWKToFaTMIA>}^~*fi9Jjn# z(kmXDXy^MOYvsL2d*OkEFSA7H14R2nkEn6@$r)&5T%z)$UnTds{s$&k`hl;!>)=rBjrM`voWkSeirkq8x@#WC_Q&;H){O||N6O7n+( ztS!AQB?I(!u3K+;;BtW8?sR+2dONJ+o+|xW!+M(t>KA(3iSd{1L|JcRmj>%?PRC1r zdaKWuQhNI>t+)O2s`YlKqNBGdpZJYAXKGpww+8whZ{8|;+w2p+$^DMrPFIAKn!X{e z)vmYmZlfQp+xO91vwyas`$7_|bvM%lg@l44r?41jsso>*ej}A!XtfAHDRkr-}KZla2<8au%Vb z)%LXcfH4(N>}k8BfK&^)Ed94i|HPht3Ar4v{?S(Rs?DCByK18LG_h*!`@zZP0KKi% zo<4U|&3fCW`WF=Nz5jwA1{sl1t7N zvBk8@dS8AZ0 zsC9mXwhIwG;u*^2$LnNSg0uDLOvLFAmFZ(Y7G8=j6i{<_bNL+P(-0GtWuY5C#MTki z6&&6`Zz@y3jB*7zTXwM25fSQPPemS3QkvJhS)(>l(V^e8$*J)m4ttmS<}^NzH!(yu zQTzPA&7f@YL)^abZ%k5rxbD(_f?0SpH;zT;j+D4fX1WT46QIaG23aN6G33)~Tqe)p zs?%2cEiWVes1tK)wZY5bLxh(I*kxM`g7(9~00tSFgI$ja=RPw!v(vOsX5q5%QhY<6 ze80KThQ90YjnsOso*RiQax}cCQxPToEP@cS4yYEDa`mEp{4do(SE*UJo0ld3mvu77 zety~bw0S-_4}8J~jYr6Jb$a69f&0ru$U!Twnx%XmM;$3I=ZpEpFIW3xrIso* z_@Lq&eM*kU#W#s7zXu_33YQmp7`Sq_VVs4DBJ<)Dj9d%2D#yc70w4x_96Q$aSnmza zJ_EWi?sEynatIrXmSv4p*54wU9#ijN^vI;XYh>6cWXnajFzpT#Gjh>I?R*ugx&SCBZ6}(}{NuKGcUh z@1b4cT`G5fS+6;dfw(iG_Kyu#{C-^ADIGc~+)23lo@2b< zY^$N~A`To9lQ@hpfoCP)oJh|jOVpXaIeef0cgqFL{$%X04d^rRL{HFyT$cU|HFeh2 zcQklWEJMTU>5bD4y8!sRxRJ=3cjYmz#*^N!er?vorRJ?OlV^Wg9XE!$EZ|qxS&{d5*76w)XKGk`R zt@3`6HLv%Q#x{A+Cs5zj*pBz}`tFnV=Jnp!*ul?``c48`PgwM0abrJH3o!!K0KXng z>92=~bNURgzDpXvDfb=%lp!i-itqSFF0NN_E-{ZHSKfW)TiipHd{oY1@>{Ry zz-bwk=Ok^CcCS}(PI=W9-`xP>6`mUWtPhuublOSi@lsAmi)lB=ABZyKKK>v z4`z-OUK+P%EPt@ww66uM%r`%O&^oF{fAEMa)}}wW6Y@+3_0=AYQ2%erxX7VRfj`&= zu8!vq9&x&30KEQSNYk@s{J{Y&vo3!y27Ri*9~{7p*6$BqoeS~@qj%LIx1HaqS#F2# z)a}dPd!?&^HnCpMGHs$t2yGm~JcTBn5S{VFza(n%c1LQWT=`px({u0Nx$IJ0s zXcgdSq}z_h9AX8WXN0dj7&(Hacrxi}+aY|}36a(A^YkMd)akn?o@ zzMiw`_fQ5{bP=*G-=)+kuRD)7@LAO97%{$4emKmCMZZA{QOx837$dRIn0@h|#pIfk zf=IP}!5faB7S`ja%fB8thT>bJfBo7eYtX;G|L;(PmI7UiY z4e+l&KGhM^3jccGHbqAiG#FnPZ^bA34*o(;8OJoNXjO8W&wmd*^*Mj(#b-EYp%&d9 z?Jh41ukG=Ih?lG-f+qfc^>r7CUmex=8(Pf$@T-T>jN@0!V`ycmPx;SnKyu?(({G-) z`fTx;n_9`3tHftEel`7Np2t9Mw-ayRRMYqEyGuNAI=m_JQsoDVkaEiNAkltEoM-+5 z`GNZyj}_x) zEB;Eq8QhnvHb3@dG&U7}>}5_n9lus`VsLCcKQ>wMd*fdQ`mrr-V#5G_=3M3p!Q&wEYzv0*)~3Hh<99|$jN@nZ*X zR(z{G2aYjobzZZ8hHLT%F1=uF`U6KHb5r5RW`Cu|HHCT2I0iqSKXB=f9H903u}zwu zG5lCnuVF!I0hYrZ$6*e|A3!?uV0m&Wd;z30=Oevy_-^y`wmzIH-@7OSKLAf8mw%)y zjzI;cfJD4$BH|76N0n*Qwqw~!*+&58Djy-vH%0tYf^S$!6_d>$l1hymoTQu3WNncQ?GhS;ayaZt1f>pb;1Pvy?1`P2K~L? z|D}vb;_oGHQ1j)3B20hLeP_;?3~D*U~n>lGb-`P8!@M^0Sw z2Zckq+==w}{PU@AJns1Et-4*e-$uQm-xqBk!|%JfNBllZ-*5EB!o9p7p@-Su+R#0R zH0k=T;kW>lf)=$#69QxsO%Oz>U?h(>4&ngG7?mIaE=UEY$thRGVNi!Bw-JGWHnNEJ zN4&vzsN(IyTGcd+GS&G@#kc)I6E6!dq3^6mJMq@>OK-;q0%cDN)JjD^@*vj5It`oG z+D6y}1_CzmCc-yq(uXwcVy0miYj?7Qc~;n{U^6O%z&A~NL)gTyuxCzS(}}L=Ud9QV zOv^S&n6+yL?q$~NUN(bPd*%z9fM8jP<3Q|9@tJ;nzZx&Tl56a`@)NG3st4z3{p!k( z{Z;*W+K*RHjemQ$(@y^{)Oaa>oYz3S*X#Ce6~8xf8|dFQEu9qJhg|(}LM*&U=fwTn zfs>{V@1K3lh4;@t7J&C;X65?XEzc>uk6o+y?t_cLdD`}qg_pJXx0wOmKADBf!b|bZ z&%e!};hOy0-<-WR{o6BH2`e6>1!H#S7`5P<(654?ldy8jKfyj@*!uScw-RdR#ts zv7UIL86zDdUU<3H5z~rzq4RRZ-zfNQe0#iA=dgjes{C;1bnw(CKRj~3_?1n%J&uc) zg_p=3;)Dcm4XV57I$h#~lJ-jtE$065^1~5Ue&| z=MQ%P+v|sCFIM!7;fGJ6em1*Yk>;wGXwhN}{2Qx&Hj5c0?&a&MpFQEXLG=;_AL_%M zyV0(~z5a{5IAYqZ!W~^d+g9=WadD@qYf`uqa`gwenFQ_(tWYyig*z&WDT-fKW8MC< zzj5Kt^S|-p&Y1PHx2#sU6T49Ho%|*=MD$PI&e_ozhy2c%QaZ*=I@ZK>kokIZXW^fGr4m-xNe#9eq)_eOYcw+kW^E>qfgc{}Eup8(MESg+F?iyTym8yql+ z)w>&pAq{GGL+f1*Iy0p_64zcT_vLU7dAa<_3HYU3=)wE?x1vY>=TE+TyTNsXH?{J1P5+Us8SofG#<(>)4ms_a7@e(Bw} zx$MI|w|VWun0378J*4bISdYsGM}z&+)K5M5HC7$(;7=9bYOH@i!!_l*EVm<+j*85xE^e!!^n6OUJEExxEoNA(QpeavRm- znnJlPoHxGQzO*nvZadFad^Y(A^Ea@LH+});aO&!K!@7TWo_2fU`dE2dZyoQfUlDhM z^R(9al)Ca7MtynOCvOsy>#5^iJ>vK&iE|Vm>+)VIH3+=yiA9hk# znJimK|2P6n@^6p`s2J? zctKMk^Ap_{-EoP6j;Zk5Kfcc8w@>@!1pM|tAqm8|ulY>H_X+v!$;&)=G?w39JVUon zX5q5%Qhf8vCl8?E+WepIu2ui%uCg^T{*NBlRQf-V(DD5Cm*zNz#p}0sE?0aW!*BQ2 zEyw#Yhf`A5(R(fGI>NgDn(I0&r~#BG%n_#u@TzWkP-{nxbsg5v*h<+ave**WuH$@D zPu=p(10Mf~;evhR9gZC^xKtnBy{#HY-E#J{8u3ooEe}-ueq6i@T_HMJFWxn|`U4AG zdOK0PYrA~v@NVO4TzL1XYXb1juWtFTLkjO&f1>zamw%hQasvMCzDKS>|8{c>$K&7j z{8;0x##dJyTaSO6gY=By-+n9Mz)*#M8`5+b`E=2t^4M%xvw8Cer}7t-_U99ccot&y5%fgQ^#DmxC}Ka6*~;@ zA}OY6d(70D9_}`?dDfSjRjB2?u({ z42;%Y$9&9{9(TGKWZJF2_LeX=<8$UzHBR5WIE2Ue)joOg0Zd3aFW!VnuQM;6{JG;? zlg^RmDa(t0e1-9E>GSY%<=4l^i?4F-o1DEl!)d4W6vb!CJ83cP2Km?Vir*VO39OrL zAE4yGsjF{aVCLj9edLpc7wMe1f1SH#>g>(c{VscRZGV8h@vECY8Oa>_*Tto3TodxI z2d@=g8ay1!zfPI=;z5LL%>0j@EQ`wqn|9bc&#kVQ+uan^Fc>eYB zeH_CUhxAF!ft=%HX?kk*uT$4y4yVMw-uW`vgTWsue$?z=cR~$({Od5(luW46zwU&< zOs#)C|I%vzdjA_8|2o}XhrZ-~S+l;hn)Ykbm-zKH>dV4I)~3E}c|(=H^qe^5`qBZe zj;AjRzZ9S^#S;`g#@?8}fpydA8;ridgiQWijSk(vJ0Cy6y6M|58ap391mSS&Mt%AC z{Vww81G#4JjZBVSpBg$|@v*LWrF7#2;+3BsvsvSF4hyT^kAfv z)gp7hrK)|FH+;bn(~5YdS<_+S2)LZ8&UvhSeDWp_-dMi*_>)qMQ;Nrx$BCwuUjyu6 zoYI440^^kZ4wN`$NZ)Vhvow9<<>QkA|J8NWQJAGk)lny*r;HA;URz5Yb?YF1UPm4E z%nLjL#4yHfZ--2i){E4!imy?8Z+L^Zs@{G3a@^pPj}L)0j1*Kpz5oIzo{!)BLMLR9 ze0;0P$0v?bbkWZzU2fb%85Ez>l9GC^i}8;LHX~-O;I!m^OLuMPyNt52a`tq%(Hj8= zH^W&1TjMN&M#gw09xFSqcQ4lYq(irm?swFV(gA%c<)AvecF_C%wT|k%fgHFyGU;6ejHz_MIcR_3LUp5 zfuSA{sHHpG_D~xoJ{NiqXWH_?J)nd;Xh9+#?Soyi_*H9ic}hM>HvVWg?~r9p|8_XnA&o5y$LR zNwJ}x#r0#6&e5_Zvh;0yM*jDEiXPv*M_T4r)t|fyBB?sVw?Ul(_V>^Dse_B1x?O{b z7H*%GkS0ncHW9RM=Sh$bJ|*=1Cf+yqgHH(qRo{lt$a9x6J;E!sFCL=C<4_kc9k$To z8%*3nOdP-;Z=jcQ$}}d9lg3k~9|zCk_OC7shep~periU6;E=t?m5h6iQGD{lQyEv^ z+#b<`9Bu)hh9b9P`XufGh8~Oukj(~$&Ig7b+z2zh>%86<@iYLS;xLM1(?CX`;}L?6 zJd*_ziF4XcF=w(2*}v`~XXk`MF-^w?-$g&TEWFsi3lEnqhO{Jc7!OVkJ|40~Y0{7l zA=S?>90Ym#9BPdQMZs(?BkEHPh}#%~KvThfcYlva2|R6ig)`r&qZNO8;vfi@g;xb# z4c&jhmuAj{B0?@D8Vn1??+~f5@V*kKQDor7Y0&7wX&$_gwd41eM#F}VJ<%5~3on@; zKF4?U+*liWQO_xjqVuq5OL3P?L)q^t`n$j|UKU<*U+*hmSyZESM58tDv+QsMT8A&E zhG}Nwu7m=7nwPG}n$`K~>#}iNQ-jk-{?_1hSkuq;IfQX>dhkxd3-o6aI6XSs!Rgd@ z6#r(pa9a3>nJuELT5!4yK83?<4K z1iYCDPHzha($mp!Ll)W(BhBK*={xXwNh;Q=`0I<)iD|U=UYu_IO)yR$b+)6oIqfI< z;q(BT2*T-^GWVf=eSd8@9T%aS98Rxu9&ozkgVVj20;fY`_`M>JeRBuK@_UyfNJCx>o@Uj%54JZTJT`4Fz$$Cm19gdqhLRHSIPKksUwtpo?VHbP_h63joBxb0aQeP z^~Ej#b-TAqrr5vT@eYHVS?w3rjGOsks{7<{bM^l?xY^?4mm1uR-BTNGMlqU5Ksz3J zas1mR2rp)3;ZuZ|BjGH^1>EPyoZr2Ytb8I3AH{S&5@NZl7{k7p{oA7FKxcS7nz|HU{JR8CR zC?WeGB#2U(!xW#!@NfG){%vstk}zfd?eCXs|2C=VsL{VY0dV8ETpHPkQ{kTbCg|U8 z>J=&RZ}+~yneU+%#h*(5R6oUU)-Y~zzLZgPH(r5gVRIbQvCDtZ?ovC7XP*#qiG9h#~-KLsbuxwbjyRhaSZ>qS<^8- zP7gxQT%`Ex@83?Z#_2>l7^lztv7@)8L$usOW_Ve6 ziQFT}*U2V=aC$aK2Tl*``)kALhzQ-}aQd@n0jHxrIDHecD=ACUGX_pijenbaXlnf1 zk-dHW+t!1%KDqL#oEMKCq%m2O@^5<{F3)fs{_QI_IsWa?Hx<2;@^9Zj7RSMPuYa4= z?ekg8#5kr0iF2|}nE)G1zW#oE378-3d<1GK_IEwxmp+NJ|2IdDX&dC2c0i8l^9xoU z{zc@OzT!NLzIWjeGEK-fEthOla^-@?1kz7V$_eQwIR+SMCnjMB`Dg$<$8Pu_HSP`1 zM!&c$yhMM>`-!$>T#zFZqN2? z)zvQZQ!5vOv=_QwLu((dv-E&u@9I79y!)pR)G(o&w70~8usS~+)$OcM%{cTu@brI~ z+n(#r*hKBSY0zAY9rK;pn5VWa$1M;HOkfr&q$MV-R|}YhikQ^`X36-YSQh5izWc_K zCvX4pxxh5ByB*D%e~&2wE&S2=6DkRFkRK=Cdgms|x9#{e2H5L_x$hkBeQxT%LES)} zFV@iab+8uygf#j>aeq1OG3ihY>@@S|%3&f|=2P(RI zXIJ%K&X=e0Z-M#==Kv+pRqeR7u~oupX5|VV-Q?oPc=2Zfa!|0pdV`~%5l!zZ zDhw_QFX8jb>#-Ij@TS_ox%xWe z-y{!E{9c!I<3)SJzb^e(>n#7ow_sVObu~51_%~c%;W`VFV6x7V$6v0qAmc6TEL>mV zItx`hWA7h#{F>ZC)$jUYbcV~qi+pp*SwlCIB95le7f6n#^)!~UphG!7dA%M{FzXRa zAk!_yZoINEdkvd z5#E46=}Xpe_-uBO(N1kQyIr|O8r#0?R#h#oRf9g2! zQKyF~4rZM^qQ~K0C)avx_}b8&=3E=z){`&HVGw49J(xWnUaNfJ1p^LVx6V_1pOioK zGvs3&T=M!;rKD=VW`8RCJE-ZJ_ov!4UE}#vvELIls{E+U6uHx6E{Hga(bLl5c-x~L)4!FYjQ>8hI{+j)% zp)574K7Z={9UXtFNB3K|KV>~#qd)aojCDyWs{5Immgv{?x5IRQprkM6yU5)K1t(`)lRT;!o{~&r4E+UsLq?`%{s!KeZ9O zK>AbpKSCYlT-&@Heb&3Yh}t*$-#Po0C5}JUqTBWHr$UiuFjAT%lwcs*v1H7iiY^=b};_dYJ8e){X0oj~OTD@t5_8jE@;7BZ81PnfjTv zciP^;^W0uqU$lZ+rXS>oGHBXA?@xVYl7&^B1-k>(4+pe^c(LrCUy6~?pUoDi`8s9< z$ts}?npI&Nh*l3HEHd~h;S-{u%^Hy`3pJeoBZWVqj^{|+DzG50Ge8AZl)F$0T;(zG zy$GoK=174eE2#4J#-IIYRQXxyuc&crcPYeiGoC^sT`6mKgCRPOZqfZz;t~6a=E#NRkq0=zv*iE4!kAt7Xmm7X=yS~rf98(ARUPFJ zbOyY%O#B^n$KOnrMRnf7GI;+k3e|D*3FT_4lYONw#0j*3;dquP0K0ka~oEy#usE*_<4}o`;n{auVDYS)v*(qJym;DrV`@yfcsi#ar2_){$MMY_<#m=vK@_CHgvVYhH zs84#KJ`Nh~cYnk&gxdB~^pAn_-u30?7sw9?|NN<_pFI93QZXkKD(tK1nC$v;0pv}n ze)7(3J)$J3oaf4Um1a#>(E76VBBj{7zTC9#rlF|5um1JrLA0z!Qpfu8{V8fP_?p^B z@pV$`%d1ax*%Rn&!kvF*0p(QZU$;Hq*p;TZqJLbwa=f-Hxxa8iOuSH=UHQXj9J|uF zyXtQ}7k-(#cI&0u?1}~ITLaqh*p>T%jAB=^1eyBm%H?Q-pqv%rCTLgg-pbgOw!PK3 z{p?EUWm0$e4Ew>u9o%agVSo1i zwlfb&-JYNQ$>7#N`|}Zo06xd{{k7SjcH!AX?9W@@q5av&Q{5!?XX$Zbe~Q}w;vDg{ znf?pERQCC83)yz|$w04lA^YS#_>Nz{HSxF{%q?_H$U za}E_AccR%)Skt$HA8=WCkv4A)j537DxV#r-cx+g>P-zAEN(bWC(B7KDkgQ`IZyD-GwhX7m?Q} zkMHW`=%Rh|p)!v#-44gZ%fgHAaZ9Ngw*<=J(k(;|3qF37=8t9kpsyJI6#5l^ge~4h z1}qJ6VbCT&q)uui`ALuPkudwcHWTOKlU#f*A}=F%doSqySF-ozWY=5aJ<^45?a8ga z>bZzpkqg7B+_p69fzBh3rH5Ix_x;?b)G9gzG7*aE@o)@$)hpMTJrrK7F}V)^b>eb; z=H`yQjBEO8lWXhssh8`|ecw;6`?cR-WSZx3i98w{c$AZknao|o9feY&moI`Bkg*7i z9qR}RnAg1h#39TxC3SmjgO`PuvH)k(t>$dg-b!*Xu7+j}ctH+;*KA&`yyW{;mj1UIQkAevnQLr!ot~jxoO18_B zhX_C{O;K!my)|smhjb`lPB@ri&O^hai`a6+{=$2L8-vDA()1brZm2)I$;1P*RUA~X z{;o+<$qk&AIqQKI=(+vpgJx7vQBpYPmIE|RB#atd*~QE`hpPYzMhi@i-v20(%w`}+g#kaiL(d-#+n8U@CmTgMeo^XuJs4Yn~X@7wXASRiM z_5(Dm3;d*fHLSPri!~N{uw#7R6EnaHi!Q5 zy7K@ut=cZ)8zc{;WB||G#SzIHp1CKvT51-qlA&s^7tf9v>G0YEc5navyPR3v(IX7< z-XV4pzmjWgJF(lYfp#Kg?8GLGZaYz1yU*?t*zSO7_uiQkZ}*Jgc85&6-}SVc*hS5k zk-2*9TJdwLoi%3H^8c8)UAu8($F8+#`f9UlCEHIfDN*(NYu`kY30hF$ucdcZeDlE@ z<=^_*walA7cI};ov}^6UJ%b+>1d{Kex~1@2W7xHkjl{0SE9f!zyJ4?v*OHhNXlp%o zZMI~JLOr^_AlzHf`yNcp4Eu+8pcwtI)(ZMuet_Wf{vg!E0?T#}!sk*aSYc{dxNEd% zFa4Ke3}{=8y)%4dK8+Xfut0mey}N1s{Juh#UStWG!~llPMjVylD8Ge9B6Y?6x&-EZ<=-Hs6KKP5L8`KK}#g|Zy?;cMjz zte)P;I082oVsGPjFj?=+dO*J7fEIpZhR*Blr078>a#{Gl&{M8c-DqU{jn5|^!ZbK# z+;8Z93_phLS|0(~#v~%!tVzntuJJNmgzm%8h-1G%S1AL!xQ!gPTT0zZ_Kiy%?|?BV z=Paq|GxJ9J_};}L6_>$jk)SY_|H2VsEAloB2}vl(sLMOpL5s5DiyN7Pjd;zd{gcIx z;7A~REIzCJ8T&PK(Es6uZc%OfdTDf~@?-jUte#)iB%8S9Fc9t(y3O*N*L=TbBHTvW z$bWJ6ur*Qkd-tv)$CQNcvxCDeCe+C-*#8~=ANIZlKCY_Td*soMyk^R)1M)c12oV&5 za3O%oKpRP=g#axE3L4}U9%5)H4U}SNs7)w^AP)n2HGq$RUJW7`h+=p)z*Qq$y#rox zfUC}-h=V8&2=x2^*M6LRX3k6|NqKzV?>oO=)0s18@4fcgYyJ1yYpuPHYCkgG8jD?m z=9`UOCC8f&b^v^6Zj8)Fwx2o}a{$`JTQEbwJ{iUilEI@(da$s)1TWwO8DpdctLX>* z-Sd`b%^+pC4P&kBk%1aT55s$uD>I)s`I&=akF3IvAkOOg7jd4-hZ1WJ0>dF<$kjd) zx!T8VhkWgwg)h!oDr4!FNpD_xV+Zxxe@L(WM<{emsT{?+KZ87O`T%fB0Ag1vWqZ&+ zI$jc+EX-1LSM(2G37U=VX7=TKGETryjBRoRgz1%aR>vJB%adLRW%O`m!{Y+5^-7~n z*6+W#u)agLU$U>h+@|_Fi}oDdc>;$70z^iIVvK@A#-1ZK@`8Mh5eFxC?#Wgi#veSi zo8lYmr>;bdw>rmq2?us@+-p9@Xq-6X&o{AlK$C9I^#{K%EmgqIq}d0_^#uONl+gzQ;&l)3h&6%OmChE+q_8O~SXLniNFSl9tqQ zxs)51^N4i*pEeHpMFrokfP+XcP$e#RF}`E}r>E$N@`HlEomyUkI9%`F!IC0B=speB z4?3XhGxMkPFD>I#7(>yr{-;+!GUH&nypdZ|-Wi{zK^(4Acr+0|=>N`xAGA}$mS%^r z=bYnZ9h}wer!XdzX>)O1MVi2mUcs?8CD+;he;9s*)>Zxo=16^gy9Ro~x;*^jctctW zSrjeHkLNcMel+Xyh8CxMEcL3W6#S$*0p`22?Ksrxer%!#!YNm1Mme-g2^c{z-jhh@`y# zR^j$?DlbivQU6-dHQa0Gn?_CF=m*ghE)V~Nugtzj5F9k7nFatFLGSYTJZyDAJ*h@y zzc9RIEwhmAP0s)J(HyBcu~_FWN;SOz z)pK&A8GNKSgYoPET~Bepx}Jv_^{a(ViH^N6-l z^TUs+D(X;0<3WE|zRux{>{h7FfMO+Wam|>dvKW>~atAF24>ZL6ePjPx-<#V>^*@F7 zjLxy?^7{W;8U0U-{`c$pLU@Myz`sHkMa%2|TdxxjTXcCti-)orKVqrZi}nA|K>tm- zDE&vd^7^mZ&3!=eVRHIk0}@65Pl?k1+`r6-Oho@d*KmKJ|C+vH`6{Ej6Vre2J-4Ik ze@Xpzy_8t_3G}i|dsRTi;}KB7fhmTHi;tvUHkYBN3{HHXA{K=c9dAq&Cw6@Eb$3IB ze>kA)jNZ{56o1O$L^H-1GFBcZR;Ok_^`B>eu5tY=bR$2!EGAY_3_Yz%?+<$8_4U2RkD;3redlMho?AwR?Rb;p^9o2V&~Lg8{HEr4Pk-QJ19(g@ z5ldB#i}rcyE-z31a*%+XD@PJn>9}4jCxvnH77mnQBfG4hHQchjT4q5m57Xsrc`J{L zmw<`(?6+oAjP?2=S+9?BZGagu-njlz+3O|7?bt47fHpMH$QOn5x9>P z1s7CLnaJkL=(V$iPJ<5rK)9~VX|enb^i|+vf$NUNWYEZ4t9=X8gdTevFWATJ zqeHg1?oX;A#Vj)1s@bQ_Jwm&G$vi?Od!eq%{^V!2E9>_iGXB{Iww$=%_siw$&6;}8 z4%M5}cAZN%=O!bkM}*>~yF2yo1{qSajZ!_@6;oA#4PP`vqcG@ZGN8a?~?9JVNBrOWcl*(-?Ob;}=;Df&s~ep9qxz9dp&#$VA4jgflA3rw_IBDS8jqyu$JU{K z^lE$2?FU`d(f#;kGT>8GKU&z2W5WG-Z05xKafZ`QQ9n|qAD@o9!;7q)E~x=A0*21XAE5V`5^gobC^H3Zy(}MM0-3VKf1k7mTymR zUfP?nLrAU;4!5T}R(T%$?N&j*ipHbP@a^7dF5l|4-Rkmfdc0geE_CXTlB*_k;l9Jd z{aCzRh;LQ(V=JefqJGqye*A4yw;yfV-VOC5S*{;H*fQW#R6qLJk88sHxP4ouj1RNB4PR1 z+%-53S$nJD;bT@I{5bSTowC)8;9PM}3kFj1yRvX`6gFx<8qM0=iIdsfSSPwkXAaHl zEIufIvQR>+8+YUwgm6wF?O4f}c;!afM8VHtHiXVcz2z{j&kR2t`H=W$V`vB<6HS|u zB+28nEv#uERxB-y#?nWfV&VskZ3PL#jSzE2x5y9EFXP8y zT#FavT;#EM^`1I0Y++$zkot=G@OQ*wFw ze@Biv)<%vJtGe(2`A6nuljx) z*#T80Q!@nc80(6YK7ZNcfReQh@jQM&{nIEa7>vZqzoE1`MJ;k3s|w#*%j4U#hD}lU zw)?@A@lDlRjBmcF(g>(#xQCwjPaXt(y9Fb`4q{Y_aD>nBGB|IYWgJ1nEPOQbIW8Wy zY#r9^GWNif@Nj+oc(}8;1g8t{09|K}OII`=_HGmA*`)E%Lni~xoH8B`g{rF>4_gkb z0uQ-ehj`e#tys-E$0lDE54#@fuwZxt%Q`j^p{!S-+(H<@3-mk2@6{+b&;cAFTab-3 zr{)@dQU{ndf$zjNW$`KH!s|>}okhCa6hBc=%s#RBMvTH)s2dAIT?YvCPdEVQ(p11X zwIAm{6(4c~+l_~HV(*pU9NgiVP|*fzx{VhYd(%TRyuk88YI`)rt-m}L@hP$9dgkMf zM7X8o4tAe4LdXPV7A-~uz3aDWGc zn8y8_DwRZ-n1-7B&gxXtWJYcy%7G_!yaN;9`0HEA z3sd98gdJ5Ba5@E%8ACx|8swa2{~lPP6UD_Y;1(abVnbiAb#K z#0^x?$4d2`IQDK{!F2nRK+eY9%tr} z^gPw|ELJwJAsyhWcm@n@F=Kr(Z3dD)pvT$Mv8zGe9P&Pa1qfE=(C&FKd4ety3^365 za(FYmuQ_icTws57TyFtI{zBPs_S(kn=eeVe4T6i@(dKRky-RRvZKm1gv-<`s8j*so zhepWr{uI#;Zw-Uy>x7>RAHZ5)@<kiR488CUPOUfcIXWhwlRAR+6#ot_P z7YbA8{1aDyiuD!i&wf;AO|DUV37cG(*R%q!Tg3KQn4H^lT}_*;I@P+AJnC$baa2CZ zUS*eo)&2Z!KoA&1pzv7DdW7ONb82oUpVSO&roDT3OJO5@hO9wbXqVTVCCw6+QTEq- zP>i%r*GS{&3}?bd8vEz}7(2bj@y|)V^LfC%Z1b)nmr$r9d8l*+-<(~S8eH|z7%xI; zUr9AQFMey5a;hvsL&vB(&$alSJ_rKFfJ5ZxYT#-u@+K%2q=c>vT-|i@S0sb zB`gt$f}x3Sc;oQhX+T)=^oQBN!*P@S!rz4(aC(e-fhhpjhb#hWF@qCnYgx!Y>0YH5 z1{a*TOrCL>^81)RhIksWOW73_@JZo6Q~e;sx&GaVPdtwR4jze+h=a$>?}iQ!yyHbZ z%CU&E3l5Yd(eJR@5j4%Wxy?$Yy56YAIVPrX0uZW*uckE?>7E>8f1eTFez zhJ{x8QfMrp+1}m*EBv;xhA5pPG*@(5e=U;+h3DH*w4qOqU%-nhns% z>W8s07{)fx;(w)v!}u14@t*gE zT^k!7FU8t8(2G7Lf`l?46krF({1fzstcLV|18MsDaDS{*70f|g8q!)n7PyI@P?Qng z7ZkhE=m%%OV#XeXK8VG9S|!~OR?#U3!Z;1qjiZH5E20}u?k3Y-S;${6Ir(%YM{Dju4Eqe*TPRJiZH=ARZ?h0(7SPn>4$}!u6w_?l}FGt{y zHFD(%RfNjYdGP%Tr;JgVSam0Q1FTYKPbNQ1+b?3-ONWq5+MT$A&3fPfv}LJtgdXPU+#!;t|s!PmD<i;E+a%pAJ*M{=$;H1h!N>m=U=pJ4$msOiLqdVc7pJ=n_; z=}XGosgfcG2q64vkcOjLBhb>tZI8D{@gd0%V`UfSm)9^N#b?B`h}fUDYWobNaBa?2 z-*7IxHfPWL6I1lhnz5uf^U`+2;&U;Et_?9ZxStG;wjqwIg~l~43cO1e+OeoxA6v79)1cpU18)gM5z zB-)%BXFa^lca{G_(`D(CFl*Re+80cNUUcJ8s~211p1WM@R4&SSl>3vk+?$nJ zzj0p<&<}YT<+W%j*DOM&G-S-E0+({oDRFg_U&`HVgq}+|3O!xaXY{V(0W!Ee`K$Xc zW8~t@{5ptoJ^5(-d8;sVygd1fauI%o0n`J(LOsUY^B@1V@NpF#inu)aOWuh6i~7y` zEXVT$DSv|T11Xl#V+WIXl*S&S4<;i-e#9+AAH;(|4|t?^Cghtg_5&Rwo6YD4dKy}b z$)rh-?$XbhX?3WG3^X!kMpZe-r$R*&c;!Eitz3v(uF}9!#J_r%e?P?YAT!9fxe7O2 zA?&3W1}7r`l`lZ94NzG5L5&mU8s1W(r#i;K4p>-}RT0Hr2(E;G@?^C2vz6m-2YdFi zZ0;g|F9vp1;;$hC0tJEJV52PjJ%?04`Ev(~&_W=gSFUdz^J7Duzsao}hIFj^0FaK$ zlfNRzz;EbDk$-G8en*#VyaGO_z&ECYXcvTdEwW5kW`rz@l7qz%Xv#7~z5<^ePf81@ z@Oxxa7#(3-L3v$1FN%_5<4q0A@nk6w9#01a+NdN*`u~(|SRDCIe03=*)+}e_VKszC zK1>nt1X9f@zZ&@ys?HZGf^p>M51AiNtXZLmif5!o<^7<~ccEGLah~N8 zviI=PdL)1E(#`am18X1JQ^7a2KAsH~=jF*?JCzvut{Ro~@yj%r!}>ZFKTPC`Yb(f>tgSrgY_NjSYb)ff860rrK81yW%`-H9 z+9s*e@zbWL0)am(qMo?KzZ^TY#7}#W82j2!+j&U!e%js!(L%t90f5BH$3VjRS%yze zf53+Dx}(HT`)ib*Q!>g>Hc27lyWJ+d6O4$)2 zqr9K?6)-|(b9vsTY=!)^f8{fQ!z;1sm$+f9noN2kEKq*hjid0>k)zvGgGsy4>sAfA zzNIKXZJBx_{IpH8MJ6bgRrqNSC}zMH9C|XH!T>QDPtvB5Vm{=i?|6k6c}J{c+SU2E2GzUx70< zRK?~liFp7#mq|q=K8!+KA4Jdxt_3*s2h7W4afX_&C%!1ZdPF_26M}l?lVsH6eX6LQ zNyMExF_`FZkaPJ{+%PyY7K5##y$lh-CoFi4Aeo#?HR!Lh4iK21BLqsalI>_>S4Gwh_O5iqK3N5F(GG)eVj z*=kgdYHdhhUzr>RMT$dfNmE-07>XV6pI~ikR}%C**8b6=?>nYf&+qYS zD0<>hMqQr%Kky$-)L%c?=r&R8ufJ}i%Kmz~zc6dt%kkF_h&^%?G!Q+>bkAio^w($M zua|R$&HHKz(Z(+Zh?C3H|D$Mrj72Btw~z9Nram22Pi;lNeTlyl^t43QlXmJ!W5B}x zf3uI@^b3B@EV^jnyH21Y@EOwoUyHHMi^r0#{_AS$@E!1)=I46#xsjjK>T?r6H{$c$ zp37^R_&@4s#{YvrYqhRdIm`H*;xmjdaG}o6+)GQxKqtkzo1Q8BlBBlu(oNFG+x^Cs zF`$31k+yCOJn)LDR2~EO$Z#Pe#X3U64T0moIz+%#*G?SDaLCP7uCF6u~$u=2%mV8#R zRMojAu|ED}Jns!2NBkFJFO=8sMAy-@%TaIY7#nY@^%t#{@s95TT5x&tm*Xe#CddTF zn`dD6{Gsd5$YouRTvl%7#hCZvKRf0F_yUXstS!QJL^aQ-2-GDtYOV={V9k&9!3_+m zaK0%k2;8oUVSalAf%N-de~p5$9)hqhOp;@d5MyCA1HU#|xp?u;NOW7gP*_xyk|) z0GeGf2;nF$Rm6YspGI+4VM48>xFK2yZ5t3nL~&0cDNv`(v7$~;6Unfx!xV`4S2xuv z9g80bs&RSpSH^{YsXAFcJ2?7YihsRoSiC1D2(Z}3ao@4{7bwuHCK>d9{(}^~>+vt4 zqA30a^JU#jG-B2TM8&OIP7s3xNH?K)U_Xm( z(0E`@YJ4~2R^Ey1Q~9{ng!nqd$|fEUEC>x57$_Sm9++OlUcH-q?GOse^L65Qcl#Yv z)0eZSSbonbmVaT;rQi7A9DP;!vX8>@hc)8*K1RKhMXns*M>`A;$+rx97`h%7&jR9t zC4M>jJ{&)~i3_$$)lOWn$d4XT4`3s_U#lc8_yONAj5xI+W|Ty0~DTj4JYc;6^q3H(tlm z)T}--W2Ni}kx@P__#jufSY}n)zwvXm3N~Kv#Hw$&Z8uGX1u8Chx#qXSclZs0c+5qr z!5}W!tQs6IE?B1Ch`3;@k_j%25f_Xo=ehKJ0H!XD`E(0a#*u4TTL3zy<4w!kH8}IHdWoCz*z*s8R$&S;ETzjxCsbYzh4`6DE)Kk&{T@C1X8DjwRJ)q+- zmyTp}Wx2Kj)lT=ZM27S`>SCj0Qjtuf<@w~5Ip0VEG~xY7w`}6db1565<@xU_yckHz zIjAODo*%`dYMpQFD~$iF1ERRiQ%hF{xt8aqbanyo*1QP7vUa zv45O#56#ae&K*C!sGg$vIij8t{P?@Vu^`S}hf+qS$C9wY>AcBCPSWs`ns`n)&V4rP zpx5M7A+WkQ_p5)j4gnfI{-1*Hb^QKYd`G465n{d^VWs2TzkdzjWzJfYqTl1Af@Z(K zZ={5U1h@uqW8JUa`1GYgJ5u<(;JdW@S=DZ=mx=)wlT>q1No@T<+vbOLY@G$<;Vs6E zt&dGWS6$j4_+RjB!m;%$QL0jGy%lSYs8Ltg?TmU^mBd}N~W^<=BtOmTdD ze-Kk?KirOJ9~O|kocMa5#MkdtdXvdXGvmhB%{sx;HG&cOy0a*yCT=9hIzeaw9~I7# zfh8=Lr~hX?9g+1^j<1_|s9VoSWIbtzo;0kUJZC(6KFj8s4!558*-`y!cIs&^sb|Zg zdf*c;;FgVNETBE;@QN{wB(S7K!nX@09-pFNw0dC^_b=?w}w#asJWdxgrEr zuXT02A6AB3p8g;7l#llxeQ`;=-{^;tZ_w8-`kGbxIx?c@Dv9^cTRj`^Wm|OMTyx&{ zC=BQ^$ZQ5N|7=m}%m{Tr;{K*RLoeA-2sKf<|Bw3(4SlwpjRUtYLLIT@FOq#a?tds~ z=kj?D;!4`kwB^uV{})_+v+?HwIsl-R_`fKv6aTMck)jntDE|Ll-ClA2jDyEVlFrl; z3AWUN*0lf4^B835jNvLNx3-~Bd!C^)@;so7&_wqc&jU)6#ld+%B{*aGg}6ByBQ4z* zn!wM=P5w4QOKi1JQ{r!6ya(&wAa4Eu1_YSX2huI(d;|A_xVg&PQ33HQb>0s412c-% zO%?AoD&8jqN)=H=m|C_7=j^JHa6z>h(0K}J{uGs`(4&Se=IQ?fJrD8}Mo<{zoyK_A`gfkK#ydJM z1v0U)UfyB-|45#K!~I?g!rwC#1m-EsqUY?ghdOcBBFEMELL4J5ya)0W9O6l)e;|lA zIH6yF;o&|nA`tvm96w+}psyqNt=c>V7)dHmq5j>=Q*gR0A?rE+Z4~z+m>885cZ26C zIHZW;-t${o2gN$uMV+7~Hcz46Kj}=Br?45{+k(rJzcMZgAZ3 zGl$_NX>;+Cv_#jaVmiUVs{Oa{1$Jaf($#zr+38>bM`6uRb<))(p`@#bk>F8-D(PxN zj0EijJrV+Bd;J&P5(NO+QQ$za7%>gT42TA@>P6^nBfJw-`HP>l?gmHNSoC7Zsv;&2nFTyMJB}8^re&HYbT3s(EO%Rsqx+9YwSzxQ+d8l9Pf9# zYHIrW+?uJCzh#Q$KOZV@eD#jL^8E3{iksm%!c6P>CPxN4MXoUGnmtI&!&wI7T5@qp zJb#$G#p8#3oDx5NnS7jrG~whe6vg`@>Y=>}=YNndP?C@H6dheAA18GY!!*_9<8*h4 z^w^YuARou@&C_@XYo``;V0{tLQL<0}e3y>CQaVD317MzPgMJ`e1GWZ3kHlJiurrRxt1i%R)8SMwP+f8jj0?aVlBhghKUacHCR^5n0q z?>w-OTQIgzvcrCq#K|DO7 z9b%kveH>V0Do`8bOaOfZYBOmnr(m*nFdf@-4WImpL3kk7dCyuI6YrrNfH ze4Ld!aO21`{Of`I{Doe!Ao`tH^`E$5u&hEpPMLZm@^MC2hU8f-=Ux4Zl;?g*P$hXT zt%v@x%JRIk)3;1&S=I8K%3NXP8JMARCslq~gkF&j@Ho(`5_!IB(}2gBzEV1>mFL=3 zrSgoH$CKynRrBf`mF8-jFOlaz&|w#e&w)JuPC4~VCPQM?y|`g@DN}9Rjy!{QUY`7A zUGR%K@_dbIFu>w$)vDA(QdkloTF0P zqsHByd$FW@D(9#ipyeSlzwA4TUX{ERhxJ6;rm*4i%XGq_j8AS9)^tSuaS80>MIq7W zsPI4^BU8Cavr2N>{+o|UnPdq^6O{#fV za;Ds3r`k5}!f)g_3&_KLxKa7MnC1!KgKku4d+BF%9tUr{tnPI6A(X0=)0T%1K?lD> z%NsRaIg(bCg;r0|SfofYGl9-&YZPq_#VJf}86&qvwMhrJWNprQF>n4f{QWQZPC*pY1ddQYoLU@VoWv!5;gbCVn;-Oh0=i^e5!abj$jA zAA%mvkr}(1&5xVsR7)KG3MR831U=x2Iz=LUi7{rGj~6$-QG9gY zzmOF@{0(kG335%>QV*+spQ@4pR0fNudI4^l`B=(eq4^?V6-);}8z z9FBuq4p(YHfPei@fU7-^<4Mo&`Sy%hZ+wl~xKDgCwhTTBpU5}hmEzMUDELs$j_V9w z6^!!WeSp2ASE_pOlw2PE^0Va=c+`4*z@r8-qu@V$1jF)kf-zz_UX)4j7Hb2u4r_09 z_>ov8@q!4RK>Q->()YSmxEGY>SY{<`a#cBDSayE&$>yK*=gF&>-V9gN3ow{rT%8$`D>P5X~PKZdh2 zuOhQjeg+SWBhQOZq%5ayh?HgKN4oSXKC7_0k>f!r3XlBbfJul7MuBWO8BGs+x&z#A zXmpDG=7sU1ABZO(W6WHR-KH!y74cT*nJTu<;dqS7c&xj;q&^s0S}gL9d#UInejdU@>|q7TgfY`(gWdd zzVoXkIm2JDUk?f>Zm>e@!O!O4Sh`xxU&XLj$yF&N!% zfmNQt?vDcmbnXf)We=}k%n~YDnWboqOBTN zAA^);yi3O&q{WBvJv|ZQ!}$b4X6KV@ocUyFx@3M;c8NLBb?%xAxC1O0sC9=EMAS@r z=r`;*$t=6ipdF{tmE+npw=(LiFrM!QJsM=Xlse>1-aRfDvBpXGY@M8 zW5YM9S!>b0-z{re$SHBAyVoQVK5Ii}O>_)P9oMX=dMp#;HAtsmToj`0&q& zKVSn-?bo1QSA@m?Qel42h<*Az8ML+`*YTYR$uWxLhgf8MKeb=@$_#tnwMVAna_xh2 z#U^MLDN*k{907wpGI*3fiCth!f(%(+*)C9{quy4_MNBPigVqQg_}sUwJ#Xw$L{;T- z)|rY=m*F-#of-PB+i9~Y@ELXPbyk*_Jqux@E}@N@p^Ym0UQNB8svb*$47NsK6}(aV zOjMhU53pL~zd>GDNbf(ZSGT9});xKCLP4$Hi|v7~=TY=u8?|q)SDdu%^m>yYdpFUB zhixDBaVsh>ng=|8^Zls_vCFk0*yk}IZXA_6wlIdR#>QLh+Q$8^Z7eW9MB8|TgE?v} zSJ|H3&p}pBmgD4Y_UD_zF03$)H z7t&*_O4Z(+8nGqAn-yL#P0@mOnv#Ioo@mOb8GlpbVQ^yxsNse6uguq{QBj6?TuD09Xe!BiDKAleXuMAy@6~Drd#XO6DFH9TqN?8XlPyV7vpilF`JF{X+tm?u8 zS%c-^{;7b= z%5ShcI0QcAlHW()OMN|M*Ik!AM0cQ8%fzaj?!NX{&t%|<0VSn{SL%Qgoj+H~ISu@s z0VSm!*VUXLAsh8hXR@$Utun8x;p@-2^zG)|UbV0_?_W3{Sj*c3EdrLxSD|rW&77JQ zl5wt&4otQ2L&jP#3t3erE^ABJ}J-@hEL8*_dhWzFDkSzPb^ z56YMcx^6IB&q}o=xSsrhNc7u->uFS8g6sS3{eL5_{|pYJcL>*yMN?D2^}!#8G3xEW z^&ft1;<(;8`1aE^b6mQjaXni^+oW;54a^UaV#>H42VFsRRpWZ{rYdm#c#Z41J1{Pi z9|B`>d4cAD|EpDYe2eWnOa-yjk645;vm_TT75$&cZ+H*Q1NDM}Rm}ta!uv_h0|OEB zz$JZZ9;iJ}`LB(gZ}>|;Am;}iuULEr=iI(KsWX-Q&ffZ2%I?d2LDg&O^Gtp4$7e#- zG>AWtgEmVU^0Geb)8(~!9<$|5+||Z45?%YD5s;VieoXO10ENj-DgT68oWtIv>p}B! zdH5^+3hbiuV8o=2y?%`8ALr>&^`;BXt@sx9UO!gG91ksVY2|1GG>wM+X^#osY$sYQjoaCND<1&puxphI-M;I! ziVA-re4&IC>lK$iG0iR z&iLHU@_KwSsDnO7jFAU#1o94aT9PN&yFLIwRe^6U#-!|cuwzl|6pet>Wkc$LY| z44=w|d2tGPy+%6+3@nKw^{1rK| z{9H=yhh>y(Jmkpf7hELVWwsMQ5w^)mJZ{GrOY}}Qt~pGSe}f5uoD{}mMkw##4Ox_q zQPTpF{2yP*R2)>JS~vkMFtY-8hKw;e!ph+=I!TYOnr`O6=ZoegcL2?ENV^`&>Qpog zrGY3m2)m$ax$gh@29@iX=%g7t4uPYu9Y(H~u)Dnj5FAQuA7!_nw+323OCahU+7DSG z>X(#=I@lpDIM;~6z563%y#quI=ZviP8aX%oGW!O!-#fA5N<2?27#mT-ssbbytBwEC zl=tvBFBB=n?k_LjCHkP``%>gcoh(7VGzv5OPcM=&%f|f!KVV|pvBOj|F;D*=_>B`? zE7^Y6!v!M}44f1{@6OBT82#lSjEZ0~Q+7Qf7?FuU?h z=j|leiLds(wnokzIW5q>Kb8X5`k?TL!MB3H*$&JzWLaLG{DoXt`>uTpBOhFua;OGW zaTzMeHQ}_RJmkja^X=}+P2Rv%LFJ8}RKxg|v*?vny}QIS1Us?9{Ac6T2ax}ndQep~ zvw?4rHHJR`9p$F^I`nwBpt)%E+~{3#-qbQMAUE=mtFTWgRfk)vnmoOLuiKHA$%l>a z`sAelrJ2aZL~u0qh>XuPFos?)ydMX{sTjRNk5B11DSZatZT?=X%lAPwgQ?~INRd?l zMoG9L!`Vcc2GxcO2^!iJB8hzeTB%KJhNZ0ORR>bk*4HFGnc17fNh0FVOw}zXY2%{56<)XZaj~;0oH+Hmdvzkm4Y_b^ZsA9t2r#F_WA zW)Og+;YB6I8G{yz5f_^f=U>i|;90a38doq*H*w-YLl8_F``T7CtTGcp&>g%Fso>%k z_j86I0jBWcC=^6?Xc4LSV;9UBM;<;RwN)VtPDNzB|8-Qv@h^u9)^BqIo`z85n@6Eb z;dK-3#$tH@ag7Gg&vf->L=kC>tPWBAlaUP*;*0PR1ETqYPp~N<-=U=i)fwVD9NQ_h zp{bGmdT7PC{SyBS@jGAlXi1;S+84&;hJFm8SkZosEw@3gbX?Oz4@9EtK{C$Sr?BoJ z@_Q59<>krW(ENb6jB?Km%n^8J*WD1Eui?xmee6Ovy8zl`Pm6LBhy@e80o^};>#Zp> zHZ5Rh%1nW-TQrz-0mE5}CqbXT6uz8cdRa-40EV3xBXC{CpVy)w2+Q?7rU=u{iwJCw zUZ;ffs6T?LV)c(}Z0~u{|JDoz?F0WQ_cm1qdD6d<_qkc>IdnCM;(rzLNyr2hTd~{O zTCR#Ab2)x<=1@r5^M(~BubLBbrFr6c)zw%h=qnimx=8V_A?d%Ibl!LBp$spPj3EC# zoYEzf=8if7Po0bbBDGM0Ficp;Dnfekq1^YSD3};PjinV;oHCZ6A|=kX;G~N@!AvxX zYIh-hD)B_<-3s58yesZR>PJaTz|IF*@`^nJpUk-%Ii36+;*(<@NxL_|ha~>OW1_pJ zq@|ek>x`h7L=D{)55)VkrOJnsW};=2(d$F{#TV~DB{q3Jm_+IC$on^(_TqXvGJ<_F zhA(D)XYu(q{K7g4zbL`7GWcxg)Qc592l@2_O`^2QpM|;AZ0PMo-Q?^T1v8_@8{10x zO}Uw%J+~>z!Y45mWm+9EjAF`#Kz1?=*)8PQjOEyOYSxA0;YvRDOBYvUBUawOYD?JO zVqX-`M-E;#gH46HUzO2SOm4ELtl%Gp%1ZY|2KMG0bS7?wSC(CjSiR&zEKb5zW|}h0 zblMfgh0haL@N{6;laYc&3Xp-$ga^Ys14mlQ#IFDSGOIv>)W5*@Q2!nOS_L`V`}0-H znXv;}#;TPw8@JJRKp{@&Xo^s!!a~(Vq5A2? z$_^M;uEgmM{Yn2iLaq+jyb8HGka9Jqi-+c6&H;g3`J2H;c;&`5oJ}LeCb4Rm$~>Ov z$T%B4@lb+S(R^}%D~;;35CKF-5}gHyh|m=m$(&)OayLgR)hvXSrs8~*L>|fFPA=gg z_&#CW`^M)cERXpoHh?_FWb{hpu>*BaLLR*cdHhI6SRM^dIerCYKV8AWgglNtspN4Y z{;&TEi7@4?VAgFV@&damjpyyYU3G+}vK^J(a!}lOzp!pQT%;^&UQTqa!EcZ^yIyWn z^NL!l4Ho&glv~{-^N!N@DvKjEx0w4`HJck;#q4c7K>)$6Ce-&8B7#p|a4H%EFQ6y%H>h)~~XnWL)IPGLy86*fG(nz1`XrNX%5dSSCTBfSy{yi>fU=53OW6E3UWG|-*8F*UiJY2w zP^+hu?RUOJF|?<@q@J-E6FLX z=i#~tIsKo-GPFRVoQq34 z6l?H1Z`uBECK6k;l6|*y-?B2nva&2t7F0di@Y)x{W9j3&JvRXl$W^i)?80sGCH_Cv z&Nqe!OBbmA2je+5B+ONIk>kBIGmQ4q6%VX1A{`!B>CqnOfzG?j&rx|BW}MA9(H`Pw zy}n(%lzqvvFBqF5TZnmMgSsA5-ZSOtc?!(X8-G@S%vF< zc<2j&{<@UOaxBqbNB&C;q`;pd?rHHmS&(kjV z&nBH;KlY5850nm=1OuSy1*fVx8$Q-Y9KW zaZ$#ktQ|DKFPICPo(;`~<~*mguE&)3@PT*$`LXMt^NVqGupa7)8)-PZp+gyXV!z0r#=l2q2A;u>a}_5N&k-5Fz;nPsrmy} z%jMy35e}c_%;!tzsWDJ%&@q#zp5YX(%xZA<3Gz6?WgJ=qIuIvw*r}~mtS`|@PO{Uj zu!{EuZI-KB1a&&<9`3Z@&3KW^H+I~?@5ShE+Qixxy8VsH%SYRiQk$jZ1*VKLC~3*y z0f<_pgC~uK{j<*;zvC6+6`_thz9;GUR;b&U)BFum5F2`4OF?PsdD8#)e`>qd$fe`& z6uBOs z1PCz{2YacFB48?20Jk#=IEp8PAig42x9IDT(N{YmG>0dI7Et8hajFwvG5X^89p$`^ zqtMrUIu|()M8%QFnhyPVu^$I^xn19u$FD@!sUU`4IMkIKLS4argrxt|S17V+(625} z|L@=**Kc+$dbo>!&Q2tY#P|>_qf5ZfL3vq%F8{m&yF}LuAQBCkkn++Evl(e;)GzCD z${a6G{)U@E6p520d=@Kzm$>?T5`tc6uaH@fR^9}~v=0tdpO29ZC(v`IzQ!g93JkA0 z#o|O4TI1!(-_X4CC9uQ#em)Pr%X()-`FU{$)%wQ+p;oUwJ&9Qy%<~A7j~Pd%V1){i zGo+KY(g;fYKep&e=)`fx#LR2e)h)g6k-8twnTbf+?s_N#{>AEEpsGG1EL6vA`8&Q$ zJIl!Tc<+BqV&R#B*_QWDtewu)Wj>tWQGNLx$1AVS=lvtt1i=y9@DW0yG z13g)a0dQRpcQD@J^)nrmM%NOn=l7F}hLkb%;W7veeenu#djMMHXK{Se zWoGK7YU!6u^_A9XtbJRj6HUb+i?uJR`@m;8F5~*;AJ+V-`wKNAv>zl2??7jV^%aRv zQG7*#ucS8)1mmRCN3Qf|&;uibh@>-14Yx;(A?iRryeApr5j@WHCF3dU8NEhLa`-X8 z{C>kz>&9;lV}1wqmoK&5!!+9W7w1ER` z<4(o+Mlc%U^8!ZteT>*CC2>+N(xqhZo-2f&{^Jo7RfZ|_V+nyeAAgj&6re5 zjXA`?CUu5PXQysKttS@+rZa!jeh4$(@hXCl>ck>xP)4)_eXY1=r?64^fE{zi1lAiiw>Se9ym3WvT|h+AMx`a}0{`t1l*6tbDxy8ScD+5DvCU$KWPZjzzS-zpnY-$)q0S{hT=l7I?8aAfH%h58A=^yup}Q0 z8!`bTz{RAUO+zju(AFOA2txw<~AdY(X+m!-Ge0GkKN z3ZE*-t%|4Kj)quwx=@wef-$Ye_qdGwA{Y8cUlqwgGRi!)aZ}05AjXAa0$E|tDJva% zvmvCQSXgf6tvsJ9NUi{QWF3=s`sfVHN-L=MM~@BS#^fC@$Il^okVmtRwXZ2TQ34`- zGkH>`oF}DYF>^km-Ml4BmjEY~qa%<{UCicJxN>zo`!q6u^c?Q5QeyJjoU28EGI{Ww zY6fvAW{BvFV#s6i_$D$pkxpls|=H*oE=%5fBQEQMcjTF zLa9G%S(Hf0K}S1&M@2$LuM>9=e2LEIzwhJI zl+VYGyIG%^^*F}EGkB`v&w8(0@O}^;-!LDqoyhs$d?us^f5d>C`bEj@rT{{Q`Wv~@vfIUa45mrhMZ2`$@*K_dW;+x-kR|;^YPIbxRhbk zfv#YRIZvQ3NYWFWhnRWT5>ftTtFyNrJk20@3LP(=PYk9N;df#MUs{hEv+>wxFcjQ) zIl1*u*w07bh{1)#D%o4&ysKs`z21y6up!IoOvICGBF^vV=@vji_B1|tm+C2&VXz3% z{UTRDFpGR$u zStihP->0pDh}QoA-<2I?_{rP6%s3wBD&Qd;DzhmE%mwrwiJf_iJlkW6x{RwRq(!kJJ5C3TmNUZuE zz68BkBS0%Jq2 zQOC_%$PuGaNn~p{{~4T98c1^q9HJRNJQRi;cERsy#C#Qj8x?T_Tnq;P9wlXnoe3L8^}I6F-Rx0?5NaBI>2Q^c*?QCl%? zP5YDu5W%fi8w_q$7*FCzV#TFYJm_z7n&E4?HE=ciZgGu2HF{sNf9igw z-*`l)Os4#u@d!I(&k=fC@b$aDvF!2CU4yUq7<1Z_{oQRYu5#yJ1fCz~;ZT8E;Ch|l zY%4ey;A}8yXIz{G)-GY(EaQLrV^#q)&gLDvk>kay81H$QrkP-u9v>hj@xFam&?1Lx zjb(%uE(8HzIl?5+AEtyH;T1;zu@L(Icwb8uXF`Sk2%?O$KC<>it}#AQ{2xR+7XKf| z7u748=jzPxT4*10y^7BYZxO9DzNi8HP0a^wfCu&+^T9&c77O5cTEj!b@kz}GqnqM^ zHP@-P*y1jBXDpzfV1afpv`tqPfP)N`W4_?=<@_R9buwQ_5(O6AvUF?gd6Kh(e=L^{ zBjNdhUG&d7e8Tg?BXt$#hYIt`Rh7z3z>fWtt;fs*PCQ8YD>qYiWS}0fDH}Hv44Fhc zhT@&J!tf&zhG2h<&Py|awfIhFVvK1>sv*)DYRc1L(g84}$~|VHFvcAxju;w_p&0V9 z#&FCO)ee&*Uy>_PQaK?-uVK?1^CfAEICcDfI=+j4t^yt_KNA>X7j&U@K`sXFinSal zvt1X^S{8qlzj|-0$R1i&ik!AS4hQd~y$xc&9x-NntJ}2ptC61#Zb#huQQOZbJHou@ z+`-XNneQ%8ay#m6Y34hwe+-N++XHg2&)lAja`6Ep=VuTLQs~{YJU>sdd6aHHnGa1n z>^Cp*m#m)ex%sKz#C;5Fi1*>hn^p}T&@34G)FDN<2x@$UIs;8Qc7M%niJ9TGH>;4_>~qNIM?Jpj6!B0Hwz&*OCUGP zbC4Oxjhsz2V&%rP=Siz#g5`TdP2l~pEToPtl^_oNTZTScF7h0t_KO@mU3wDDl+otR zjT~XF%ZTMNid%L(@u6OekXek^yCRe}BGia6t@pb=92(O!`r&`+5b!q;^raoJO=S1% zz>pT=!N%3gy}3P?)C}Q6BR`CAwjO1}W3*HhVQpIpVItC$?X)J$$aX1Vw}DZLuor4A zFtm`U7Y?T1)Zmaaj|u+m95(UVgS>_nySwo_VvJdftJB= z5(5~LF2(UP^6jw_Tx`CNMZ&Ha^cik&#GqAz3tb-JIG(W+J*h?3(>Z*!5VJkWaq6T^ zCGSjrKigWEn%i?-O&tvz+^@&~ow(0?jrv{_{vXo!TJ*hE{GY?f@Hwu{QIE&Z9qKb+ zVFBWUfU0hqO>B){dijM-@Jk=Rux@_orw|T|CP|SBcnxu!M?_o+iMS1TBlJN=lw=rK z)VWTV*PNv*6YK0zJ}uVSfSLZebg$#meKc&Ekz4*R>&-d|?2@ZGzwGXNOwK-gY4-}{ z#<$Pxy8k;arA^Vb|;XB3&mmgDxSHAi3{|o%gv%Y;Sd&cK$T-v%&4W;aRqyld|*TGhJ|f58HXQ+nf1$!`XSye9*D; zp8eq4ZRaI+3)uuMkW2p@_!qTIkXHe%yN7;ED zs(L5%vLWrf^may$terQATa&f(zP78HvfS0}SN8>fBkjC?EyPvYdCe&yY*KdKMj*^x zP;3OEg7~-@Z(}d(cz$9<4}<`;+aRU0=`sKZ8ub`xtiKl>N^4|j6ok^YfT2n+gm4zt zYL*skZa#j<&&LlAV%s1Kgv1H5%-_Wl-2_62+A6+e)*%r%8urr;eZb(^2J_Qq;kkl% z#38mRe|YC8Kkd)(2#Jldqs!X~%{v)An&`fP|JVFMr|)eMNl5d zvJ&TMiDO=zS%)}yDC?mn=!W$_)rS{H<>Q%Ks00J9Qv8GOvt88<8viz$ckx&4Bk0CW zw3#-3hqmZ84G1fr`)KRV7UayDF(bE3xHIragx&CF5lf8D`1kE-nUe+`bO`8t&kE~3 zMfZSS@1=Kzj8AC2SLkFBS(}-ISFzTUjSO7p$wmg7Z)nz>9?0W`xM>0Z*>&EYcAd9K z{N_n4hjLr9e)Wz`S%qPZSBv|e7?xM6#Tf3Taj#k5lQkLc(b?Uv?{U3n-p@I-BN=|B zS?gi_h_#+t0E&BEuk+YEaT4piA4{8D)A#cWE9RF0#%J&0r$Is1HsIOZH9r+%ls^Dp z&XVu# zppHYN1|?$Q0$R0$`h}TR=W0P9XB8*@716$$UpCVEHnN*ho(+(0NOjvLq9RLNV;`w--9LU}EN7#NGsYek%bG%FL^%z6}KBH4AJ_aLW4 zzUW7TKy|l4*om~gCc8y&wM|25Kc5-!YSc4>#N8qK*A&zuhQP_LN13g}(SCW-2&+kV z(Hq2RzVdk(w<>OCb6zrG@MQP=>p!IBZesj@X&Zxk2B#czn#LHi8Q-Oe`VYcu@N?$J|M*S|tw!v7pg`-8r5XVK8u673wj^PRd9j z%p=?0*EXcgyhn)jjD1r}toNUpA?U&{b^fz6%=%y4^5%t}b$&lcaDXL^ul|o`ae&L) zi5mo05kUi!nqS?J-o~yMwGx*3_XVBKLuqt~s8{d{ERRk8c- zz@NkJYg4aa%lm(OdEI(tosf?c!u($=%Vai(vtcNu4rAYen`%!OMzICIgK z6Tq2yyS@WB^W7i5oj5bHr(&doGxeIci(6dzh5#K;7{RYH6BrREorg-&pf}ZZOFyy zI36W?n#_51gStLrS9vH#ei!c-mF<7pmqFXM1GZ^56vE6v-7*ztMbPKf^ugp!(xB}p z^1v0Kg2%k0yaBb454%F(x#sv<;-W9i}{zEb~G{@E-1vbJHgZ$IiE@er2laj;yM!E#-+ zi%C5*DMZT=P{N`|VhHl);Zc8wX~37_yt9x=d@b4#y-SHOsN4#u+)3ID?$tvyWDLR) ze5j?~!5(BH4lF^(93J@?MM~izfzcDy!-u-S%UYUkM$=ejn>BA50!f<3{(_lme5$sO z2ln4U_HmZLCt1bDKCZ`5u=7>h$1<;^!kCg~uP%iHN7=`H>q_n8J@81hef--$RJM=X zXdj;vwvV6q)8y^rGd3~!V{m73>+oG{J;n|&^-USah7Nd_ajXsmY$zN%ej^9RPS|Jy zIQEfk-vJz3^{vU{SWEq6aqO7)RgGiWf1@yz;8?RBqAGE$`#{z*c^vDFmEzcyTfYP2 z^XFSi#wV4Vp#7aZ*o@Pp?C-%p2kimIs&3I_bKZMa^>ys+Jj_xU>_p8 z*o+grFO}@?H{aUSbzO=5{aW&EwZBiixnwY4e|P_Bg7$akAsmmg_IFy>XYkYm&#Se+ z2Si)cNdwCMjzLK|!;Ncy4`2)`+uuWwBf?^}_V=PUH;oOa!*iwB-^V6sf17!OGR4c; ze=c!^Ps3I!^nILjzkRnz)INXX0^{ScPmsiCxD8EZPZ#`ee-o$rG-)a*go!TYH*0XY+0wrAnxaIb}nt0r` z!#u%*Ye?p%@^}umiqAU!T#hgP^H|eD-fI6>$(!+)YVw4Cdc7y{pZOp%pCggsz58aJ zmwR5->T%omQ4-pR0%qiboGAa# z|Bj~Hbkk~F4%Z#_^#5w?+;hR(wZWM_3_}sK!5G3*c7S zac@VH8256&8@p2UWfXKyKwnbnfa?vagG;^+j(0oy(tZHvUvysS%BU+Z^oYsuRy5b zi>}u;#M=&I`CppXhrADkdMlit`xC=gIrK{Nm7hhle*mgHGd_&~=yYQbG9f_PrzlT;wg#;8hHvZ;*HoM3(Hu@YP;iXyK5 zCAv<-!^+nOYy`jhgkR|IQ^ow6b`wov?8(F1kLII!@K;M3d(zn0Gs;4%PpWA&xJ*6Z z<;h>&esE6BkI-Ih4E#l4!^3Au$CFhw$Dc79VmACkXea0Y^*4!_VJ`OyK+h`3p~NW{ zvC{h4l))ud0R5Lhjlud|-25{7p)(um(bwSt%Y#mK-Lzjq z=NfFTI;ddIJ%V+KXqfPl(C?gkl$*n`%IJBTF}u8f^;c=UOZ}!^kB#AS@a#6j-Y7h) zASZ)@SEH;9veMcxVZ0h(kxAl}I}aUWD&ZIudcg>Z`thVb?0tR>xdnu?{J^L9!>f$i zLEU-&Ag!k!(Z#%f>J5OjK|LsXpk&&*VpHfY!iPkmMAw__?&^iL;I9k-;RE`M`f!fR z-x^n602TfUU z_#!;&I6~uZ2_9W|z47Bv7I=B`*WzXS7Q@dfn@#lZ>EJUsSsODI(`2pno3RWcx+S_U zLoHDV*AyUJlYa{JvV=dx*8txJ(M+rv0|tDnrFaRL&`TJFZ%coX0K7`VS3TZ8w@y)8 z4~?^WZRFqLM74UAZYLOG~(6I zr4T)$&1BDiP}%2NT&kBFjY9@cBKl4Lar>U8--)gtC}DzXh`K>lXj#A<`2+M#B`k~; zK;66^tkvF<33SnxjjNB@6gsVvSXR&7u80|9{<5!d>;!Mw2akVnh53=_x`?`j`K;yB zB7CpO7XcP7EH(2|zGI3*SaNDX03} zRQTTKF+Elecb`{-SH_zcdURkY@f6%6ZUP71&4UDvwGF8;5-W)uab-}Z{4q@2!$aYD z)bPpEACx`uz9l=ENsf5tW*B}CUK`ie7%xA%r!Wty!UJp{ft}-DAnFj<{gcL-fqCp- zc>ey?)$a+MX_{|HtBf-q$Te{x!~d{ewU@`4el+sl#hI3)CWPac#fz?&hel1?nd z`e^~zPdwrXpRj&fpf_g?QmW2yfyiRf#u8-t+F_O)m(YAl_u8$lHlGy-=P2Z)z#8 zV3R9)&lr{YCJ`L8EsAZ<;^L{)O>o*Gu0McoX}aA+0jr zv@M?k-ZY_+_b%QfTPBJ(r(QB4yy;*A)z~+``|&%CH(|eU>=X*aMC_YFnnm80byN&W z6W~lARcPFGR4=8uyuT(V{VQEZ#dlF#BD6oZykEGCzvfzhgZOJqoTtPu9K@-gdab%R z^Q_>&nN#y43NFm=IW@QN6U^^9+_%HC$nj|fKjr4Gxx8jETg8_=zkFVQDe%j& z@7dtF<({E@d;E`P`m zEC0Stuhif9(;$!5$UJE!UG(jmJg#FA(<$_wPL#HJk9a?NZ=){HGQ2$eV?7p+P%MvP zCW{VUaz@|2eIcUv9h!%dgnK9=4>rqY-DrNeTpnPiD?1$}HfkT0+zG_>{jWX=-5g;L0vv-d`O=^3xf;(_f~jL_h0fpRsYW@>3_2>k1FNz@VB`CsWVIazk~@{ zrvH*(#CZJIP#S$eq*5hiA)^5NYn1XfPYEaUkcFQ|6=(Ej?k&S7ax;h*BjrMlCz-zP z2Nm*x?DL5(>ZhVamGhbJXO5QN;|XR?BRz^KjY6!yEq)$uGea;952$wPHGO5r;cF^B zozl-m>BDq#WsSTaF|p!X{DSO|+Ez6d&U+~-kC}T)`61&7KDMEVl}qMtA(K?aH7IzJ zZ-+3hqPthumS8%BDqUa z;6^2&f)uuOk4c)`LN(Myzx|*$rQ3J&N|js{=e4!}q;ch=OK#N4kn*n>gEDw(BvSq* z{FYCNYNY)0@J;nEiqGg#z~^f;pS#a0;WP7{NeeGe{>qRPM)Bx4{Izi-m#?e>+7DJD zFHf^GeYR$&c74SC#f!nzQNvWeRjliwd?T3aCIqg-n?7)I_$7*~PNv|x+f~0^eg^Hj zd4lafb90q;BXh4|ujXQgDX90Jt0{p8`7>YFO+MQ4S+JXD0_)#;%jE<38{aATJbHI| z{3Vb5{Vq{BHQsX@Us!p*SpDV7zklzt%DzsC3qQ;GvHVjXmfv>(t?Yxjs0Y0KSN=zS-w~fpt`qOu-}ie%exHZ4Q|3wT z?Q+QLk~r2B9P3(tKR&!`Y!Eoea>T6S%e`moeQ>uBUyNSZ{c39(=>J?S?}e@XLP){X z`7a3T%31D`Zd_i!0GX|}xH+mS$Z2Ox82HI-9?4@V_J3mOtmoZC*M~qPA+I0xq5t5+ z$tnNI^JG1CIYAPaCx1n+-Fe78M{y}9B`7>J8LBnqcWTrIs+dOO{)*qLNh;BGIur>y zU8jxIrJp1^u+53TTf=Fjj*aY$MucCw+hzKl=<3ANjt`lyGYI-Vq~5o{xH!OUl%$QB zgT*sry95W1XPIoHQdbA`+rgfq?Fw@h`^%Yn!>zJ>(>C+4U8nB_|D&hu&sE}tyr@TB zs?dPb251u#^detj;xr(f*hU(7IBs5RB8lKMLXcSAcOJp~5#v*psn>(pB6|{9l`tXv z>(8b1%n9E8=+B?if%Zd7Teb6AegKcEdClm}B;IT7 z9uagsgu$(lT<*=D%T{<2KHnt==J)gVK=zBgJ;~$f=hR%Imo{^1%A7^daT;#kHFO?9 z2Sxkvr(rADd`u(XPTu1Pap^+vGCO*H34;_ie~{npRIFvi;Wvksp?zxm6f%#Q3t)plO=_yw0cUfM(u6`KP!7#Rg7XO9cav0yjFb+aKUHLlC45LF8 zXdD_}wx&W<3yE3?q6B}ZYX$dkmzU;qNH4C!eV6X@Lwcd49ljaPRYT;}2su4!dNHQo zq=BObK{o2I*J^>YRQaI1Zc&O-HG0SE?Ej^1}~&hCvSB$Z{O-TYBsi0@zg@TeG4C6 zWAiWoGs`$7U{4|@SeSbtC9!fxkg$H1;ZLYPMf+r4LtjI59O=?gx3q+gA(sv|NLuiw z<){2Fid&1Wwu=;_3S(pxEmC^ioQ;ztlrEvfO1{wtGaLO1M})}u7J6VHJCiSEM~Dnd z!i#Wtp_-(fp}v4>2z&*3o^PHu)ZULr)r@}@pK*tx(QUhJA}nAA#~HmVwEQ@Hch+f% zE(%(R%8gWm$_=6@RbwoCory{lwBO6r>%WR%!#%67UK8_Qaqb{jk>GB2SlSKZFvMx7*KH(#X;6}E>#?;mZ2d1f4{$T&b{Z(+&hn?)!qO7 zw3(Uv_?_SRo!{&He!p`rs3M1>Kk2H2ojiHGp}4&t+U+&=l6M2`DWehArYB*II-nX2@zjlvF++N`r=Yb>Cm2&(l-A8`D5VkOV8?q zEXna*XX`2HjZaqJNN9^gVDyRe7dj)mmLMf>8=6faaB$&QfUl<(6g5#9HDV~oM@Beov2EfM6 z>;c#-Q`Dt!`_y{^8u?{_vNuc)8W{%%Kz8eSW{g72FK}Tm*7E^+wK(nY^fbO;*%M}V zw0~+{vGH!b_rP&M8t*|`v2_97&8uD65#!2oJ8RDHCcA=j?_o;ieGi&Ay|IsEV;&ek zRS!A9A4UE{^T&mtm=uZs0LLJ>Cx3|l0G{-=(SNfdoQlU~jUTUcp&>~@^<9bDQ|JRD z;0(WLv5*~a_5k|Y|26SqGyX;KgT$HxXjkrU%Ouy>%wQ(}PpUXVR=l9WrC?FDMv_Wj z-gj!?IwTGbk|Y%X75?7JVm|Wcp(~aEMl9b?be7R;N~~Q6S<&nJOzhZ^)>M1B3hkW* z?}29F{Wh=O51ZY}2D)a{s9vDc2LM-u&9TudAr)>-r9CGS*m4UL!gT*y8M z$KiR%O&@OcoRHlK(+Y14m{-6KQwByTBcq1L_3L3NAK>jl^0t~Zn;WL{BH2osIK_k5 zN#vt=iZ|`aMPQ0Yxlobl*bO=m?)8WLzTRdP8Q%u5dLx;_=&c*jIUbJuMc*v?eOIwu ztP5}uXK19IbNBBQ`rWXXdcb>5#f1RB+PIL4FPIHP6&X1PhN_sRXZJM{G);o4@H0*! za_hZ48s|%+H3;(h#;rIm^so2PxG^sDOK1xSbcYF8y~mha9bop*KqG#DSx}q}79Aj& zyFai%{)7Gw4@drzrzEb{Xw&bTxCS)+Ez=oLu$gaI#k^NR+p_EfntGJ<8Z$wen|W%S zr*y~6=IK0DzGFkJ9Dw4fe-wQs5W4VQL*FaGIOXVT&;Ub$<9FI93w^(R53m69kFFJ_ z1w%rxRFwe2nxaAm+Zxf=x+U2n%RYJdLu{@FeMtyw;Q`7ED5X_n7F zzsBx=h##loK;p0#`El{}V&EXKRr_&J4TTgRGbPTU5Jou zp*1*5cV$>0s;CHaBTMUzp8`8euW$HF{k#Pyo;v-kJ+8&pW~LZCI73qN=CdH;JRJEe z?W^Yw)z6_4hw5%xFxX7f{wums-l7&YUiJSJ?aZ~!LCVrc`MYsk1F$y5D_CcVq<7h)Ct3M!vT~C$hFNxniil^8)`UaVa zQamPXJg9NJh-hj2c9?`Jno;3|AX*`Q`&xyDDh27SfQE-cN&I#z2q9jMpdB8+{S)u8 z5x-!BhwmlK}?mdHta+PbL_T)?^CW8IMjYkh8mJk1gL; zVa&H_e%SIw3HINK0du?w@&<*kFiWlh0?!Fufr$T5 zsi2ierBZ5`7n(UV1NimANX!FmBMcxo_9^M8?1d?rDt0unwiWa$jiMiOmp4(MfpF*h zzZ>~`9)1I8yo(IV=^1!Z!2K82?gj(7PuxlGo|ya_t`QSHBscfrMENLsZw+!|$E}y6 zQBcxohbp7!je;uDVDGR-VfCAg8cQeP)#yM^U<8ypw?@FEG&D+*VE@T?1*Jw4yEsvd zL$`2oU@mE(Wz2XML6ZSkOKA76rP3p3x~qzQzaPIjK#d%AFUX!)`|FoDK8RzOgHQAD z<43i|@w-1`H?gWHj{mFgl#k=rqiv`q?=W?vhy#yH9{Ej>9P}jH^jQHfRh{v!w1t@FR##q zF6F5>yu5;mCmVba*USJlPi-#{6`_{ugHd0@d_W_{ctS$uOPlz<%O?DWT5aZczJnOw zQ~aL7_x3@xmWj{tJ(k_#>M@{sy}TzA6Y+X}M|CuwW7Q{PH@``}srugW`^bpe@w=Nt2u6~F+QiGP)Wt7X30?mI)P z`N}KQXQ|>!b}8c=#@adw85>Qah>NZ$TB>m9FVGFDaw`EL;(x;(CVxVH1q*mJ--cfx zKNBK9hbs9=k9^K%zS+O02>hH5fDF$=l*oY>r&f80-Y*cX(mX^-d>ixsp3mD|koGV{ zSXa@n7PnY=h&XR8@|q#Ahz}}DwW^vt#BFh9I-75okR*nGS)=<ZHMQ1I;X5Z%Izb6+Qur(?{zgS*@)6PFoan!cItqqA z4|vE&G=YxwZvPoV$32+H#o@?b(niPAvEJXVd%O$Ri)nca&e`GI0afg{Ql~tP-WXM3 z^_9%zm=}|plGO<+tSN@uC3k_9l*Li)J9sKfVO7<825QBaZy&I8fBj$dei-vT2^l#k zg-&Dt-)G#4@i1JVBueA_Ge)J8s9XS4mJgSV6Xa_ARwGxT^{!pKY@+dPGEevGT_GZJ zIQrA~BNF}R(_hE9=Kw&DdxN|FEi&%$!;79%dAw%WCde80y8BK4?@{x$12tbi!mSwl zVSIRYZwx>14liBys%(#M8??+Cl@r zLe@%`NlsYfMV#G3zh(q@9SmtX0S@58NzrU|iG_*?@XcQppFTD=YRr+8m8sG9;F_@U?jltt7pDEk73Gcfwafs^kWP5&ac5&+m zyJz?OCuaHlxwCwJ&sjeI;0I>e|5-kN?ku0*bC%CPxZLi)nWtOxuIPML<5$EnfkRMJ zp0J0H?bLkMgh2dz=CksGL3BQ=Cb|xc&4{kkd~B!EHThLS{Cmj(@^oEa zQaOnn{Wj$x_S$(mD_hFRt74ZW=XfD{$-g||siK<5jyrFf{2 zuwHjUv+pJAO7n$NBveu411Dr*N`-vkc1%&t>?1Q;0Sym@l6>K2&U7(>Ew|p|ZZ#V= z(eT8&TkW=;|0o%XXcDM=;q~y_csTM`{9dq~pQrhlYS3f^66-ougO&1y5pYBDg-wbl z$k)ghhCJuk_#6UPmviIfH;VY$Apk!Q9s-APCcyIZMst+g>=W~=;6k6TONkl9*U8kk z3|~9+F@?7`!L)?RX-T~6IndsUdnVSk*mz`1@dym6$565pk7SHiX(Ek~NJTu&C=_Xx zSo=}T?U@!WS-*69oz2hHHveapcJw*rQh*8P=Lc}Bs!aU=@9{&viFIe&Z988s&(B`h zdjU|@4_&VfhsDo<{N-V)K_APP8EnzIOiP}%e(4ARmV9vpT=x}k{nDTH`la}|@Pg)N zjD#Ff_p2m^|C><;N@mHF=xFCak2$DQy0ZshNI_zj@(Vd{K) z71^(`cVbcg`?H+Izlea}k8zEd@F7uL<2bS9Q5|>?xZl9d`nR-utN&ZB-$-Bp(M7>P zh)KXKEXlclz-#k3lXJ%da`WC5bMB)x$f}L|^Pd6kHRs%afTu)tN95d_Fy|=Bl=-?C z@w~LHKA0-gC^d1I-lI@5hHSt;!@;}g?aya@ET$+#FMJ_e@Bj)QW?<)hZOb$nX5>6@<4qPBFZ%%I|m^X)K zFNdQ)31>JI4#L$QoTd^u=KXv&oJ=U34hv342^_QEm4Snpcpj*EG4T{#9g9}X$Jaxb zG)azC304A zb6E4(^!WFLadq5D>RsV(R#orX?$>Xvep_%r(c7%-lp{`$wO0p-jt+uuNq#A)AyEYY zSYs?(U0DSHqS@Bo%x<;%?`bu1W99$HM2>%?#`ovwBwM7ID~Wo(BX9eCGzOk0r1tnv4$TKJzWQI0&wPZ8vR?Rnu$63lkN3Q z7I%gFD0xE6dH_)dRy{zHj}*-ypg{b3fUoHG4E?eZNgz40xk}hrD$&Jv{d(hfCgi;8^vbqn~GQ zK;I_lU$o=X_y0(}f|X!mm@%2Fn|FC9fPm=mcM0r@$B0)+xYD|F5f4SUG3}_hWFy z%L#6AodVpy+0{H13$8mL^PpJAMiD27iPR}HKm|9tpFBv_DZJ_mC5YCz)I*QrX4HKZ z)&G23jZGguJbzhL%9#2el%c9}AC`>-TvJu*b2V$fu7-`mHM`zQN=H_P*M5m*f(1eW zNnoxRx?3n~P4(Q6Xu7{!XT&EDU&bDeF53G@Jb+(O-PcUf5FPq%prPW4d%8diha-P! z=VgCE+N}oBV^V&TX~8DA?bv)i(LaqFiyee7;oKsbq+EnOZT+IF#Xz!;eX>Sj=m)y! z>S|pO961u)k`OEio4+$gf9bBm;tenua1Rw8RC6J z{Pwk8xIsGdDg0KZc`Yv6ELB`eSS;a~mjxs|$Wq{hCbGCnd4+PfMN?s`Jp`3|^JcR^ zUZ>M7l_`0tOevr;1*W-uj&C>rmF5J-fW>nX`O;?ku0* z)HXZ(*Ua+yGiUky+*v-qsdbk9pXKvs&hq)WvwVKjS+nf_ET2C!@H|opa+JhF!q)3g zJSYw~40KI(I0ZhoQ|m>VA0ouRXT3D@D;4CU59fO zoIR< z%GKj^JVMlFwEyaZ5|7iba%iZ4hF3#SQjc>BLw)dQ%hluD#Cz=eg%8_pk5y4hCIxRdwzD7Mx$a9#G`h0EbaYo5Wc0Rm; z0Q`EK5ICH-0+!F$CG|KTL-fh#>r!Gy@^!;c4PO(D#M=2fFy8E~_p|6rJOc7nQjfE* zjYs!%dA{}-s2wI4-8wau5*?&E+kQRHT0~WNIPzEc8S!+VfBwiQnVP|s8{B-VW&Corz6 z?Xhaxw)h#i^Kj&^@K4<4=bKf7zJBge4Myl^ufA+;INT6^?ta|nXU&F@_#9qLfTb2b znVb-y=K8XNps>^G%TCq&5L#dMWreQ{ST6Hp#jAy2@fMTtGu>ZB7aYp?Q+&pp10IRY$9o$xoFyTYuEo5;bSYP%wza44!t^RLm_juKA zEKgg5O+E$82T`ULY;zB<&3ED&+vEds^P6!Z*yb;Lf_;6^|1E8PAHNA=io$5xyjN<^gGQ1SiVxBh#SAHpfV)3Un$T9%*PZtfu}{H!8RtPF#JfUgbVA zxsMRl=zV0S5JL##G=q}IX+=A~Fy-y82XM=?(KT)LBCUZug@G36V7(t5mkz##(5#xa zHx&Ioj9p=&OL~#zp|Ssu4ns~50|fJi+Zmi>U;*I4#uH!yT2_n z@M}b*E7!AWGv?bPOtI5=)Gp~^Bud_~>Xn{Avli8%!R?g8(VsveU;ktn9LFkQaZ2D| zb|iO)Eq6Km|`jc?RLg92+a7ydhUagjczM3d@x!J$(@rt)UX#=uE$w8@n>K4*{GP-$n7D3!XZ;+$_wc)}o$KZI2ApS| z8|&r>k2Q1k63=K$@q9|2Q}uEk>U#svcdGC8{H|-~;{4u?^Q@PXx;dQ|(Zy!bznqjgx zSV6~;a1Xwebr>8cW2^Die{bmi&&zv5Bd=fbr}EdIK)eEagk=^cc51_i{K|Xy_=zkiUQoJ;GMVAD|DE(Nqu;pJ%_n-3WiB^mfhhg9#i7;$s zHU3>}EyQ=M4z}e4Pt?@n)4Xdg>ppU7A~yM8>rJpC_cm}`UR2*5eAoVA6usPsWTl7q z9$Q0Gqd#=rZn8I6?@KUDrDPY966RMrI+(%!;d&i6E ztm%>H?+0-#n$&L@lUH`&J)r1l|Gkco^k2%+=@Hy2FA*3OWbOlAc}*&~gg}CsXTFY4 zkxI(^+%LTmq_W6k$VNlQ@r$Ap=pgSszZ$LNhM%sQuiE>)Jrh^=2uAw-uDK3ijTtL6 z0(J#wD287Olrl7tET9SSAcHEbS53MrFiw+Wngf>)3v=O*qrVtFJJfV2jt<$Dy8i>< zVBK+E(|i#rhhP8ivT_J|aQ~~zJ4yA?|0X@QLe2`nRca|soi{Xs9FG1Z2~Jcm0LO!= z-}#c}zkApH>ii8 z^8ll`PHs(-%Ur%0=&WM+zC7NGE*5g=;v(4!9&*RF^m`uNE!)Jua8Mdq?E(7j`_XBZNaGp>SJh!ej?Yy}Zln0s-R-|*{OV6XReBZ% zhhyXJ_KmXo)Ls8gxt@Jf1vs0>%fmVE+j4!Z5}coWNA9CPWq5}jApSgz9G=TTN&a5> zX8meEFY0x5moFDa+{=6-~aCO z&lub8LffKdV;ra^Ie*-_nPf+iZz7CxM!)K?T5r+5nF~sCYtr^HECjoPy zezhH^tP?Qs96Zj$ueV)sAi%}yw;274+UnKMsaa;zAJ_)U;o*YG%>Go6QoXdjUn>ts zpxN-Su`J=k#&&ryMW-X4DXvG-eGTAi`>4Uh3>?^V6AxOQqN-1;LP9LIr{bUwo)rsF zIDQ%4{ixsC8myIi#x?_#bZrJ?zW&5}7!1J6%NElAnAB+LE{+gr_gh0K7V}$#YQ_M%-+DI*_2O{;5l&G4-tIGo4GJL$4!9#bqgK(oWRA_0GM zqE`e``I}S5-<&3K(xg{Lb%%Qw(t+td{~Tdod2@|yoQih>6)iTRV@iISOlt$GnXZFf z-5*_reQJKA(qrr!kNNmd9zs9!^dC=KH25dfRj2y@5I=D$_u*qWruW2CYo}Hog5KvR zZsV@1ZH1N%^*4)Wly?taI#0=Xp8k67lv4PlNjUs{%D_KL!~fh88~#WL{Am2Y@eh&s zHyQXR^=cg@_#1iJ7dZ1Ucpt>xn>A(-NHu%;@*Xel;LFm=bKjUb=)uF5zXgG+~dCP zUBc(Qm;VpIe;!(nFYf`~-Z-*@Y4jP&9FvucI7`g|s0j0XhDV!YE$Z=@qdzU0u5L&T zaj_D7&ezpj9W}2ORw~k3`6u|Tf2ZI_{vdul#{>9rJ>%t<+Io#|`ty-pe-@@k@&XSB z$To;t7?2UuSsqgI{{*YJLI^WT_CoRr>{< z25ha)C)P>Dg_H%Kw-4}{?@?g!;3=FkXF9f$!=I;ze}CIlazYqtnhe!Gw33XpD(zu6 zxC~4sF36Po9IzaoXbk6bi#&;S)X74IIE2ZV`#ioN#0S2U8zgGh7m}KqhC2S+p@VvBvumH)beGAC%#laPy8LfmZo+L+GWOoPN z;RWp*(F3;^zo$-6{iQ$0aUgH-;5tHnH+m>VmKgZ6@a#P0zd6mJ|1wRok@wGwoS=Q{pp%uYm)Y zxu(AmcgR}5dXcM^GoUGlqd!yqSM4$9+I{>N#*$elKc`#&oxjnDgRxE!C%wyMU*?l0^I^dL-0n6l?s73;ut z7qYK?B;oYy72h9-@9cYs{uu^8Ce~bwkp_P0(HFGcd_~#Ky|Ih%0T|FasyujOS&4lz zBCDcbY4;cZ4L`YCx3jw@u!FWZ<`85D&KF4L*QxN88|a@|I+<8Ek8RUN>UR&O);^F} zdooV4$K&IWMy{@%qGk{xqzgPXgljyd9Jn4ZlhR5sSzQ}8UVR*+(GX=$Ol zm*PKmupe9nea=#vwgyN|#!X+oZO6##6y5Cn6#HZ8t;9MiNNi|CvY8)>y3Q$e4fTiCsaYHG35=FC(N4NItlXyeJBk~8^g>NTU*J>k zC4)vuSdc6~qVPfM5?zfAY{#I&vU7mDmFJOBo(J9%2n$A9Vn7*ghuNpGxWBESy^ls< zl6HRunxHN7uHeMFR^3)sh5lF)z?RjlhsFUQpE6zv=QEAsl_2Xo0ggf$z{9>{(&(9WY)vCDkO8F`c?g@ZGEXI}Zg=rR-`V3u- zHER9$OrTHkf{Z|^2ga^rIlu6<=XkMNaG7F>Uw?F)ifi;8r|?-vLxRJ>e~k~=cU2?s zX#x=)bhz35x$uX)g+vU|pE^9l#QBi>8~=9$e?NlXT5j>A95b^U&wjX)UMjI0Jug+I zmv)KW$V=N*+YRSsG0%S+yK(yYyTERIsZ=W&;3xB~aJ#V>cHpo`!}vSOzJK&|Df=<>)R=(ppS2N{)98ox$sx;I0MydpGd4d zM1+<~1WJ<@1$Kw8ZiZe-H-b^=-ooyfz`+<#(MfH$>`oyIG_|JJcE{87nh1-5w5W-! z+jZHt9Ss`avi2saQOop-1o-ww%nZzjigp;sJl39wDD_ zyM3+C!5T79P3|Ko7_;olLmYS5mkT}nf^K)}aSz&A^CC!P;4SmIOqthfF4gwMG5BDp zc{unVf=@k&)a0(l+)7V;#J=2gZqUA5SM>WM_^s`W@dJze;KZ8$M1zoLZ*GF`+0i*1 zPQ+v&=hhsBKCvTSLq9x(E4#rvrSVc)Q#>v%tP}&y#Lur~{@*V8I--A1OS$0$i+}=Rsi7f4|o9p8g%;Qn%>PvDn27#98ZIv z6~CGmKl~hACC!_56QaFFwK=V|NLswM``a>u5;uY#lu87~t~tY(Xx6lwz)dA<$9s%ExLdRKN7j;>I!5T zril39BPVXtsYirq+|O(^`*yPLJRJEeU5#b&go*DKU$=+rEX71zTMxoF%q4+zJ%RH4 z@iIng=PZPSk!Z`IY({f#&pDoWh`ZH=-{VIp`e-#L@gm}Ycz_y@2K)jNDUVot<3u>$ zEOB5&8i?G~)SncMRH%6hp$$?pOCpN$n^FYCt%a1#WmYcuWxI;&Oec3I0o!EjukHAP zsR6AgCM*4FTWH213Wo>rc7U_s9axXHVv)opq%g6;ZTva<-|yFFTqwgiEp$}21o~LL zf2^RmKq*+py}g*?20(=OzM1FTCm;7HngRmWJe2sjJK8*b)2#6g%g0d`bo?c;Ms^&4 z{)x{c6#_LD>~~DVVPAPT_|NYaKSQi#4+j5zV$+><^(`LrPI4XH)as+}_%t*)j{W5r1aT$s8hsU!Y&lhw&r|~d<{HW@+x{q-mJi;{b z$~T~6o{MKo`^znW+i$l?Vk2NPcJnd zs`_75Jgz>@;X5lV9+y8v!Lj?x?}2z6N;+hAiFn+EzCW^ER<^BKK0KoDGvmT}m>w6U z7jifePyk>Nmq;_?EYDW00{06IMNecq)sQ7?CF_k35A^mZy5=#qgy2SlZpYXm z2W<(z!GDVHrR<~Vzo`2H`Kc9GTJoM)_Z`V>Y{TLdtRxZp4(!OYW7wFoxXD|#9_di@N>asqiL(L&!o zgOu|0WKmosJRY6eTl7Y~@Qda-IvNr2=w5aEEaD0^_^D67Rr+JbyT}i(HBS`->UvTH zA87Dl45ZFe(M`RW!A?*Aq}>yid2TA{Pw^g^?~e=l&WsQJQ-0TSjrjqt0(x%Z)k0ek zOW9eEL;CN{x!dkHdHo4wxRc^q_J|d#LM- z0z>#$#XY|f@*~<5JLK&G6h%TJ`N32We}Qs3+_19=@_~@ zXo?5g_wr<&l-*2PxKyeB90VBFh61XsLV-y+g3SOVixn*2r3vudOW*9dY|Z?Ak^fuf zkmuny2Ll8a0>8Pxyf>kj_yAyOOkY0&Ldsyq0!qM30C6YGA86Si*my)&)br}iZy(jf_| zc9|$B^-eFXRJ~KR|L$E9hB3{p{ve0PYl3`MzTn{3TI~;~_S5=>LWRS@e|}{QpG>@H zsArB2);R80@Ra4%x_2$~*rhF}kn9&-jI= zos#+aOGFyJOnN`jfAbd&KBwKiz!aTt^P$hIrsw+vrsq9qwMn;U+A;KiJebnz#JXG1 z773o~15+6Zr>Kj}i>L#Yc+>v8x+>XrB5GYk-TUeHixKx?orNuTfJ(XZ!XRg`jciOh zr1VOuI^mpJyMlpS`=L#qI*~c`-uTV-IJW$6)rZKu=tv;!$Cmo9s-JW1e#)JDx_~C~ zQqAZkqVrH-YCaQ7s_`*-Ow%80zNF&OSD{t%de;G34*htv1s|J&MeYoD%xJ_B88EW~LYSSz`3!z}|{()KeTUqpwQzqMrX`^RE%TIHS1bJJ785 z$Lg(i(QM4Yf6Xr@j*(dRO`H^_jYArZeuVf@Kg#5W6Pjd4JuVL3F9AtftUrS(lI}xr zwjh^;$-|MqqB>$dc%b%pWW98}%6OzqX|g8;b!QsCoxQXk()f_~h$H+h6?dq|FEEeq z6u-=?wo>)t*nT`R-2?+d_bE$q<+`EjE#DLZl-80qJ$w*}rGk&o;7dvH@o-hQ*SlvB zPsiX{CjL0S3H|l$+iDem>=U~AZmdH*If!0RDmwo7ZbDQAcXV#8I0f->uRGE68>U{R z@C}PUl9xeW+9yB$IB+ltQ4)Xb({OCQ;dk`Q%o9T5k2$j7%;Jv|L5H@P{rXCy*Dr%d zb$;#Je`WmI@wh*Jw59w{Se9Ii{x}{TGYWe3{6(j)n4kFMTHJ@zQ2|KtXIpR&4@dsW z{hq(kL?#ro!%@cSHIBHlK3-6gT0Kxc!eFee^uBlkqmtY;)rv~$(#ZVSAvFGQ%t8W_ zs@g>dCK1t~M!ofXFYmdBqKokZ4ShrF1ji5Mu!hDZJ2f2hJn6vifw<&nwZViQaw@f} zIDbGDIA z(A><0NAU%7wnf-c8bhlBlszC8NA+_&HANPf&goOt1}Nzo(3d9|Z|X0bcH! zH*j6{^zN!373XiKV{|~b%;@3TZ`5_;<>Plh+(1dh{H=Z`yRK-S_lU%T`f$7FXH=T!iAyLI+30rBJdd7}n&-XsT;tD-@22rX8^p`@XZYQV zYj8moNSPaTM0UdCT>E_2#JRdOTw7iQ9>*Ub+^zNGlvq>5eHd%sr0<2cIR@#Z$dtXz zDh^RDjdP`rq-;gTxnA=_&t6Q;jg)JD-uZbFLUL#-*P3ev2OHVO+%ULyJ2r;a5!Ax; zQ{q|f7|IfCIsh7Z+0*~$vv1JAifg7HmtRRAX!0kf+j8GR9@$Rw-HV6AsiT+`JEztAu zSw(z0|H05+P@zpSbS#E%%j=oO#%G76LyE6M!m*yi=4H>bK@y6Hx>z(O`&^Wx-@A!# z{1`Lv7X3c=%`o}_U!%WPAH#9aIk$2#g&KEHt_UpeXMnc z8e9dq-}qxB+-?K+QvtYLFTYVh)2>s7%t5;IKjf#txWzwW{0s30kcpX*cki}E*CjUS z=go5tzOZJpeef486VA~$#_s;=Cx>Di_QkiB4S7&ablA1qp4lOB;#CoN#Rka z0TCbaBibLAc_1Aa@}RZ0COuAk)b!d>?{AlNF7_NbO`$q?$I&AizUiZ5;GQ<79a8x_c%{|gBdI}&LH6I<=uRQjRWlXhyXI_d1 zzfrdKQLFadW4;cZBYZRUqM}3bxY~9{=C_#+VHTx-5E}La>zIaFj!p)|F3Qu1(ckP) zBgIm>JqC1HV;u!WPufpoOL?BU;8^@O`rw`DTfuof zx%7oagWH(upkip-@eH^PLXy;Q_$&_x|10Z-<O^VS6IU-vE!=#acs_atcjy8wR|P#yikT@iXM}Mfoxo^yRPL&{IzR{XW#MUuRzStB0bV8Y@!k5BsJ0 z$CHo6wtRG?hR&OlTDY--jBq8a$t)=u*}kw;Mh-uuL`E)E_HTS^4f0VyM+HYUXH)Zp zZ+(gK(WBuM)2CEE1~~ZD%E$W;*76b8@T-!K(Gw%(WBU18jsM>izZ!o@}So1IZ5wvHS zfs+IBngwst!{p>Co&?&Is8u${F^`oBTrSurv%Nt1ZtKQBGmTczS$HoklpORcEFg3^mRF zFi)YRY7v)wasdw`OL5Rg&*An)u`P3qqRjX}4vZmBPJ7yHO$!r*>f<4`W~!*ZOZ3^B1<@+?*#z;NjXuj@pebEunknG ztfbi6u($*JtL=hUFOi)9{tHV75ojkHnIXsoW){lmY zaLqQpCBVC4$J`HnpL&tJ$HS4o!FjdRede0cQNt%HPA(cPucHNC!d)~QdY^amuMa3R zf_4uO)O~(8bmqL32lz$i*%H^!0^gGP&Zf^&kCnq$#r1O~_(FZL%VBZ-YhJDOY}ow9 z#!K=ey>A6x!TEn}as4srSPk=2#nvlc#eT4u?o9n!HH_;f0SPmcu7k?%b)@-F^|;U*B0((obR*j79V=P&u|p`Wg5#KG~|^CuDrS{TGZ+p9a6YB7DKWxwTgO z2WrB9v?}-t|E+%p{=**rX1px@9y-rvIhR>C>*p5kM39l1ZF#x63$eH7fMLDFxCAzG z)4+Q1;7ZooycyG%ZS*GS;h5=*3P0}8SD^TNSx$~<)V1C>{+#7ki+#G7(5#$kCetQ5 zltDBH^KAAZi$EC-w#3}@{)C1ej&LdKBxP+yTwE{8=Vm1L*k#>*8NXEey$JpG0#c_? zP_qNTg#FI94_>{Xu$YOeVCR9CEL6|C^Fd#$*mQE#8@H%--G0yu`8v{tGHK+Jb)!5C z-=9pm%A8G_h~g=@58g<7qVDqjw8=YKZ<5@#F0iTOznoz!rej4hjiD92r-V1YO!=ts zJvq3(VRAe;zES!C>eOv`KHc1JsMvmhs@YD9i-ED{#+>j&Y z=x?ICUdTiC8~#D5M%Di?JopIUOPs8U@Z;_1Kj_f;ZIrTbGwgn3_rH%Y;H@%vh#ZCRRTHp^=Bp=wo)yZPY|`jxxh*s9(jF4ao^ME*c@z#?lPMOAYmHNoGLx-qp z^~TGLCLOX0lArUPfJQ)??C>anJhkDg5d9$iKOYU(n}WjA=mD|ud=i^UE1i9R-Gb+! z8m#mK_4f0gTp#kMI>fpplt^6#m5G9vX0MMkvp4hb)dd>sD3Vbfdf2RsdWOB{#<$Tb0+=S|}aB16>QjJ?Ii@xCZyyyEqT?qWlV|>%JD;5p7?$Jie>=Y-G_4`K+fFK0DjC z7sneuEAY)d;>^lQ0nco38zN;ke((p6y=eLsdx5Ww49$$czKo64YUHnmx0UkOj=$8v zUyX}x{u;rr8u@GAE#R--5dMn)^?x&e6+k$ulA86{@J`?_z5$~we_i~{uHdh;|6DVF z4Rn<9*S}*Mv#Ryi@cA}>74WM@{<sfF%4c?!UC9Hv8Oi;$E%(N6vGTg&w}kI^_Tjvt|Ln%`1`m!IM+49Jb?`qT z{3lGbWWzvN*{*yjZjll+aL;)L?up-d3dr`K%Csx~`VugR=eM11g4^VZeEdQ(3fRL} zd^x%-+!KP_V%pBRcmH>3+YkoRSA4bo(+=Y%wy~Lsz9njWr}-;Ap?_IgzK?jIy$O}O z#J9BJQ%m|fD1GUQeCqp2e4Ahye%@t%($vx!@^fzH{QS26sgp&~ z!mR!HxBk({W0anQ9I3qI*T4sGuCv4M5IZRE(Lol}dL@%P{D;u}iafqtA$-~KcHiSZWFAfsYzUcRh?e<&IJ{F$)@8!v5->G!GX&>nTF)&)utIb#p4mtPnCqr=P12&QK zQZ(OV^!+k+dBl+>SLza$PW@|&j+PR$QJhi+pA_nPm(uziOP{Jo*ImcB7`Z9iN%TsKNr>EcQ!7==8;O%t(<(6N1jJ}in=#KX&9b4ItUj2*GwxP~U zU#VxUIIrigC_j2ykFQdqF*I5he_eT2BDL^xRhePJX0ekQ9rShXkFiu9p zD&EZCOqd^?LQ^yFqgx(_KJE$XWAUS#a{rh7==3GCvHt_Q|F!Ao8-8Q>!RVNo`O&v} zaB6G+&Yu^{li?>5&)fNa^tXQM36=wf-8p`A!~2zvuhNgc@h2fT^Z}bl|Dn{6?tUMe zG=B7`{$=^mIh^wS=rLjlonMn5J?z;K~YIk+PE$y4i|#X$K;Ps#lkD6>Y+g8MJr@Sl^_w`8p^9KI8sG0Hi3y5p@Ve=7b2lW=oV^MFh1Y}3uMA&`kE`p?6-HAsK zp2v5iTY28_k*Oy!d}j2fnXh53xa9hO3gnmvH}??+4+97M=9LRcd_U`aNb!G8xG#UH z`X&CJw?Bu)ek|Rc>_CsG2$v5he^@$x(ez#ZwMhDsNHTu!LJxfUj{iWx59<%xLBCrz zbdtbd`!(aUQS`Ir?BJrF>Y_%glOkgSx|1@GsUEH`zY%bUZMd;NtC^7*^EwU|4pYDA z6kRW_Z)`5QUi^G_(e>iz!{{pQ+x4ZRsQ=LQKU@n|w!U=hk5HSF)?M`D$I>bMF?B| zBk;FA0Qkw;;KzEZ!T)@Le+%K)d+?21mERZX*)K)v-Pk|reUTpfLhbt^eI^>NW8hvH zfZKFWslAA{_oqg~?*a)xki2^^(jvaSsE!^_ele0BjRx;cpSS7Jx49H=@@BZ7a&0vH zQG@q;vo_vQ_GR*eeK*F+)Gt=LPQRk-exr3O?Voku?U8h8GIaUc=WM!ENAC|u!|gP1 zFPH(``O$ED4BYMiYU4Y-QH>*c&iGL511ZGclQ$n%mfmK(ucKc*wL;0QcCGDo(gwBz zm^@g&m&ffYqf>cZH6tKgU!3^#RN~I5)W+;?sr4fhtv8Y9xd3c313cASw2$zk_$PpG z&&rzc9mVZ6P^&G_CDfp7e^wbM6U8@{nCW`OT!Bk)bm0N*|! zK)m$iHii4#x8I%6>*}-LFK-9kty04tSyxHFA`WQL zalWl?ZbNiDW0J-F=wFw{BP_olc#mESyl(|06^{z*AMKyJ*WGnomty3qx_slQn~USg zW*%_Eslz{+35CL4ZUR4>7iw7h&A~+cwukNo%f%r%MM`U$Q6DXm*Nt6+<+-ck(4N%2j(ZwAuKGWYZjui7 z7{TQaeGoTukWM_H$HXoy176v*;1#+Tt?@TDYq*X)jpx^26X(0^@U|Rm%XJ=<{2$^c zPUYTzDK2pXYqeSKWCmSWG`K1Y7acXJ*W?$e^+{RJUeL~&m@h$F_(?tA+0?P!YrvY} z`xR}{_&EC0^MCl3`@y=0fC#rsn#^ii(k>bs#YaqgkcXtH+dHUzecd+d=0XRS^O@S~ z7Xd~KC@aDya~h(u>x64$Y<6(-0l3wU`}H-B`#*8qr~Ao|WyhVb*WlsEUyeJh^-wSQ zuz2i0_`%@V7s`zN@PU9=Zro|wb6wX*j{6#okB=8$r+~PGjC<=t+}u$HKKA;+Ja`{G zS84nYZeQQJEm@HP;vQu9D}-BV{HuhUwBbhSmB~071V>iOA2ZSmxwRGfqe{JS*d;;U z=tCc8r5D=BAAL7O@<%znFi^Lb;f?`K>)~qj!oe+xJL^srzDO;9ccfw%w#Tm;y-+3G z5gTr`<31z3kX=`C+-uMaNB&cA>_^LteMP;{&T;P@h#dE_dZB+~(i;0Qo1WF^g~Qs1 z&Q5{_8Y{BExCXs^xEj4sJ=_ToZlqqIzTVY(A@+%i{86P|IPg6|-e`EkEcJr;3nRd9 z2L8hG!MgK|VrT>+bW*C+3wPCBAxtq)MlUpJkTSomQZG~kx7mifOZ7rweZ_IFK`$J% zEI9V5GGkv+FNnV|{K?31FQ*rl54N7?`3oH$HTxh*V%IDA3x~8M?rOb4ISl0(pwk20 zT$R62E!-{(ZlqqIbF!=TLj8>u`J+m`@Yjojypb-$8zN7Y<`LpAj03+J=!L<$^+qjZ zG^wld7Y=G!Uw5adh3WT4y9-$jvW9s?Rd90wxVuy@B!?@GdkuPF&PBno&zBkdih4op z!5Hw18255|VX$?*rxpsDn$`FT2e+(my;G@!aswYb-pov@oj+6uH*Uj?)CZh=?P`6{ z@TrP?QKddu_O2jL^rDZmnm-6%OaZ?LzSu`XXclFT%k`ByBa^ik1NE> zxCsLqVh#Ghi&vC`I~;(!OZ9>CFBQkV27Q3l6M>l0NSU#(s1L+Xm;ine<6cf5qz0|H z!l)*vj=xo<7yP(Fxq%whI7Ks&V*a%QtkY~*9+=30wsHrNW8I8L!60TCxFV~J8igsSG~~rxr+QzrC#{2w*`4)x(shr zKYz#rzX<*)rx&c4Q(Duys`3d@+(g%IO6w-sk`iP9v)F7Y=H_M8_NZ%D4*+8e}c=h-%-q@_ES&cq8xcw3nZ!9;ld(3EHl}f*tc%Pq$YcS23-YTjw|J@58K+3NNSIv z+xb8YKlcrfJ@y*d;)hhS8`Z<@^Wg3({qTO!H#`2H7017lekkIBAGZW`#6TGy5c^Q6 z-cjNV9sd={2gQ1#m=9Vxt(f*BPTH>VZa$dg6KN2~`n2 z4LyOM5qiQgu&dJ(Rl{xY;OJ5t=pZ>hwhQa8m|uq@LKt{)DWTh<&>vpOn)R)_RG1-xB1H ziAwxY$)Aw8!wB$;h*uZu3A?VriaSghI#)H%@amBopdF&tOH6B!zJD^;Og`}$HvjbN zr^>-i2jK21{UG+C@STd|UP(V#WBZa6i}gZa+^ssNtfppF zaRYg~1CiS685(}T6@=k)iXIKI27TbwIhBLk8-Tk@^+Ei5700~>eejD@ zf@9xTX6!5K1Bp9~0>6lHFQ*Rzafbm-&Y8s>$_>=82f6mRLpiu3Hrz{Do&teAbyvR|EM9pSrJ`#YYSR67z*aP!hB+4g@iw)Rgi9$d5_gXMG( z5WMu%th~+POOj{u_)^a=e8Yxggy;@<@eN3;=!J-=jKgMNZxkJo!5Ygf)>!7S#uDo+ zWlevEA}e}=YLL+jb6EI#>mJp6l1bXA_arCLl*}E5hyR0`C+5+>z&88-jTc=n-nTEU zuM-BJHFH$+e6Hv^hl_`~u6|Y859-d&$o-(Y->dfx`&@^;zfyH@-yIEi*uXtA0C(gX zwO@q|pM5s_8wK|vedQgIc#mQTzyx{sxBp`Azh%Sa_i(shE(6!#{fYB!dStII#hWq} z4*%?E_*sMZYXf+b55xR{O8bIUy3Tdo4Oba1uf!)ezCDuOV}>r5zs;r#Y0RVizICTY z!<{y851s+sCznRzn=^1XEw=G(xJr#9dCtfx@h64&d-Bm!Z)CnUuI~%en{waBF^;$| zccp?CdEXT8J9>Cp-xoH{0xyPk-D^K)_D31j_ebIBE>Y|GxkmzZnmNo!bKDyNt=#n_ zu7}}6SY}@rN8=H;KY`#a`?}oMYw(VO=brqr8SLxw?rUn=Ph(^w?EHEzfS%F5F6qGI zZB#Ea*w^LztIO=C@rK^N^?n+Yt7o^LMs^c@yWqYq$4W2y$R|c;IsAd6bU%%xP}Sbo zr2}We_S2|GQ^xEU+U2Ep;qS{;`?|DTf&DZFPE(fH-q)pRpz?kio&y){OT2+P*|6|qPnh#G#i?i9+rTgAeKKys-MIXnpG9Qj?7Ve7E zm(=g0z?m>U92NRky|2snR)7yjLilieZDl@;(wETRJ8fT=h81P>e3kpU7(2vI(%O1Y z!^EP6h09kUzf@?xA7g|!mE-$_+S2N**I)~#Dg2)9{wCfax&Evp@H>s)8U6cM{LbRH zdT0Flv#=i*cH-*4cfvjDD`D@Am-oQqdK|Ww9{9n)Wgh;U!?S-wZ5iN|So0FDu)T5M zrsjZ{9IOgV4($CtX~%gu@>d>>W%;O>6>Qyw9l9#rpPcsYcW}QGxL-4>fe(GzXy!>5 zvk}gfGU@vWVHtS!Vor&cHSi0jM9VM}x|manA>EbDB6c9N$NwIEpLai|xvBms>>+baeQM7Ag0cKu<)r4^hh2rRg^=thwB)ki z@8FI?MgTbbRkPYYf~+V958)=#WrD~JZdJv;!AY`>r=hPy;5gW?oZqjCauCkfokGcF znAj`67A_`V3xkudg~4I`g|FjiHH5DlJ_e@i3E}HA`aHg_$R}G>r!tv`%wWx$PvSo^ zpsM4OCjb6w_yqe)Ep~(>hI*2z-LUUa|K>eXLm$KU(^CsKu57@&4I!j>L8xXK=R@Hv zQ+(evUdKn)!aKHytLCHFk7vwBjeN99eHzY3eKKgX<)iEs;G^CUK6>Gr5q z0BUac)d}%A=(BSPAP?A+H0i$(u)M7=;d>BvT8{yhR0hAZ+ShRKo10yx-Fdf~_g_WM zkInng?qFkpk$c3@6{cgAw}BgVChZsbgNGx36+P?I(ey07-=^oe9z9cRRQmy;WK0?| z!ludVg_G`{D?!GA5HcQ#Fwk(=Jf0|np6Wfy!~6k0%@BF96EKt4(Avw!sAeC$Vt*Tt z#Nv;7{VmaF#rMN&p>{8*p=#s(Y&NckY7hKog1+Fs^m%k=Sa+xLdq|cN=l~F@;9r2= zUcC3Uis_r<Xeaktp?JipLZ28ufmIsP_d-X#6$4^eYVv@ zyk?Q#20Pbk3cIzZr@L*Xfmg;}sQu-~h#c%i{O3jo zRBbPs_=xg1O6U7HSI{;-Fg{>DIFv` zjX&%q`Wm1+`ExJbuA%#4+Lf#ztZ9A{)a`OwOF10z(OKL8?rURATXdbGfH?jJ{>JBk7g=1&2q|>r+r#JBwa#2O>4lYm|71FEc}W zWkK+0dX0Pt^vZ_N>zg0-=tcj%Y@F&b+yEZSbpF!d3YRW=eqQX4HG0;$jL^U8yy3^+fxKZBVrqHc9YD$L{a_*%#;?S8 z(cr^m#RH}K14c@l^(yn&`&?WTKjwZrD}HpIwjZA$m@{`SDV;IGa3n zNN0?tky2<-#{<>pFQsWbb z_Yt_S{p0ua;X|v|#JXE}4oY)i;^m7`X1j91Fn^8AebbF{dUQ|yW$YmRW&Ak(W#Ucx z%hZ|r%k;VWOZr0nC3CUoEK6w<0eIcxxY6ni{HGy(Dq{!|2}H#}YS=;In;js%7xemi}y_ z{n1?e3mJUdqh(>bHF3_S{_T4vZn_fpv<#+O`U`Uw4Ry?2J{WHude@G`^>V(yFc&B5 zmJg=p;_NGl>)*$_`wP3_>^z*U!`Z(ku78_4TZgl8oSlcWFDI^VQfGI^**$TVa9>JX zf0Q~q4`=tr**$S~d*b@N)!998b|0MG8)sikT)z#JLThoHP2%i6I9o_upH*k~#M%9D zHi@$@B-TENv-q`N|1*1{P~d>Jg&PyskKkO};6p9_?wr=ad)toN+;-f?wxK13mW|Ks z*3!RePD}rb^UfSP^k=v&cE!od6Cd7~n)7UG=*_E7+_pUNPgBbiJyWs%`{tzj?@uO< zJ15_=@cGsG!6%RVWy``RK9rw?7e0|Z;U?b;Ljw}W)4xhos`x9^58bt{kP-%h&C zTRFdf`|kJ>U-|0(?WEbBD|vqJin4#BHg;`%`lsb2pqxX24zhGKj(!I|7Y$A=U4pT18GJ0YF*g@$ z2>zUUA=97TZDCp%U|!;;=g|4VG=_iiP^zxQ4F49K#pvT)yhV*OM*nd+xf@RIjguTu z4E{zrS%;HJoaD%1?Eh0v&cn$AaFRpxQey3AaS~_hapr*jXXdpm+_dteZG%5)>3?R< z;Jq!!ZEiVkQ`^v4FSh{Emi{S>&i1(&owax>cEyPp9U?#H*%PNA7I$H6HpXyMs{cNW z&Dj{6DU3}<#%A%*-XCB2nxQjyv<$v#?bNlP``nhn_PUkmU3*;79b{koDi9YnJ1)v3 zc7Wb4BA*Dc82JRX7lGOve>>MbzvcJ1&__JBZdP^zr33X!=2D<3UUBs17gk=i_OWX} zGIZuE>sKy_uV1tPB>KstIiQHDeP+IO;q>ZfTaVk+Iylv~a5I{?e`T_N`<%hk2G6g%cHZFX_~7|_ zBP3E!K2qGV@wdC>Zf}+bRl;Xx?+JVfR9Ar77ex3VNZ@ZtwR?;;l7B|qHkN`IN1W#dI3c4 zX*mmh+p;&$Lgp@j%>7u-Lf^JO29zLkeT;sHQ_&-g`P(`H;step!vYag6;do6iu z9em8a#QJ@aR(Fqx06zSd5`71LUJmTARYB{5`0~V`rYMb&!sUtMH(oh+<#jWZ#S1Bs z@7**TS?nX}e0kgtxQmnqJ|6LPXh zRo^Eki&XU;aR8 z1c~P%pR*5L^{jcdY>rdUJWmyzw_q2}q1FXYF;_yDdb@@)*?4*&%pqkxHzUwA+>uiA z7@cmA`W|qL7bkr^`e4=foX3Pi{oQx8-h`OUie$@%g#e63^6o?Z=B2fL>{9+5f1YVz z^E~G#{0};*{N)$<1NqC$Rs<^s^BWHOBv%n`ZATT|;4+4dr1ZsI^y@l_OO9%|#=my( zIN>v&68kgf;ZM5F`MOwd$bIaWP0v$=jty*B$CsEVkX4UJW~vNr7M+v#_jQI)@cegp zaq;>x{bjrEUcyw;cY`}l%Wr;~xHR97oKK@8@=|1pmsP6g@ba>+V}J6_Iq#Hc1lMb# zfLSrZbLd7=3TcAf;56ACK!hi1ex>>Oa>>7T{UyN5VRggy{OKrR$}YhtnD3q(4Wc30 z%{f4$Vm*)Gk(&t~qZS^XT#SX_@i8oFs}7HzZ8M-p*23c@BcJ0Tcsz$7Om%n^W`c*4 zBA=*ndD-AG5rW4Di3fR<$9(nS@oO-T^6+7id7tL@>2v<3*Y$os}4<4i_h-%O;SuX|slzJ3XH>|R{o&fgjx=iqi8RIGT_d;e3gaWC>U z>?$uM+VyC=6K_EWEF*^wu;jXZ@WPNz@M(9=TM;(x!{}RKe6eqL{9_gJ!+q}xP1`HV zv3Y;|-jjTbyAhWMt?vUG1vQUTy{;rLw;mkHA3cUY*6de1-<=%|x6iY zNe5zxdhjlNUsybxIuO8S2x4``Jee?`$s^rc_VeFT?1VLmZ+rs|iiH^mQ!6K806g3$1g6Q2OQn6rcW7mLj{ zqv}RVXIjB$d}K>@k{E3Hg%EP6?2wzY)IMjc<_vo;?To*6;DY@CF{nb)xV@ zxtopz7A@Z+6~loH5(u$uBdDL1yY=yQf)f4pWa!`&~69&2Q>W@yO zxMZ@icS-^&7a~PNxNfE(mMAp>&}46bA2Vl^@6QP({Xt+kqC>Vn)2ZQx^@kak(*BIk znOT1Z0{uzOpg(h~=+D4g6`jKRb7W|L`sU88KO=$uq;$JzLinth-@?Xcw<`KG@s{ZR zw1oDjW4D?0XDra4PTg*pePF&+&l3`BuI3NOQg_`ui|6F1>lv=sa435`9Q>E~MwH&p z08UMMdm@1M*qar-NE;pw{uj4*9Ch}JeN$_vt~-@+6iofy)|Yo6T3DEK-2!uFF0#g= zwhpKNaNXYK{P%I*=m~}laCNuqo;6o5lXB7KShL0>jDA#ICG;EHJ(PYi4acS*zcY9d zYWM2r)kweT0R4tfFQs2mdx?IDw2O`UIZ?U4E#8e*Pu!-65O=R@V=$@@*J8~Y9>4Q& z@L%8!KH0LN9Zl2Oac?-GPS*h>tGfT~-u>A(DSQc=hlBs6@Q?BCAFt~EZO6l8p<5&9 z)&_zzJ^PPVb)mou$^?;r;_fGTfky5rJ~z$F$|9=E|BTDxS2SDg6L7JfXre4-{vCS} z3@$^23iH)T7;qlfr50u)6vnXtq%2fyU}3brm;roo zLEGC?77hL>HTa}n`Fr2q{yeFkJ)XFYJ#H(sA=OHoyOcdXTJ@=q0FxH{T|u{wrZRMk zhtX|3J~O(-->RlMY98FA+hrel6w@sjhq-YtpKgcPbZZeV71CW`k*+zGJ+@Et8zH{)6mz%A?(PV9nrJC3yGh#<9(=yFh>yX z+*KD(S`Z`e+ile;RozzyLukPZ;?PGN%8VP=kzd{gDisqs6M@HM($HG$ei)w-l*u1Syl7PLDZB5?P8p}kCWBkW zc$+R^zf1n$sO7`i z#%R3|@Y^XtB5^;BIVYz+4u$2TI z`z?pbxRsGBuD4%t$Yi(1flYZGLCctEK}`%$ z4|6}qj|b$4@x;sD%SJr^8F9q|8q}$HAO@szZo?nxt*FD%pEms^FPm5O1K7mM6t^-* zthe<-Il$Mw(@@4n+`PcR(7XUn(uTL14BYRYHyB!|B&4dKf)m_@4WCkVaY#6Kih86_6u0FrU1Rx*Y7MCL3O> zHBNfn*YJRbXZlCF3!FecG||5Y!Pz-c9bf3s&l^1WJinvqSb1oP z_cy#o-~XvT+&_1>dAL9STGihY_`V+RNMWy-7KzP+i<0iXM?y{~^mBH<1TXl1ex5hc z&w5=vkD?l~V7>cOM*<9mF5;rgnT(Dn&F@~ z0O+(9SwK>|4g742EVMG4Dv;a$A9?QrA6HfFj}I-6K^_@JA#*hC|83of_l9{xf+b(V8KSYSA$$}0L1}ca|Cq& z9|I`;eZOn(ea=2-&Y78ng7@?PpMKJrIcGoCUhlp3+WWXS9%bn<2X}aJY{qVM05+SC zj$|97aj<_cj)#^I}WM|KY<^TFSq&OBd`K1^T|5pGp4-o!xPva4~?MT z+cwiy%NNp*&llcmfD|(V>Rj{?`Syd$g4V6=@4KH_$_B%LHxoeR`|s#shwu_i~V&RYvvF&ew)7y zo(Ir`FL#H*Y^}_X)hRz_$_t*a+rA6R55$%C@q4O?!ZQCXqstq7I>4pCLp`#o8@duF z6^=YK^jqXtJUef7COdLpCw6gAqu?aUw>^VcFZ`<+LgGo?{XDt@tA`kjh>dJk{i=ke zsy3b4L7MnIN#R941lF;dL+-DB(m|vvrsCMSYiLN5uLw-!O-%!|};5GCc%2JGe zLnr-)V}HG4{f5VnfS#CnO_2Wd8wB6#oUT>9BC95jiK$io070$Tf8dknoRz514pQe@ z=5%{uxmCx=XqovF$V8(Iy!GhvhTfDP-9OJ`SoJTV{)?>#n*Nn502rVSaUR3aU2?vr zhNGGej>|Fa;@DU@6O1fDMZFdBt6<5YNG%=3HWw+DuXOi{@DJsAiO+Y6e_rPEhs&|` zD|~)O{PQZG-x&Wq@h&{SCjNPn&(Dj0p5pU`d~Q5yqsQO}@cg@$^;{SZ(PC!oAe$CT z9q@D;=urecK$B&p$qab|ezBpiLnPzU^URi^Wvbo8jI_0))s)u^WPKeSf&!O{U%9xOO|y zE(bMjjbPl&zZ&&-T)4lpOn=jH{oTJGmr#&;b1{4Ea0HdR5O1Gtj5qp+0ldA^^p{i& zQj52X*dKZtS3T{_o-jU}`V?@h)paTprXM4yp~C)X&7Ku5J*>qBNLL+?s#@ANShY2> zYB{Rv7eZBkacESpZ9qW{z!!(Aeil^`|5%{(U)1>)2a?Opxz#I`{1pdYMLMm3jSRlk z28oZHZHsPw1p=YEUHW;v9Q^HtKWm@2> z`p%IX(!==9dwG0jF4N{KvCiSxdJ~J{w>2B*B*_@u% z_h;~#7x#5@`g^>GXGQ(2gwKlD`pxOGzE{C#4px_KC$RoPn3DL+!055xdsq(7TKNpW zS)RWgUA7IMl3%rDv(#gM?fO{u_zH7(*i=ij4 z0nD&7Ufh2y^ql+Epwe<0gSF?Ih2zN&_#w%uhoisixWDx@KA!L8H9l&!71PIT+Fi9s zO7A%p(^g)Hh5sD=MU9i|26hb#DjiQ~n(jS^JQuo`QM;DznKt{bP4|h=lU+h|9}GSJ z4-6Z0A8wlNanbX+t@q6L=wsElS83|d$F5;PrRk%|>Cx2=`%^zOq~GV!0<=vfb?B_= z*9D%Nw_4Wg#!dVam4UEa`6;(9gXw$Q|J zo6FH(!g6h4(x!v`UCUpfVbiRKZ{6VP14Vcm(E|^8QvX(1tGMSXnQ?rWM_N7Lp>;jAGBP1KOmsZd}`;_zhK>5xX9Ye zp*qJj`SiG;Z{>3Ir{}lMU){zz;A-1@B~WT_LFgMMHx>U0>0Z;WJs+IE>J$MJ2W!Yq zg+Ob;bubSuyZ+8=?V4Wn9L?k#${F{xlTICn&xKBB3!V6~szeD51WBXhDv>xM^q}S1 z51>;;xAEGCy8~A?-TG>ad|K*HjeE3E<0G~2os6Pa5 zS@AuOJ|@mEf7L;1z5|}H+mE1hB%hdec3vCHd92rv&c=^*+MA}cu`NBmJ)A`CT6>r} z(!Oi^Gr7={us@RxJ=gxsgwd%n`pMr%V`(N^ui4-KPv}c9tXz)%v<))pXVyjZW1%O% zV;&-TRBwieRg1tDbt&=y7{rLm&%jzC;=${IKa@(k*FLlhUPzl!*+A?k;@!HAy8sfW z^3w ze|HA|-Cp7E+f!WS8Cj8VhyE0ZxAw)rV@GRV$@LRXODpXFM(wje+-%|PtqfaUcdxfv z!ex9NS7rnNzY-htKr4Iu^Gy@uIJadK&#YEW zIrHrJzk{}T+3Ri7I|t%IQz_6(y%%XMGL)|J-ths@t2qs46u;=WxLQZsz)rw3t#1tQ zjLBQcSmPx;4*rM=R_Q?%pi~{}uJcaFZ_M*g>UtV&UOn&?_BUODqmWm(AeN8S7p#44 z1Cpm4&3(#_74}kij@mEAF#*qNzu4CmFqI;K;hM7S6_Yan2uDu06NZEEr`{9~e^%E+ zkV!5F|I4@uKb-U|>f%JN&`^@@-;n?jsh_QN)5LrPG1@(0%dvx*J=J)l^fUJn)r@x< z0EGM{jyJE{i5hR>==kyW>UweG?LghA@$T8gcvJH*-b`@3)ji_JD|ps#Z#xmy-0wQO z7`@XaXL#eR>P=T+>1b^dYcSMcZSGM(671^)!cWBK@XPss@Jd=giDzEGtK|P(0iu?i zW5`30BP;}BMamK>_hTh5(NPl`3zi|bK$3(py5{c!^K_vbtt>t)()bBO;89_OX=RcU;c-UD#4 zu!6e`?;Z12aYa?MnstmjSs9lj{|kuKcGXUeo@2k)YQ&iGU7MC*U2w6Z`4i_5tZfsR z`MRS`@_I=;1DmLq9=5tyaQjeR3&+ZOez>2fIs<@YP5wsIBjeWOsqXd5y+DRVdJy<9 z@F`!dUY_cxfko;^=_9sk>|BO4?0GX8hVSTW_`U+A_wgiuKBg|QcA)!zr$U!nQ_ zV1~W@mrFnZFvIc|n&Tov*Ct7(#L%<~NUP&um@)(N{D9ev>755Nt)bO1;&!0I9Zbca ze`@e_IpH3BOVfC=;Xc`dSDm9<;+?Wu1%MNwVCMTZBVnG2fcefA71xgP4>WznpF9h2 zSKE#Y_y$q_r0wp6&eiGMwsTrQ-EwZ);#fR>K+w~J= zUyZyo&p^XVe`eJw03>A+4Egd-Kl#&2HmnX~M6%8>@=!OH82Db9ikts|=U=7JCOyD< z@~Hf$kDw&G>3M4nZKL!U!1K=QW?rwykCWp7$?)Se`EkZ0JC{pJJfCW^X+A9l@!JC^ z-I=|7{1RupEITOlek1AKdVE8AOCAPi4$FTC<6hRi`RfVcb8n6d?Dx9wzP(|!?@VIL ztj&`%{+WqNM^D)O)zIcxC#@heY9L$159A6w5WQEl!44_r0z6xEi1Lb#e zHH`fj|Dkuj@9&5G2kl2sOJ2i!z_B2%Np5Y~csg%TOiR}f zxv_i?k#%7WW?~$GX?WBv*Zu+^F)=1FGf%;@`!R%4>2=DA7k@(b!59ET7m1?kA}cNI zfl@k@asoMZD?Rleu+1FX8KM7#%aQ+4f79Z2aAODZq%yGe+3d(KhkgfdeLLE}7)TBb z^}l$-3^kPVgk*6rt_xK6z%|IH4E$Dq0{^DPZQ3@q44nlcZ~*y}45TgB&c~pz2&|Uo z2<232VI!{z_HS$_jjwfTV63V8Yxm-a7}FBmWS6ZA+2!|nfV(^KKYJzmbp4U2`UXFK z9@)_rUe>LN!HLQZwb24^0T%IDIhpv8^A^elC^M0~?vXvy zRQ7n6HnaT5j&@&PODbe_kNn6k5Q(YIAXf(mNNo)VAxF^x9& zguCgra{PNO26h3VK+`v(+ z1IM_oXZz_=5BdgUXlq-HVTXKnCQ_+4yJLzeE<0RzaoIU>O1Vj#FAo&R<>*g{naR;w zcL@2xcgn*1MW!4mF2-my_lfWGm0j!S8QAT=!fT%g(Sz00**lN>49zB|+I2VL#~Z&& zgX`ISwClM`>iqV;lNqK`O+Mu}Nsnl%LpM2_^Wev<_MQ&4mzhI*C9Az>LhWVe&>qkA zGvobxsJ$Mqy~IH(BiHcr&Ki;Cym}|}JapcCKBJ$L_js9hO#Qyl^KkuK=sD{P9}jJv z2cYw#q35h`Kc5IaXMO(Ro!s+Te>(J>_3h`S&~rW$Ju-x#3~N?Q6dxh z@_n6jAUGFBY}Y@x%H)|6Z@e7&U-=xvQl$tT4l}Sg<+h>ga5>1SaV^)$IjrTLx1K{U z4N(||kr8VWqpH&Sl*1+Gu#V{=*rsmVPELIfdyYQ` z{((Bz(>v#MA_xtYpZj4b&BpV=kE1AXR_R+}aOTBCqUM9juz2S@o(TB7c*R+WRmgkF zi;mvsQ6~P>*~KY>y#;X$6QbZ8R(6&kI$cHQnBZWq20fjm`)`1IYBD&cc8=*g+hg`K z+jx38?M*cbPnxL&J*&`E-T0Nv&o3ixa$PmJG4es3#mkZZfl4vF9)1qC;W}F25=7`@ zdjmL-PSp7Cdkn%{2##NX{?4;IZv1E}e*POgx8uHT{`@y|ZpXld`rOxVeRnTRc+}K4 zlSpWPN~5L0xv!VTw_gSpz!Mes9IPh!?HjyX`%Z*jT(b8DglLD?+7U*LUKxKD4!yu;r5zq zYRpIu}0^;z~h{w-h ze200f5!PLiLE)_Xr!u8E$0A9G z|66*5bNka3XyV_?8w*jh6(HbmamIcBrWTGMF)brlE;}@)&HSULe~IyTXRxL)^awnX zrx8PV7X1OwUVN{Q{5v@e0&#jq)s47bmmSwLA-zZ@wqwwWT{f-gka2FiuEm}}^q^n& z$*08L{i}9N9o*vucsh(colbaW9HBek28drJ6GINV6UI!pD&ulx`W_}?yO^jl9>G~q zhkO19J-+QgNA4;BfM`()C`=Uu(^mnnc>5nGQ?Nw$63M6u{{}UUe`E2ttZy8O>Op;j z<&C~ua0~~|(MJnqv`}&n{;SbH5$%ZHdhT+0{)jg|PN!xomwih^a`_Upx1;28*J@ZU zjXau9$mN8{kAOA$R;esbr?gGx3hAsCR)WsuLckk6}%kWI*EH{^2} z4j$PtJ>YIr6`#%*5z2vWl!}BR67g zhl&SrKF|)1?{LSqv?Mm_0h)Tzat%A#L8BNc+u{A-om(uq#v-N2b;i98%0=5Fk?T+X z#h2?oK#Evpja*YLrQ9CWjF87!$n~jD7`e_=RgA@~|7di{hkehQuM~yfZ&v(Xtegd; zj%>v|tON!wtHu0oGOcVuGX7=+-+%_)2>dLANnPt;v~8dbVszc0%d$+@rWIMl+ZJNu za3?knw+zwW$JV4_e0W=vE+nHtyXIP<`@2Dpd^eQ;C~u89ur9O$<7&qY0yvW_QRv3K z>27SCnPFMHs`cD-j%rw$hW;~HixxpGA9Un{qd0M8_VT$fS+-XP8R zFlK=90E~qQ7_awWoCg@E`r!)2EPP1jL(RHAW1UbHT<~@)rTKUOmM~_y1kI5&oc@A~uvhP`ZDD&nk0cCmcY*8&3;bLe^FyF{kP>gF+7;!7; zBxk+stM)sG^#b6+5*31uls4oLDAOya8{jwd3*cUjbmNnG4J+D!)^;@6>OP5p@YFy9 zw62WzcNuSnzdPG;yYsxEmYu9*sYcBRWwLE06&qsSZ%3hy^h|Vni z=n~-hXZg`L{lc@;Nk{Rz{tySb?_331q@B*Vhvt->PD!zlou0cNJ#&r-Q<4g2ddK+D zS6^Lgr@yS?MlYNn{fZ%vZ^hmo1^|p7om{~&*VJe&$lA&lwk2TRkaz_MJaEeq{M!OZTb@kOGT#=^jY zvVbyy6TpS6cW@mK+BG@z4m1a|NBbws=(K;-t4a5ZF5clO^H$@JIC?;~{g`+lU_YjE z4Ya1pi|%%`uLd8%&p!;?3ma#;>i}*I9^t2pz2JF&<*|3tXSrMXDtM9C2-=6aFs6d> z5}khN`Hy<-3b0@W8U70FL>tfu8zJ@qpJE>zpav_bun#9O*LJwUNSn70&5qOEr-6M~ zj*08@Y9Bswg(qiou@CL%h3vzLXm3Z^hogTVwhsoc=Cfu#mps3|eRv_}b65Y&vlCJC zxnT`rz)pY@;kCd~b$7a4*@+G*7P1p&+(vHw`DDwGJ`=->v-DH(Oji1c5T!tKqypHJKIjGi)|5Y1QQ$BiLs62LHY1Z)` zC=(s;S#_l+KeSUE00-t?{yW&KZHrUwYLpytLIrH#rH;^pW%P&fwO`{91*4DW7WX+E zO)wCH_uAm-AEMmw3BQ}mzGw7ocsBHH6gD%VoZ=iYS;NL;sTt8Qq@G4+Y*uzlO|X1s z>-(3G=^B1l$aHa9q)gYNkBA>_@Z{)0*>x`iN5%cf&o$4AKa!nu zJEsKNss2jALwXpPNH6}Db$10<%X(%GLL@8I3!!X+IoizcnbhrQH70sY#znp3zkjY5 zdL`qL%6GXYfarf7Kxmt;Kz4gvhRd@nT z^y{|DY^%cNt21m1-X5Cw-_^<%rY67?RWN#B1Xy@;r;WXNBG`-X$ZbIN5W@v3XDDh{ul>rS^rTY6EXeK ziwzFF%^3=haOb;$OIiPs6X9h2$F%3+G030tmKMwjWFrLk-AGEBMQ{EufU1^~}gp@9NzIxb}6q8@(S2cfqiS4O`yx4!(1VPoeFpNIT~mi0VUfqKn4 z+qqP{M0kqSM~K=#QxNCInf@IOEJ)?8GcP0J3%ycVks|0e7JS?X+(s%V-(_UP)@&1@ zkD_DfS#;>0^^o!Jqx3aFvi0EW2~RN(c*qFQfjry|w<2^PHK$KMykI zPT#%vEa`FZf9o81Zy#85bo?Wte#&2qpd;tKE$cU{!Kch3<(dFd?L8Y}0g$MJ0_DPc zfgCJJKCS%WvU}@$ls`;d@^a*V!K>GFn;@}49*ae~6xwh<^>bObiL(o!o0pfBR`EKu zzo^^`5Xm@lUN~VbyDb1xlZ)_C=NP@lzIYjb;*~)(_%F2;pW+=482K=Hh*o`t*UzId z0B6pkZrR8Xd9YD)n5;T*k;o|xypKS87F%PxeL!KmWU&3VOEC8pdrFvjIr9H3@!f_> zVSK;#LBY4lOEY|9?3^tphXdccK-TvXd6^K<5e}lzz~j&gl9(^LAAh%pc?t?KAB+!K z`bGS?Cif8;p0s$e;*4tL}-c0N3Rr1>%P$MSoWrXD6A<{hdg z^ghO4;|{rUi$5X68F^f7gXNgy^Fm%z8GxA`UwwizhCOks%uW+ zS(L_`OksYmOyiiFCz+q|Bpe*~nE?-_dB8YT(k4OU)#x!}56v2u);lfhZ$TxJwQY^^ z&y-U}$5uAVnmC22@1Qs@iFNq%g=4@bp5A>Iy)llXT0MLPcpABu;)zL^fQ}2a_~N8{ z$6fGMtZEQ%u2!O2e{{8{q}p|;MtRnXl@jOv7W>PTd>c3|dnNJKnmnr1T8`I0OIfeW z$>8vxqrX`G`(7NDIFRe^WXPT`5QaB-F@8|woAcLC#fZK9v7>DTP?-S*Br#o(RW@E8 zeB;IVll+Ua``A{`!P8MqxUq};oL-`X7wD_j$H(|1=rbwB9Cx>T}NYmWrW?Wh2KN0tQR5D*ol2M9!twPGqDDbO8V|wr<^$zyQ5N(`n~$I@6}*?E=*_C~n(2Zh5$py6O82wt(N= z-LNR4;V|ln#|ju22#3)R9)9n@O>|%EUk98+$=Pwxx{2?V`md}$RtPF??s+u-1yyRl%F5_{6Q7}k9|I+o|B1 ze!EBR=p3nj_m)K;O1M1THLjd{uWE;Nd4>0(2J>)Fy#a!&_o0UJa7!i+_YEJj^KeIh zqT()OXJmm{2EemMd6Jbn8s{(wAATt;cXW8oyH7*OmoR48`7 zCr1f;#r=dFwvj`PL@ES_gL@0`XXz&%X^}`=es?$iB8;fwfn?{2_fS3p)_zhmP&LujN_@P zM+@^~<3M(~0hHs(x@fuScmeR)Zl*eC5TC^|C?qZmkP2ak!zXA?U7>Dc`ml4lYh)S& zOVa4W*gu0;f8&@E;{9=|Dp?XpxjXp|O*I25><<^Luh{e}Y3STA zpPwHMZ}EQ=UQ9nm2QeO};bz=w)%$IRJX<-`OW@foeHjwA4}`6JjWB6JBdbK0S~2JV z;9*z`*84c|N#TCNoctJ2(V&1&v4YJQ)Uo{@h~!J6bY(uH;WOiJ9-k-PW#hB*-*cw_ z2O{ae!UNXPz$*Ider6BvNA9%Y&FFRvT}*pT(EsX4`u9b{Tf93+e={Ep)Bhry{-^u& zUoM+Liv^7&o9+UKY;pGJUW}sq!j&FqKHVqvx}DJ{?HW$tI-o=8SM3Bw1$aG1U#=u8 zP8LND)-WLv4iICiGe&b3m0jZ02_?%#ffT_2VN<4!Ai1J*Gr9zZZP&_IXII$oOlp`uIVcyZI+qmlju$3TB3bUTKBnwOt>-?RB~;s`HLI3smP3a zL%#Cq0I{d?4Wy->e-`6!^wt|6PXK+qIEmVq#r^GOLd-)wqV{F& z`h64MFyl7kGVvU9UeW<0bc-{dUqn5@%lIu##yKZ38Ulsch(yl>FMYY%^O6i47Jj4g zll#}_5kJ303?>+VF>rp7!@M0@$+tEImEUUhZiRY3lKz?xeA1-VDxDpdMET!>$3cggSqcoCKg!&1M zdhU*2nK%BM*PkqMhu>q@GQ{^Vp>N|ewQPKZz@URkM?@HVIQVO(D8Fit6%%+6aYA5O zc6u<}Oj^ktlUxAYR7Z&$@3nY~sU>;PaLctTK`ynQp$?z4Z2XIcsW=Y0&xTi~W`LzI zKRi|Nay{s?xh{VX-Pv#4#>*LufGq6IfsbWGQu(qPBBd(7u=A!9mToMRRSws(#QT%H zuUL5u%&lT+TlDFGz(*>39q-C1MvsG8m~oJD&-a6e{RHa_A53B6Z{c?n`==QTL?4xj zP0X=^kKmuN7`1L|x~sQIPlMi` zz3HV07ssR@E-D6$j`Km1AB(`ajV}^IqdR*)HU(;L`zeW|J%p1~y;pyx+^Jol-9n;hoy=f|6W}$ir+{>;Me$k>)uar zCwm3lD`k5X2DL~#eiNV}2LNXrfcn#a)~ODB6yx8rD1EP`FmJO*rob2(Qm`*G!)DK|LgeH++^MVOa-9!C*n4UW8dooc{jTyj zV1w%NHo?W@W!Uf?)*O6c{c_8#&@WN)McUZy>$koFFm?1Il8m@(kJRn%^n`)_)l{FM zLtMM==M`TTr5ga=(~O|ll7F6 ztMe8j;Hwi)``~|=I8a1A!Sl-SxY|C|)VOSUI9TZK&A)uV+SiR?-Segis>OPFTRc-F z1Y2=NV3Ran2YgWDk0I~f_QR;h=yA#UCgxlmoT>bM-p2`6t25RpS~k7~b!8+fCd3s# zeUd-mNG1Or?Cpn!Qtlfv;A%gb(6aFvKpbDcEnNSJ6GHW;>ejD@>wgXPF^Zj6e=7jR z+Pbae!>wF`R!AJ;ikBn*Lz7Edj$%&6JIv+iFX+=tKYJ5LUFtiT_Q7Ou3J$j{NU8I)l*K zD8FR!WsF~X@MRnaCQabLq)8k#SHMwo7HeEp%5LgP_e#`3@}MOgp7;1;F9p7*w}Iq- zYac6@JB^-h*?2Dsi*74_noPQ)gZjFHFByK3DL&5C$jX!+xQDNWgO-Nw8gN&>RcuwC z7iqX2En&poGQ)Vg@X0a+HL%ox<6PSLWfEU{_@#g^y%K1^mp*=(;Ti+x3?r5{lBx}}c?GT}wj{`@9S^Y#Ho_rLKwW<5AspR|2G zq)*OgOgN9WU@H$t0atlCeUY}F|k8cm2Z+${?XWUPG%-1J6;AF;a^hxduVSSQ{ z&?mgdCM)hGtCc=+P!B>OXF$wepOinx+WPPcd~s}j!eyuq_ftpL>XU6>5PgEzYRCd_ zyA*s0)~ozHf6LCyLZ5u_vqqno`JGvBuhA!C&^F-beDWrt=X^-d9#9qgK$+|hMe=GW zlGkPtwaS3lM^U3dkt}%&H3}5TQn&=mmo%+NmO+uMC;<1qBH6TvN`&Fdz}bMJNVu*R z)+5;eGYAdn3H)!U4g+qn8e2$a6alfDUCwYI% zt?3W*bL7@^L6_q@M;W1n?g2r+oi57r&FK<8aSul0+v&0{Tft`;Q?KqV8`7-TJ+dL4 zKuCf8CGj~3&4w6UYxl_JbPB)mJ;U#K&^xzKL;u!Vwcn(6(Oh0JSZfH_0$@1Mq{8A7t${NHj??98v`H45APtgsQ z*hV?=MM|iS+;)yU+d!Fq6fPn?MeVkd`0j^3>*)c*-&+0IaY41urkxD3ZE4>RJQ{Afs*cW3RchfIdAw{0V-54`FzgV10W-nsmw` zGyooJC66iE+#s~!bJ8URej(qnEctGbpFmMgxzB4z8%05e!Sj4HIw8~ht6-0=)O*-_ z1fN%u6j!BqTaf}CJKCU;44`z0R4EhnvgK#JngMM=qtsShnfxz3xT#?s3DHRBNZnW5 z$aQjHQ?7>b!s3@W_!lBxc+D8>R$N>U_R!0_JB}Efp>%Pk0(6)>z)`?T6AqRoA`mB% z%}3ui(Zua<^a4d482wb<3lzn#I}L%DSZ{9{U&*h$Q209iGfl?NBoD4K{pDc%jFGcH z9_1lK!mDE%AuD6)pmt6`0=HT@jF@idJzhyy<13DiW*skf9pi2gW;Xa9{Ert3-w*#g z@ZAb_px~H!6Th3wzGv1oY(Gv?|0^8;*o$*>{RgwAO)IF6Qtmt65TwT>=mAX^HHDMo zT$?|i$A+yQyl$iQ;g3QR>d>cVA86};HcOwBiBG7!%`u7h1m7cKh4~n0aJk=1t&7FX z+gjHDJIcXs*s;~pguuiY#H`M>;C2pKrzsS_%0a2w#0<5Oy#17_x8P4XWc>!utW_Q8 zrkYovT4Ty`OqYL(`nd+7Qo3NXoQg$y~|A zZ z7wogz)_ov2Nkvp#&p_eHpK1Jas$V&)4f=kX#DkHS4PHtMaa+DVtIe}{JgPt)&Y+G! zQI0&{pCxCqCEgZD70qBU?&%-*LQ$f`7UDPFOXcs`#8(^7T*ve6;lwv)i-+TEopC;G zA?)XVVrw{9%pidSIqHVosx|H$#+nR{)xjv-cOhb=CowYCWfDQc`d%!*4sr1D=g-;u zj;lk>?N6RTInK$^@@(Y1-S{ZF&Xg7Cb&Wi&WJrP;%oqoAF(7{BP*A0?q$CcbF zCYHmqUPTdC03{f6eqKsSB4t)#K9iSH8JZ;9kSn$C&ixD|{}&NmJRov^8KJt(e!wrhBe|7nkp-@Ux~UEPJ?xP0Y0 zH9lkS**7oNXUqe`${4>X%VAAdF%;Tl6>rHcTA`!Acvjws%@iEw4}A;$MF7YAs)sN| z;8f}UVA9Ieqz8Ns-Nnn*Z1q&~doL89o<6ce^wjhnjr7#?fk9@T2I}fNnsxNlGtd^0 z`_zb{zu~`qKm*~EEsLjRp7LJ&3dijRwu)Ux-T>Aktn+BGPogla+B1CTnD)TTV^VE- z3+I#zxSbMya6Z0#rJ}m=QlzlwS3+kzLwTedtSssBvggd(KbFz$ZAHJl9Q?_6kPhB< zr-04r65cnkm@yTZ-}1chq^`F?1Mb!1JE^uUb_P%vM{KB9S6zX8n}hC0(=;{MENHsD})_tn*boIXwRqJ8kG{_WfX7-n{!X@Z~((km3xaN#=E2{8sbs3J}O!h*%t# z#;gdMP4+WBh|_HRb3pZ>U`h9}13XYT=_ad+J}C^v@~h-ehxg_B?=$$`752W|0o{(V zixK$r;{1nTTwp?dK5}In@u~9-RlFZ7e2?wp!Ap{R@TTSr?@I#k7S^kA*P(v^UQa)i z$EG#B-hNh|zjf|@(eU<$`XPRJF%M=Z{4;UH_u7QV3*V`b{LN}WmO6hcgU&h2FHt#Z zMi6+;RE)r#tvJL8`7PV%SKJR>s}A4#JoeXGK^G67g=^+a|H}gO*X_)K{y&JM|BIvX znVK`aFA2a~$jzDlKa8aR%c9}!4fR7Gm{*woD{cBCJ<`x$pTCunPI(T2Pj|T`AxrQ4 zty;Q&<(X)@m+|Ig!eQ3wCazZaul#w<`n zO`8zm489<^3JpeA_N)FHWAELnIQCHL05fJF^^fE_tkuJC9{`)0Y2eMxZr`Dq3$|N$ zF!y{sG%-KC7Yi!z6Jz64G4s;G2YmcT^=tAIj9#VR$qV{J^3{*DeNK2z)#*f(i_M@Go$~b3>sM68PC(>Ua?yH|e=t;nm1_Q}fsMpTy2j61qL($2u4QzjJ=lC)I-UlbOp@ z{}JUY6RMk8%};W=y{P#~S+y5AKgsHPar2Y*dnq!_&0iCj?9lni&4ZYqj14M08U8f% zqF!EzKk%pLpT0iePnYf?4Gk#imm7@0# zvh9j+mlzlF*8T0~I6TB9s_W*!SHu4s%U9#Ny$C)@OiHyNUk%2WuOxpu`+0AhZZC?j zGOE2uzN%cR@DRsW!>HRVUyWb1L;33TOTkxJ4WHqwpg$Vqt0NU(`TOn49l*S#1X#TF zBehuQp7Wvz-b#$GRroOWE6m4Ud^L0~$)K)h;A7yHe6RhTmi1BRl9cWfLL)ye_FNK2 zw`<^Vbi0rzFW#iiCFzyMW^pdbWov-n$u+_88u)3ewcHMByVA08BM0QU`b*`g-MmS@ z9_8$QjHYM2LS=+ZxR1~^n&hoQS@;O9HvOX+o=!GS!W8+iGz`$`Ynu~Fm=}c;N~{As ze&!!fveljOwZb65WW2w!Iyep^hm2DQ9ppS2>wJ<|tM!;kUC;PIC@vT6_(DV;fak2S ztLMo`@}g=Wnc66$Lhf` z-JZd}16cT-_O&3@f_iWuzI-M1!0h#)quYzpgIU#Hq#i84U*RE659U#~Sv@%RFFRBZ zcD|qSKMkMJgN9ya-V<+MGr)R;eZ2*amwVPO9?y|bmVF%?s4q{JB;5#D^5eR^fvYJ# zDn1y?N4>heC_YO5oYjJS)D~a9(ktctt=P@1GZf#a#vjE;dDUJdAC2jHaeP!n-Ddfy z_xv5oM?1X_d{lj}8do!X)E@BDhCwVZ?y1l5e`w+D|U+d5;>GnSbpJcIIW-F>n6PaHVWK!iKzk(Vwg@&vXC) zWs+dDO4Q%wQMu)XdU2+-F-bquA?vbsCf>TMH+s(TDM(6h_iDI|KVkUU*dFC5jGp?bI>8otkV=-q@)zUC!W-e!tiibB^$J zxDn#1a(hV>g?9!M)-QW?J18xega4%+&i_>L!1`rdeEI5_l;_5K?8@QWZe+#LJ@W9q z$N)I$1@nyZyA?hR++Ke?&%}H0*xDm(f9`bB!`jV&)%8k7t*)CFb=t-4e3-k!)T^hkZH5O0 zaV-R~wXJSq``$UFJ`1c^6B(o+knn@J;=f)@b2K5Y|*nSFW?9J1@&L4<@5$=Z?c-@pyqoxMm~V(x>)EU) znV5RzUwnQs_Xq>=%6{vtgNQ%Lm&OHTw!IuJvoZdpEq6!3KcsW7_FVKd+;c%=ukD>f zP@N0*PE;5Jj&hZ`3j#=a;M+76q390?`q_36!@(pciF!NpkC{L_X9h=Usb5%f9Ia`_*ne!NsEui zb-!_ZEUtWn|2^2CUPHg?%OG@EN6-8rT1UtDRmneUddneaHGY*lzGQFjeGQ~DFI%ri z_){j|Be0Jy>O8xy70RD#eTSl(;isnLU{U}N==GTu@p4dB#RGCM7GJ*F_NPcWxOssk z2YtG}f!hIYMDG4+a`5zW%0b~=g@;JJ4j^m&sbMfp$e$Vj!s_Vtfr=*&;!l-rdC>jG z$-{Hi>pi-Cp!)^Y>!syBe?{37<4?^tA7Z#syRTLL->l|W#m8r*2U?$yqur3C4PPck z7o7WhC9eh!u##LmN*^3|wrW3l&K&f?GzI{`?YLCoY@c2P)WM&~C;YssDjv`W`S|kH zjwd7a!S(xF`k+VG|G%RTe*bprgNfcc`T!WI)dzVnPe>o+fUr9HpzpDuKIrK5;|`|( z=Sv^->hY1rQF8fw`FZ8H`}`Hv?_BjkzEQhcAH?bzeLe+aj=Z>T&dcQSy)xi4Y`Vfh zBA@@RrGu{0IlbO~FFWq9+mZcSePA4Ofabca(j4Z+m&+G$qFyTe1zdx}1#pOf4*4?- ziOpS-mWaGTvQ$YY50>2@_RTX<&NlR<*3J^lZvKAbK5v2F28 z<*z)OfjNp%rxDG#AARRM&f85}4jaK`4^Q4VTS}rKlbr*PlsshXb&NCzD~BJI60_28JQE;$E`qJtlY0oDE^cDd-2egJS_z&{Wkp-8L2(T3=T0XlCd~S#(JO|=ww&noO+R0#)FBWveZ!~# zE^0vL?{@ci#4{S?cqQ%`?>sxh2V9Tm1wN>P4_5I|6NAHb84z+F@bx0WSL@S6kKGw^ z%Def}T5Ny&8xvk!wXCFeM4W=-D1+n1j+oeSqJPnQA3*=D2B9l`y{Cd(m7KtUlyq)OtPPw}U6 zn3~icWu0>aH(>-#$nO#gWn#P74aB6E$XnDfAUFtkDR-y1L5h^b$!>d~9 zx+`4yyn@l;;sZ2hpaE{5P2niG67p8JJU{{QBO#rc&>{P~Wt{p1JAIdzB9V@Yg6g~mk! zlYXZr4|c;*VD5_bT*ZRjYSy1MdY^rm%f4syOQU{2{yg<-^k=zK;f3%Rok4i{o4Uc) zf3Fk$mpe}F6+x;KPeP_kww7l-AS>l2IS%67^ur-2j;PWmvl|Bw-LPle&wEBG`xZR%3paP8s0YDkHO2X7z{7UJn;;E z_VQDDgXU=U0vs|4TrHP%fnr7DspK!Rj0q^%&qwcAUc#&2!27rC$bISzNcW_NJiyw~ zpF(6Nk$;=Qqsilo7{9+>3Apecf#rKpxMq^Os__@CpcZoGksA-m>mJ!t0J(=WoQCDs zGXl=%*tO>eSo2ZYZ@C!gjl2#7sm`bn9nvzMlP{bISKf6 zAY;$8o@Ej`Zlmh4nekscu&G(P2=Vgic7gSchyQ<{YyS=ny%h~b}xbZy%`g081RA1S}6S-N%| zsd|p^7lofL04+Vl&`I@~D;yUnB^yu*nUji0M}Yl;Q`}0=NwIv@K!5(^SX&<@bUQ{* z7<@L?pCur)R)7Beo&d=`{W*5xT;Y9H0Nx(m&g}JP{zV$zfd0JXr_u117bBEiQljt3bC@0t-b@*O9j%d z6-fNK((V)vM1X(Qq2V?3GxE)OF~6%R@NVuRoe!31vi#0Chk^K*JR!&*Xi_ff%VY6p zt8}&RIJuXNj}HB7hS(_<-fHhVR&FE$V9JkNl>UKI=s?dRH3mLo+nwz>+T(lks9t}K?|FRx?{V1IVd!u4wVCt4#lg&*2U+1&?H596 z>3!8^ox;Wial^~LXZ&>&U-=gh+;d#INYt5rjFh|jv|Vmdzqrz%4K(OELwdqWC zt(a-X?08Uq)qUttPw`V2r}{zVdP@&=;wqu}pgk5DT+H~~{pXgqXxikb-Iu|etK(rt zF0J{5*sqt{rqkQ1{BN!E#6|JrI+opU;6K>@+*iGJBKntjP3`&bFMgr;_Nil=<=g-K zk;k`D_JFttf692?ZS&{SfMIYjGUZc)Ys&@wOZnB@kP03(o}^y#TOrXV6Iw32#~c!1 zQ!)DJ+xQZM!_eK!5Od-4-8jyig1*K3U)isdsUcP;C`3Vc~i z-?H%|ya7p@>;pzf5XJb3m#JTHkZ3Xtzbgl+4G+yqRFwts7*pNFLNBg~tB`lg2F6}< z=)jXbhd*$sd1~~zs)Mig#8;$fR8yCJPOROZqdmcC#0bG7uxJh=W>oRV!pu3sxug4Y zH!1ryJNkZqy`is>t-0Bmjj-)7Gkf z&Bo6B*zp+Eo11`V42{S?M$cO!w@%rar0!mcTgC$h5~zf%7Z7=JSKrP|c=|6^{zG;q zg8p^%%iD5>Z_L=j{C5@x=&fHLZ#zq{?Fe2iZ>5f@aGRMV2}rs@$*c-fWiYf*au4uP z+6we}@t^0|FSkL~?Kh1P>X1gD-v~TK%Sq)GFO-~I)ZVO|EVye&$jJmo=F3UX{Ob*Lnj9pG0pzyB)7ckD)Ag-NJwdzws z3C27jgx-?uKg=L#rIm4h$pPLV#L5PyonzS{b;&-jmWto!)HfeH~5^jRi}sX`IAEDz=&^-HZ8|U(2-?{7q1XI(V`vJU|aW?cX6ANA_eQ@^cn$-s_cX;|BVjOk! z|G~!?{ojCp>-m=jO%G-8`hXwOD$>6k#zW&@_BtpC4v+9Jk2rcx{$=aSgPcF(5%~W* z{-u#iBTGhp&3fi(&@V-(9PXnp7UiudE0;xVK?&?+#i4LSh1=cf(Cgl7c zo|D*sk5(-Qd|n>#NtEu=z$=x&V}TpXY`j%1<5sMyd)QNThwSIU%Iu4&vPbZy^c>%5 z95)YmUgzZ-?`=3QZvx-vA*F5>dUf_cES3ako*7%=hy;UZZ}^W|iA(%FV3)+{#Bp{=RyjVK^T# zxkN2UH}U?)FG7)#$NLWfKaM z$6f;RS!(w*rR8|>I|O~^pbMb{3c`Z9_HP=MJ+<h5!u;)-Dv3b$OO{;o#W}- zxcQ3lvrYg#ytv3Agsn0mu*v+)^Q%nEwBqjH;^|NZBBmV8nmUeZOehbvLp9qH=UWzfHvOz zQ?z=yFsZOv$?k+DKY4w}OC@oS`{Eqm3=$-aGEw5lMlg_j;cB$H7w^yg6&h?ik5ByG z^FnwjkF^JNM10zxN8l(|drzrwy0j)2zou+0o3ALD+D< zP)fIhmgRErKih%b%;UqeoBxg<0CPW4Wn=P#s*F?n4QagZYJ1P&N=psXSmrsJ(JT;2 zgpYS_*(_!F17S7E<75yOg{J#}FWy(tG^5i*{Ygj-W*F=%*lEU&5@`1`FNaRM=1y#w z+a6SFnMCXU3U5*Rjs963`&t!9@4wZ*1NCNc6KmS9!2CL z+=LTs9`a8o-Y|Q8*W>9swn;enNBQ^jhje6oXe-XL`(bweK1V*7J@%ffPHFk(nk-b@ zvs7`b56lidv(wdwXSd%075C^b<(HEkx?>)H&Y%?a-=)wAD3#QuZku{^(T5TcKi<7^ zZ~njbv8e~ty{U)Qr{psmeFU&bpJ~}&OG4X77z_xamxH<#$_dUf8gJSBQ4Esrq`2qV z?9j72wS4I3Xqb#u${s}?6nEKd|K^cw4@pC`3!Xj4rY8n$d)FNN?1P_5K}-z5gWE$cterwWbh-YqbX-%YKC>|>D+ zc=z-81#bR{$of!j<|EK=ZPafBdE4UY{2Qs*@QO9OI(so@63d|D)|Q~KsjR2n7h`qW z8jO4PzRZvWdTP3YlcKuvW)xmmvn-#-O1@l<`XHX5&+i|4csI;>=B+&rkOFUJ&eOL2 z)n+i0Z>k*(Ezeptm_-N%+U$W;AP={WjoVe18N6nq2U`cPDxbU!pu4Yo+4GMq3qIjh zY=;H84KYp%5QClqhS_6SXw|W1n72hYV}^NBfPIw1;qgFI-A1?ne-2DPAD%kzrH23X zzMQMUJf4BRuvWJ$Zw>f(?=e2!k|uq;8dGn%b~N+GwbSL0mg=&We_%HAYJZ-y?rJy&HRoyPi(09UDHj0qWo`PQA_^THO52N#Z*8Jqc{Y&tD$g9$3hq>I>TUD7()7j9s7o{CW7z zv$yB{o;{BnKiJv}8@z&&YDKd2eikcu$VtZ3fHzXa)8p1x(5~lp%W*1Yo}0-CS%ov& zs@jZjZraMQbJ+NxZoK(+^G&sz)9o6%pf9_!Gt#cw((|-GE1)n=4SRTP zzP%LAt>9Xt2yUpo{2bcjIT)tBFnpt4d!@q&u)o&5v-|?zZ|5F^mHBGuxye~J&r`2e z_301tqHg46p0|abhwEoT&%^b5L(jwY2lR7OkM04#XNR`V!vONbq35h`KOYM{*Y1S} z|77TSxc`~Z^Kk#=(DQKraqD^R@;wk-Uf|)=ihI^skJ|g~dJj`R_tMz;p41P%_v*9V z$e-utK7r%9}B)^;%1nZgO&lXenf1XsWv zUv1vWTXx^}_MP;;G}MyI(VwGFZ=SY4#8E-EF@eeP9rfIAbk5bP#WD9#!eJ` zS?OSEpD_6M2+;SK&XN1^!X`{hrZI7{CQ(Ki|O{sC4eu-bv zSN?j%8JL=2vV2#@{oP;p0(EmJlE|BSnlKLTNj(Ip+D|edB4#G%%eMm-Op_M3v)?yj zVF;y)GLYrF^41R+gv+6cM2BgYKX5ttGwt?!?XEzBs<8#E34TkMdP#i8<=~I?!s{!y z;vV>-J^PlEc5B)24VHlL=ElK=eqcym8HU?qZ6EodEWPGP*KwAd=sOvwfNWWm{v>Zr z@>W5Lb_vjgSs{?Ik;=n(!;wpEk8Poa9Rchj?com z<Mbwk$GRdQcQEYF>U8!==68;jT?<(iv#IQGUtd%NW1(;LA8zc>=6F*)_7P&^5Bc zV)d&^*-c&PUI`k=DKxS?ocH*>xR)BwUV0o3K83$FE$;W{^{Y>TxcjjW&P_<^Qbm;L ziZ-%J1vu{!JwvJ?nZ8%v0S9V0ctSlp;QreuL8+lT`@Asa^=QdnT^?@}DOd*n!2AON z=5~IW#Fq@e6!0a>FVpza$1gJ~7K#2#gs42Qh_bcPgA|FgzvkfjxI&d_Z`t4=}oa-&xI5#`jeCB93^`&IrErJah->#hVimda+IS z+q7PsJlQB6b8O;s(u)&&sBt&YiyfjDfBd+o7Y9u}ZTK96FKE1M)_`dAVhVhUzr`Jv zUaZJK!g|p$?V>$i4*rA=XgBAzyQ0H1X7pnDMS2_|cw+QoM@TOg-uC?JMMzStUUcf| z#REQCs~5BLY`ut6IM=p9G?1JCJ$k0zFKqmXx#`7Sw?E5Ms$jQ={~SE8ZE$ymXVS*- z48K!v(iegq9}_*v4v+vzOTS9l(4NG4!9Aw;+ zmW@9}kJJv8am>k-2ZYQ)d2Ov60i%pXhx@mWd+YgyWDLK8k_*Rbhf=$QKUL)XV zc<*G~C1TL4<1!)~d%jeXXC#t~1Nzotn9IoMG*I$#nJ;gDb-qXUXX5zYxR9>akN%Vz zMQoobYkb`Wl{wdUn1`u6;F7!FKc2;&=p0aj!*mqEca<7LTy^s%lk7@?$-3pQtsAtQI{*> zb3l)$g72_(us7dMSJij;FW*il#2LZ4fcT!ocfm0}dtos(Yi-L7%;z|0L1v_>8RIEEP8(w*;TnPNDv?&D=(M}D~J#rvBh&v%*-jJ z;UH{Axg2z0vxB#6BuXpVXY)28^a0%Wp zCV0y*!CS%PyD{qJ{h?>e^Ax;$=n1(4Scx+$AB{^-S=8xscXK^IX2R4v359Vv_>+3@ zH&UmoAu*SdX%XHl#FBt4>t3^IZ;m`MDI-^o%rxejGEeI@?S|pmv>4+u>uN1S8FU8L z8SoVMbpU|EIof*~h0{#OlupG=%uLlF#+Z_^Q0wa^!#DSB|ajZl`XgykK&J6~pZ> zYFWP?CHQUarLbdowyX!^?C{39gaZdSGfE`P>Vuh3O4yp3szP;CHOBoO?>ts6{Q}Sf zKB$OLBCSTYf*o3}rEY|&Mz4=<1_ZmW{WHl_Ipdtf?VL3OWT$J(z;+gJf4*%`h;=5h z=}9#pM}64i!kE@#qIE82ZVWiw$MlvS_XzX>eXvKU9>(a!-h3!6ynj0tuDXnm!(a3VsXO48P@X)ppDSeF zAhwg3p-rT%qCITICy)TH-w?2$rBf+~D}cBgl+8pM%kC&kn=iH#HlDWAwAaIDTTaJH z=f{-&#Bci$(U)$iXlbaXHlUe-Q)*ZH-#G)A0Hl^R&tx$L(e{)bQR82?|LGdBU?FsgFL zS>!}yI;@4x##!9-lZWmq8@-*;?V0rv2h~U?RILoMs@f6CQ)_Gdaq9hqt{P zBXefNjw95)woUuht>7^S`~)oy*&D&J`v{r3OOdEBRcU~++4~)Re~-r($LZb;VTK+t zb{4nfqWtih`k_j|N$GZ?&hcbj%)1ocZ{`o+ed6uJJNFG#U^{6m1?OhIHT{f&OPi;J zgK7rv6;^G4_hDV1ee-hg$NDzjZ-4QrT>jwfR3_@}qgSl6%v)sLXS`UwT@NFKWLG>jGaYe`%6GFi)-Y%An=^M;K@o zTQ0#LfjE+N<&{Z3&(TvyazWT*AM#9Ul``E{3w2LeQK0?^cq^+G2S1~fix^-1+;N{ z+Bj9?EIGrHo(CmyY^AY{Z&InU6*T;DG3ERw5pAw8TPFlDhCS7x864l`+E;%X{2bFY z@+U?Rh8{~EStvhy+g{L)cP5eDxn_T=z{wjiZ3UVZ-k!hsVk*vx`^YVOCR8#m^>_7e zK|VM1r(9@0SL=bd;09VO%`8`Zt{B{A?h@bbC?y;Ybcmzvm$f2h7VCY9}SDIgFSK_V$VNw_gmpaPGy8^Hh#i_mLw# zuZl6msbNhy)&Im_6`rH|C!XCaVCJF6%~hYy`%cEvdCbuH>HoCpoYMUpd22}L$rVk} zx$qY?t|&TJRTEr-i?zQwUB51!uc=4p2mWHyxlOkhh37kf+&Xmb2e>tK{$UNBpN8kI zy=S3wIY8&)pLZmk5C29iohJ>QU-DI(&TYE?rs+KP&Zg*Gd@`QSCDlY-I*;o5b?JOj zJvu+}q)q3HZZC??JAoPN(76ZT*3kK|)57xnlEZ^^&Z2~`PZIU|pS3){?bcX27Yv;b z`-)BH%oB(cqWdUSr#6E>ZDb$gL?#vHN^ojU+- z4V|y6q4Qy{3(|Q!K_*PyCWi=ibUJ={#^jQ*=)1cBAz6gleKL zou~h#;HpdK)9casRTZ1g1G>FPI=9!QvjcEz==}Q{I-iIjw5_+3J+?ge)a!rNbiQ;V zmd-^(=X1twIuHDDmUQlYS5tI$bh}Y>9#u`$rE}>IP0;zWdUSsCA8k4h>-Hk)T&PRu zB*3kq^C_TW&<{HYp%k0W{Q)`;*6V-PbpGI1W9eKmbYAsEo6f_J&63WU3!9>Ihi*5D z&N4EZGz67_2_&C4hi+`VPU_di>I z`-@+RrE~J#dR}$i=WRL{ey{Lp{Os_2I+*9_0(LLY^X$h3k@~#`x}7?9UgpV%hUUq) zzv6UhGB{B_{xzCL`BvR7^|yf$UuB-WQx5xA{k)!aZJY*`X8K7M^XeGqA~l6AsmS`d z>3{gC(M*(?>OlWie1UEAsz0we{>!m=P8mGE>T@=pdu74SA47dScPgZ)eA>tVWZ~K1 zfc1HSKLxJ~IEyZRhO_7um_=X46A4syXvHnOe{T*Egvxk0oK5|lRo~FTz~RTGmha|% z;z!~N zasqK@=+;!+=riwB;(&SgXsBJA4tBdWa&}#moZa_IBWDx8_4TT06JRPiO8{3xclH~4 z$opQ$I)oN$^q~Pgf@+4JK%N50GhM;vx*bCg)1HxU z$cwi=dWc$N(8tmh-bby4>`wZKbO{lg-0B{1iKmYofaK|;nO`YblbR*S;U?)vGW9 zIKIm3n(Nb~VLlb=w`qNF*clOi(ZL58eK7j48jry<`jd<62XDn6@Z4+gyp%e2A_Kl7 zDwT51>0e4Y7dXZ(C={ifJ65TOQOda&T}@>Hs$$p-eyXd!-gx%LSiO-kdgGDn1A60^ zLHb4DF%d`gMKMftQ0n!WLK`e1E<9$oGD!X)1aprQ3_1 zk0jdb%tvwKf_wHV#vf;o%TpG$ceX%LOm^hX0?AUWgdGs%-gZigJ98p3`sZE ztliVo9lD<=x*dpq>d9off~9UhO`l@=c#IdZZp47c#G zye(gN;=$j8c}BH$9R=fx-GG&axA&j)AuiZekta4k;rV9{E8!aY71E@hnYVgRS>Q)G z?lPNt3XA>vyQWhIEIiAbe4CUWkKE&b`l5cLtlD(jPkhMIrKB16zrw|LFZp>8Tdhl> zPU~c1#^Qx&1zsjJd?puU;O7e81k2pxcfv=$0=^oqd#58{{dJ zA5`!dd+Pv(upUBwSL6JU&p~#k+8SVM_W2<_8a{wkgD>GvogWfQhYL`#9)H^G=>B!s zyniqkqFdpCCh7K5^aoxqr!KEcw?W-r6y17QwE^8abp0^hZ2o?)ZUlbPa>eVp%h)n^ z8R2B95hOnrnExZ3F9|>+E25Ks&blAO%{CyerDWW@W^`U%EL~#cqyPSRJPW-)s`7zi z+r8qYLhp*!1IAz52V`M=Gk=cv*H4_b{q-^3j`5dFdvX3RjK22Q2djMIZ9DjD4yhHZMP9AdhV|dDRHShPV_2Y;|X`VA4JI)Qz z`ohqudAgtSeH)MCx}Dk6z5l8xy03XhG#-t9Gx$pZcbZRC{`kLPBzBAr--`nu5Cs8Q zUE%5O%S~=!&aPb=HW=-kxk(^Jna{1IPOCKyd3<=_y9-y)iR7oIE;S#R~E+Q;7`}9 z$Hg#tt?fN+4El>52cxo3(^$>r!zh^yH@w(eE*kNkcA z^fehM5pTBl$L`>lt{6SHrg*>!n+7$j!)4 zyKXN^eg;%~k#JP+Q}9R0PazVH`tmcb+l!K)Y8^NRbiFwF=^2{6{FJAj-QKF(jgp@n z+YHH1`KJmWHF(tWGo#^XT7E775Ia_WcAtj)bZ9t@{Wg3QCqDsmTIvO7`toB8xya8x z=SIp;;eQogOn=6o4BK&TEX|m}(1pGoU-~j+ksk;R_!?*!Irx3L0#(FZeypDG2w)g? zwb0VOf%h4@r&mPa_^SFxJ4a@G>;41iCzWov4L-s}FTz%L^3L zBff?20YG|wI&g1LkL-g-q7O`d^?UIvWZ(ZEdtV+HS5^H#X#oc)%t%qfCJ(6+{3-@S z4N_zRjZPqiC@n+_7!_l{E#H<%lmcl(X~q&5aQViSATDtwfI?)jPHAZeiWnAg5WhNr z;yjBwfWnle{e3>?-usrxd&x`){{Hzsm}ZuD&pr3-=iKELl9wC%B)+`}gDZM`!>!yvb-Zli>CKn!H^BGg0JlKC{$6|X}~Ct3nMt= z)VAO{n!If+7hu2AR=e~8XGDWQixQshzgN+%Ci!k!7b@S48eWimcS|$Bd`H6XFO92i zYLf4O$FXvLg1o@=nI_@wX7i2%$6}&+IQm@;E*^gngt=4`F|9DpIM>96*rF%9jx|%%A@XO<0 zoOt>z&|?ry*UgilIu*omCRpdPxq1DKnEJC%UF;YPGD^kN{dni>g`Ce1xb!^Q@=sOd zR>jdTvfzLtN4K=(<>_DQd3Xf~Z{A*irgmr`E_r4+?nG#5c+ZsY9CNus)vAfg^1sIppJG zkk2N+LP=bll$=*v`pqCNpz%yEoLLITfKx46;`XyR%1OzQrSaUX4`4KSlD>TenCflx z<^Ol6ac!=o2hYCT($bhyNHj?O+Lw0|1$Rp|O3XU{uD82^4ah2&rT=>4jiad_Rn?6d z7203L<}j@^_557-bJ&kYjkl>wY4n}*bv%5zFrng8cUoy80?Abg4dVfNUlg4@X*#s$ zUTsodNIE9P#Hd{FZ0yy1J-$$TQvRPQ?8&D$%&tB8^v%Ye)Nk%lUHp+#zRe zH<&#!Htg6FaF+IDnFTJxjx2^9S;{)ogtjB&Sq0zF-2xqq9v1|RUyldF?=LleRl2Ro zjx=d_lj^mYH|kdK0`)ke+f~-RJ@OJ;yB>p?q{pLRB-Gb3dJL7AR*yx6qFW#MbmjFj^ydRN`t@f6KBr6T75|L>77 zE_J6uZJ5#J?VmI|+R_ND>4248>ev05I))4i|1fT3Z5HEm>ariDeHbrGgtC%#S1kJG zR})QO0hKk+)Uv?ul^yK^g(a3>oZ@pN7A^P%LK|IvMI~ZOGKFWEJMp~T(dr=Cj;=Ek zh>}&Pkf6b}z$u7-<@seq)?Ke-;?nFd6&>+w#C*s1PCSgq;IyT(iuoEBsR?g}GS%C= zO4PcD>-uWzw|$y^O+0M)I-f}4GV2?7n3OY-*97Hv4S^i8?K^J`(F~o_0ZY}IKY4J{0#B^B}RPpn390@mqk2dk~$sltm};hD!-b_8<<9G;(PH zHD2Cxn1;XRoWnGTpE6C5yIS?rn|n(K_{aNQ1>KgnQ3Zytg-oVi@SL+G!RvgSljQYt zga>`a*@iflXWd2cGb>(&xpXdWsJB;eom&DJPqiwr`n=nV^Hk%o-=^|kbI;W4q#wE< zbp33HSwDN*C%x-uL+#Tx^a%MjcHQumeuS5?H&yLN`V45N7#-;zS9UcBF5?WZ`Fa!d zRn8rv)RwX%%0Hp7a}Y`<&rw7F4e_$S>J~?|!75`t5V|CuhR&s1U3+f6eJg4^ohOdV^`a18rsI-PNMO@+7*~7hYMX~?e%Fcps3*p2uSH@Y> zmB;(csge%(%Z7@6On&N_=XKoM+f_e||4)AnVp_@1OB3GyID3I|AL4$lBeSmryFDp~ z>a`yviH!ezrgYi^NAChqN$2|-PVICWy*`LeOBM#xDN@mov137WI?AP!T7Fk5OJ9L& z?d2c+liA~TQVP}k)bL#w#8nm0HF}%Zq zzY7*@Bg59X!AKIlkYS3>ag9%aT&wfTg67vpzbml`g1|}h>)D&t_^2DaEWAWd5N711 znLqDIhu>dn_?|Ze;`%GDmz#QiJ)z-kWaqdnymbHNP6aP8?}_SmVfDaKw5_%tI5<3Y zeqZCdu%o_F zki4W7yg+%$k10BY$x9w>tCg3Iugt2v)LqZ|kH&9i@-hg9)gmv?z9URtMs84aGI6=F zGmL+4kVyhci31)t#Nf z!YF5U>U-|&R017){8e1zXYiVD=6oR?;Pc}|DlUuyW#4D6qV z7bMS}3SOW*M|Ha}c^*aEYUOzldkjEExh(zH8yD7U|FD@Y-T4zmSCc;n*gq$3Vm-zw zmWj-CfbukUj-5m7gn7Zu_VLF!f=f(YzgYgU>d*A!sSl1yeeg<1jIS)Pr6r&Hv5||= zb>$-(u8}wPYV2KEn)~IWC;a|W@+Y;+ho#|dLchE$ymbHNeg!X3K8in5^jM<>+taQz z5r{{FXP$%QJ4qFt_2k1E-j;y%hqj(&8K(ljB2=>G-EvDi=+uN)oXd@1@b>s^q53Py&kV1cr31;JTHL$xt5)A45leC zkD=!UqINs*06XNe^xv1EH``I&NjGRbjox_k0J0MBo%Q7Ja`lGwre%jnpwI)Ubl1e1 zKmqk`DiF^A-`?oxPy--}4yDI_py*@dd_H~=Ih!_Ln)4-Z9?+@b7(ZseiP+Eqz5 zGRCafn>i#?zhfE5UBUZk*;%ZR(5QB$J2ak#4%O53hj?rWc%$>HsD@+Y!oUlot6T4j z-l*wHQDC?TTe{JH@J)^o_~<(N{h7+a^H+QE?a*)xf2PA1>$+7vzBq31_2tcrjts`P z^gX{E82fMXLDXwxA9NSwz?lGGqUKvjp6`%O8L~JWkKRPOu~e*AZX=)0q4-XwyPL9} zeAZ#QnII7P?9h0H=8da1r6D9bl!~pr79W6>F8f?2=g((#`c#yIz?J=uJ3jLrzvuX9FJH0sLeunX=0`%uvkVww zJh|%?{zf0?YrIWeGrTT#z?EM8?$dB;*YDw<2if^^L+nw!qMu4T?=|n8u386}_oD7s zm0~DjI;UR3$#NZQVo4e`VXK@^jv1TZNPbO&`AG2ojJ|Krl%98A;iYGThEqE|i?;;P zbKfI^?Pc~lg|F#{{)CsYmtJ~)ppu@j(QhE(a!t2VXT?>btQA7b5JFyquC$IO&@oL3 znlyaFnPzMdR(K1M_aO zR^#gHu0~uv@hvqj6F+(7i{pcQIdSRae6%>O1ZPq{`ja;}GC@kYez9BkXZoosAMMB( zxd_ci;~K89-|W@M$DlO#%SYjxe);s=U&^cQYLbt%hBqmX!a9}s?csS~hi(^?k9Mkd z6?jaYk481TpnPlqY+5il=yZulHS+Y!duSJnacSS#yaf-=9YRE??AOZ}B z1M|@|u$v|yy(=gm&3#qT!_c96x*hb4*yEi)t8ShIw+W~ z^)trzd^{@D#Wy!RQ#nXxgXG|6hXmu>S<#QN|0cdNaxhIkS`;Gr^3h?zW4e6w!H|43 z_djarEk zr*`|%e@BqqtUNeaZW=23@!DC+5aJVO{{LuiT#gu6&;Lt*TzBoSSJ;PQNl3-ye^)yD z<(blFpMEcWdNiEc=`*r1h(2e9*nwz8Kb3mrr4QpbUwNlglD;PEj=d`mJguaS)Nck+ zNdVcMy2jv_6urFP@x9bFz%2CNY39W~$7Ex47_v;27-JD*oL^;|fCkeh>_tUNViu># z(zBnqOV2tssk=~|k$NLHN^uiXRF(+H*=Q(2VWB`9mVuf%v$*|!*CKTSu}opQ+DA?6 zb4;yc;)^aF%y)(kj9;d$f8exL?rRFIQxJSW-KBGyey6Q}oB|I8xD(fe%6)jgR@`jj z@=5txzlO)L^Rn=gI1cM4>bJ0&KOS!nzrWNi_q$VJ)#Pgt4R0em$7SKA`!A0uc!Bv^ z?rKGcuzanEw$2Ifk7pT8c-7ZXjN71%g{T;*_UyhxZCI9;4jaujb`=P&` zLyE35)87tIK2U#;-?vKrEnMNsTc!T4!XPK>Z}gtp_4mlX`t>(4>-yX88Ap)bOzCfD zQGX-T;9>OF=#l5S8AYB$e165+i(=!w;vBiiTpmP=eGJ@(W-hQuF7U~Td$}$;Mq8`* z+A*Hfdkm*Kr|pP~A&(~S(O|{?@x2%RVFJ7KYldGu`VF>RPVVJ|Kc>d)?5iE&lNHcC z;5IXkkmrR2kGtVF|EX~wwG!iQ|ANv3Gk(J#bIy;+M=c1F_Y`OKOjdn1)j!cn4b<5W zRuM%2T9F%d^f~Vc5%8-O^zGm!109pX`wth81I z*O4m+Zsoxqvxe{BLWDapk}>?!d*1lc?% zwz$@{`-ErV#n??2^rRjhcofH6Z=bW`?OwgRRAi+HgPJ91Ez}sfOT15~ja%GVdiov+UmOJ9cLJ zwElV$Ks@ip*<47}?I-cs=r?5(r|rrG`pEN1e9wIXU+UY2dhpPC)el^4blS(y3?x+_dN|XtA zk|mkw@AFFYDj9 zc+Inyyj}P{D6p|ez*vJ~<`Qt#{`aeVLZ2BltRC1@$n@d^h9UWHLibC#uk2UkR`WSY z(v%)FI>0mgWPzNK`-p}^8uPO7;(MG+ihWfpAoV!TkYYWNjaA9v>+IzV-`?#1jIBKH^V?h|M# zwa9No_haB!B@g4j3zdhlRpIhblxBW;=nucY)ReDX9vU^gAbIFf@B-zb+^_HslZSD% ztyUiTx@J`#4qd@GOyg(t-0*99dFTe!C(FYzego&oL-A5Y2jka`UYmH&Ywk~jZ&Bw- zMbQV{3Ve$>PpbZ5^_7&9;Yb+)Gq4CbPwK%v9Qo9KLCI%_#>b4;BcI|w!`B=A@H}sw zIjZ59IMKihqn|t96#YHvS9vb|gLMwR7EGu^ztKw+{S5r-@qHdv1Yq?1ScisFJHN*b zzW()(y9VQ1x>(_B`XPOIF;~?7OV&UBx0msu3w!b%y7Pi(9pobv1b^*(!ac#(T?%=f zTT3@0fc38$zuM{f!;gFE8P#xR!2dr4@_(l<&U5*{a>o3J)$s6N!!dj@;}4Tp*Zz+i zeEs~N8^ZsK{QM`+c~$a%n&%R9=uW+S|6kJ0yW-hYFe{!*@B_Dq>EXM^%j7fO@e@ag zqjNsS>99l2e&_KX$Q$)FOQVO)lRRA!;-?p6GuZDD%oyzB4n5tqXhFu=Jel0hp;bG& zB5%{V&nr3^yGR=GQu&Vmxqz(T9sLC!UWoQ;XC&O)Kit%p* zdr|v?NHKI~!DS7ZabMh5?fi$SU5#n{iL?2R@0~bNPSC@q33mNfsipSw_iFnwb2;sv ze$01-WBQr0-o(DAtK*Ul0rNYB&nf<}ub_U-{7z2aXXI%{Kzztki5*ESDSzEF)PC~g{6@B-tetZo+; zHND_IZe#>NS2-*ik2c_Mh820%lQv3$813@?}%s)91GS^(Ds{n2dS! zvony7_~W7S(V^i5$wxw(`Q@V_{Qgo}byL$kL%ug$K5`0PpnQzzc46`n|8w>7VJ(|g z`MB%jkdN{OYFxF;NA|I*8;T}|BTjnA~4`0Bb2(WJc93ChbJ zBxA6O`s7(GeL8x(Bb0PDDuRua{#*5D`iUDqG}JO0x({~ZuSPCH*BuXQxJKUCCGkgD zED|ZQxnDlI!|yM(%l)UGCy4KHZj zaoiR%2IA47+l8$=?nc{M*BwtRg}iFGLF5qbg7GbW!Y>EL{+l|0 zHy&wo4{uv7Z-EjNz;UArE$oYXu+97~v<5+%CV-tReQ`GW~gIyD|aaS?ICQGTQN zt$CQqXvSVK? z3z#FVL*H2NdE87P9_5W=J&<1}1LG9wEG1m6!E7D6V!_AcPHg#BGS3P_p9~)Jkh~KW zhIwWkvXnq?cK3(rLrd)6y6VZ{i7gTR>^Og>a`eL`UO9?tIJL`B^q)cYIf)YxHA2s3`t@+Wj7@PxsQP(Cx?H zzzeevuD&&vg6I@xANnf#3D7sk|4lxJtY7*HtgYFUvsaF6@m{-#eKqINpJLoSLigz*qUm zKa^I=)^Dh$$%i_g@)X-->o=#1|Lsmav#ggX>w=o-*|^5X;8MN(ydUcC`t7kUHLd_S z;dP&a&HQn5WBC20LDh|uB2=?JxbQJGo{j7rmxY(^ zznoR@0^`+D-7YMzivEkNt8PDM!zr^GAKrH+;=_o>ubMc(|Gb6qr-?btx;Lj%k1@0V zxXlrF5{hPA+o$xoijGGANJCzpc{NAh52Hh)%$K@BCCWVdQd?QzIXBv)Zp>jcJl&|_ z2kBE?q`%JVzvZ!m`5ugeu#5C-YTZkoOc{b=nWZ2vxhg{kor#{QR;+cU`*eTCpU7bF zkE!#z>kd{!Kf2QGRo_1c_G^msV6VqP{;2;ZJ{qcL)6{XVS?smBGyDKRL^O&UE8Jb#4M;X4&VT@6ml0+)TiFj$-GT4m5G0KMmOQq=T0U4aH6;HC|@i z^MRAtqiOy8*I-3lJ6-OaDc|eML44ozxPz|+l$7R!@58#E+VTC{$zFVu8jj(Ifj2$h za|T}@-;eogFusKk`T6dROGsz09XZYAyUqi;bzdHS*Ka4eJfVu=H=ioyrhO0o&B4dV z?{kKa7%7&RjwgCA7%H1^E!RmFi(pM5=!_KdbHpG2RG)e7$Vs%{WaLPJwu!JN-Z z=E|FG>tSc*fU%|Nxb8Q=ZcP(^d}NW=4`n}~@SlQiA$7_2oupf3UGm2TheR}ej^FI4 z=*M42i2Lfp!TXsC;rvkJnGn#naN@r=5Ia@_y#5^yLY{^x1Uw#ghvxYMpW7U;h1#<7X;*foGG} zlc4`y(0`9pq`Lw)QI3b>u&or@5gJ%kSu4;GAm{ideYM)=90hi6iOsjo`RBY#tq*Ug zQ+L(4&G{3LIRxziTA3!KG*dmALg#O_u7m0J&?ibF>C5Ct)2@Tb%xs@?`3#pYLH(L_ zFj0M9fISG0W5(t#W3e^p9Qg62s$XNzER5I0F$HPn_fv!6_m>)Xk#1`8Q%xFPke}*S z@B;l*M7Im`Q)6gbZ5-48u37a{N4yt)s$+?wYc=_)zfRE!s)yAn-tmZ|1Z0%5y8U<; zDW0zS3tHy}e(quRdoA)Bm^V|oOYvRV;mQSNrLns#z!qgWd=W*97Cz~wY(L>H^<(8C z)9us~YSpiLO&8)EBXH_^lajNYCJ)DHlg4J>e;Yv7p7*eMPJsM8!^ck5KM4z)B2&PZ8qMzFGg_87D zOTI9CilR?Y9D)2Gf$*WjtSk8x!-ugr=uZLFM;%FzD>=E z<_K0f>T9Fts4wg~Mpi5f+dut~L!AytPiDC0_`|H7AJyZd|2N<9ebw=Ojn92IeKbwe zuZizNX8?e?J)RA*d*;Opo=*A6V)8jNr8B!#c($2;H4Si$7|Rqg}r)SVaH ziQo8ZC@IEF7~{L|0- zW(~f6{@)dhZ?W0We}8=F@_(9rpq;u?FW>hg-8>V(h{n`OcGc_yZP$32{Kq?f;)poX zng8|g1MP#nQD3t(dV%x5eS%r|KG4KH4z0`-aJmoYqAa$@@N z=cgja&U{Vqy4W6Xf1Y)*jOx~JbTW9>RaI2ik9QFxpS9EJ{01+b^6ysiVDLBarnf`M z1B2-FvrUd}SwPc?LwhRvskB4hvh(D1vBT2WWLrZTeeI3_8bu8C z(&VWhWS*MMgAa^x0!>QfAoU~G!=ez*ReLJrnJOuL*bO0)=rI%TFvr4S{ZO@fYx2Xy z@vh#Q?*O#=ymZgn>fxr3iG@@5YxFjBJSf7_4h?HKM!r0H9iEpaUl*E(BsDw}zgnP$ z*a@t!>62#uJfuGS{!&hLQ&T-OcbuZjMlu1Hg_rKX963bL4$MQ+x?NZvl0@5T^N`{p zvzmuo{buAL#doQ3)ou^U2P^;Q&r83P4Ymh^x}Tclp~DK5hb9d#NFD~InO`2F;rEyF zs+*eRVf@%|d59kxE)V^>U6?#{pl!ACkUw}<HRGgfberbKMJoM;( zjJ-B|oH{QZg|<}WrQ;wNzY;N2MtZ9AiH^C$!N-@E=H98s9U!06wap- z_x=OD_$D-*+T)Od!PjSp4jK=}H-D60-Ye}8`0dm~m!NKleSz*iX=gt~Kl-Gt@rYq# z1Igx@b~NkbJ^N&Da98CS=hLq7shxh;9N?v2M8m0_-_{X9{J#CBVETLW z@om>|YUlTa!Pm#{H{TMBZ}F{ueplKZFTW@6hwhQSeEXrTH<4VP@@D{_x46rr44+4y zR`n)RA8FTk!Ng2j_jHu9JAKZ&%P;c_u)-1Wq@#zhWE%2+)v5)@smxVWLh4=3hy>Zc15&M=K1FTLzSQZ)n zFGa_irY3n9ZwQx%_|f6=(68Ht$wLR)Rx1zrd9x}H ztM+I8d) zLV1+e#tr3hA>BebqU64|l$5Hsx$CE1Q0u4cqg|WD#jBYfU8Yw4x%5Ugep8ph9da3e zE6cAwB(>#!{t#LRCK%6rl&LQdYxrzyzTqT=#f6d|} zIzb^8Ce;*@*-O!u+R8aUTOI_LO{U7~3?bP-t=2YH*o(}VPd{sw`zDPybu38Vh!-D0 zCwk52Qp67F=e^bTWAd5&>lJ<2)_lkJRqOQ(&kOFJreCAiQGH)cdYx|y)$8#?)p&#S zI(jUd`Sp4*{Qgph++W*%?JViY^Jbx>_D^xB+T_C0@Pg!GRKW|Bi{k4P9m3?IgtpbnMPlx(%7q<+TqHDpQ^e^` z-R>PGPS1~kQEH727nsv5m#yQ^hFMmRb<6XV_U9S2|NVMLKupC(+5L%wXCNQ(<3r`6 zU&9NMkAyVy+l}_{`%7unO-=DYM8gY`kDP)RC?C0lrk0QRyQ`NEt8P~1!2iYeCcJy z2@QH2^w~ji!ZdMt+@3$P^(Ny7DEfuDKbPNM^;eC5Io!8y zIGLcVRL;+S>FW*`ER4aKpY7BA)Q<0MbG-OAXgEf$4ZI+KNPOLM49f;zU!8oHYlHF4 z*8Az=JwLXt-<_ZB^A^lI6@gBH#W;PxA>vG9^{bC2=5#d!YlQf!y+wUX;DZos3b+@-3T3PhsAXlE zHq?Fl)aYIj<*$15I0EUzTOX;d9&T)brQrg^OzcC{=yA1qh3R+fwbj`NqaVbN7xNBY zh~tWK-ubosu%)Fqx(L2G^$cbzK-`P@{62Z??0$UgEY|56{j%5?7tb}%vx#gWI6Kb$ z=Fe_?Rj;{!wYp8@g>SuiXA>JqE?D>~A*eYRJSS1j!GPE5L5(($sK*I?naDC9Yc0UD zSM0_IPs(@#V!c0kTxgU-5)56T;C}6bu2M2La$pUN7dasv2Oh_xAYYiXV$aM7Is#hJorh)m-M5W;Btd*2EW`Kd zemDKTR=+Xw@Xof>Ka;6HCI_C39+fSA>(}#u!=`9*P4O1!YL5!SK2lqYUaQh70H_ZU(UEjKn`Xo<0_M$Ab68_{qy68QqoGS3Dn;7B&*E=*I$Bu`8)OTq>S3 zJ7>iQp{-6X_elvQ3U51GCcq1;fW25$bK-YNNaolPDFC=;#2AQ&MZrEsgH_G~wdVCt zlMJb|Ns6+4>mGB&0D8g=`-OsW)BFz7XJ~S>-Yt%qu7qQ z7=&_uSTwF8dk@@E7s-r)?o1uJ(%yK7@Py9sT|(&m#Fi?@|K)ot$FJk6!12d%ew~E1 zew^(~v+nqH`#}F0kHb{>D7V)=Y>D_P_Zk(?1@~(O_j~y5PQQawwoe4NKjG(2d(xB_ z>B`Hp)_q9SvuI!P2-(Sa&0Lm#+zZbux)>S&nO8P9 zZ=dwsJjS)=nwlRwHihzI)bQi6+r9j#4(|8D;pPn7FZkf*=PUUQwadQ%k3daxO+BtR zhWDR0{qN!HzgzcD`1Aw&=)aI-<~hqhM@ceqKHe8c-nUH25c2bQ%Tdq5=oIbG&Y7$E zUGITMn3jeIIdb-~9YHxNsfXt2`p5c6=amswPoD<7sD1epbzTQbqi7%f{5<%v@qOI< z&5N%W{-N-nap|KS$SR+Wd9&vA1<=4g`Dc5YIsoCS05sC+fy+GQH5zZwLB%Uq;fo4d z6vp0PK?|ONmue|u3C-)o zY-OH-45IVTb(NeH#&0Zoh5>w+2@}GL#l2o$xNfhq$}N^+XeYw;$r;ag~D3&E2n!)okVDe zI9~jCac_mcm!5o&W|8O_)C?C78z&{1d1deY#2qy?#Kn}4xSe0)Hcf%=cqP7Tu})j}KNY^|M}cpwbE4yC8XBy9|9l{L0`I_j%=prlOoabCTS&>-MBQFAFb$Z>iXVWr$H{ zND29k_c?Y#pU+=WPnwHzg;P)Jzs#*CmF6jWc(xN zm4jnA6ycC)Dy+)WYn+O<$3OH1^y{%F%a?j}`}nYai;<21yNamHbl&TBPD;|WsyM2& zXSf_NF7$TaAf}}cUFnT%oSlRTZ%bjQCDog~r@yDnxWlA=fQzJce?fXpdfV%!nV=_QNi}( zE)QUPBGSKyqC5L%zwF=3_g?hxEUY^_xc}2F;2=zyC~B9UCq{*mV8k*c*ABI&_646- zF1U}_6&y~9tNW(QttMdL%0)X&A-;(0swY@-yDNOsTG`_@~CM2;wN zvT%Z*@;x6^Qd8tKw_0k%-Ri{aF5;E<3DIsYS_uHpz z7(I*r0t*dUTkoX}mf8>Npb-tn*Z~XOlRtRY<$jnQ!3@$xn8)sox4|EvUA>$;ktu2+ z?@H&Qe!ilqT%;4>*aJ9DV+#4*-^*$^M;;nmvUh{W5#FSY-8J}eevOxoCzqeY@s&6} zeU=b{25~hl80unYsP#J!Q~Gb`wAYrF0+C_N#bbh1Nc~=5qk|u#1yj&j;@wYp z@#8@-kP1~;bMbNK6DQ+yw}Vf~iw_x8vTsG&?8m1ZKqt;0F8?U-a1x+XrlM0Reva2i z2rcqsKWF`XaluQEy!}7FcltN3%Fx5qkj(xQ@M}Wq2G5guNT&NfWQ4~|w=O#b1$-rg z1@whbcd1dkJjH5X$YR>SwI~F*0IEFdfLaytw%6eH)no^xo4#(N;$OhIxK7YN7_Y%-$J9MlW83D@Bsv!S6n3E{V+kjO!X?#}49hDS?8~yh z`LM$oN~-fwA|*y1OFgMze+y8R9Zbx1?JVKZeh{{avzK`FVxbp!rTr*%ewbtA@!`Mm`fn=YdU!#t zh(-}~9Gsow_RoIVKWT6Je_8%}OfZ_-e?K6W0w*gN1dZiVcHPqW8NKr0r}Xs^BD=*` zgPCajsOT=jS(?|=QBYfEfung^2xu*h)i1JlIS7F53+ZfIN(xc7HJ2T z?MDR|&33YbrBQ0#7~aJBW}Isl_$JGHByOOzskou>BV>*&Js>?GV?WZmiLHN5@Zb$< zEIW#{h*F|C*9o-j2mh+_*@(v5=nH<6i~ji}ytMy`t-hTfAcIZkGB<(2g0FDr;tTcz z57C1~#v{|y;bIwkw>V`rKRnKFvZMHhBh7J>IVfu^M83Y@rNh=RxwC` zWfvDCK{y!~5`S!Yz%iCai>ILTD<6Nna}qwY5r3q+lrKR-VrUT(f9!X^Ll0wi4LuCM zJpN6squQeMHDCU?k-e7{f547)7(2GY8{UnTL^>BkF=gknGF>@pC;TRNEJKA0^}vER zKy%Nw_%#O2v$>EoARIQT3!@6XhU$*tjRn<>+fQNw%A>U%7?oZB_`FxjzmEu>Gw|;h zOgJo>MgP7YP?eqOe1Yrg+*<3)@b8K9$cq~Nd*OMv|5^9%X~F1a`S*mz&*(!{{yqMQ zs{MOmyE}gJ!P2~#+P{x<*XrNn=aV@v-@pIsPs+br8t)+gK7cVy^6&MZ4EFEOU?v*= zJzt)l4$8k55h%blY70l!kE` zdm7-!#lM^eMmzI4@AMkLqRF?_rZn+sP7aG0NzG%}&j3dqdQf(h<4#P~ujDDGqhBYV zxX8NuD&Y`Bau$55EgzC9_5kJruLMkGFB_lr z%jwIompz~6xB~6vy>7Z;9J9`c#{TX0KkN1~D;QN{FLCyAa6Xj9Q=Um@Q_n2_OW`Zu z@gIFL515MqKpY(ZFXwQM6~Jyvz&I{4g6o_K4aew%g|_5dXq|H#D4XffHfM_G zWiuUueHlX;AMYY9x_&(P%oOxS5&?S0opWSTXxKWiqi*H#_;=1q_MP2Fg(`ua4@W)w~TpV6*<^qAEyUyFp2aaiYm3%@N8JR#+ zWg*@5-lkojZnv6Dz-8eTz~89Uw^+rxi2UuFp1)rNCg5-GDK$>QhjrIa@AINwKmnmP2_uKNW?q`yi#$3>Zr-#XD(;E;JbDQuuhsOC+I zjVoyDR0KW@bL*)7BwP$EbVm%*6Qx&r+;^WBH0}=FFUL(;s2umj7`IdC z{8;$7SFotlNUwNs`m5amtsI92iT4~n!-_xz;=-Oc%(KND~E-)lDT=|aw=u7Oi<+s;z4#n6AMnHR= zrM<=&S1y>Kt~uuq zOE+m^bfPTy;;*SQoC|ssMm|d$uo1@JS7Y+73mE^0qAU5&%fgFvg}ufa3Pwp6qhzP& zrPiIaA2Uk`alQRG^?KOR>$rx)wtUUL-tO^nhh7v?t+&H}f2H;2ny#RJ>vg{~mB)pE z$|2;QRQQvB1{U5be)cX#Pu;B#y08w>jQ7sA{xOW%gRAvaQ$2l;K4H;zm2OFXW^hW+@571yIN%|_;Dhy?=MhY)Wn*)AHPXt!x-l_hKg(`>&Ljc zWmF5BRvHe=UV6WtrwGkUv|s7j_Daji`R4}7N%?QDbiYr3G^pP`-LH|UTJ7aG0G0CD zsNon}Q|TXS^oxC;cg#Q18al<+)V;hva@bj z8e3}-hB!}SWOari%Xt7iaS3?sO*0;rHRfDMq2{AY_JKg0`OXt+{3lU(a9MbXUHA5v z#h2`l0wbX>p)vf$Kq4a*eQ_NH4!p5%`w;ipv&vIQ7}S3fsaw>5zS?`#HhiKZDP@9uUMo+*0*^ zz)(L?kzZnU)ugLZk9mV5H~sv8m@C>(xxrfh&7d;EE-w3*^)Ur|{K`Eeo3uh$xSf|? z-?IE;*bO;%#nCMEk-*7g^DEzvf4JegC7wL4#fp718@nZ&+)$XCTsJ(9RURN{0}0A` zee=HmBU7jP87^1RH>(PmEiwRg@COj!OKKsozr`Fw+b1 zUJUBUaZ3`qIO~Nr3N@5`^Q|ZT1VJSJL>%ggKL;3p4r07;6WBNOiu1L=K?U=*aK+2v z>$O$zHT}x*b!>Ijd@bYF{|sM;|8smD9|+}ZbluD0>$gJq>QTYW$aH-5D0hweI(S*t ze4W6p{~5lH{^$6bUK7gK#?;H<>o=<4>)0#D*UrnU=IbbK{m<}q{FUbG@?QGZ?zN#j zJ!|cr2oVyY{`Cy;uZMa4>q+#luZDB6bg{C*es*ZjNM@VsBQx3Q82PAsv(#s*_NNVl zRr9e2x4zeCvISHyq6r zrsI~^7pAM`S9)F5{L16jS6t72M1B<=eoZlsoUDIlnTzpv#}(C%qd1CNlXy1ix>FE> zpDwE;dDMvt!7&?z%Ap&E%MOM8xvQ<8arY+vgUgbCRo5lL!+tuLNfU#YK_|6#Iwi~U zOZFqHU^?R;HSzf7iaZBQZ#22i+pwS-%Z`!n93;68)@vq@ePHE5_@{Rdd}Ae#J3D#_ zwjyrTTM?Uf9wyZd*_Vh9$cw9{TY9K!x)pHiY|^da$|~q~eLv_{KNZ~?ymV`P<>!tYH-Oc~Mvk z7gkG<^P+k**>vrIFzu6WXRTl=`S6c(49HhG&XPM$%!ADOIHmMWGifT{&be590pnbj znQokFJtuiNoSrmBbAA_VJ-jUWSL!~_G$;Attg+TS2|C4vc*^lp{Q-F1e4F5D)&=Qq zgg<h0E zg}qki72HDNLsk=CoFuDZb*4ews_f3p>rCG9osb-&5ksYFZoM;9C?v|AYOOr%5r(YR z6?jUTV}8b3BzM9Zam*iHh0B2@u?K&g*{@cbHr@mg*|!~IYOWWV5qrH34mALVQqvM z*#KhP`g7K`wLcRWoL?#@hfV|_WvxtIyt4l3l}p)QrtNQ~Fpfuw?Gbqq+d3SX$!RrL zHZhLfV{2q0cVJTi`W3OhvMjQmjoOBm@3j9t;5)LxJ{TB_J!%uuTny6maxD*w#+Lm~ zG}CdSS%*)u+hF>x{5DPQd1>eay19ujrmMi@mxRwS4RsomA z^Ux?;V-)4B8c-5SE5aF z=N)px)7$Q8OFfMR6Uo$eq&eHxBaR5e<2FTi7PhTq-2);)0JZH4nmz;Cxj6W{=ex}Z z{`FFFps7*fL+jp1T-TknH-@$wuqDYEJH^&SFb_{m$;vjoB^$?av&+UKSMRC!-%M*~ z*ONZ5v!lb+=^fLyEiKUkZ)g2|-9-oqR=i3b^%}JoAf2I|Gnb{`c;)v@j}9Q7qw|0f z<@Bl&RC?=5`B$o`&t1ZL6FFU0PFnhIW@56c0mY()87K&qPH^OCyQ2MvpD242biN8v z_2PMmgQxOu3eSZK&kDbm*ElrXzqgE-?B*P$W;;Z1BU*H&6BWPn>;qor_b|VVI7G#% zzv0aoUFX*fzc4^|J)eo=%>1ZD;JDBvl139{FFEnD)9cGHNP+De>$FF|bni*QwRMH85sehW-XmGHt7QJ5o8;4k&C8O1{d$3X-NRqy$2b(;%Ggi-dUTl!H#{+* zJ@(Uik%pSbvBy;7=>F#ahjA2POUzYyu35$Tj~BW;uqd(P`aD@V;k0>upE@$BWPhsL zJ+!T#u#Mb#_A!gx2k)Q6UJ_X*)8(A&R9(BTIPHwx;QAn5kSi6JUdj)^+;f&%q3|s+ zC~(3!IawcaK;_wI=V1nKi$HKeU%cBbIIE4sWX&V7D}KvgAwH!BK%)|%muT`@wIBj( zZ+I3`)IRrS-;tzTmST7R*rmUPFL-(Td7Xguozq4aBS*Bk=37908K5N2P*8kw@8Den zycWQd-a9>m8m=7FRX5Es@l#m7rSs3&>T7@*C{u19QFdPi1CIT!#M@`*_UIA?r(Xqq znvC5-?c8$=`>F|#mI6UImx8fF>*no*k8?@ zMoinM<*fI6WvJM2UBwx612~WG2@pojZ&r@W%iq^e&0mk%5gy+Nw4{DO8Rz+Uyd3$y zo*(?U6>^ohdC$i?kvOKC1&U8z9KRrOPPPDssdS0-12yv^k$6*h7!HPH)jokrP$8`s zEcm@SRWNQhLQOq`63_65AEKKE%mZpD5p55!j^87?k$L3JunW#xEJks`}z`?qO7&RQ_8R$~L3Tw1=O z3x+c;@OzJ7gYY?(zv11eBiZN$aR+hZRh|7j1G|1)I#%EAbxymQ>~6<*X4CGDT<_Z5 zEFg0snqzmL{K;gyTl(It+1-P`Kf8AK*FcSOSju|_75{FPLB&(#w~>Fo zckIF$_yh?wi{D~v--Ry%^+2D~mFt7mpu9oo%r1whU<0%y-`6Yg3XR`e7QqRmlJ?LH zT_bEs9@pk`Jzr@r9RM4UoGg$nQ#Nx!GKV8Ly!{pw+7YL`<2 z7Z*ypc)$658)j-TxmKBpsD#h;*jjim;R+j)M1)FTUNaJw>Jlk>>>5oFo(KI9ZQ z8qhq`sQuT-uT(!lewh709;7b42&^yXzwh(GTyNj4+v8TbEc~nZ^jg@d;f$i=6!^u~UX9yDu`uEdFMt@2 z#I72`cfSyv56!8+g7DqR)P2BctJHCcblukEsuzgurRU)LiR6aIrOvqKk(H-V;v=FiGspP8dBwp;Q`9vvp0~qiq2)Ka)dBsljB&!Q# z+A_K3{@7Jd;;SklZeZ&Qh(GZ|ba8eOZmSafM*_f~s=;; zbFbl(*4%&TqN;kk^x%q~WIc&9RwMB^`jg)PQEma;#_SarP=C2_jNHk=;`b2M}p8lj(P_ZZ26l`trZtVNiZ z$!j~Q^;klwQ@?KNg=i(0rT=>E<^F+&L#hNGn{WVOrN?hk^f*z&Av`?}$Nnx7+eT!+ zgkNb#U~1)D&c+*wG`CE}?fYTHXqd)jAT9WQv19jd^qZr#U!(Ky2QcTd^t;-}@qPdk zYpOj_>JDQ%+9wOpA0aF>9l4}qIxf8gpYzIWJPfn3^3xvjaqpE%cgq5`Ow zCw`!$r;$?EF4zCuZO*F#ctiMSz1LRrX8f*$>&ZscCpZL zlWP}?YQh1A@llcGwdhW44UA(yd(_5p4tDluihkqBl+QluE4mKIuGufI$@WAYb?pXJ zm3DCsz;vZm>z4!PwlBjj&8|&SsJrHai?Lp|O$q|)wMp=tVq_ZOmkmF19)2u`-S0|w zjw!h_bmP29cs}#mbEeN{p8uLRpJ~wWr^siRH^o-pgpMiKqqhdib@2v;CxlBb3;*&x z<+^|-VRAjD+ciropIkeB@+4i{BEB!k#Vf|68-*6YP$&$MI zkNfKFl7Mu6QAh1%6}5vC>7aTEQ37Y2yj;z1bB?yMUNU*zR)g+0fAiGy+og)%E9bX^ z_(Hr){%`?#()5c-JPDi6#dsWhfi>kcHtrtV!su33sxaSb3h-_Lj{f>F9X)48{8SY) zvBx#k@1S~v##ibx2Laz={cSWmzGtY~TQ8l5BMLO!F6a3%78~P|B$Ut5m9-4N!I~7T zpxAcPu2ffd0FzWz{OOY^Zb^1D(b4Y7XlqG?-8r9(04jkm#la# z5-ge9DpD3$*#ntmO@`VrTmm~-6t=m@gKJb$OXK#s!<=p9?Av}M%~;K;zZkqsr5OBG z^N4!ANue=Anqg2}l+NQ@e=n&PEFAF)^m(%Vt^W_$1XKmeNGR@oMZXYmQk~ZFTY;4kDKYP z1hBCmy$b#$Oin;^C(ajrD;2;^>Ko#FEO|-opddbF|6zx7pco_g%$SxOJ=|&PO8@8x zwUg0L>F1T+-|np|RR{Mg;c(*y?&oI!_ub)e>kZu3```wyKRXRlq4R^DAG!9LvPZ+H z{ff%d#_)wl0b*;JqtMtm6WY$XP3n0YUV+dD>r&VAzXbb4CI&E3x!2o?!JB^<5&a6yS&3UG~hkF9yXQp zm+LNSfX-u&n>_QOXyaL*uyctJ{MQ#Ch-MQ0hR>-9Na%Syq<@UJ(ahg1g!-u|!gcNu z#`z==5u2%X~R@dK*7%X(>!(>5Bu;jADJG{Cx$_yS`E2NZn39 zC*FNd!a~r)`0LnOCQTe>p#w_AK^ynHFVbn5v$2#lu+BSM{hAlzWr4&VJXGOTxGCBK|)6^H!ion+STR_5GFoW4zPY zpBxCN6ifv=e*2T4{rT&Olk88u?(aWte>yf9eh1l~p(8c_`@f^;XY`!(3${N=Fk)8h z&vh%pghdqN#I>|P6W1%eg636E0FI8m`5Ql=EZB6Xiv0)FOpvJ;q%|DeC6|SN55db5 z2li#M@Kp!|vC$>nsqfz?cPn|)b_p&J6-UmpICd#Ea2f9N*rp3VE_NxuA;c~<8QXDt zVo#!7>;~F8+Jree{dMpvd!w?6SqL6-(n7SjzS7jKGmS7eoc!>bmfNmv_Km- z4*pebuy#rsSSZDYiM5|Q9u5`U_AH-knpJm>> z%WH^a#;TOw49P|eOs+R>!JuIB@ldmNg>u>c@CkVCX70LRyI?|+7r)>Lp~TGzP1m$; z7laq}0^=iIEB4K_>lPFoaBy$+^n`L27%?NMki$d>J{~!oXO7@u#V9#&(d#0YUT@I- zI|wKCx;Qcuy5H-p7aGy+gT}|Tn|gf91Lz*jxpW`JdrkK~LwEal(7j#52PnBL{44%M zugAPB<)?e6ref2K#`Q)(SMpT6Hr!r#__q90l$y@Fd^}=2GN#)L()h>1OWL{l;=If+ zfUMXFSr6%?i?0X!UxymjrAI(mvxa3ifn}KTS@g2k(qiNaB&Zy5 z%D6_=9~gk3T#3bIl39CB!D0b|Qqncm{&mqqS?AtlKT{Hdu!AY1iPX>3o!?xz)XI|Q_##Ud+4@gg}dnWNTWPf9%9k)V6 z!4r1@j^Tf^Kv(k4w_bDWtiLIhA0h;`9|QFVRa<-tLMXLG>pY)Nl8|o~)Q!m3DaNDn z>+kFFl!&B%FGk3C%8kD^<6-@0Hug{J{U&i)Uo>f;&i?5J|3EFEZXbx+k*9uzujKOZ zP5hYbOP&DY9^VkOehBn;>b-9S)27&$+~~)KnXNr^F|k>sa6GR;nY91QTT0Mt)4t5qQ66_jTfNAYj z8zT+)v*GbQl64!CLj$x4G+v^3G@OX{c3D7vO4ZNMsM9Y2qIl~rVxH+VrMdNNGo{X| zbx70Qq3vBzoB%XToDf_6MSg%!9h>mUwy`g~mzO2~ihXh9`&>ix*sX0HAk=meYWam+ zazi35g-r#K@QWhS&{uMEBGy!@1OJ< zB0iMXTko_qN7kK!GTpNJig!v45`DQ-lruR86_Vi4`9#v$ z85zPI6pq#TIB~cizAsCtc*LY*05YQiB;CIk^H`j(3yL?;uTw`nfPIQfbLX*!Fp1?x z;q+jcG2MsQ-R}Q!<88v<4KH3M-tMpXy)qsj{G!SWnak1E@gf{TlAwt!cDe#S zD3Tecw7b=3~u zwfvLgBpnP2o}BTM_Bx^SJ-5e6{M|ODEw6 zNrSv%+qF2r&-AtJn#{Ns3h({+o%xC**Qk4W^3+I~ zKrY#5EvKE3C+k@F-984Nna?CO-uO-~u0s(-b=}LquKvp7Lg!asLRyP~mh5X#Cy)ir zC{HIMg|wneP~7FMi?svea>MU^HkNgaQQcmn7qRe0_zBX0ajPDey$LEN?cFz%16jpf z9+oK@)y8B!45aN=;pi*gSO+A!EAtafEeQJm0OoG3OO?282k4^dMu z!&BxksvVccu3U`f$yGbxlOwS!cT*q!DIb1B^%{ELF3F+K&5hl%uqipPrN0gCwgoW+t)!ZajyH7N*>=s!+^`eOZX|JA?F;G z20Y)T5j|dVQ)>z&y9k-|Q%619hGKbZ>Vejw_v6pqN8PnJwRv%BB02CRRPm0ZvTf|F z4eab`1KIkD@dJVNz$WT{6M5Q0?shvQZMXLZN+H-j18JrHj11L=@7PT6?Igb4#m)o# z_;wQC4iCQP0I3jsPty37uJ{k&+fIBtievk`_}X`%Bn-Xn(fu!?;^MOK^6(e&{Zh<( z;Q07~&2umm@Oc@|Y=I`8Mb2zZrk>X9Do206%Hd{(Bp`|!BKTt32k7D3}Hpi#ft2QT8%iY2?+CD;B{&$^i@eNfP!Xw{y zr5n~w$w!xt>n?6Ut+P?Y!mahh)_$F4V&DbXtoMnTdO_K&sQTdAthS-|sDZZ)ol0Xh zFWNSA#$3GFSG)Z~K8_=q&e>%#9Pna9SKC_$?&xnF*Z_O>=x&Sa?$f4i-r~9(@-=10 z9^a>pabLbI^+@X~xJ#O?CxB1e&}nt8$KDqk+M5Q({PG}vX&oA)#cD+yu%Wz1>#D3+ ztVO9spNp@0LYb`1G+DHHT_>h4Xy$VMe8(Tf!xj)Q6*0kuNiI2nCNC3QoX^EF{uCBV zJe|Z-gD6JWw1}tPC)ZsepX{yBf1QVnrxd+sAh*y^Be!@9x%HaTKf`JHOzGF)iN%y= z@WwHvf2}m74>F89tSfC*i`OK%pM;iuE(p?X4LxJ-;?%y-&?VGRXs3=ilv*k?_BhO# zQp*SIb768EcpfmP&fx=m7Gs(SV6y#CX=TVB-_5k$YB!**(PtNxn@UgL^*r@7IrPE0BvK!q#6pp39S3E2C0bJtFFtg`Vn!eP;|Ef!?+?rh z^1MIQ5>B%$cDY6_SMtrYgO`ODR1y&sr=rZd*FPbYwfA_=S^CJk&{47YXR-wxf!Sz* zd6B%VXkXRkOZv?bN@xVMRI!ieO)`Ekm!;ppPOIXe^N>vrDEinm>^~SiI_z>RwZjCO z?3&pB>zBd)tHas;{oySF8h-sol_#RlCV*FFO z==V>(-OdI%3y70c1-LL#6(mwn6#-$MPyL~fPC+kSAe&lW((%=5JO~^_fAL2yrV&Ts z1x%fJ05!)oie#3{I=E1AyS?B8b4>nCo12NAujUwO3;5zb1zx6pGxd2jtj(%*0%7f6 z2by?G+`jW}wtbk5r5;sF`#A`fxxl=%?NFz^p@)HE9uEb2IO})1aDGiJHuQSj!^HSR zOpo-K>5WgYFeIO6&hqFgzEyvf;veHPmbpgnhJi@J`#ay zre2GzCz7!L{vka-Yxw_va-7Y98?TrgC!Y)iKKpVU4en^BavZ%_*-sW+d2wwPWd?Gr z_QPO?ly=;;Sy*$O_y=sdtkw6Qt9QW8!^T%Cc!a^r!i(==cg(ui*xGgYB3Rb*X&D|& z3>PVR)EpXGZny?TL|tD6N|7AU(CY9otq#&TJSXrm#NA!##t=Ms7Oz@46}Jl=zO$nm zftCHUvy`7KUZloBKVoQuw@%#}<7qPc2;M<0ohbdCeg&(-)q^h`lVUI@h7+bV?6HeY zfSR$i4yXI3=vVlXdafY-+LeGoV)6{c`E#&Z3=y$$P!NJ{fS@@T5pbw58 z>kiiKQlHRH`!OnTKj0gGX73|);Jy&}>raHhnAv z;;H5d^G~_)U@1cz*!a?uoJ?A|I>dO;_Mix{)+ke#(xC@e+Bga<&L64 z|9h3(8edkGpKo|J)Xz^`;I}7~XKe?n^7DN{$Ljq27|;mw^T`lAynepi?lTwS=kHmf z{Cq^W5AyT0kS{T%3> zLi&z1CY-J)+ZV%dyllIX4zL@GF#fJ1V~1P@WVydGIkfP?#dX=_&@m^srS7o5`R+e+ z*2cXfIkd~k^83OI@jH$NvA?kJ&pSQ8ANx?RWph!EvU8Zn!F1+(FfFxZPV(5NyHfAn zalt1N&u*UE`yP~mMa$Tv@%CTGS!Jp?-8#WZ{H`wtm z%uHgf!D%m|1%WKT7tk(vQ`!&zA^z06?U{|}T#ZO~vi#a-HVXaP)*X;sw_Ed>&1XQ8 znwK^&X*>4erENp|zW4N&b%(a4^3Ch&W0&6w^xKBs694Spu;b^wNc>vX{5iH}3%*Yt zduQx&o^`bj@#DtlHuU4VVBc*mdY+(p-Ja^Z-nYeW+0Z($aTm;oM7x?(Ct^f*^6&Gh z+y=XTLowd<28;+_yx4l|HvBz#$MQRxW4G+td^=|9QHVaN4)X^1q76H_A9!)mp^vx3 zZu!n$R4(As`x&%200;p3oR*{h+LrL%@vf=UFnp0cQ%c5N)%>#cuVbSg{G!I?2i}Vt^<=kD_ z*9C7&rgDVX`&9*9L2lks$3-}RzAQOVtgC>}GvKf=Esm!4`$TvZKT`SD)K(z9%ZB0} zU2jP=2mw-g&|+@aTOtei5i`R%`@c9A6kY!&(SR#o%}bUhQ@>8G!=|N))4_}6(7wC3 z4ehdD>~fyg*EV$UvJ3XcpQSGzb-yB{<_j0pj1k>qCt?FflYRBAsSVF<6!yKww(yO} zNAtS<)tBTSsJj9D%aVTy@NWzMKA*~O*yiD1;>E?s-iIGL6#sT_#rm$6)T7ATLDqSD zHb1bv`Oy3D_Dg$`s%!4=J+rGN6+P;Hz=cNK8C&~dVOzQNzVe#;+fuvrwvbogQa{jz z{0X0$F`1Uy2q?SE9eDhN=G`A2x@-=?;hTNuuDSmL3p5*eeqQfSTaO?hfFVx=kkZ3u zo+}52U;%s1zDO7%@E4_WK*Yn1#EbaK!;XZo<8)!i2Kzw#P2Tr>GWFVR-xhj-{%5qU zdsXW%`gf}TT5luT{pgD}gjVbb%)pmlb;-fWb#vO*zaHZ3lQL|~HaeFp9-H4i3VYP{IJ75NJyTDG!MeE-wmL3b^)TD#zHK91sjosm1AdwBg?ajjrht^BTeqG zZxl`V0cndCy$8!ZcD!xP#Q!7jTj1lW>imaNOL!)zNK}LiR0z645XB&fDYWjCrWoWE zErkefjrbt66e1J|6eOV*g7}E*it#V2@v$02F*v&=JR3!E5Elp0?w~8q6;}sXVE~u@ zzu(_EzjM#rnLC+D1G=BRpHJGkuXBFq_ddV#JHLxJwma`tco!??cg&Xu*#S=Gg*W1@ z^z8+#r{A#v7q@3~;kCGE`HS{wJ}G7o+CLtc_nW+Z3Jq*hq3wCie}!GD?>innc*RTs zD))h?{}He=9GnIWMbATT)c%f#YZq%YtA-aZYsuWS_*y#IlFZ+Rv@@=vnYt*|#wVN% z%T~?a3p|>S=JvmA)$vPO89yJ8uwNwAjYl1PvG13F;pGVI|L`kZTpIgdmSE9o#SRFI z_L$Z6c$sq9|I%ScXZ`;cG!@S8GJXu(=U-#)EuL`ISv=%-iXI1Scwp8&Zz&+zKG7v<7oTed}ZgKa zw(ZIH$jGH@e&J8Kf80J6;RSr2#$&1{;`e>N-j~XP{84p0)MGv?zY0THHBv3^z&`wT z%{o^J$c@&yjyk%0ovYU(tH!uZ9kScexQu9=p^kFx)^ zy!}gRv=2am@M3somtU7I2@lHuTzD?EEtpYWt$4`3hzW}m&ZFvTf2gtcC%yKOa_DmQ zi6c+n7&}I{5@X1vcA$=9Ei{;{iwj7kK{AcxZ;0vA{bcGp1Z)fk`MRC2$`T#EAw9gL zl|1X7w~QOe)8_f!==lK82W8KbcsK(27thngZ5%-U9=}@q0PSAYn-miL8fC z72aKhONX>o^?2IA*qJGdgQW3?&xy~MO1kgt{GR{_@e?%78b959wE_GLM$gZPA78(9 z*MY3AKN)0+dNsugr_|)qVhHlG7I~f^hc_QXi;;*gn;V#T-{DjFt$)W^<8zF!Hh|A; z^!$wYtOJGNe^uePe4YH(d8W}4|JVD*;R)n4kAp`FU~3ilT@+4rq@h@4Qw1RqyU zt-Cm#v9~%oA=;M}kJt85N^@uonJY*F3xB=@=`TeKadms;^OdP>JRaNp5=+YpKhbG( zYQRNJ;S~oP|GVeC$>Sy5;m$G-t11 z6#*W~wBSQ|GfnAFHr@mfZ%`KQ^iXAq}6?8VPYF{Z@Q_p#$*YK63CX z6}iE|Ap4nbnJ?f84su9|tsA*&f?h8B&SbUc+je!&SIkeVJ>L^OUuh>Q^*(gH)BCUi z)cebJK<+l??xOeK`}-<#$XPF_KQe<}U(GGGxgr4S8opQ2=_Qbg&7*&>Iv` znBHi<+ZNsto6+*@go9KlMS=?rvNa^i{U>pYMpCuha)s+V6{=ui%II))@Hh zk4Dc|;<+yUQRX);dem@E`m8A?Z|pGkNCU0pti`7UYeL8L1ym!eL{h3DHs1QEkXuEkV* z{7PSq$N2n$B6c=@QaX60o10^i;?D42HoI-LWJEdy#y?Sb>uY!D<=&j1?Vg;}E}>Ul zK|b^Jl+4eM@d1CG2u@xahbMIK z>0;G|`+nte(04=h$+z${dAu_*J_xW~p4(dpc6NFXLq{y=NwV8Io2D1h7lXK8T~u$= zeFxBz$=NY9Mu!Ue{`l@Wp>N+SV)R{`)NZ1@*!|d5=sShRmky%>*zi-;>D$g-5hh$K z+A{CaH>tlkeN}I9NtQ>~@YATu*o^AQJA}QYEw1S^ysvx-x@w-r1#cu>bK`p&y5^(& z#WIpURE4DNXfacCU@tbdnz9v_FY38)&$~ET8pLfE4~jqMi%BHkovkrC{rJuV`X}KH zdNWB5`_OnzIt@h|K!i>uH{fKsdEw~P{mNO=sp-QyJFGz`;NR)(169Au`i0Zo{M4s@=X@_loFSkTKak8Pv1?b-Qb}Tz}7kzUf!ZK;Q9Fxg54QMEy1B z+y3fV(l>BmH;n(_Z87`#;i&}tH>S6zWh@?D_eg4Y7IY2vnt`s_r^@Nt<`DGPplj1> zW=Yo$2X+m*ihh0i)%ECCr}qz4`Ofi^6I?tgn1w|yNsR$qx+5_26~QK|eIw~kkE@MQ zJLK!}*P2P=3i%9nXeameX?B?Yus1HNCq4rDl`C?yTN#Ly5zBlZ%TSTyw~_) zYJcN)E-iWdFw+adL-Ax{eN_z4t$)3Nb~@j^j~SlX98qSXf339gye_VHWqREBP)Z^x zuEPBut51Zhk`DrQfh3!?{`yEhy!1(zKcYAaES}2Zg2P+fbieB!bl>YZIF;1D#*0)B zD9v@9Ugtggq2LF7SXBSmaM2!cb#?^~Ut$Sc3f~M|k~0(MEx>2YpB=ZZ(IZxztN40`K% ztZLaA14oh>u~_=wptqV9Hm{rVHjq}0u%;Ph8i>r?X!U{R*g7!-bWfa0Y z|3Dq<=E4DygG1J_oV{udKSaHnwcX)))e~`h6py2*KcM!@v>xHV((bezSciU0j-yx* z6Y1^aqkyiAJ&*8l^J8`4<6nu7{ELB)plw_5QBV+pc-85of%>*|4jPl-n_WBX06eaaVYeB92yz_k85H`ugBD47~jNPkFOp*eIP1Z znK+l~jX>Tm&(lLb8y5d=ed4{JfBeULp8vk|k<0d3dqn!y&9@%-%S8*%`xMR(T+6s( zQM_rCPetQF_|pkf{L_mZhR^Rq%Z6Fo04SiYD$`s7iLY}ySLFud$dnI-ksx~V;^H)~ zk*24mg*PokO-?s&d-N5~qSEeVS{yx-+6}*C=0!<*Qs;H25Yc0QCu@~9@4Q%(F46Zh zb{E?48w9BD8Gh+oOmT4El1N(!37^Vx(zwm~Rv*?D@7UUv#~~o9FGz zd7knm`{d!_+s(^mKY6a>4Mrd4iTy(RDdr5>&7kJ}7n{P%zffAUtdM00PR=tu7BE?# zXP>u}tva7gv^O#T;>MfUWQ}!-`sc?V_;xDg@TN4= zID;SWZbzRoe8>42#Rn)};Yk*5Z7(E@$vd)^7?E--V_}aV39^t`Pnu7CWA>kR|n}>jH`NwCfbD-l~!6zwi)r zmYLGAOa66IJK@bn&nkW5a)XMBMs)CjLd2l{ELo!9+eCa?xb}kjx3*8>YHBmX>ro}m z!~_S)3)(M#^WZs;N;%9PYBU@6Mx2KN8Dx&s8|z?>L^;g*a+o+Cu18(<)otOAETEi` zKYkgDLFek^k3_gF9o`8?hogo z@vDPqkM&cuU;x(H%yY>aT{Eer0ArgEulcincP)wjXwU2~yPA!|ff{-feMSWISVwOy zVJn2cLwMHOBjwwGz~I2Jot->Um}TfNGRtXJX_s)u+*aKR&>|`Xwak#`LkXtzqDC4X zz>kOUqb0lvIXIburHf}o!*O^wN%9rx-Pb|TqVHoVylS6fa`rDMP9t)gL|@gfKNErM zY(S1W-drI^eYixas;OiX<)~D*9KHR^+agD;hu0xTpG4@{^LR6AP zH&TXVUjcbm54D?CZ>~NI3eYWJETaO<_8dXLVK$ee`nC~uv!1tZVTnasJ^w|upExo1 zTV^hVZ^6zIOSlenoN05AC&Huq=5#!>u~sdQO-3eSY5j`ronpZDh{tkaMr z*MPrU{pEL(tdmVg8h)H22bxJrhrI;&t15Lw3$5pz(GhwR!)}tc(~hugy$-p#2r)?d zXLuH#suB0pAc)V}Az*h1&q@qn^8@W)nbyt@BG=P9f$!$a-RD=Yk~_1L4g1wmRPAIev=le4E>JB{^!4>pLG z%csVQymeX0tLgzA-3FFU+EFQFxnYHDMlCe$WftbJX<0waiDY-Ul$!MzI?H+olKQPO z3V7s6r#dV z2yb|{3JimQCea^6_x&or!p5ULZ!`L5oJ>72V$UGW>#Q{AaEXhRMrDr@Lg=PZ115e= zIBCwRH2*#d^YjClOpnu7Nq!I(%FFT=PLgS1r<>#^RPJ*mNnvgTe4wxY>be9szQ@NsR`Ye&e4@lH2jp*G!-Qegl zhkAE#(cJ6ZU;VC(W|{u~9eQ^awoJ^0-o3=NqjFQ9-ar1C7hmrl_f!>~x2<}2P_~yMr&R-fjMzlW*1Q z%0G4L-QFbz33H)$U-_S9GWl5*|n31*Tgs_JPSz#^^>*e!k4*& zQL4+$k2{q>SupNkex+kxd<@i?^aLim|t zW#527`=nmd`3$;q^EX-Vm>mCmqh`$1EpN~AoVpe00~N;!2Q<%QrJv`eBFL<5-07Pn zKPHMtu9kSDKBurMzgNy*_mg_rN=M}<)iWB8+{^ln>W6deJiPJ8{HW=rI)04U#Pv(K zlrVLT7Jcv~8Z$YM`%#llD!g@y`1qVWZ@7N8@;rXrw#xJGwv@~Bl!JVZ<$2Su=0=_$ zbnPe~RN!^4OedEWeo%D%zFI@TCJ$K-innesD)H#=d^ zJb4}<9QDa__J5%~k1p5oJ9(bQrP<4K-bsZg&vE@D^U(j;==`Ci`~;1UmdEp{XG;Ue z6L7{sxzAE&m@FtkQt4jHLinbKoyfL;4>AP{TvC6!j;rw2XMfKJ^P71^4Stt+O6B@q zgLd=li;4eS$$~t`Z_8(=KP{ z!xUQ6_(Q-(aQJp~4aqmz_ReTU!r0P2Twxq1=cLVqP;%zU7O|%Y9=3`lk+r`jjSX_` zuZ8b1`ptx@rtqc$=v}h(wvi`V-EjQbo$Joym>;u`IxdZq*=-9OE_wwllv#6M3d8I2 zER-&4r~SC`cv^V;2t0()6}m!2%WxG z{#SoNq&|7+Ktwf zuLJM{k4kyXfqc4xXymo^#Om@ogzI>+QF-0&w_wG<(%YBU(o_E%<+TWeGaM0@*Wl!B zme=-3UX%1S=;y-r`%r&)nT7zWBpahQp0?0)#siQ&(_x#QeznPqR=!Yupn1{7*nM3u z(feu#$xA#uI}+8=7(?=7V|me?7Cfh4P3x8IOWtzo)Oy-CdC}MZdgoLoZJUqc&o$fc zt*d>L7kwDp?{2L9sk++VN37igkD&dYiuU97N7tq3hd2h2JR|i(3c6|3&ZC)PalaDyP763^)e^)-K&u=;&7SQ-jN%K$Z|21EJH9Dc2m+uih1~{U;qOZW>)}2>W z1X5Ky!OK6*&f0s?u2FAXvnb0eViJ>=SM=^Y|`fQVBc?I!y!iQz7B2P+NKBN7>9}D|oax}gef8VSdAu1Do z0t8IXM`1f{Xs3StLbkDc^p28`FoIW}4F7VO%Ono~OJ>9lGD$yxE!))ZX{X-GPkh$s zQ4?Gt%6PeSJsM)g8My#O_DHmZ*2a!T9X1DXIs-nU{l8rw11{^xZ%*<@1iwGA`Pb)2 zW72=p^O}F1#Q&tj&=y1AYV-~#_Y;mM zVJ7n{jD4Hp*>vhOwRYvS+=zQ-0fEH)x|9uCyzu+#p?cJmKv~vOb0ld$ZrAWMmf&Db z5N4XONH4|PaW5{wi@SyYju%8-QfbM~-%!Za8v`D-h$nG|^`- z!Bty_6(wAnp0Jm&M8D3iZAXd-%!?Fuu72UycU+kFb5*#vAFyPa&UN#vBtERcFOQI4 zlHU6(@b9g_`CpxXQL1N-`S(H$Yg_sE2B;e7OXM%8KAwSp|9NA>{9Ed+;NQ0QnoA!4 z_S;Ky!oQsn|LS;V7iZer<&h`JtNN#B`~K;>D3XQFGtDSv?n0-uAQzsZ5JrCK=cJZ} z+piT+8Q`!k9X+pb^uaRMHIsJ3>rC`_!n2H>Xv}`z2Vji-RDVa`clKH8XFcfhAgkb4 z{Kn&ej}~=|ShU?G?PCoLWkpxC5=W)MvxuX;%tx?MBLN1m7!C|LAFKtaAV6;Zr2RR) z?oA68`pawO(*o`kEQI?+4F{&-(tP~SgB|fudY%LLU4HASmGCb^MbQ%jjH8X?$d1W4 zPC^cqbI@Df$Dws`vlhNtt%Jm(o*Crz7q~%kt(AkMeN((ETssO>65nW7bRJ>GiSILS zIB`#aAoJy1uk8L;Rui~5N z131*6VDnX<;054nq7%5H<82IANxc3jp2KX%S%@MY}vv23(Bu&0@rSxSrW*KS>npzt=Rj1{ub4v7%PSW zT32`i+pw>9f}cA4kldMm4?jupXg;>`aa>;gc=8nL*{NPtI8@IprAy3D48v`DN%&<< zA`O1^x%&9^hCeF5R(VhA;jH%Y#*ZJC=_&GSv89i=n@|4BkIV0Sl=IAPqa2cYwf$;% z%w@~)DEcf3e*mXX<@`)`KQ;x@QC!9uG@sz5$%0T*B`7U0QOa@8n|^L|Qx^O}A~w`5 z;r?P3udk2f9dzWawGL+2U(46GsF2uuNeg7g(kP<+Dj$k)L6r+!KntNi<&)Xj>GMGW zqnDEK3OOm??=^6CWn89NYI6(%E(cG*6C9w6)4yiF*Wd@p7P{Z7fHM=00TxWSrXnsw zqwmFKZodymAF@dI<1&-^=6F0->su0>3ttR zX5T~bLE;BhSxt^Sxuc(#z=AntL9b3TZBk~`Vk3%YR=~53{P%|+J6SB_KkcVJz48u} z!Z-Y;coQbUKjc3ij^8fk3DipdL&|R^9{D9?5qtJG;7d4wM;A|$_(VR17bCBt4`=0J zKeye0ie1o)Z$H}Y2B-fBNF6I@u{QJ)p1g$~9Qa4|uXK)o6n-pHhaF%t9iQSy`9kw? zZba=^-*3_QyZSBh`ZPb2aA0SHe#bXm+%*wiZ{GZVs-n@M4;%g)A); zr%t3d_2#!e==5d{zIArR=*^yf;)lt3P@Y91sWi?@8*Avz=@(pYerLKm|EXT6PjBw_ zTje*!TU_r{=*`yE%5O$*eh^u}b?MEHa}A%FNyHe=>erhGYzB*E%UMkH=4&3ZdNaw- zVElVFdQKIErwV92Fp(c<@uWJX#EMr@9g}`TaXxCZts;IY7fOv zy6ye5koWX?2CbgFkMdG2c`xbMUED4%N94mXWJf2_U)Nz&4lBlE{j9_~8`~R{z8XW9E6&HuK@vr>gQ{V{*OV zS8@D-yX2sp^Kg8p^QYiKK};vGnFgT;8_& z3#vED{HO~~pM~BWx!AC!=SSsvsg~aCsatQ(mjBjes`H@zGkQQc6%_+huWUvU*~O=eg_&QufqO!Th6J*K5pv%T{zli#bgP zKih53^5g*Hg0x-^IG~j|zB=Dh zK2!aS@wzlz_q_vIYv-6tTyK=Mc7E?*qQ|W`2S6F8EVaIe5sQPhuQy`j>GMHe^7Z+% zQ52SzEHmWrRfA6&*w>^>I4+-9_v9ACFMYR?M=&2#eATDdpT9qjZ;V0?_OR7F2wE;k7)*32i~@jJluNV$?1KO%Kc{eDCeKgYl4 zsQ6U=({+a{8t|LP;5REjB(?WRM9es!R=$tZ0es)9axUw#4jHhwH?Kywm0W`e;KMQ z+e!T#>HX2GNT_=B{vkJ2_6-W?SjiJAmz8?I1>Hn?KW)!Ez27oqv{xN^f5PdpBsrN| zz5n2kmA=aVaXD#3?@zvKTl9Y0u#qcI?+@@&ExkYG@HIF5SwruC{ackh(y-oN@S`}s z$y+>>zbf>8+lETLe+G(|*RA(EuCA*0$IazB^#1Nh>B>x3(fdtP|CjWB351}MH+nz# zc!l0i<5GgZ-;mzV&tC6;8cbR~UsN47=lc3{->51N+TZN_&@cZ$P(k;Q}o@_xIzahzQ23YJSiR&bA7Nzr3$0g{_gv~2KgzJ%TG5% zKAis70k?bhF}D^<`Y&%X-$Ix?CKFws<}jls!~W!7jx7_SS2OwX(dQ zK3?+mcRcT> zi^;t2HC#;A`tc}%(2D%h7RfrlT-VHNt|u?O?5;r!RHp*x5}`u{(1;p;gnU2BOJgmc zFm_?wmq3!xej*NZi!E>vP4#&3DC?ZZ8{D}Gh(RL|)=T&QMVMoYdP44^M~RN9A@Pe*)h z>_a!MkgwzRVahyNhkbbTi(uvUa#j}m@T;5uFWQHuQ6jX=KD6T!qXlvM&|@E+6Z_B^ z*@qhbo69#|NDJj{AOLtpN-6^86_F{f>SWSU`?=h%!e8nmD&K2;jnqTs_jiz|;o@w) z6XCAN53rYge<-TI5&R>0{YjYX62HOrvaS1%=<|WLhrCPsnYE^^`)9f>gwD^<=RJQ* z+L!tpgLSoU>TkU43#?yZo1YneX+K|A`=t^V89lW~o zaH8o~?ONQQbpAJX#!^|jpzk@+raMzhe%#a@=~_5x;=Yib={^v^dIVh*ZT${LUar%f zllpJ0*5N9Qb61EseAD>BwOV`!;|mU1y#NCitfcZ(pB*^>Ua+xyGun}B(E-63`n=c? z0^{6a3BU0< z=#_rUmX>fG=r8=zztD2HJVV8Y?~g!{B<4ecuHyf%0N_sH9V-ftAM56i!cB{>1%y<3 zI4iZ@0C+bpUib)sCgbZT0<>6PF(iI0jG_+*EZiQPf-L-_`o5nMg>f__nu|u#sZlw(KG6 zWBIQ|^>!2wj(=^v34U+1)bvGyKtqO4hMaxmF0hYEZ{m`N&qoK4U!{z(Fs@-^=;Dpw zB{b0lxgh#IH5i@@P(=UM&<`RnZ%0QhI@>)^+Rp*QZeJ<(r&CBGnfM@ZZF_0~oS9L_ zb%TUk`8Pg(bmR2NTXj2OR!ckOsbWo#LZ!7N!$jBcl#F-c$qh9IhaA;4VBb7c4pm;N zjStvQ9^VFh`_LcXSo!!UvFZbr^%wj8#UHu=3*;f`d97!XbUz*!++}%v?Iq5a`RTjo zxtIB^Xes*c5XZnn@uusu$~SR3x=p(a!W}V0r;lqqcLJYF;tO5xz0u-J`!!HSaDjh% zluhNkClg~|A{n`Z0n#xwZO_ciy=c!&0H*Y?@x=?|NVGKD0|+uX zOZ=z~M;xv=ox0|j?jNeNy_xC$k7#L5=>CCa_0jz%J~tEH=Qm9E(SP>oK4s4g-3#_? zTj}0%o(X-fO008Jqdv}dZ^O7}s*h7!?kT4)J&N>7syE=*DPaAig^P@SNP1rNjq*v{ zFQ}}a^j7I#=@)l^^u|-Oo{c8IxYF(=Oxjx2K{$Dc24O3s$&|W z|B|_;|1r{kJ@oG^`S^z#7{B^8_04Clsi#hb_}x|Nxs1v1qz+E8 z{a@Tr8DlXi-dU8dPOaC{CzgQiY5qzCc+Yc<A65-EyIRAN1XaZ6j( z&pIw|zA1c`u&-gpIxaV2zU@tefQz}P<8rY3K4cOobPXz+8TqTiSl8< z6C9w6%U3XUT+-hnE9kzO37qL_d7X7!o*9BHO;~(eoXC8?_>al!cJVqcFBF~r0^sJJ zP6q(NMjq>?Q{kpcI_-n<6LsgW6+!5TPCaO@K{}m)kZxwG3Z2rQ{p-`|Bmh^9PAa$c z>B)ofnL|StdRil&2ZGHOa@QUvsiqghE>c>~;{r+2(E=KQPk5UlT=1CQLe`M0v z`z4&!ulMh}6r^ZcTb4H{djIb0W>}A4J(GIs>bzKbKS@tj>iyR56JMGy-f7Q_-tV<% z+p70lElQK)x2jKCnILT!GwlbkisASE1IvSfwox|V`&{n?=y?6H`)HbeZ4p^wj<9ouGlZ2*)OxVfX(Ex%}(UOiKl^!ipK z^)`BL^XWB>vj*w)$N=coSA|}=tN(`R^)R5ULa)a3)GaxskLpS4Odg5;NAY&0kMTcV zh9>IrKbr7jlvOlPHxIr2a5s&n4iwT<)6B)eB>4@U3s?ZK2i zGxi{F&$iVb4ApH966T#V*714M`HoGQR$|Nm7K^rRKC{Wyvq-|H^P3Uxl>DNJyOeJu zJ8&w>Yt(HAChzq1N`U4X)GNd1fr&@TnON+=;K$}pugsQC9|v&N<}=$yr(1re`lW6< z_1sfQr*EOWMcs7jz1yeLG|n2N(<7@vr?Dz@%3bl-r_+A|xN3B2Oz&^{snVrxyHWXGdFRNqulFbInbG?>d$z55 zf6D3oZIkcAT^$tVBjrOEw`4u#FPuYa4MG#w$`5htJEorU_zw&o3JkuQ)ZP*=A=fLX zse|$TM$>aNuIF9-jhf@y{E=CVYw(8^2;u zlQ=(g<4QGtm@-c`$`3#213#qj1yN37e14d^@P+1wOFsCb@xywIvI;*m#=obda)+@S zN&4H(&pr={LSVbl{Zo(r(G=}FsCZG|e%Rpti2i0jY%i{m{(0(msC=!LkTp+&{;CF& z>Lon53M6kSCwZDG;Ku{j|4ig>mzQ6Ey@VWg%_Ql6KM!jP+n1`yr{o1C*Gae5sI<)qM)|>Bu{Ju#1uneQDqBpmVAI@*QUdHIp6ZxU9u6h|g561an6j!S8 zLle4!JJl#ZT=rh@Lq`>U7+CW{^TXlqd(rseNQ|-yKQv}XU*YO`)NMycAM)rQ+0hS8 z)oVxlauNNF9UaG&YId|0T^ah%WJj+#10+wElU(fRmFNDSv7^1esIa3$_L65u$L*y# zv7>6@vFX9Jm~nd zvHMBmSG<+QL(V{7Hh!jlP5e2~(Z$aW)qS`*-G_^BIqLTKj$eTd;SVRp&|of+5ia=A zu@Gm9FZ9!*{^4ur`IUOvAj(H~4HsEK8as;b43AH_N}^o#$qYC=Dg4^D#*y57;FEZs z^MSrCR4&Kv!0<+T_#u*AN*pX___@F`A}`;%f8}?B)5E#-d2GNg&0DiOH!aAAgV*2P z8b16#JCoTR@Q0!C1u_8U%+nL?+OW0>JvV8+0Dk_gEpM*F`vMBNF=hHQ5;#BJ4|uCgE7^k=p>RrdGlSbrns{msB9tJji8M)EW9NGo_m z@TL3~fOb3*`Q+y3c24=6fUiy)COG@uh6zl2HT-j_XJ3WxX+T>C-OubPr~7Cb-D~tK zbYBd9bM+toj{Igns2=f~D~Q1gCT20`nyAkJ$jOXppS9|~yKeSz-MHb|TJleZ?|T+v zxB1E;#BZeKaoe)$ulnY7mw;J}AFpvB@+c4RpUkf=!nj=_g0uX|7UUe?t><^&R|Et! z8~mCIi$x-cou<7^6_KJTzi^sg*?;&xG~|lngl?L4#;J}(9e{z5sXXeqJpH{O{K6?t ze<#t;2mg%%W)Hw5KJ%P>`->n1eI7wQZa{B@5!}BW)k0TD9wBOju zd-LTtqALX9hwz_OZ_QU-$!kFBps_pa7LF`OEtyeX8XNkJ8O{XHCZ+xl1~EuNm|3SO zMN~!>Jb+Q!%~O;7C7)dwGl3hI4@qp0IEI(+IN1@0z-1Y!x7?WOx%bhxeP4-0%P#HpVz=58|{z zdLIBrHse#iR6VJ7*;gkAL6lwsG1`>_62T#V8W)i;Q|QBR^;2aMkLKx5s6JP}NWU|T z_MLfrv$6Nfn$sIj+!OtXUMWugmf{MzWSyP#@Xyo3_pu|m19yf8MB1elgExH%9+K#V z{yNnhA0>ntK>Hkr30k#2%HFifp`!^%WX6YYG(Q<$`)4=APIQ}@b~H%bSMK9c%CT6r zEZ+4l3)36crbK6U4c{p)$1YF1E&_IuwOusEzwdx782S=DihKNY{+!zHGXS8|pMOup zWP5(63P{OK#1zTD!ly<7MQO?9VtC}c9G`Y@06B-FLH6I+I4%Lx&w3m|AwCZIvU#23 zSaU-8IP&G=cooL7fCI9J=O;V+SP#ATidZT@Q<=i7=zYqGil-$0S9({`SLyJD&{v0b zJN${hDwgA~F+MmSOlA0B4*Y<&-*2lQaOykV*vR9Atfn9End4{S2lN8WYJNcKu^Ie; zlEZYve!y;EdV}X0d}Q|X>U^!`4-$7;4xefGIT+(8^z`21&Z!Z#D`ajSzPedy^!^I@ z%v5#+<3bs_rl<;^xM<=A&1W2-z&p+Y%Y6TulUxWCSN}_M2og72^k)7=PuR84H z`~T>=?L=RhCQFir*L5yAUhz-x8?zTcI`89{=98?-Gbn` zKdbJjyT94v_3Wrm!E2}X`2yngslRvQls?niXM^>`j|Lwaxzl-w+9PkC1+D_VBtH%H&r$*_)U^eu&ayvO57mV zi*^ZbL7*>5FPLS}Z06h$IE(o~!HuGwg3@h~JBxWT`Ed^Mdq@P??D3oW?`rt{+3(z- zwdn@&JN2ZG-yZ3uDtUZeQ#^-}mn;zv8kSp1zm$ki(!{OSwPKxZaXs*vu9y&Gfnviv3U-V+UUQ^c&ag znCY_*W8DDUNL}9d6g)p0#$kZ}Fw_axHUfbX=p}~k+DViBp>*%{ z`e(l{#UJUb_F`}LqIo2n+6J!Sh|GsjuG?&cQ24pUwnJZu?dU-|@DF;!t@|B9O_A?> z+VFLeXQk4!kRGUvJXOY~%g_&1)HC5xSPHS0rwz?yrYse+mm0iP<151No7KJ9LviR` zSaxAokD!U98p^HcnCf)|O~^rd@KAh|)8n4K66w*m_H09suf2RHj~=5IZqsTiRh!f9W&2szi0M%5v0TAkb1yThLjk>NySSwd|UjO`Psh^Sz!M0XUb%G&#n6l zpXj&)`-6|>`6$=Uz-n1C^oC=x1Shgm3|G7x4788qDSZ$0bxUjSNKby_qGj*<)qWeU zPak>gK5KElBKvnYyzj8L?uhdP*B&lp=hiVuGv;~79@u!=!e=2Zl+?_$9h+sd7C;uR zJOOHZ{awY(2L=Vrd{E%8G5+ZL17l$3#@3Cqir>^FhObq}S~Q6aQLZwN<4FKBeqp4~ z`Hbo!D-YN6RMQLdQ?NGl7oNA2s+>yy+ZI@i!H_AIIOMy-z&yP@SjmPsHxW-ygU4 z)lS9VAB)|Ozh8rXQGP+&|CG@#`8ya`bN=8_$S-KOC|ottw{9jr{G#xo!o9megVU2z zUtaBoGZ{~H&g8d2&&vAR=}-oR)bq1nZ-rjzD0|)5UfTIri+M!!192+K8IM5zO{LcV z28;R6&0Di840bCtL=e8~NLip|=%}qNtAnirFwplr!w4O+HE-WDR!aTwaQ{ z8=x5;XsXoinqo>z#Q)R-s<#4p8qZ^!3ZkGvdc(=!?k(#dg%~_PZw=X~Ti35nryZRv zL8{CuD%b@Ka*|!i3Q|mKfun_{+AN-4&LkH~PAd^5{v7}b_+t`3+8{%%;Z27L%V@Ss zHy{dswN&)BdQlKCed0i&Plj4NP*VD_gaj@DatICD& zM~6E=i4gjv0%!4jqnC9Ji2O{Q@=*o!0W7Vc{C zU*g=s{|laMUXo4CUkM)yy+6-Rkgg={cOlT`Tp?{Hmu_U{09bm8*QbjZzOD-7@T0|kr3MSpXds9)I=^Vd zuk|=Sp9a*z=QrVp;qzzS1oy4?!ZIhNACQH`ckJx^hx+X3H=$stWoz!=i|lCnC8|@B za@&&gmY_!l%U+N4NMm+%r#IEGqZb1=FOD638G5Q>M^%4Po_K&C>(29`EUjoG+azl! zQI$-%aJHk09lZdW(9=$TbvydIH^$+a3p<)$U<`$aiv&Bm8M0kYt6FxH_PqJ>%_JV| zXu3&xew*wl^hl4|zcs#_GSP`)sA8Cc*@RL#$)wg~sZdOMN8b({YZr~;N+=CFQ<#3* ze7_doD7I3MPEc!zWBE^iS7sD@Fsg9+n5Z7a9NVd)zzOBnsGV8}4R1-*4H%uBO838D zb}9>XL@@J|xIz(ho~4}%V2mv67=snH#U3lY`mS~y2`>V$(~r~0edsdVSgF88DbxZnYNOo`lmhbO-Kym`q~ zc4v`6IF`$xB2R?7u?FtOMIBI=E#P$6$mLmhv(CDM^QY+1zI5yUKAxnX%}Y|LU8FhY zSO*joKC1DEm)MC$z=v@_Zk_Xpz9Cgd9=pSN2jKEFUWY;c4YT*!O`z1%x#3xFXTTn+ zoGu++1ZEMH#1D7?#`r_f;pOs~5@Sk~TS$BqRBA_frrLUu_>u36;i!<6K>;7@O_up9 z7%1zMG4P+j{sQ1G-euN{woVBMg?*4uYI}bMjo7bv0X|8BC7r@+k9P59^>eGt%Z&cK z8!u3Q4(=+*mi#;9!!u+qKHl;|SM*Kf(m%{wTc3?z2cz)&-C@PKb1{48R>JA$WZC+CN=sJYShnE)t zNiO{U%lZA4Zrd-qkR!mq^ivTUG5b57+t(>0&KWa6z_$hHvV9NPt zJwBZ}g*W<|9i5Qqh=l6C+s$<4zrn!;TqwTuA_R3eEJ@+Kgc$|n^!f0mC_P{YEd&^` z1TgSWACX@C7&VOwdBC;&@TF71HOGyq+DX>I)?vEXg zEH&`GxzV$CCw z_qy$S%3r>Gu|Izwej9?oO%3<+I#e25HBwq-#-;6p*_B^Jk0kHo|9+Fv0EUhuww-GF zfbfF4nKaiVz9IHd!8HvqmM{4nq(^V6w+m@OWUL(@^eZL@CY?A`o!a_=+n=r}MGIe7l` z+rh7w-8BxnxKKzDCrdY9v9K4_8G2qy$@$L0KKx#a|NHqr?hWAo5qodY-W#&_M)3c% zy*Fy_joEwS_`hWDP1t*r_TCi!Z+n^PFKh4R?7ckxAF%gWtBJ4_?Y$EIpSJf>Tg|;D z{tq}?@PEnP3+%l%d#@e;cfQ>8$9mvwv(w&7(N~PuLz$#`xU$Ls%H$kBNt1WqA9I_Vy&NPCfDe%vA!$*v5Co!i($)T%ju#o+T&7AsvP%WUU(c zATwcA9c7ir?&d#dPm}9Lz^{26L3gp0_w8qSaAfk#*~-J2kmE=ms_8$127My>sdD`U zj)o-gN{wjx7_wm_wtn)2RXN4*)d1Nu@6l;tv*Q<14!1{he z{Au(`r#5)C^2LhX-24oDuw3~dU&aR-FADHF504La$ym7#IJV2~8pLhK2_NUP9w!W0 zPG}`3jDizDa-sHVHlW_Z`RK;eSl^CObs%<%%?p<(C*;5?-~@(nfMB!aXx^hfRGho7 z={^CjCTt!v5XNxw5Y+ED-QZpEhU;?hoH7MIaPt$h&vEEghVtlJ{oE`rnPm6f$t8eO>L6p0JUi_gtlcQ*4r*1n4<%ufS_s-ued0U@xVdzqNa zqBf#T;e&>9B?;&woEW|t@LGG-hTg(GUN4q4muX|jfv;@;N~R1xx82$TK*=rIB)V7P zE^XmgGHxE+{qAHrz$#G{IYuP+9mQ2{;R%9%WBb)B2U0gg z#}lwI9Kw3T53PR$T>H$tH7_k^gd1)ZwsDL2X$ZJ;#&TH<3JMt(^dzoEo0X@cv75sP zd6}{1giD7X5U%^MWmLRsXWL=sU#V}q(R+-~x`B(C`78wyFm5;O zr`kP12L9nW57reP+AEdnJk`Kuu9`eqtB*vVmgnIf{rFB0s;YU>(}=~2`r8l78c|+! z&%0{p|8>Xi$Mf&fvHMD2&Hw9+-H*TDVejksfNGfwAfNsvkWb0aQCq@i9DY1AVDg#= z5DF(f;3v;t_%l68t z%jpx?b~X*7CxlEy8He{Fo!r=&ar->=x%Q2pGA`mq<3_7|J0~BIEVcsz*^3X8(R2Vf zjdpF(rlt!d!MYR<=XXqv^d!K;7%I#{xDe~9-t;fiZxKQmc+}4G-txyp{^~GbU?13{ zJ9_+;#NU!o3<8gL*UsM^i`|d&&-h6O|EjOdC=5P*Iq4!jI}Zd6xl2}zbCEW3ADfTe zXWLPl1ZYV3VZ%izi?C(~YuQ@D{r8%O+7=dT$={g@ZwASsN84??)#%OkGw;1v@<%m} z=)=$7mLHoh|13|yhp9Fl112~&N$M;A;_RjREdgJ~0XA~l^UU<*Z~v{o_{ZmWeM<6* zasI%CzdE?(sy_}%Ua{DGsa@qS^Fh7BnW8)3micn(#4>lh6;#X=EJA#}y6^s?ytA4+ z&Ic3aIdjvO1P|5d$Z@2HpASc0J1A&Jv?-*?(hF}gKn-&1`U;2pMM^J<&dKYtK7CNjZkFSq6lFDE2TXstxn7Qb`AwnvzG z1o$HyQG06^Q88rNHi~^{4bN`o`e3JhFAhKYPK|KL8`cIuTXT3MC`N#~D*(dMwgAN8 z2|#yl-Jd?BU2|@u?>&GxoVRG4Qc{UaEMuqJ(>&4TL@1L5LsN8DjpWmn@Q8l1`!RE| z`-I28uki31kFxdbGj?)zwf}g-Z`J%6>t~4H*yRu8O=2}W4&kgo3NtIivbqGEeO?FVUTea+&C3Z17+j~BOgAT+;QhryM?dXa~xav`u)TosRlpWWD-LA zH!vl)?Px#LcfKE0KHs?SKO>on?ZeDpB08rSetTbkzR^+xPTP;Ho1OwBl?v@-XjgZX z@r>N^a=8xxpU_j|A@kPkmKigBH-$GeVMH5NETF0iufs_ui(BLze|-E6y-{U8^~c{N zj<0FpY%`zw>BGK0S3cU^cA)K6-v@L69;X6K_9N~4&6jT^kkIy}Lk&(mAC~(VwBNw? z3pRB50jI-J*av8kdPq})Xh2sWvZCoHddQ%fp~6dMEombX+FcZSN_{>CE@i)9>QaMB z%dlzm9KJ!c4Cb{8PkngU8}AxCRO4R`$>G7qflH~w%6LQb-}o$#K>j6PySk*8Xndbm zOX1V!e0*J8hOePF&JDiE&}{%3jbi}|Jn2RHF59|)rl|@#x9q8Pb2=9rJx3X#Z>#X@ zJUbn`AJ@CxvHS7&dt&$F?~fm6jOF7f6iO*u5dHB1U_KA7jm%jbBAZ($gb;ylu1+pDJE2s7yG!p3_E zi}#@i6EA>nmO2pO=8K*BrJc+KmL#y7HTY8W)tgA(kvEs|WWqkfePmGE&*wfv+d))M zm-7`KsyCAJQJ~L_%#^K{$;ATVE|SU|xSIa(X^<@d{>PjyA3ZHwK_+?4+ zUY~DGUB&_k==c`ff+Wlp{)M>?CRI^bx6|TJ@iY@(wO}%bnHg4L8sw|%F$nV2NJm|E zNv6C}ymwbgwUiv>maY3^ux^p^@BL73wgs(MGf{$SFc4VDtV=uVlrCqW4&wUSmpXs0 zE_v=fq8@oRd8>z|AkW=Sp6hCVs)6<&*t!$GX6@R~9v#^O49)3BwFlF&`*D3<7ks^M zt!Mm3pB+Z{dL4XqwLeu?`zD0?!1HLoukQBWOnn?2Sr7c6pDhiC@moWlo%-013bMRRv@Pb2Y44rk7suSfOaKaJCKNWVkCu)#_P83JX^%5g zS6q_{Pe&8c{G8YI@a#imzq*gA2VZ-N{W|u4K#wL=g`oLeH8OUT!I$Dm`%-+x@5k{~ zZ5)IZdOd=#SQmVTU%vDgz}Mp7>$LDGT%;?1Yu%oX*nPt1-=7IS;kOZNgYf1n3HBfG zIeu%k0FGpjH27mbJQPmFU;KU?f260{Fuw26SLQWmitRtzz-Q+U;W?ji`cV4|_%aSW zp6bQpVnP{PT+$SF;_-^-Oidt}5CnEG-?Zij=?dAA5C^D)C6lE(>?@ATp8 zoj#eWHjhC5b?X;vcFC~504)I~1sPWCu)pm-9hFUe zFY>2XU&7wA(!0NYQL$Vg<5QV(?Qs9wv4otZA+VT$3M3qq&i}W!2yxG|o&&bLHD7Tf zJY>SCz;Zci)kyAe!#8$#DXu^BP`x_?zc*igIUfekj{qo{VVJeW@MWK%Y**?_z&}a& zIW@6*wQyafUTst^Mytrh*bV>z;3*C{E}rwS^TO3{CG6dc36Pr;hNl7`OUFw7k{WO# zi(|G=>ih9G*OtGr*!{Tt<&P|nFBm8dyo4dV_u=h`&+JUk9s5gpZpuDaZT!;S{%92K zP1JafcvC#3iKoFOWimE%u4WK3b)9bKyoVv{VOfqk0ANme{I{Jin zz730=b;cc<-cgTUdONv4-0&pyQmeu+(uHk?T~hPpVyx2;*0q%6w(v`U%JMH|nc-+2 zijRGX54VkK2RUJXgg6SHjwbDG2JB)dF5zeDB`P31u?KCG9xBHG&&7F{ES_G_dMebs3dv&Epazr#B znB?lg8QXa$1~GVj);YXUl(5hOYVO|e77#*yXkZze7EJ3 z4p$BF-Iwv+3&eLVOHHKYMdrIp4c|?mcM9t)`0f+eJ6v)pA=6eT-+doBN#MInXW+ZT z(0sl6v}aj8`t&WLPme_RnRcg7vj-bHsD6a%cJ(KwWA|0e^*-a7)J1xzoOd1Z)Wyx| z+wA4R@L!LZmrCD;RcRiVh98EW6?;-emj~evqRR*Qvg+Zuo|B^9PM>c$whc~GaNbM1 zHui4^ttOGd$6imBt_nUp=D&7=|K#g;j@8reof;=b)@D@4i`rp2=pvJ%QiE0T$lt84 z;-{U8Ujv`Ss-;f!L(N0KgL~$1nwn4L9Xm7@!OMzAXd*Y?IH>E0&6jo&puzwEG7wNv zb8EJZtcIa%Tl2o8)oJ(=y3or`Sbulk>Ox$9GCbf9z>UyDZQo4zW?hC>hi_v-1>d@8 zRfM|={#AT)Ol+Gu4?HlgZpHWU#5adEIkMbnvuRGIvK(NJ*Yj!<%eS07;^Og>E}Y7c zzZrZtdf^z&xRUr3aJY5+y_O#F)TJ`1D-{F~Q&aVs@SWgU+bZ#rNn7#3%SBDN@%&Hn zY#e`$`X6XQcpsZa$-YCOmx+B(@P}b-| zccSelwb@1xYWTOU-OM)>x3%*e9=$U$4`2uY3i^JCrlP!Rzg_-Tzqver;+h)mUTE_R zR%iVDf~i9c+?0JDyW@|)wf(()7JyIQlF2K8CtR)D3KpkQ{kENIaSzhlXDji@i-i+N zS|h^6@O||5y!EC@OQ+U0WB=5KsSZ~A7R2ty?O&U{ufDF1Q{Ru@kH1g;)V}f4>HYA5 z!|R_<^_*Cb{Wo#uBOitR&)U(i8c82)=u-`^980+D%>u{Zfd)@1Tk&xY#O}w($@ln< zzUT6mY`r$gUvE2UW$MtU#2R1~(qs!4!w=k&it6$NXoCmXrqqkakx$MuL?>?l4eJz; zw@cx{2=fPgXaO1HpG$Cv?i&oPcE^gsO0GUqrEZWrf z6^IP;`OJ5NO5vW(^OTvWZ^GX_g+SvzgY05G|G^Q+zrvTUKWkbrBSg%sC4GB-zU?#B zb~2P4R$rgNbhb6j;$6?&ghOb4y+xe1i(ztWWnzA^KTeT{QV~o-c@PgJ{P@bUJ~Bni z5z31*t-o^qELJ~6jKJt#@gK;~$|FR9>R-saS?|6F0|A-~t*5L+P#RBQu7(s#i9!{^ z|6wScb$JzzfQ{ggDC0($hT)&Erha<(jzgy~H%-GSOBcTPv+Y24Y$E~r2GB0pfuXGp zT?;$oNyZv?JJvMo=!92O<9szCPIqh^{~InwD)d_9iNaMpD{JfgZ~B!3Bvs%5g+1CZ zsEYT&aZLE-w}fRpw{txA6?Q>5h(lS_e9HpD)Ojk0vw0KciDfmnQZ6w3m961*yU$CF zRE&f9DC?)1nr|UCQUmh(Pt5D|jfYn@g*|vtX%tvIfM1-Sd5EwlL)tKrg%R?mBtCet zZSr2GWO>H&Dw_&_iEs`5+$6nb^?vi^*WhVDSZqZymlua*jH+sW2L_YIqn19vz!KRr zsPtT9$3Y-?`1SzfG5%$dnPUuN(v62hVV2-ocuL}fDF7v2abzdLUF>)!_A~mAZId^( zwvp=j$=H3JPwD;EgA(naq(X!H(t^c*U<@A?u}#SC)eJxG_rtKI+NwSssD>>&NqD111JY zPJDK~87zL&4Fnw12PWcM))$xh13k11`G}K==UD^=43EgZr4ED8VtCW9+-xB7I|&}? zfL%0lfX{`lXO}e%y0)xXX>zu~lr8Cv{acs7;;l!n*|R0q8?&#w@%muO`g^Qw#>UeY zGKGX#;K)4}C;UNir0PlFoX_$My14&MD=+fmKaY{q|D()gdA>+%1o%J_YJ z?n@E~si#2{Z>WoKlV7k;Ww5MUE;1QTBW02jJ|A-H^ZvE z4_7dh%a7eX>PO_HgL0ByIisAU*I%^5c9-lHE!~qlGGQbq-h7o^#QTv=I}=_%;f0t4 zSLILV-!xp`@LLGUSU7@(MqbtK)BhlztsI&CWFC&2uez9beWmH+c@U5j&v>9Pcsj5( zyxDF)eCF$-DhlBfOJ?G?Hwek3hCS_tP9|tCC~uyu#YOLU#+t;B>E6F`T(spF7yY5t zA1WIH^8n8vZCM%sQ7luQP163X{!iKVh#MXO{-iyz`xotyYQFXlxP(@l2H8@yjQU!g z>3n_5W`7j z_pKbKv=hO-{@Zvi)BSO4Ld^GW#;Uxh_{mCVTP%8x`*+I4K$Yjq@w58aZN$xGzsJn2 z^fd*Olo}IEtTDCDF8hCWp2U7V{bc;^FXLjI*GAtfyasy>Kf~iS*xf~VoJS!4;#K;& zTc>3Wc)L5vUOBuhn~$(OWo%eecsO#bE%x~#9+-@T(=;|lt;>|35CL-6qXQ7?T#l*9(Zdw1kUg@LkGGH{}sEs=pT3QWB8I|;;}pagukrcK>b_h z52nu&rstfi5dQHQ@SNzECfklQf`0;ShxA%sN?qEV=~tyM9~aXk^)>In$$)>8IVhx|YpYqgc+gZd$a0K`h{5ZK?b5bS`zZ35u6L+MgO1~V7%p0-a6y~tK z`O5F{3JhppAA3at2{wGLmt?NyD}RsXO{PgVVXCt0;b!#Xj|+{leXtpFP=M3$f%loVI#R|y;*Qj>$Rg<6v z)XoBqsMs2LBBjAq!gd@8LLN($_tsv$b^pM^GaszNBfy`)1IA4?U%7{j3L*rN=_VMF zt$U5^2gtvw#&|rrdxSyrXbryks>1**0i8-gu%pPn5-D$pg!{bbkp-`m9)U69V15y& z3bdYX8feEr!h5hU4ZU{jijVBvpPUe9_%u^G%+SB0+sRnBnm}LHCB?;hW8LiTRCH(U zf9aK#c)^IHeeIt@Nz=@PQIP=%>COFH2(>w<{7?eZ|FAL@j%{(*)9kMB>zz{lwjZ|5 zV|V=VH)=7oSVv*sAH$DICp~BP^Oe<`ie3h57sLFIj6I?KVB7rj?7YnD%HruzVy##a zg*@0KmwjoDg#Q`m);93d?IQ)1oE^lR=K1Z`V)GZGC+ksvUDkKVE7^_@kXKL#j%z0g zOaXgnw>U)9p$Q~!K)<&dx+n}B2Y*G;H8O^-!_Jzav@CqJ1*Mdh`Evazf>%9Eu*4iKFEYZ(OcZ=j}FrM(zFEE+^$ zMbkoO{tvjL`B~v?Dhk1QQXGQ@DOE8)JK`JGyW`sFAlvov!*j*Yi$mw&gUNIztVB_5 zIum{#lm{MVcxw63oZ%_Ihv6rxPxeVaaXb7#f5!j)2`+$BG&idGs+(~EA{{wd!dIpq zTiWne^R<8BTVS31BuHv9qreGyG*ra9h4hE1icz)!lL0re{Onuchj&|ebo>DtB0P9A zG8Bw~vh`vfc&5cBw^7CSOS`7@m20^vd^=jU3aJgRQkdIpKRA^mz`yLXYxpTGp%Wer zcv3SzcRQZ*)!*)-<}h|AC_-|`kCBl+GKb0tpw8z(PIPKyg&#aykMiu-qZ9%BOl#Is z-nxR!f8SL`0yNV85u&1U{%gOl;Nz16#_Opbd1Zyn2N4e@T3q}j;6pf~eBL$7#Ww<$ zNBCZ3NF{&QJe^7f_J@8~&}}M=#~VF@Uf@k^K-H3%PCMDveO^9-Cw{q8qI~}Y@zQaQ z;6mqT+>%>?4~yL({`u$Go$7JUlE7~2)QAmQk9o@}*zH*F{4g=@;sMS0WBAC!c7BKxpTES8 z978+~_LuRLkH>2KG%k-f&QE#1_gCbn-e2rgP0omi=F5kG9O7c+-0HYUlCNmK^(vK{ z)atTvc9prm7s%HJ&D@_;YUj+1TG7sjr?Tp1L*g+F7c^o4I zALJ%D2$|$AV{K|~@6TgmX}=N^RRgv2`T^U%KR=On_4||F{C5GmfIiao#OA9mW1m<4 zp!u31-T_w>vepxmNgXR{mbl0%=|sqMWFmc>|X8~^)SSdW1XX6uSJn|}smj~f{Z-@V`d3%I| zM`Tx;*B5y%d#`1`912FEu>m*jzDaHa)4;^Wdo3nLy2WU+2tEAiak>~2#L#4cE`YcM za9n9-N21BuOtWN6nxfssZAQ=Qd@KMI;o%P&Jzq$PTLS~J6a^?5AulZ2G-Vcg+QPz! zTLBs1TPb-`MjB?QxM$Wk)s%%_XdXFI>nY^M81Dadm62eyJ^qnC56rl$P+TJDA+hA-{ld=zu-S~){nkCUqj;N9rD2Y zogE$B!PpOfzCs=cUmJd7T}zL6Gps{40dif3Y`O@es9c9U`=A$Y9rB*6u0u{Qs2o?# zb;v0~TV)=m{(x;y<)Al&i@ewqBAu*&+wPhWp~^ZeoR`oObv2O#%BpPxpm8K z+m0QE$d$A+)4F8_>Js)ZRRs>=^C;ea(|4gSa@$qHE6>#tZ|_F~W~yrZG`{D>J;dI= zIC0ou^ z@e$MdJ|9rcMF7*-li27|Vg~ zy#1g6_9p*71|Gt~BfwvByuDix5yji{(r!h({U^{fHr}N1_DS0h``{7ak9~Ua_KzM2 zct&P^?gTvNN3*_okD1ga#oKd4iOL8}XucazZ*#nT>`L-PL-F=$d8P6AXzF96o^u3W z^mu#c-6lRtdU^KP#jgt!1W^1C$s1y15bN~I886oP_T_k&M_n``XR}uDDy#3KD z>i28vj<=r+c&qt$Vh<(WUKCgyPt6o>Zyh4&jq_7C-}@`_Q}K>E;_WGJ9E#-2;i7?f zd%x^Ga&q(6i??sR-OZB+OGe+SKbjbCPhBm1SuNh)@{Ri9?fq;bqVr#I{8MiHy-%C* z?+FQ}-^%?IJQ!=U_YZg>Rvn<+nUOu#XDccT(OYCJ!$AK@Fu zzK51>jOXX&F#$FaYTTdTeNEE)8_LgX`R_`+&6J-vagB&r1z*JT^V%sMnx8j@7^aQT zl>#;}d?%eO*!?Abe%|1d1|GaBM}U75^7D$O6xvR*}`#Rnr zZ%$1jI1sI7XimoL^7B@Wj6Y$9PT#_y8ANdNqj?4;%7a!pUcrcj{tv{;Scf`tq=a3jmX-OSyI1uQDFC;;+E{v+1V|3ZWf382J%DZQl4ji{OzdObUqLF)JLp zpwuJot|{=hO)GI7aQ=X+RQCw^luND;8Ew%Hlr~>^0&+Z^-`Aw$p|Zdc;E%RN-oH-P zJw>PMx@WFv$8QU4=<{WG{w|5h51p8G&vsq+yxJft&&J2mxWDe%9)93P#8DP_Z~zQE zqIK$<*MCHsWzA_>_v{cY-8%G1j&fxOsU+k3DteLZ99@be#NpR(74J8e8rmUJi4X#3 z!&%YI6&#OM&Z?TaW@_kB=#Fu${GSZIe0jt$qP)=8;Pbu-d7-6APSj)_begCD)(X)4 z;m~*7^)!c;jh+j5J|*XXx&Jc5X;^hNTL!S|n!{R;F!bs*ZoNlVU9XO{av{%ath%;) ztFBY<$T|2^)rAwe_O5Ene zRo9O2_4dh;eoWdZu@GAakzIP7AZY?&=xFH`E>?T^XRx#Ar?LMseBkE`s6PcY!7wb- zsMfs_>TZWiUuH|OnF8x=;g`1{*<7o$fqHG>kM3i-TW2b5+Xc_3$X6}++lo%%7cviH z_4xqJpTFhOpIRxKcmwR9eaVB5?t(n2Q>PbgdWf0HCP^hPQ&Y1|Cl}uND#?$?|G~h| zes~1^PZcpnm|9q z#&jOal;c6B0unNxSk%0Gnd-wMrGsQ25>a8}4g3za#kJH!cf2s>zIFKMfLU@>(hi6qMjc9w7_VQ7XgJywy8PEA6HgHkbnhuE9=&qI~hwv?oZF z1y0bOASEBJ{1(+P_%QhW4Ezi4UG~7VhF^UGb_he@<_uT(u{DGo0Ka5B{>9_-tT*HW zH1T>v#QL$V_-EG-|3(Dvb|Skp9lSq96wf!cGH9dMBlG+AW8JRz7WBk0&MH@bgMIVR zx+dt>t;@WXaUr&BKP~|ZR>_-J`el9kS@p{$7@>ii-*|bn5_dTf9lAu0Bg>SF4L%Tn zC@pW~6Ug3%^)U%Ac7*?Nj2mIA>9L5Zh~Tx#_?*ec_n2+{uJ+H8O~Hd4U(9Ul_~K@p z7;hpp8~u$W;9WcRZXLVuOBU(GxR6pg;%`0Fmh;@YE7V(N-JajU_IRQBs%P*Nd0M6Z z4xCd!oMM6=6BU*&JpDOO_OHWp5t~q#bsA=Y_`B+FpIXG~ec{uL0SdFTIU z?pxp^E2{K+hF9~@Zgtg0K`sy_;wnK_2qKbkW}wH(V0Z_H8G_0X5G5oN5_w2S2uTP7 z%|i@`7{o_d1p^2MT0?*VA}Thxiw(HgfUA9B7aLUQftC4x->Evct8cpVK-~Y{-!JL= zs5*7()TvYFoH|t{bAXn1*(78Md7a%n4@8#7O*a=0cou8b%6^r)_=BWnU=QX`(vsV3B6d)J%W>*9XsR)3 zVyZ2r(m5aZMv+qxJ@RzrPvQzQg--K?nu;(3AhuO~V(cT@-;9eHo%f#S4@xe|CLe)9S@JbAQk~>;+S)(xW-E6IpEx@ERR}$IE5nbX zgNsPx8jZ_c{RE~QbyV8)oX`ruD;7(2tTsP4K|O@qzo9!MuTH+Q3AR~h z+}*UB#p+(ztXe6KoLS$AKVHfgGwXr<3eSzF?Ft*Mhwg~LXQ>Ba{9lGgxlcJq9C7Vu_h(wlRIwz7adfeui^ z%e|66pyMQGn28N!(CQQlg>E!3S&#Cspfs)nO;Zy+itPRYC&Eh&Z zsw|v5Ht+=$5(Je}hg=I3fkqy+jOJ`DxzH1cS`gQ4-hFAPTx2Nu8-_?D^*8LFja|@( z)T~Ip;W{&bp(E{7W6pM`pkqV|SDUU&Ewzju)W@-d*Biu2bsN77(>i4LS( z%VuV-!nE-84qT5F8ADBzLuP*1EU4s8{;O*Jeykp~@|82h{(p>_VY1R3?goZ8V0gv~ zd=)#Uuu??zb&|dGd`al}D|j|+xkiSC)S#t0)^ba=_G64+U5wy7q_oMCfEMV zkKRB4bB;sOj%7naFwEG~@2+`%k=4i9q|W$P8V{o14$6A7$AiLCMi0?>8Ov6p50Vxb zAB>#b3r}c`k}~!VzCgogv)7tEK@GdqL&8v-6{|7JehbQFbF2a7>GB-)Rv5fx0yRr^ zmHF*0EdrkX1&g}!v>Pa>+8!JDHWCT%wV*L($WsRLi@iZm9{=HT@^^IuIDDJNhuYs| zDo8OIY55+}y$@K$`d`I+GmldD9X7*C*`lTFL=6g3X_)H+bBIZ%o&DL0m7qSvwhrm6ya?o<$_v%|J%K84BQ2%$aWsU; z3QgaK+Vb+`f2heX#7oc&YZgRi#3?gk7xdt*Faj6NQEue;lo$Ua@`W0lBb-Iw1(rFfCPDRP66$D~)eJhl^yo}@14FZj$Ye{sxw ziqQ7Yp1UV20V2SM$u%5G2U;aoG74YZcY~=_$pjVjAKbErxyrDo;&87mU-2mUn>&tn zd47N3gmzmVja@9WSd`pKH$$LGC4`at0FbMIJ}SkQON^0TolzrO;mBbBNcbyS7#<8f zEsF`pj@>Epj^~vWivYk$UWe}`G5&e>M%IIOzSC8B)2+6#s!xZ`^;{aaYdQ=5o=8RA-00)uj~h6Ydtth;ucPf$foj1DfxMoo`edd=TnoIJHEo#INTZ++IK z6WbSBU2r+=P5UX3GJ=o~uOKdt# z4`Ky&;NHm%OShq?0GXOaWI3)Ywa?=qQaV#ExZ?ooe{_`l;al*L+4xM_p>#Uy zM3+wUgZs(qa2pivZe?&2S;JqI+JU0W@@uU3d_JHZdVVmY9T*3Z{f&X+wuj|U9gn+k z$_B;;*?{HJk07Cl^?)6XP&VuJBR65Z=F%}|AES>BVFIZQ-i+{wdFOSApK7t?E1f*t z5SNmii}n5x&#tU{1N*71LRm5n6dp761xUF({4X!>?_L-1^f$0BAQkLS2F%4oYXfac z6N<3V{KVkq%{>;MO6_RydIcesOD31x1Z{S&8>!9q5OI~aOv6k4ttzJ)*ye3Fn*q)Q z*3b=KQ2Rmid6FCRB*PtM9YNpyasPK8Hs{?!f1&(hKUe*PbFaJt{qbvjcyM{9$g;%F zh8}eUV-McNi5Jd+sIAR&7kCDZEUL};JAMo8zm-)CJp#q$_Uol&G~?UBfGa8|2e}8A z$6J30$%vVbO^w_>c=+7JBu_QtmR{Hp7}bpWJMFsIWwUt}AUhHCp#L%qQCHuW2-BA_SRjr3I6Im2&p zEm{TzEA9^lwv>_w>=<_@?{xfF|;^N&7G;~KSnJiz7!5XEkQSTachvtjOeb}{mb z(&@kJdR-5-Oj1W8p8a*`9~<~5;391h-Wxm%$YyVF?A5(wGA$k%8 zk^Xjn2tH{Txdl5y-w27|uf0|A2&V%ct-*?6?3N&Sj85E2dw|oM;EeIeU6eMdog#wbuF;wR&PCn9{xF>iiUy2ct$lvo<%#tO!0dJA11Kr@~Jni$;|aRhk| z)r$Mu!0GNtF=47dUmfWEtti2N7SCwsu)b|MAVqu3vOEzIdyK#6PsTq#zz6t4>rhqc zJ=_)iT=v~Oc~tdze>$j+U)!k#iZM7s}p51^>=k=Uj$p1vu=JfFt|69EAo72Gj#lxsuZX&SkP>p$D}! z{;)b00U6M83pbv_Cv;r8-g5rV|Go%4K^!AGGiB=Alc`=`(%voJoC`6H;&dz5g8z%l z12!h$bly@^>8CVwfE01l&_SW_f#!qFuVf(^%pyF>mHH7B`V&7%cEn+g7FRZuYUTRxNR_qcEb`Ute|0?| zv2UfMOsXV-fX(@nLpmO5J9{h~7uu)f&t69uq7%QiD0cDAeCoqp|7#{;4)CMR6V!(| z@<;uhgP3&d8vx!HKIJ!MXH_$X|?JbciJ9Xo;=z4tW;o( z9Ev&>f?D7vL7_+X^g%4ozpJ0iYRg9+V((uMNfFHZYki0{$=w31D)8-Jcb}VYtvsz~ z8Sh6KG0rc9+eyoru3XNB1(x$uNFga_Gx?xYB&H_Fu)TBp;VTF>Q-B4*dy64PyoNp348`cmqCt z3$$^g@2cFakRSF&Go9u_2hY|+(`$V=Uh^I5L%kr@`)xizH%O+zWK<09#cHN?sr=8% z>EI!m&;j~p8M$W%-oL*(c+Alr=&dmT~R` za+fmqQDtJ?%{$!yf;u8m*z18ywS3Z5X+jjj`j4EmUi%Zu#o7I3!>i4C;9ocw-KNQw zxh@qA(Sv>sp-07dfyw5od~uDcJI~;Nn-X7SrpxI)JN&iP;U9LZ<-3cpWm5@$%EGTi zC-MW@D^RE2#}+CK9**|HP4ONOK^2=9!C#KPlrCBVRrOc8eDEoP%d~DZaI-v5gl}?> zgCxAki^mpoA_y%&x#s(pHS!B__DHF0Hh!9lqtSFAUlO){$^)u*PG-QT)HD6VanJzv zF?i6>S>;h^eNp>7_cxtgVk-0 za>#p=1kG+>;llx*h11Hv<&YqN*R$Z)r4klCPm$3&;a2$H_H#2%{|J;pKQGkZ&B4ST z&V5zmw$`r9K49pg^z#5i_#6GbRkC0|h($j{pTD<(adBhS(-%i2y&RR~EOs#K720e* z#Wg4=@C(HH{uO0&K(o3~@lNsu4l#0Q7903)Bod}cDZLDja^Kh?hVXlS3q1D`TOMh_ z%flb*f-X7yf5uKLF;pf%30tv0g`J=MQz6 z!)2C+e=9Tx?1O8|tJdGG{BLg(*?&)&T%;c}YV)Hsxjg(Q-5Q5i?u8|0yCjFthC1F6 z6F(PtgiYlC38QJc#o}x1sNBZ#dTYPb@pMP>r0&_lekwibORt%b;&rJJn_tIGK?eVH z9CO;S%h+KlR7S;B!CwaL#}!yT7Q0GxA#C7f?2nuHfTnG^w~RLGFJM|;p8PjSN0^j; zKU67mJxvOjEv5$){2NlTUnyzG%ai}Yhk@Vy;N-+hCw}9_U%vay&*K!-T{`jn;GKK? zc1g|pui|-+&V5BJdIyr%sLL8H?^SXEL}NNt&M0w|;D2XO)W|}bLewTqaUP@lKGQB1 zjXCt37Y?gBp1r8!%~?@*ylK8uEn8CpJ_`R}iO6Cgo2p+>`CqDD{*GGy<-5D%X=Fk0 z-&!61DL=B~>2dFK;g3$3`eE^)T-vUxXNJFr^~}M0tMm)mXQXgD1nu=5h)Zs<=~Q0o zc;)i_ZtnO|7~}XVyupEV=qdkLz;U_&hb8DU72w+O!pt`fqgrI-w);i2alry7bpxlj z-LGltp7MHl$R=ru$ z*W}{{TfWM7a=rD>1Vwzv(8uh3BgNICQk;P=jj&Okd&*mSfxco7fEC@be;z4zk*^;V~1Yyfi)ln@x@h}aPx2wY3#as@#S!w*-% zs99PlK7e)@`Z;yuT!nV158>$nx|Cnu4m%h-GVcEtes-6K%$Y<@D8%I*8DMrq{VeI} zu_Rd>cJe=U0mqxn-E-3E5uEdo8mo|wZRg@r+PALzK?k2DlM}-r_eB8XluvZ%ceHTb zeiDXT-cLqd*z6~J&jh?KRh*o&UYkxwy)qTjh08D1t7&>>y>11Vnf2hb5E3*SoS_*`J#FzX#t`*5Ouo>pZ46_D`($Ysig8)Jgc*z}b8O ze$I9aQ;A-7PEBDIRa=Z-!e=u0|BM6d&pC}H&Ndw}sXy%+=ugcS52b^LvJYbUj^6kv zpULm=Uw99(yNJ7pfIM9{8nzHLXiLozAhn#^FCb3;e{Op-ccDb(Cv%`}?V6Rek6(KtyvE{N6u6dk@wb zj9dIk3*|i)L>avqf9OYyA8c;}^A@weK*RRI7qc%`ei}Wx+vaB;ULO9W|3UYT{u2I} z7TCGu7&|UERY))W1?d}*9<9HP-xb{+YNI8ADJM}SAG&s+r+$uXQ=}eB&RcS4do_)3)}2HSa-3otNl35qaUXTZy@iBVbUi-h*_VGWvZd z^m`s3k2l6+0`MvqXKK*e^(X_-E_<{aWRb*G`DTTk+& zmE-M=Kv0EO7oBFM3cF54=ZfO<{sQd8f>|0$0=Rt|Fq?2 z#UF|7ghlVn|4L{JrznG91GQ7vr57hmJrs_oaDZ`LCa}ZujvZFSbUK?p@4ve*kn7_X z4sqb+;g9z&8JZyE!|HTtAo!=CfJ|kU|u!D{lc=vk?fBRUDQ5C zQn~odKh#TA(5}76UAa-O!5K<-lsOh?$~G0iBz@sItH zm-11$pZw;fRr_P|+*3_|y!-$+&a1`NgKeR0O!yV$W%N;L*rLBRmVX*KR%`P!4=)dY zDlhAiJS;CG71FD`Y$JHe%R{z+ylk^IH|0#TqQ z4Vb4L{Iw8?{u>FbsIuP7>?O2C=MHHJE$NdJPtzaA;DwAD@{e-a&b;F02j%uN4p&6P zG>|GUUcQb08!>PVs*XCisp{dbYJl4+**JVeQ{(XJX1HitlIWlfNZcw1y+a1KB_U1G z(U0g(Lhd#vhi~ga$!PUjt~qZ>4xhs_-_PygO%gYQylKKsiZ{);8Q~28pF4_;md3Er z(s<+0Q4@_rYo?&uPD6%e$|ASUzn}H-w>-({Pds0NmnZ+xp673zz-=&*|PHUesdW5+0-Jc_F^+%)lK z95=1JnZQjmZ>Dh5!kcN_wDBf`n+D!wag*dt4mY*D$*QJ%P(+e?6^Q4f zxx33pDc0BjOQ)d+`Ic9y{mr_}L*0(GZy6T^O~2ZsU@P{-*J6w^#}8~$AN{{T<#GCo z8KE$LFmFC@du#!Gz8L3?yyK?OIzy1v8bO)xQ7&+YjSSLW7|JaIi}><^>~`roK@ zf_1PyQ2os4Z-~#DIG8L8zdpv1bFl=EVS%zZmrL+s{nsHUO)2>OEPO4`!xz>aZ4-z4 z+r#mOb!eIb$gJ~0v4QuZERwX4L?>S{^iK@uDmFY$yG;%yg(?)E08e6bF{&a3FgyN^ z!VB3*nKB{gKd}w>D=6M#>Nlf&$Bx??P85R=BI3EF4)D2)+MyglzhdaI zZw!74@N?saF0**B-DgI}<|m|{X$s?@vT382sXSsm zd4a#00wMhfv|HA5qW|+saWC4#= zCj13j(LB&1fvDg|{SJ8cIZj%|&|@lGtYYnx)PFl`abIY@O~#4_)T4;*=&>*Pv8}kr zOAphB>tELI-)8GmsDscmUIzB=VSoXdGQTC69#7vwp+=s-VK(eQes*BHNc`q1{Tw(A z<|wil(uKKp#6^)UDXr{OiAbz}1Ix&2vdAE6gOuV9xhL=kjo)P8bKaAehd=VEY40s# zz1t(Ul+;Hg(N?j(#i$8sSfsSHQAA(fg!XT>a5f+>FAsl&QzkcFu>2d?ya3$5rg)X) z&J)2Pyi2e@6Jp88+vt4Yf2At?=dY8Qo9Dk4<~ue(Q5pb+ljv7`P543eG}eO`^oT+H z1T1JbqmkWsNF|4{_Uu1gKj z*@nxL|AxJ)>M#v*`9`Q~RR zU`lJ(aXzNWU6Mm#`T7JBIBq@0NWissHe)9CgAsZVjL<`1gnkA_=rL-9o}fnP$!dh2 zZjI26E);(ryN9vm0#kGa?gqsc9iEW=aTvrn4t2a+-o6Z=H%zm3Ooi`_ulOi!Fs^Qx>JYo%z|=a^u!IF5Yj z+KY@s%*vB7TTZ3;Y4JnpegQIR1p}(^d-m1h-4{(#o5BW5FJqn3lF24{vN^!(u#-S3O;^3F)jphJ90@$U&drn96+lZyS0+Ly^nF ze+$2us*-Q_&AX@DEIGz(e)0z|4}Z)b=;e>&0lX2<2(V5#qdF68LBAba@2pF;+WdV; z#>>N>@D=J8`2+D@lOV3@7p~XzOoYqBA8&1Wu*YSbGwa7D$)zZecAw|(k2tqkm3_KjBh*U>|M%qcB6* z@2>jQ5(2>G$$yb`ha`s^sAGYOo3@MfOI*W)%d@R{))w0R5m59?LJ)N7a{Uw{2*g)F z0CFBttp5%`m$9JuDO*mdJd%4QrcDGa`a&FzNIwx`0^FhNX*8Xw*MrsSvC<%^GtXBW|#bJL3jm3tc`_-YffVScjhg*mAE0kVWtsNiS603_rlFj$Aa--E+5-z4SW(@h>l0Y6VupFvq zD5q57^B1$sVu_%WrvG@Ork~O;qOumZGG>r8Gslet*lGnPQMeY+j2l_Va{t$dmya7G z<>N;Fo2DFaiColEMBdss^EMQu3tYO&o$&B~a=>z?3-OfO5%Ft$o#&{0WC{f1VBlY_v+&$;P~Z(O-8|gzKiCa#OX<_>hP6c&AOl4$#n1tpcZX<; z+u;Wz4ENvVAXDcbcp5o>8T`iIFmyoG+`jLVc*UN;-7Q2Gv(rgXj|PGhKMzNOW2E0?`f^3D%zB23`+cL2S;) zfuc#*`LxcDP>ZGbq<_J%LY?1@RUcLZZ$LHtX)F(NAKL=y3J_mM-$n-Z12fZ4NF)BS z-|@2jF4p^FK9u*psm!0;zIQ||^a2b5XV;s4c$70qX67+KgDDaocGq$neCDwbT&@^A zLWVNh(ZfffPorxLp9|R7uWJ9-)*s9o8qX{28<+}52Aelae5~x%_6b=pNBL)It`Uxu zfPTwr(tS24_*fLIth-iS4uodt)NqaAThfaCQu&wtOZaTV@^R^3SECg{w`}A^p%oMz zi4U=cFc{Owt1kQ}})N@yxa$J2~;DhIz01|pE^(CleX9IKxbXu%UrB1*po8hH< z;n$3*yFYCDMFn^wR{*aY@Pd9(JzX{<C0`iqOZ6()^{Q34yID4 zl-aByx&KSC3!X%M+58g)$N_emDKZgu247Z_MviHs()MSdviac^L$9N=`sbD628ULX zFUs}2G2l&Pxo=PSI{-EZ&RTA~2x6e2R>z3Jc&l`vRS+Yv;i+=-1~LP7JcJ6It5{x# zo4AS@Ps9w~z*~(2;FCiu(Fm*RWsxD)$ov;nxcl}-bso;2R%28*7E_=|vOyqby$hvL zla)qRAT*&;{=tw)hQBM+qeRLfq(vV^KbOg;I`mOA#JN$7Xri)A$ixU75kTb}*5^q2 zC1CRtn;bF={qu6O;mDdhlS79Y#q(iPhkHyN#&(}i9bEh`JjV2Fi+~W-$Yvmc4iBV3 z%ZiBLlS}~snPw0b=TXqw_*1ZWlSF-Y7$G)CaQ?Xx)gsi4>iK^?8dU&44T42rzN{ER zAOB4fOP>&)zUzsLaUS7UP5-VmPVWK;kiTY}rU?Z|xrV=r9GUMpJ!s)mX7KXxCvc(n z3=))VNplF)p3}jV5F0bq9vSZ&EF6s)4&apLc?YfpY$!g9JKjd-1&h`DU&TTUJIpBi zbhQ}q-W(-2Of-nzu?n0mt#wqwbVhaoe$S2;NI7n<2QJF9@gUdibOT*l9M?8Z2Jqe4KC;ugDWExpjK2-W%#COq`M2?%Yiv90PAg=mD|6Lj+iLYlA?s}Qn8NoN^?3F?nJ<`8?@&FaF0WpXO~{OXVB$7!*p}H>B=D<}t5+3BThDF8(j^zt5TR#660yREKu$d9O zMcjZZ&89cwEY=+T^c;#3*A{7_{;G&A4-n<@@L%|;)KB_8YN}8unko===!AgV2Xk#T zLXn}rPFz-^2LUOZGQ4lW2f@2VnA6P9mAZ$i30IXZ!`=b?PsaLF$Y8Wj&u?E&`ZUd5 zPS+_?My)W;TxB4TQVbo>e>>ny*Eid-umb)iu*a-;lxJCoX47AULDv2DC_1ac+Lx2R z=!7ksq|v#_Q;A|9L~wAbJ7wslaulV>MIZ2HbZ*eCMfLgPSf4S*jBrpC1$tuYIfxn1 zNlyMSv-{0Z_9<_2QvCv|&*XAG$OPYuf}f#+PZ{L0;msfIX)dyyJ3# zpDWC(9Q__M;wAg1*1wk(p5U@WRCdW^OECZOc6a_GV(ZO%stjWR`iycUzEAd(Z+(r- z%gz2pCv^FC>QX~Lmv0FV;{#MGk?Mh~H4e=I$Q7puuEHu=`itu!8QJ=+7OpkJgpUO- z2E~Hp@7RVqt3Uh#ZNf-Hh4jRU`)Z1A%gvYekSL)Zybi9}>H2!2DqVY&uFu5F=xQO) z4)?p&;f^TWi{1d-L#x9bQ@9^3gPZCxkw$Tgx3;6MUmOX2r;W`^zniDI;(qUVcU3w@ zzjCS(VAsT4IyTvIwf)tO(Q=zZ-@|yd*zbxTtOuEw!n)Hfz=o;T3g4Ml;kQ-zF8tSb z-qMz{4RYe{d~G+bpWvnP*au!?aq zLyrzkP$rPu-xaEz#3?9F1W7r^3wW9J1~>8nxFsWN!?Ld8zN#hp)?jz`<U)GSWc51|<@Hfh|$1En(D^T9oPUw<53?W~mqL zvyN@kbrt|7#9=yOm}M=aTdaG1OaqNc-Q1e1O&Mwz}*^d=RXEHAMO|E4hiiWw)1=b*BCA|^nmDv#-8;2 z-LvS--Ihk{g8k6`0sPDQpx^h{vZUX?D6G6SJ3V`Rpk^mEp1D%Jq>Bgfj2$OPcfZ5< z;bydl+uxm$iseqTTs!v2z{5~nv|cF`*MI-Ni?|HB%Eu`tGxf-5yNG-G2}Mx3p`%@d z0>X|S(lg$=O#Ozl$VnsrF9lNo*?e7;M4BQ0kC6q^!Boc=UB=F}$i9w&IHw7Q^&lWu zf*cN!j+F$z14BH2UC{0xnGjcK{P?<#A4l#Db{W(z<;ea6u*41a2<=I21Hy6mnftA^ zCsCK;IO@U<)mJ*Nf@yhq^1me4cTgEi4MzpG+^3Xh=aQSGBlvE_^auY=hyYiN+0Wn?bI;|0U!!a!&E{?9Ja{Cu}+h;|BvlW@)!r?^lt4IJWJ; zPBTOASYq+;?61>L-agY#aMkyuY9B^(+q9@trYuKgQWgsP7)9MJhullc{%-Je=_j%53}^a8Krx+ zbWclv08YYj<@COd-D>@QMX_d^rh3qh=tl{1`zY7B(UKcelMbEWc-sj^p&Bqz1_PDH z*PJ)4866-kka@J+QfAwt)?4Q^Xm`TF4At|Yn0-udsD;8ZVF_0{SC}w)IpdS`6M^6Kw)w!{kL~R*CH$#{ z!5^O&{FuOhb`QXx4&W1CrD+I%V;^3Ox9nqyx6c?!E82(fD<_c@T!d+MGnd9bqke_3 zT!$D5;=@0j#5p;VX^RB8Pmb2mu=!2EUc_@onbs(a6bSxX_gDS5>5GP6ln<0|0)7d7 z*L3=QUi{*{V?ON(PYKr*egO2&2K1f_KF|9r_5eOI7yUcBqt(affNtW)n?Wp5YI7Bc zwFxep+5C9r?H>Q9dAEB5lKy?|{-Iggz3!5-VOiS!U8suDU*@9gCrH<pz=iVvSHcA zjv4y1U-N*`i*sFdLh(xNX7yvr&sgsSlCkYZ-&NM3DPfaKM*o0Fn}55XBPa8fPfsgP;rQ+I>56=Z)w|5>2mje z&4z`-zHBPzS#fH9_Fq7&s{1>uekJ3^;JeG}OnEy4Z!VJ{pKiY!}14E`vhEXSvu_xD80R-8Ww4W#}JBiTY->+a2)E7`&P-UP_NQ&~9zOw5;8_-xF@P zt?$+HiXC&eTO3nd;dUFh`BV;pxN`BCV?Ej}sjBXB_T;Gu&|-5<^GRBePdRQEX0=v} z<~@QuJAFpAR;L-00G{p%`k(SkST585S|*p<-plqYt%+J_CM2>GD41=RzHjV=rTX1!hm~^G})z0!U~{mH1ZS>iESt zE?zLl7;207Snl_v>fSH=RbcBc`K4T z{f+R|+W!9?zIyp|<*Pc2r^+dpKY5RJ(0TmWE*Tr}@De10Dsn-M2ggnZJ#)p-k7{ah z&v$kBt=)<5E~u%;{VIHG;I|Fe*6hmPp=)cB{Iz>tH8U-~?QOrg`(BOMZ`>P;`M8jr z`MAN>l>K&!d^^6Thf;G;bO1oZfepxUd`*gPMT13+uCs!DHN{ss!pSFgF{vKsE2Dmy0uffHlK9nUcNzV*3bQ41nll>Ba_XSLM0wv zx~0td!#@D~%U`{V#G5r&fKQwQ_={t`f5S7zC)LSg16d|ey*vTJmKY<&Cva3QU<{NN z*2{@(=LwWa6rfhy>k;}t>ww=u%>-{{sOuCl@GI&~M6H{S7_=5O4-Fr{)-NsM1Sh(80 zEhdJN|dTk?<&ZYS&S;tAa9qUtLry9Dd9!dMe)&EaGgV(7-atJFC7_+k2&>ZfPRfRiG zsbfULC@M=12psLyiVFVO;Cf42mJE!s&AIWX5@*F*`_r4FM{ErZRcMnMKc&1sy5(7W zqDiZJ4BLv5Z=xAgCvRhGiS;_Qz*nf=L`gnI-)~;cQ$9AC>Kpm!S-h&XLlfE|5RmoN z+M(D)6vPOW16QZX8Zzt`{I^d8Dq}n#d}O?}Iz336GX5R?Kvn*2vv8E29`Z{55dY=@ zVlstpCj9%TpK89Mt}nn~&K6cJDFw5bFwOwO6vShT(s~ z_*_XI6K~L`f_*gzBvscC`)aG(g3j^=?5jWC5!hGVCzCvUSH4nu&1qjv>}g~`Y5nG#ZeK+{#3KHe?5hKAe>3c>X`(#CzUr2W%sf8p z@3F6je?vFeK7Xb6iQQ>_o{!|f0f%;Nh|INgV!AEKmM>S6y%EgppEpLO5M5OU-VSeiI>S9 zX692=-Y8$_d`%|wops=)-&z~s;9giAZcgEzIxn~B4s=BLF$UYo~bWUa$I@&Z4>F@E+8& zkz3Y++o)Z;o>(?(fME641Exh!2W0UpWY!u!(DBPHN92n$-j|m%QO92El=C9X*#SmC zrE=PAIkXXY#qme@s%IYSR%nS!98?a$UZq323f|r<*onc%c4)4me##HRRmFOOO7$Zi zC|}}<*Q3aM@}oL7bK{oBjhP93Mt01WX!{_(S?S~v2(G}+-=g!~02LV#P^-71w{RbL z3u*mYLsP=)@%;P?jy_lw-s1KL0k4=fsLeP@QsWVnuAX26e8m4sAM$H!+E?&@tiKB; zI$%ZH_9+`|Pvd@L%BPxN{Q@5;w|4>PpJV->G=SoX08pIu{5e8#9AjGetJmTahHC;r zjU5f5YCaR?xhxWCINtE3;x#|LZ*ANE&iMTDaXLPyR+sl5#g}>}?=e1);wSKb-hc;V z7MtDh+t7>X{}zWmq+=2ECL2tfnD>tp+AQ_aY6R*&blDc791jP z#K^5b9N_MpL&-#6twPOFIBZ&RAtbZyV9w@>q=x07hYyWop zAx>aau%v+lJk8`8@ zakvSOb2X(^=4IpQpe;w`aU8G-{|$_D(RvnKeVjZ0JK?H2Pc#Bm63FivhGrsZKF{|Xmet%s30QG@1slmw zA!2k#!N2CysEAS6SQ(?RMY2bg^NCAGw;jbF-S+W{@`wKD5erB2dniKkm*kN6qbC4j zvRVDnZ{6na_2)%xxo-Qp`|-7c(Sv}G^2wdDMgw_k_h*aA6ohO5td8kApiDYT^Z@B; z9MjLV2K1~i(Npy1Apl%L8JvLM#;^el#VVFoH`BK1GJa`J764N^D_~xyn90Y?ocCOMf?G0 zj@Z80fI`xVlyRPx^mx3Li+J#Ye3Cfjk5O4J9#}R9SS8*};ww1NW7w;;1q612foj@l z2K?qvE);&nHPMQJ}vX5kKzA$!FTzmRpCz^ zWHc|04^p|UexvaBuwSY9Gu7n<)1seBT*1-kr}>E`RCEiI$KJ<-H2y5p>cMvAc|UPL zG!nP)bX@QNL-dip*A{hPv*S)|e~RdtJ}kfYH*XV3=WIpNk$YvTIpN>+%C_)dsT^lt z<`tG3b(9-*p9YbT=|x;?VN(1=-}%{E*KrI=-x(5-B}*g8pnWof z$hdtn_G8a7vsF=!L(R`Qh{!QsX)~PQoosScT!GCkpGFH(h(8Xy!3ypc;E|4AW(0R? zd{v1rbPOb-#FMmGG4!%Og&W0t7W&+YZ}XwgomYZB^|stf?N2;FpVE9a=`%65)X>LJ zBx9cpMIuX-B1oBk2$f@&!tNVcdrKn;kOhrQD5FD=CKQ+Mwgee(H1xnbx#n2^pQ-9s zji78WWx@X_?7z}_%4Q2+`BKYKddqt0Uh&#aVMSjNy1jR z{;y3suHRPQw0`F=`hQm9;dQ@;iRF+1h&z-m#<5=Q@E*FIJGoemtKPHzbANdqdY$rv zMfXk!))TP@6{mPS6(!QSZ|A*LEd4^ihJ4P-pnz?=~a70nGdDB_j zK9-3I#_!&0yU57O+54I5AIDLS^c=i4ayM6Ig38PHei^Wf{tcii=%*I}^8)_`^Qm&q zZ@K@LeTqxUB=V!8~-6d@sI7nOYxF%Eq+KK-{`Naq8FL+k;9yAyv-rCsIq1}5)3F{}CT^u( z&Nve5{S{t<=7plIo3j}O?XU(5$K@Z%uXfntjx)+#oCeQm2u}~iFdy10;HMU_5nR*Q zS4E7O*LLe%D;zcmR4jLyQzrA+cI`?#96kG|*Xe{U)+K4b%ybxC2W_s&lHFy(KQE@W z5B_bK0o}y^C;TirTtmGXzqJo*y>GHIoJ#=TNVxo7FF8mAan-J^03@_cz^X0ON zIFdRvhDEwTPBgKxFO`$&`9>qr8F?PI-P!e`vQ zrTqu^|JL?tgV9@K{l5^G3}{j>>_Q)tP)LLtI$)B}wgxmIY^^;4^|Q z@%=2Tc?LK#S`5O>wBGTteu>c+vStYI_Phm{L7$QUJen@fDtv%1I?ZL2?w0`3jwjSZ zbu1+7s$PVm1Ah9Xplm{LWyRDv;S%;QF~pWNz%`gw-}&Oe2QS=}Ktght=&Kd_<;?v| z#+xW_jPkSM6>c7p_rH0`yv9Sb@1fZb#LiE+`XYs=I|zR8wQbG5((}SAdDu+6w)uzP zbs0QNfqw7EXQOZ2f<{AQsnQi2&<$5yeIreCJ2`Yua)ND)t0#GN@|D-vuK5TmVy98$ zfa<(=xRG&S#0Qk(AKpNUW8PUW&)%TuKtG?KoMX-~>2HRU$jG@$@{L6~RqT4}Dr~~@ z3B1YqU%hy-+S7!auCx3lHERXyuusU&@np$-dd2;hM5r4CbXc+f1D%gb>Jgy>5AfT- zPH5zrW~j!mf2Y1@29?wihTyVw9Qiv2A@dK__dZ!vdXt~3^nYckt`Aeg>wo#&{i*YP zWgnqdf;i*Q0SJAw|dpAhVyEemY3btjOnmUql%A9zCO6A& z1RDMYf8AE}9>p(A@6$o=I&~}@Q<>hYJ<>X>YDMluv4M1Fyao^|&@V9gfuU>YDavo2 z|4{I6C{2M-Gh!o953APxjMLYJMO_uvnUuGGuI^}4IP^S+2|%%c33eX{n1E||wESx0 zskNJ8y|=OvAH<;$$B+-WA68(Ju+?XYhlo4-LmJ(;&GdnU|M1OGO2}Zv^Re!Bep6GZ zjBe#4DjS+#4tki;{44A@Ue^3HrqU_x$!11ac%bLc>II)G?(q*lsoIabwI4t9Bex%W z2N->~nqLz1l=-Z4LCa#Mxy)}vzefJ!CO@bxmxuox*O5F@WOA&z^J4?E=@G%asM&YL zsBC8c16_cfo-QW~dx3vGJVSvzzzexluTs3l-_&z#8QxX=O=ceD9Xa@$vbMO=JnroB z^GoTfbnj8RAAXxlcg1&hxbLbCcTnNJdh5dBPTo}&-;~1r)*FDkt~%Tih5P9@0Qarc z;f^ZYmu_+C(C`5r84N$F{8ax^_V%>E z&j8|L56We1T3_{jdh|$4aqv!+;KwaqmCAAH5Sb$#jFlym&pkk&`h9*3m9TnOZoiWJ z(J`I)2XubN*C;z88JkYqL)(N3H}AE+2eZE2Ybb~rbP9*}L)ZgyU24SUCv09G{v==j zlj~PgSdAkOXvDF>oQr7UwOXp>LzXPEESVf+)1WZ_`ez}J2%DED|Dh@0vP^bgCtW#i zMnm-_4!kPXqhYPoV{56$VyQ=FUqdgGt3o}xk*7jEMylmQJw}nmsmJ5b%%dI+7G9R`~=noaV5GZ#HX<*D&(t$qjd04G3(#faUnJk#aF5@#h!CdfUY9m z+ekA2O4N^EyY+UFiH{k&RDjcB)uY%z2EYkttN|@Yt!$i66Y;|U6*p63;7?j561zIh zSD7ei!<5E>AZH;W!K223fIBCqg$J-OH%=)Odm~Z=hV(DLx@7W$U=lz2u0_IgY&(zt zaM6EwHyJ4Ip|kAxnK-ieCqKU}5SPXDEqp!(&$eHU z{)?eUrG9JUWt6^MCLSq+nsOb9>84ZwH~H(p3bp_in6Ce-&cjsF7my<8ha&HaEpy5p zIeQ8Ry6)7N2y!Q@7g{d6cxpx_b@Vdd>@vo)Z^>$6;0RX!<+xh<*=hZi5H)($Oy zZ~Z^Fkos?1wf?R1ufNg%<}R0dD#R@Iiv%^(ZMJ~9<28i7xw+vxe178n)#%&(#_4+k z$Gz6i&yT(vn!#VMZF}ZE$qmhS<8G@nKM0=tCU|bEsx#_zUwFD&{}N3i7@KbGNHT2VB~j(8`}D9|A=z_gk6?GX4e6J`IXRk(o1 z%flb*S5~EcEnGnxaN`Phx`g_gxZe!|W&hdWxfC#XdHAz>TM5sX@lx=tJ6Z5Vtc$_Z zJ0*l?)ZfS8IcVW3KN2pm5AkiSK7}oiNqmxv5yI)_Md*bOiA(|DLu>gd+?kZ`%tOBg!oJ3)926-b?V3C zpiGr^rU{fsXa?{(DEI7p`CI= z8K|qG+$i*%%DNkGc)`^3upmsE6lYm=wjA;i%h8KGzZrk%*JfVl0DMI?i{oEd3-24h z&}jT3*5C?X6+T$PmoPm1ork~VhNbbnF$0Uh5uQ?PPxyW8qQypq{oE9Wv(25IPHkcX zTd*jjWBqM{w;Q9Qm=vVOy^_TV< z%KE#&UPGf6~8@sa4WG}XS5e2cyzI80)2U9jbzRKm{KY4&9rH~YnaF8ATzwfrlv~Np=^k}At zY+b^}n&4CZ+=oni5ljwX@Oj!FWuR{y3=f8bx1a|JBk?NmIF+`)DO_53Cq%{2AFza( zaC!0{g)ofkmB*96e$9xuxc|@}wh;!6eu>zlsW893+*J9GJ5#pzFzeJF3#8i!zzN+> zZ6@6YZGMY};G=Y#mXd{T-`LgCt+_&aQYu8ZGu2o zoG;xjM@lqTu>r+~==Q^%WK4A9NoM!MUhW^x z2H-yR?W*`rDcpOnb@BB+P~smQLs*Iy?m2KhY6&HjTu^64*m z{@=HC`(>*wk9A>LT1RThd`9R4&TZ|8`F%Ll9&qaxf?vJ@e*4UU-^z0QrfUrS=EU#W zrv*Pv=h6+;Kt14zJo%S_AEwSTlLF=h@sAjL;EgO4b=2Q-%HWWV*!9Xd` z!qaj+WFsyZbLs;>+jseb-m`HKrsO^I0Gj?TXWXG3ki_dUzga_vQIsFWfF^z@G2f6rc z#~-6N$Y757#XJjj4t?}b1@YIVin|#+mCronpP?U5<0T0qXIV3zMAU(9(gWjpQ8jR# zj7|8LJfwQTh=uRc!M1}=zs3eIXbH$%+_r<6h3>(Vwu7jR9MuZz4bc%dCPc?B8X)>f z4`aOU+n7g+Xc8%eGZ^7XEv4yrjQ{`9O5}i(aZ80)ed)cEY5eSZFo;A^=CJv_C;#aA?ZF>dr84?$tPXcQO ze}QuUQgio1%Xsb)LSB|kP7T7xyAgqF7EurAq-!mCD(N%C*HI9=-Y3o9wB3moKGw5v z8w)o7U+5|^+B7MguD4+4I(I_OCoBw}i3Tq}6RN7;qZE%G#K+1;1YnUYz=#Ykou3x< zZ#W723v2HXg|<448~vUr<>)R0uw6)xyV@xwrlH` z&A@?>9;+0*3x%8Z$?sf6?l}DDVL`gnS1H9(<2K)1cuHtX9tg;smIN4C94`MX=e64A zQGOekjD=DUZLsN;F7sd4vZsM!`-huf+RZLa_n*h?654@d1h2UH(SFl@1b8hFbO(^S zrOsHs?@_+_EIU4#MN15Wg#p?J>+aH@1~JYa;Ir3Oq9cn&ajGwLeOzfshRt+a@Hw(| z-Yn3jnoxV0Y3+=%@83!?k>fWhxh|D|uW9#6a)NcYaw67y3CPB3j-Ac%yX^2->a$}O zjw=TwKjnne&m(=OvM!}D_XNU4hi6@K5ppQHC@7@67PQ)G$Sk4JZcHyMgR-N6VopjK zn+Zkt>kgoBF9|C$)a@D@xQ&D+?W9oaVW6wkrqmXQ4O~sqIKm~9C~F0gBpjGbnAQd~ zleWTNO5l_TU28#rErb9C3&tTpRn*h1R&v`uNfz}lpaNnBJ~pzyzVs}Lz~}MI{!`e| zw0k9fV;j2cUAC`^tixmTh**)K9OBsD5`%w8Hi$ncHAgwBe~5gDensSi9M%xXsP?s# z4^0-1%U`_byn|Z)O@9+jMdU+#p5@LdKW#;Y^@-lleG-Qop!e%Fvfg+sVdyyTWy&_mX@e5OpKAU@MOkF@FVL{GyRnm~Zg@SOkABKOa5%M~~dU25-qJy;J^ zslA!Lx_rr^*6fpSOukf*pIk@UeqN}4*=Ucny(eS4>>7u-Li+rrnpyt~#|xcRUVB6u z7r;d7Bx`4!j;fkhD7G6Sz2$`-cry)h zl!b>vn9u+z_`Cf0O&D+T0{)Hi!;Jb{J;wC^Ug3d+(eKdyRz*1dIJSKcn{rk@2MIZb zvi&RYo%lx|M$Hw0cNRv87-z&bu$Sb!! zNL!W1)#1Dc$x3j>ESySm#f7&JIUB#Af}H(Av-JN4Tb|1YQjR01j?oQ*E9zNK~0 zdjeXiz7uaZbgQH<(f+maJJ$O!C<5V>ZygeS$#r>%MRNmYwV*e(S$M9z5;!Hjsc#d` zv$&phD(Qf+0UvX+Wg19xpUY2kXdto>m8a{#FF_HSGbE>XvY#8zMY3<3IiAhHYm3fP zFdmjnAwY_D_p|Xhkpb~d&Xa?8ru96eo_WEI^)CfuhG9oCF6?r+wex|yl`$mCG{@hd z9Rl^M$;$Tms9*FpS@K0|FBFc|+FrDI_mTKK=(o7DgT!wepxEOgT1z%#^A4fOjm@A{wtbrEF zWeZT0uy_w9L`AioD^}+8hX{RJP()do2%2l{~ii(>uv!$2nery$_i@B!?A#Iy@j7H(Dg0#XMcmDP1; zLtkSPjzO+*mLf#oigqFC3+x~-_b@O^7Te=w9M@t?Lgbak-+9Q(bhp}DC0^*-AADe} z&KB@|1w5;^iyfiFDtj2~$s7uFeT?Ej48jJheb1*Sxe(7GL}Ld^38#ggkH<48wN=OA zmCGHo+Q~x8-O|(~2+d$kq@QHtc6@Rms*574#_``oLIti{vZR0O-9b&nqWxCsS!#B9 z=~=$_;(1-F@G^H#Ea{8nYj6PSeBWX)Nvat7&OYyc=RGfHU90GimCvoX4&X&c2-eqV ze$LPFk{*J+4ODKcz7$S})@abMmSyzwkPD{OmFH{{IDRqMcY}B{Rpe-w@RgjQvrK?t zv0AxrI(|(X{%_+~_&<(c>XN^UeunF2`1@nMe;_kLY`0!&{CIXwTIV-3pJ#7eJz@~= z(vSa4^ax#_q5P}q9cdC9=tBnO;anRSR^_8?A(=}a$dK3Ag;Pv6^q>v(*$uumJyYQ* za(^*PR!6j!>-}RDMoN)WR6dvX z4ro;zMN053nSypfU4qrV$FMF_IzKzjr;JR{vWoRrpo*x=Mx%q_RleE2n&&3>NtB(= z+16J)W{)3wxu!U6(a4;eo&AEled>!W|c9PwxHi?}Li4p~T%Smz6 zn;mdYK3T>hCcbJqh|CL>=8f6!w4RXkmOD=zd z?brRae^~ozJ#}@3mD}y@;G2A8#1*UyI=2OE9`J$PuMHbl^ldu6y^a4nKY#>N;4<_a z;WC_6LN2rH-GCPLkG+kC1vn&gmE|6qm^r@6H-I8@a*q|hC~pr8{U}d)m?GKwtJ^m3 zg|Z9}@i)v*W&PdknzL-)+H5XGpGj%T zy5$3qN{HThMn%*AKs5Phd@5jT8hqvB&p)8NMU~2%`kQG-t*6R|Q2b@AmvhJ>cCV?} zr}SLoZVON0upM|0dL`8UJ6)V^!{F4Gf#|r zxjg#|`~p5Xghd!fm(_+jt4=LS${qs;mX+Q8^_gXFJTurRiK5Zp_(Rdp^V*fDpOgRf z^6ZU^$Bwh$5iF?iPX%PeJG?ftKXQGq%J)+MSe-^)hlR&a7L&@Z8VUF0qMt-$gsnEM@LotfimTzD? z+rzIm5pgdihn~XWa7(eee#qIY`x7Ub`BE*{15{py_29rCdZOy6vRa~y;{Bh zIdU-8%UD`gzV$j(eq@9jl)o&SDYUZc;-_?~e;|&(7XN2)lY#Hjfj-NU{fqrCorA!f zrsz6D$e%~g3bb_GU^-eBZ^g5~#CEwwzmP5$_kY=8x?GC1=H3DJ7-jC}%ZeN?`1+_CF;#E&%(K5wF^fbwKU#5ikFO_eI+^G(06z~^Jd z>g`v?=idXOY(H-l?U$Xa{m%WYZ9li&NXl8-Ef|lMlD;wyndYKDokEilg+hAa*$v$A z(DL|eMsEd^|Mq~g?FGaW8U6mYk-=AH%9qWk-~!}J{Wo2@XY5l&6}F7-=Oa+pcBYbi zQMsag5cngly&(E~_w^OWs%rZCZu8LJyI-zA2XrWOj~wE}%0$Si$gz3}c(igpL_te29j9pjMp9Jw^rX4ThGK8;OKa|P9K&fM|lFuDo8 zpEAbJ@!YH9cuUd=5;5rDEvO_(de8hw`i`dql6D6qo#i}x%WsFX3i%u6P0x9pcSZuI zihnlr)b<2Qa>ej}Gyb{k)Fr%ZL8{+7*+qlr&?XV#Hg*W_G`zkpkJ*0vt_ITdD{FP_{2;s zNZwy}V8rsF;^)~LcU&|3lxBX@0xk*S{medhRPxx1oWa{a|GQWZ5?v@>1sAV}Kk*O1 z%g3UzRNG62KjuxZ!S6cs+V>xU*I~pf^P<74(*As+e{5JjE$ivAg{zEBnZ8G0=g zPtvJ&#h``fj)$ysX*`Ve-H2zjvyOwYfdi15eIl1YW3a8wV51xKID0U$~r6RG_S!XOTk68Amx7bK$R5-%Q1_>cC~--(9!xX1eX-B zA3)LiWAmKv?}NW-uwdwk=oq;?{1?1%?o6z2F-IVTKeUcvY0i!?iMjmAZ@y@oNYkwO z9x}v_Oy5YnJF(gN`OxJ2lXngF>5JR^m`az+!+$B4!8Iri^v9Us0bP%%dO8o7{gc6W znQgEjALDCiXzx8woK6R}Ijn1mdV1ly|?I|~AQ44pqsfce_?JY2qRJdrILGC@v3w zA^5#_XI{@c=niE(-O<1J~QeC0{xijRS97zv48DbUDq|AS9s8L+K) zz1DkV7C6t}$-=$wvv9`7CQ&vZ71G>)05=4J6vaCBhP`Q;3?r6-B`)XZqJIcVT+ldn z)hSiSu?Zc=&N|T@$87ay%(IvI#g)tFZz?%MXo<}l3`tCNaol*Ck>F+MTN`J5Bzm5OU(LX-& zA2<_4fbtL3?D14#aHm9YbmYa z#H*Ek|4UQsW_llkS(`0S^=dmzMd;7B`U&Y3>%9suAWRAw;w^`#!3c7;FFfGAn7qZl zIu@SN!9zBo1LRP29CGMsa2in_T4Q9;_kTti6e;9Qy|sMJhZ+X{()VC%u0%9^$P;#Bx zwCAw)q;0kt#n7}c&V@nHhiZ>3EtH8|ir^xuEh}Awh38-7mfyPY{ExVD zt9Ie}uXgdze{jL|zthEkY~lHDbn$Opc>Y^lxmUaJ{9ks<&(|)v{>QrG_SnMn-}p<1 z|5_KG|1dXy?ZWdv;^Lp*W5M-5!!3Vo;rXw2`KNW^`G;KotzCHj74Ep3|Gj1mwqORRryJzJ|>B+wwjRTgd~Pg93jzhauUaTv>@~8jTlB-0imlA ziQ53?yhbGMZXCX109Z8+U0c(`-{G%cil5}r1vP{G9qu!S!(CjHlE>k1%GWDvM&$7d znSdDjQO&44-u6TJ`jeV5c})KpKaBu2&fnoanv{)07uQV4cxBC$JYMlDdAzn} zS{}dt8~hNB41b6FekYF?*JR~!_>b~N74{qTkWIJaOid(9o0DeBSXWX+q>=K zlqBx#;U^*BQ0E};Nj-SKQoJYWa6iKPoVg$6J&A_*V>ncAym4sxMB~t^sm7tBrW=RW zWMJK9&B{{jCdrLxhA$9u;(alB{{7@$Iv%Wk?*S4oPyVwhxZiNGDc1WjI%E2Z&9UAi z$me~<<72)5X71L;dUrr@rOd_m?r!fo-wB^agM_1;e?NEVHW4XiYQVmMJ>FMr=zKmo z{0(YoWr^`+Nqdg}JAaPvMIaRZ{;AGe@P)iF<4gM#axQIug8w^*k%}Y=r&<>4|01Z5 zuel0em*bqXzT)y&{|b{v_?FQ%S{-~nIM)9m^Oems6Miono9Wtb#{Wawf5HE;{#Uq` zM?=CKaLHKzZ_OtY$K!lj(f&K+T@mX~n*{KYl%w+LSpTT`>Ml`X4Y~Cn|hBOq%JiSpT<78uqeq`G;fql=(VV>1+E0 za5$pqv#KM+qiJ#rhK_O{zkgqhtNA{*Tmju)^0PW4)&t z>KrW$bBr*|F{r=E(^DZ&bF6<%zOLyGSNm9LwPR!b1114N#maf+xLE&b=2Pp8Pr@^+ zg=bdB`j?wzE#YK13U5#IsX6>M!zcF5h z^9*tSmW^gPx9eX1&M>W4)I;?TNJ+WE^V%|R+caggj(NtVuARrcZBN$FFKWw;&B_>JFY;IS|Borm8h`>xKutH*E3zDwG7+>|3@-?i9xt@w@q$iVBi?|SgtWZ$Li zyAk}R?7K1hZXCZE`)Mhvcp@ji7uV$FJv2i8Zn#$XW(8E=qJ1XM@R=$izms41 zOf`|u0?KAm=&r}!rojk&4s*HRlfAE=VBcG$BEuQP_vuB^FKJt6LeWw1%XYvEn zQ-S0&d4bPO_L+RZXR46=P9EShbx1z5{rOBKlFw{=K2x#aGuxfdR3rJ!Hs_RP4dQF0Q-26mz%xgg;K=j0&$ zktTj^Z2ErQzq(?>IW?PB4E=fXdKm%sr)591d>pFu1SVpkUax_AeN+bOHfGAWamyO+ zPc!Bpp5%VH$q?S2m774dC6JRnc*!whEG2^5j1d!<5<@H7ypSSDmL_xytrS}zPzvFzRzQetLn{^hO-|x)K-MgFJG_5}W`#igQ@7>KsOckB#Da>G8<|Yo)TtGK;L0Pw{IVD3`K)o7UHQha`NI z@yO8)Z^I-}){3M7gikGcgWnC$yT*$7=duRyNsn{PyDJ+W!n=SNHRj!AVq{(^2HjOM zF1f1V4x|d^q*`D_|52-OC1**X6%vLaMJc(3eoQ|1zN#4_HO zWYep8mF7X!t_+`rnE0~rVf-Gubo{uY`g^`Z_fdz|p1=(2EO-n=Q{de)yeoM~y%U9j zcQL%H)$c@a;9V!)wd;4?xF@_geiQoLpnjLYZ^I#&4~DC#oHJsnXl^yAs?> zH;vzfekUp#=}4OrnUr`$sbRb$9fN4-tcOyys%|ttjH+e5vZ@yT6M1gcs`ehK4|hg~ zs(nQFUrVTJRj0*MS!1)>FxW=6S!kKY#TgQJoswrhM9!g` zg*KguZB+C3vXf56@l_2`<;rF2UysVw=R>8A`V!P;?v$EG!BF2gZ)4q~ooylyx(ee}ayQrlC1Py-(6Z?~Ukw^}3xy3t|g3JOj%H3{;q1gF9b# z5*d)LL*<|>Rk(8W@0^87%dWtT1 zPDW#gXV+!A@z#u*hfZerDiXTuwcFo`~dy^uR9VX>i}&D(8MA-=lIC?p`@l_p}_}?v=A? zpFONkJ2Fxuj-*FC{Q2^pmQ%ia<@oosoPkNZRiE!7`5wtZ-R_lBv8Ux^_TH`fJc;Cc zRG--Hm2>5umQ%KS<-9*}59;qXfg_Ea=xBf$7dba|`zfXl{*<>kPyVqLfkUCS(+2Z5t9 zm?3Py5MbxtR%;9YZQ2>MTHi5ukyGXF!*Z+X->`}h?{lTq^fh%CvYN)?PVnt`MsA~;o|u|oNC?SH{`3#5zWS;qRA!@nT}ji;^R`{U`~l8#q)l6j&;XPhM<8#Z~bQT zsc`+6>oAimk(0~bR6N%L>yEW>vH{P~VufdYPTua3OZ*ZYbQIi9mVvgS8f|)n5<$=B z;f6$sS1w*Cg(Z@FDm`ZZOqscA4LZ*8%>+5J+e z19_Qo62#Iq>p#gc5>e7)2l(N*bw3rrR#6S^qE9viJ#LIE{RF)z`Za&ta3u<`O-$kp zv

S2!#a^U;*Vj&t{>iwA95c{uoG*Dm>u~=hPu6oLIbxwv%?g`aTIKxY#I_Jzeqo ziAw)(jvqQ-Qv88$z&Q8Jc;9jRqAazl6o#3`ClsB$;}`N`Uwm}GRB6bRvroaG%>q$Y zQpIpWB`X0P)QCV)X%(I=wNjV5AQs3gmwe*I@gvK1=iQdz3G7Lg{8f#WK{#wSRA^6( zBe<_ncW;*OglFR;@ZA1<@mXfoA%kF>b$axWa@qKn^w5!=Zjtc5MQeieE>2f_8->+h zSavgSKW^~IAvn*b!&x_w1=$7Zk6a7kE7S0s6nGaOh+o#8V2rGh@#O56Sy8>OBW{B1 zu&^=M%+k$h(&+yqOx^S$`hSMi@UCG2oPOy0F9GJbL*MVnKberV@>}Ze9BXwHcNFN1 z>IviMsmx|9SfSou6OW5orco^p>oU=>nFTkWid>;Zo%lXy z>5sj56tAXC$#@9zU{Qi>7wwjTetlSx^UB4aXL;7jQ=}(Ce8=kJbx*cy@^Wekxfk55 zVbJkMysg!5=w4>mFs{*B+N3Ow`{{Wpi_>8R^9+&`rD@wwn> zF*egq)tlLU=_~&OI2k7kC*7^+uqXI*dEj(vIHnDdUm%3(mloZeV=`de*|nKuU0f3C zmHN?$FmWKMwBJ{ohnEdl>~p{$*UmXkxKSd23^!gej0ifH+^;0cthZE6+p{O>Q%0f*=BlAvu?LU!_nD& zHuK}-T_5=kJcEwLoU>MoFF>Md=UJp_stXcMTO~uqfYN;F*RiCg4?*lCZ_3&EBeRaE z>(SxuXa&pj?mLftzC#cU016EJ18nDB?`pMaSj>ZTE#G3%AneFPl!-7a199LOD@`ln zH|{#gDqWtDR~u!W#qwNx#cDblB=X3KwHha_N>83{76qYY1=y6o;i(pzZ@@VQRf8Rp z_}%b&v78*b1z9OpR2Bu_!cv;nC0WhJ*GNEhT;DgpKEW4j*6_S|pGLev+%6=RU3J(J zoHzgF$2@m!f%GS<^qHgp&n|6hKW~DstN^~pX!t=e&pn^QVwXOeOGCGfP!2$zEO%2VzZR( z_aL=r1mfIvtvgTe8%_SD+59Dd?VOMNUU(O0;dT91(R(G*@v`wDKHl?W%JRVZkbRlX zhoo}Z_#Re|civ(>&~EEQ7b+7NZCC9Z)a?~=c7s9Z^Y^JUddne6io|Gq-W9vA*W>8* zEQ^*NOOlHy)aJ2B(Xzz39xgSnrk!>TY3a*6tm=Iz@J6$AFAH}^;e-Bs0RG5DH-fjR z_&+ID!}cWL{_ouy4%(PpHogfX+wQTik`WeIPXL!GNl{d&RXFGnZ6YI$V<0RYT3G5d zT!UKyxC_;Up=|%>uD37K`KYgX+4u-P2q{5%nCtqm%(^Q=1p!ljz+uH;ln936shnR1 z!vvN}O_^}yq3;Pt(zA&(-Lc%FfM~yr(vgfi6v%i95eG^qep|*%9lufZ<*}%|Yik$=e5r*$Lb-_pAvR;B;<(p|$xhy7C1X4LfkF^kU-oh~H84vFA< zz`zAAyli|VADVCpal#^Yh>mkjm6F7I^)5gmq!*R!BI_`W1kxF&^}AGCRlcq+U0(vl zW#ePuCWPM#?mmFa^f8_O945wPB}qr3QVR*c8VOMmrZ_`Bg9L*dA?7$E}D_?uLm zRA9G)1?h0~X=x+#%bl;B#2p)8M^tL~8))p{vhnfb1G`W_4#i2CzAb054F4_2zgG3$gK|QuoJ>Xup@L1NnsH8TM?W4T zow_yrgOQl@F&AZ;AKgxI&ZiH70#vgzqd2M-JFxMn&s1g$#gook88nBIDu@6aJ5Q$v`)O_8^~g9fp>A-D~Psif+To zb?t@WdL#T6<#V{+pdM=1@VxC!*8_c=X%AM@>kxu$n}FKT_|z82ujP>k=mb(M+nlaZ zpuLuike}@}^Gj9V-EFUNozL)|{1Ln$paVh=)vg{nL$z1?U($w)w%5OXTeZK1BfxF; zz`YD`DTkFh{dgT1?U9rG_KF6RZLi0Hcy=SCP`6hwBiml7Vr}QK6U2hByHzU4T3&lo z$?jIkQk|?JTl~{n5g~L=6caSDtSL`9JMIB7T6j9qttDkEHnK4r5hc#k zNT}Lz<3ox+h3tHxxA(mFfwyyPe9B)~=LdV_vhhuQFaBZ%?;1{`aKPrDgRhnh;48&sog8!>A z{(_(9!naW;)(u8dp1&XsrqSx<_(}N->ZNLCges9y9)H0H+tp}N8&Bdd7(dU@uThul zr6cd5k9X-W2)>*hr2ke#jdala<5*2E;lUU^ zWn0;F-9hFwHOP#kM$(jv3^E^~KRl?*A#7eYKD_tXnF~-iAvVJqvS@=PZ$PNiFstGxYMb^WpLt>dlFtOQt5e@ePKr zY`46Od^29nC3b;$HMI|YvKBSW62JRY>=D}rzL5AFq*9jBPCd%gR40`=;pFa1Z_3}( zc)WwMusIZT$DxKl|0(=O{^{bL1HbcUxpF|>^FlA61q2-xZR z@2=z~{zo@lhj%IVopHjG{ms~G%0R^(Zw>rZ)iWQSr(K?lk&>+-NXQ8F#_W}=>v(REJ73T9OEnc@uyp}<%`<89$j zBLleg&JVcpj#F9EKs!X4GXhYASjNUzsU!;Lt2AH9hA#s~vK{C2&$t8cDgf?jcl&kFN8;@TI#osZqa2HY}s1z+?}GvJH<*$yYpX!VcG z#^%L6_f#VA!oyh6KQGMzoogS+%7@WKtS9SB+4btTsWYQEr{}FeMLhL?V4B|iyg`-~ z$__@HEq|gL>mFs&I@HT8pPfthcBiXZY|m_i3TNgvR^R2LZg%yFX)kPtyimStCrnd) zA$KsCcPJU0SoV1+EEV39vypv5Z)E>6{je0#o#@t_&VRVNfYt)(5nJ{XRe!?|BWu)W z#6|Pl-CxK!f0xSsLO?`0eivqp9!1A2Q3I5Z+V}Am%XXaJDezE+dcVruK$_5>^d2-C zewMM01^W}-Tx?wn{U}@=`$h2|b^JKDUWT`fd(d_Z<=9%;iWgqxvV=rt!ReH)lUtp# z4^(yD?Y-a`Rwtw;STfE#2fF((0-9X5{`JbwF6(17w6{JdUm*1vyg#=-8obCU{bAm6 z)cjl=#8=@P2%x}j`#{c-pbmWB;-LYOy z^-QX}DzW+S>>dA$9x8nP<*3eUQ~LgH5)AxE4dvJ_rroeiUbcMa@N*v{>l|Hr`{nbp z45%(m)B`ZdpvLe*0d`|w17lg~go>HKavVBT(Sn?bl{<%e%5xPJ`)8-}yoo+D|KaVI zi5m0*=Rd5K-F)b;8BF-DVB^FDz+UK;_ciAEEJ)IYkR&J~?llv=m6~FZ&0DSCWWUeL zmT!RKJcR3yTzrzZYn&_HqB`aSH9}H|RhE@{x8zK{pP0}cFH=K>Be$Fn|0aXD98-Jx zxnzDLQ5mMcP#9&J(n@^|KY7zXF^4cTw&6nH7o%UGlf#Kj7~LqvLOQEHL3blbY6$*mdz&g6raq&p4m_>u}~?7e<|9 z|8>5i#c2!JghnX=Ey{+huoUL&Oah!sLCFOu3apTzc=&q9bi-Hn-)yt__PpC}+ZA6E zv2moPgfQrh#r3!vOyz=#3k_4Hd&eZ18V7mDvw)P}ZqfeX#*%q82AjiX$*>$oP|nd4 zgop!JEAkS(kc?x;D=`yCsv&T(cIes>R?}7~*IgN1NqeCHf6-nc7A+T|?KYH*y4{*) z_Fv;KbQO9l%F3Se_h&V*d*N{?+edr*P+tR(bd!=#q_2ZyNiLHbcRGjuw%*HT-2S#jD;rX zB*|~^Z9u&MMp=7>*pPrSpKJJ%?}wZXgj~l}CAnfYNdj^doRVCnJEMPGDcQ(DJ5N_l zJ6oS~N9}rihy{zTf5wzs$p2W1BH*u6L-gF3egW^?I}EgYKKFkF_pIS?4ZQz8eV%=` z5Pgctht|J~$B}bva~w)-2VVxe_f`rLbJH!e_k!Yutj>lW^;%Cd&Z6~XMSctJvoU1G zT1~Uix;=chR-ech5V~|aaD|V}Au}U-P$}41DN(vx?kc1wZL}TOIHD&Z8MmUHBtlKe z2`FRC;_u|Ze+q>Q{Pu$IofBbYt9HE$`|dn|b=MtynIH#k0SUuK*?0M^6dII0A;k1t zZP8LpjqNv^L>$>R7?Tx_N>s!7VpR_RoU{4t(J^w0Z>LfsY6T!#@Ddtq%k?=zRTCAF z(SqlCZM!zqra%iO8**E*^YmG!-yW6R%#30!Jw+!R-6^88j~1P6;g))c4u)?n^$;Bn z;b?fX4|heUVR?~$vWR_aMP4Ddvueaz9WvtO+TvU(Bc{6+v8@gcmP0Iq=m})^+5Ezl zXWx_mu76SZpD-|s@EMpVr z)!mXAwzE@~ey@Ojp&UbhVL5H|m8Lf^M%y{I;WiKbtku8PWoP>&)9oQNgT8Z&jS)S; zU2@i!JGXNgM?X9$)-Gl1XHVyhJ4C*=eoo}eouxdM)yt&!rOrU0qbd+9%vd0e;BqIC zU0_D{pVLJMo(Y-`JQuU;JoWsKXj^i<{4CI*w%a>fv7?4-pqRhGq>alyzHyECpHTty{i@!qO>09z8>0 zYy3OP-#M&&#upmDhufa4NEM6r;_@{wF1dL0*92{;skd!0XesC%n-z6RR8OULL&a9< zfvYW2DB}$0Nw_i#z5h*-_uno29wrS|VU1ZlwVTSuS&UQ*Vyl2YFI&Ec^;2c}<5^!F zYb1J7f^_9ntBo?$^`#HsUth<#WwG)=%?~)QZG#wl+VI~_%hd|{kl3Ks3Lse^OEQmk z2s)4d+l3_B;ci0mKwgPw3fDrxf}yA!BZ7%$j93mu9+WZSjwfAzm#)6o->Llme+EG) zKJKugzb4gj&=m~al9(rF46@?9Rejm|7t%=isB(2g6n{`w2V$S(x-ATa+0xMXWaP7) z$6!N{XDM4%jlQ0wh=`)Ea_1{N@GCi%)4IL{V|yDmYZ>NL=x;Bd5q+Pkl?SP;of(bK zkf=Hdu!P}_1*|fjs{&4_+o11Y)TfZsn{jYW>j#||D)RehqR<1xJ1%?}x4pc>UD2#s{i-AsFJ4{e3*B zVc77E=OGfOQ6+OfwmMQ@D2c6A)+`?1#GebVv(+&B8)aNL-1iu}3t9)hpUAfLTBl-um z+ZpmP9m`|4!+h*=%5^?=GkiyXzrynocON(Dnvjp(4AZcSiGP#j&D1@N%E74!6vMwM zupJcN&e=L)H=p7v;Y@TX=qEZwtoc5Xj45y)>rnM3_>bK_Nje5_xgXqT2_Kup;V57H zE-Ag6gX1+~>9Ci37L-G4r69ub&tTh3$swY9pkTP3q{fH8IKgB^c4Cz*770}4I`b(I z&h;mYKgje;R2{r99+i2Gi#^JG=~+1q-d!g@2Q6$~8SAGFC;B*H_-l(v9C}Ub(_2pP zs3W#E%BitGfr?zluGM}hH6E664WhFXC_iZ*#?J9M41!TdZdK2%U1Ss^Q9d~D57jQ) z^1QN}ji1xj@Uwm?tBI<|_@=l9nfMqwxaqyyu$X>s%;Nh%7USDrS}!aQmnb^}Lp!+g zOs|{F8~Yh?~Ki-!oYM7W$FVbDos%oAf=#Zp_Uf0r_J~?A3pfR`Det@*X!iinJP>r zyA3r;r9VMtz04Kh!Y7Hwl6cs2lwFa}A9JqlH6);z+A5OX-qIy_Ko!bm>)$Lt;b(jw z)dBOhpD`0>;c$bZOM-71vCgteUo{Koz_kcTWS9#wDCP_QjU1Y|KXzx%T_{ZZokyUv z>rRsxnDp$!DG%JH0)bA>ACA}wog&2L$gZbZQ>$Qk44lyA8GBw=*X1kdF7Zy>_b^j( z1p6tsPbn1dltU-79o5$Jg)ZJF8M{TAa$NA|K8+HnrRD_xeK_U>W4UTXMyjPJQ4Cdl z7IDqjBU6BF|h1v9;xPy*irQ6VH050d4dgBg8hyzzL7QH{NYln(kfpNLiTs{evX z5PcUt5>9!h`xcvDYs1I+%F$;1o`ye7Gr`tnpgS$Wk;Z`~2h41%_oE?lkY;a*k)lF= zK7s}5uPeHemZojtR`^I>f(~k3#i>gFW;%dlPezej6cy%aVUKiaILyn-#)ou<=ws@q zisq^>fvn2Skv;c$S+RT&!jfayQkefd9F)avfO01e8K+&T^BdgVa#7xFH$Q{Q)P6o@ z9f(ioTL~O_+4vA&v|HP>+w;XHY0CJl*14=brbVe5Q*nr_X~AiwzM`_tKp=q?`gO6>yG(EcDcCN!IoNi*jE3l+tI7wMoF)VKVw0CT}_< z%dz*)Cb5X2+9Zb7&(K;G=EHpnqqTvV(RUaTqhg0I(86rQLDZH~Bkawc5KxSbRNm#g zSKj8Ws`2EM*QE9vs5ez5)mYto-Se&mm){*na#e#az&+K!-{zqf+^!3(ofG{q)s4q! z$-K2}_uZu6+6AAnj#@?X_$uOS7vL)T+)ZM8(sxskyw4mVc%Q5C{%_2CW-IchCpUAR z13Ax5i?w-ZB>dPhd-8`{rq`lIZhi1v?tN~VUcw4{{-2QdJU!q|ALbO&&L>C(Cpc*{ zMwna8V`$&aLox6FT_pSTeRAMMm*zf)+otdDh2MQfF8*P7)dUcBYhho}btc_&OJj7Zj>}z80(HkZw2whNf;>en`vB<0|6*7pA_u zd{RYx>L%+)@wRH;&^9l>(7sAS-FDd(zQ@?`I9q)63!Gkz{u7F29BUiK4Y}q^SrZ{J zFd6n14G%By+E{nG`g*oZNTJ(ayZwj?xLx9nd(R@!51vS_y3S{vpH8&_Gu4utl70|L z+V=?Q=ey~T-8r<=zcxmF5dEN+X7Uqu&Go+2=iC%c$ua8x5#a6Xrasm;Cg9s;`u~GI zSNI;wA;j63m3HuRkm7ub01kHTI(tpSe*0Sk?yGsA3-1GBo3HFL~_p`zN>6BPs|MY|SqvbDjam$2iD6Q(2ivyvH zLKjxI+%zsU_rf_XpQLZG_ka{P01u;ub2+U_Y^_P}*7BI(J~1IJ7sR}Gu{wUdz% z!SlalpT^<@|AdYxeQ4spy-$>E!drh5Q52O`*Q{{uO;8|6ujxzKXtT z|C8smwU+z;FhZvT+~d6YJJGYRnLvw`-} z`^T=YjwVBW>rwL>|LfJ0Qx${$ftD|v!Ycby)ou6f{jIOIe_S1Xv%2C{R{zy%|H~k8 zWy{TH=rSKU;?8Mb`&lTuuBPIx(B$XwUE_bRrtOjcnH+dzMkx9hDY#-i%C4FGdZ=Q3 zjsM@(Etq#;p(rxcwrc!U$9{4<-=#57{ir&cs;)>*9t^eJb4b;1tK$44gEwRGA6WlU zUwkiM76mSER!@Evbw2KbOD{j}oVG_k{qz1u9lRZjMAgx2kaEpL|C&(r`B25Wn#phB zyLv3%0-ybeOccocB{X?GzJU@D9y339(hI=qAQD0&fpV+;Y5WGGzxJ@lD@51;!dU`=@A&zmPx0zUF0Q9TwfiWPt03lmOTTc~&z zk&?1WiPii5MGAdS>hD&aW&i7-OKYmz9`Wzx{Nq7G3c;ZOJ&L2k;$BmDkUyE9yz>zV zaLh|%Zu$~=W4NNZkV_L_G36UGk8dM8KpWQIE&Gj7#S1mjf0G?;tHzu?^@Aa>#fwHw z#oHnOhL-Bm_dFSCU z$~|G9%GW<;GfILceeqyT#e4oi!Q-v!mK!LG>kbY1*G-4iR=?T%Kqx9wQSrK#Rq${< z%7m=mbI60wymB7sIJWM*p6#r1b@Wx}1d59iyow|kVb}lRiC)3w&5A+b9UTPLLEyqB zz2Ua+mxcT<0A~~l6j?Y30`w?sXmbx8{K2R0e-nWF;^V3-wgT&lH6j0BS`gm^L?(s& z>p}C+M#|rLp7eedB?BD(1*8o@kmj7W2aewB$YyBMH-Q=fyjs)tz=WxT&%cD?`qmt( zh%)8%@BZ}-P>UF@BZlixS{k5F%`E@%QD`E-2W2V!FiGi$iWHiI7J?vkJ-f2nD^=YXjl-}R+zvH>+p#LvBpgeCVeQ)BHisztv{QubTY~R|w{aYp`h(V$+Zut`v z*VMGF^4~9I5&Rf{;zc0`ZkoR;QccZk?RXaI ze&6$N>%6JjKR6N8eHI$HCORlZ4zftdRlG)ek3*7goVXLaMD)eS?|6YIyvBZK;)aSB zs{K#bw6%^uXqx{g$hu+g9fNK6?0^6MfiG11H%x@g#zW{b(4F-4Sv$a;cdI83XbFD{ z1)&Fm^7gH~ZO)D;dY@H$_dNUJ@jC_uVJL67tx%$Wu2^@JL%;dl9a~xsMM?g5{cCm%Mh|Vdc-+K+dGq}nE7D`n4~$*9 z4~P)DEHu9_esJ{sfPWC9kI>~&^v72idnPn@M)ae{PlEw)VYuzak~uBsVCcWCDS1}3 zKkR>J!-Pf{6#l7etY!uxJ$%-bHQ}qDt=OLW_6NzKUYgF~=sT%}J7A)4KgYKbCEj+> zdc5}arH+iwncXtypuShf!Y-LMH}zwr!vDRnw0x=m;X}*V?Q8vb^*Cd@=*-0U7;ZjT z%Q$8hud259kFg?L_=CG~R-^-W(M=WcK48A9 zO|SZwjK$tb^X7*xLshGMkJFH@*e>{|UVIe?r>mTQQf$wt0)1ixDRYhM2 zT{t89F=_wag>z`~wM-AT9W-X@VD#eP&EuM;ALIuI{zx>YtPf3n8>jx_c1GK+wV~)c zGuq~t%#408Gx|no%G)!i49)WYGxex{v#HSEQ!gRV0U=!QU8Fw4y+)dLo>d*)YTe1{ zyqf5HGov4K+<-U(O@hCNn%=4kN5|q7LcgXVGypS8Q3g4~B^JeQDYCR^nvGwCb4)A4 zZ#jO;@e6O|dSsnenYt!h=wrAIHGOo}itmToE{aDt^*Q5V8f_jQZi@S-Yz+4$$ItNh zLyTr}l=OERw&YT1e(3Vh70z3}%^+}G1 zN7m@vEZ37itdk6_2v1%U?gsU6rB{T}8t#$O^3uEI?dVId@c9}JGypthaO{{P4>{$j zB7BY6B4XQE-;Yq;kNQ%<1;;j`wvDE?EMNU!5r>NUh@=jpvPg9M`;9A>jNP_2RuRAb z)uEvkK2%ZKK^ESzkj)im`g{Oqs)O;uFn9!q%3uKO0zxHRe@PY|K=~RqsA2yTyTQKH zp=W%1>HITpwJwg|e3A8N`Y|s0ioQ7I-CmB9Z~rF|eeR9hp8+6Wb=$a8Lv7)q$?sP@ zGxh1Er%io#$qCi|{@aI;(!ZoqCBFStBpsUg0lTejRuEJ&{H>1kHw;3~BSR>xVG~C~ zjmYVP3^EfieKg*eJapokY*wLx8laXqoi=vZLCJ5&x$bqh3&+XnN-{8&CLJX&hZ=c(f%fH zJa&jZNni4mygD>(@EcX&Youf#714VG3E>&cvO?3U({Du{f=fZ>9U+gwYn1<*ZaA>j zy)4{`|6k8rpU%0S#OXQn*7V;eu2%U?MjJPT)3fY;HKT(tmbmtxvtDtXzF2wi-@EhM zpQJB5-TcM*5^$E;3^3*#3C{-QB`mGvM{2SuR-)@e-1F-rc-@bbm^T?AK0@MXs!-qb zz~?Yg!03Eg?J9GKCjQI7wowi*t|i4x5Bwd7hFtN{$3r~{jgr#uNe`Wv_W*n}eWkpd zbI*HccVP9l3d~D8n^x}Ri7^PjsrLC|8V*{|u=Sv-}V@-k}U&dVKhYb4{~#d4x^Zsk!*fdW54puxS+Cth2oVXjN!R?^P2gSms7%PW%) zd~)M_&Ixy~`bn%a6DvI>{JCjIHQ@P&`(1bXdr#Hx#Pg^0#xUH`3nmT>QZq*Jr6gr%mvn|O)*q^?x$br0H~2uoC*7ec*S83vteag2A54b{lDMSWO*gK8(lk(W5;@wUOf|kI5HQP3wo^H%(pLP zf8D;URQ1;#sh?n{3cTq&Mc;HSJ6m-{alRfXyYou)=Vme1vX3s4j_D~5xRdOnx_GC8 zXu2Ozpfbw{3jclAXu+2tQ(E!W1D&4QAFH;NzFgINgmz7RzvxQHN2+_8v}=Tpr*&U1 zA&-=kE)B=@U$&v2i5nW%us?MFIEhtcJXcHmM05r``wtH?^^`v5KjT4d|r`xw12;F$6~@n=$xE4+s1bYSHM zKcZrAJ?Qn-gRS6N%7tnX()vjmr>Rwh&rl>tZ2l!^N8*e0>kC;l_ zUXt%qjY5C3>Ik7Qs#3nL->FI=bO~UPXA^FM&P!X-hsCu}>nhF$3eMoTi9TB6v`x*$ z`tpKabGi^f5}&8qWg&Uh{jKP2+TWS*^kI6tS?5P!5*c1do0+bd5M z#cv_>00cAbteJ@6pKA|iE>-*>Ors-63(||vJ$h%hJvDhYZya(>FR8A(oGu%u61FjVz@mUFnOU4-vXV-I$EZ0BVSd<=(2JdgI@zObQ ziIN*Hy^G7`ImO|3|3%B?@jS)OmCIu7)%oykYI0NTF6`H*pDbFhc2lp1`@HokR<6+# zb-Lb#;_nm>Fbn7s5yCv?Wo2kd>?2GTbyIb}} z-K_t}zG%HQs_Tw`{HYF!oFzK67RJy>OTsIyc^tz7v-H-{x$}&PNOf*{exFu zbX=zF3ByZcGaA1~{{Q*o=R$NQu2@#(gj2=kg#VX~@IUor0RN8!KlRU%;Sb>d0&*nd z&8yfic-LT;eG%=@tij%nVwJsW=x*y9@9;#{1*X+dMDLQ!h;?os&Lv_TYIsH-&Trli z_+(#b(%RtVS+}Xy&2WZ7EDPX+;m&xy5rTAD2Mir!@)>-P)R&T^jPI9i`y}q$_(?+= zZ#O;mA!5I#4Vu0Ff>{&Hw0dL7*};t-&$>CI#xo{K_XyAV&lkb7`HR{1PP(%1=jB-! zl8|+8UjpSotVH=->BF!vUD$w49zYI^-`HAh z;SHO9rcpRiW3x?@GtDTB8)kpNt@3!xRb;+CM5c@wr`zIfIQjfay$d?l9CI_3fU3>=lV5rWrDAJb}m0rMY*WE z`El3L{FM)A!)XBN2}Wd>-3-lcQem>Yzh1qD=dG96hZxqDT_mD_J^ILhj>;sslxx8vOb*NXN>0u{MN?hh{NE!rQXO@DCuqu%~tbZ~e6u_#>oS9<*Y z>hHX84gEcKX<w0(!sOav`Z|Y0g;-&p@)=JD*Q@%1)wK={IqgN#{ zzHEJyUC(MY-H&(P9VS$Fpz2}hVDdqp>Re;Qd!Bh`JqTe|M|JZU^G+-gup*5BPPvPV zlp$DI86Dgpfh!@EpH?k`M4v=4Oi;==yBL=}5ZFx7JF#xdP&c^MhVOf@fJ511dIoc4 zunt8#i{U&fP`)WK$r9sPdq?55kCgv1%TMd_J#tK%a2}SIOaGT(X|R2}eKg&FO_?*T z)_2h+ad(B)>PI(?yX&piOQ4@|S8ufn4VyBHt=41JyCqiZUh3`^tM#*3_JVY`G~kfP zU#kHxXwg&gsC$opKiTm1mLz@;vswp%8}2?~wZ5gwIvnT7Ll5BH;SB>@9>?##4e>1x zS218oa&MiY(;)qqwiKBA4-=u+Ow2vw8nR+#hd6s(F7m?#C~`1>XUym0MHbZlcxt zBSj^gd;fsBlK>0n3S?pyE3y~v9KyrnSSzv}<9;Wk9>-X%Q_Nk2i!~f>9D;NRw|g3o zJu@Em)^P0dKk>ii#CNad34U9VpE2Eozw@U1iWQ0R?c^@++b>&@Tkv)Z9JZNDt;mhM z{~PWvwjx*Yeh~L(SrHuBJ+x&V?vJrr?@&A_wOY5R8Xs%5o@MSLCo<*tkn$)iV)On^ z+#i7e6W*`HeaUi*-&SM{-Z)=TRXfy*Y{Q}o=W_M9kEGcL+x79~4E1u76?uk_r>n;a zRx3A40xWD6@+kk9tp2#(iu^AgduIIJThU9b$T#s;DmvGSM0n4N&b3^wZ5ZL9lsoVcVtemT3<(6+?`>y_Ng>ySdpXf z&S88a{`i#DdZv#4Q9uv2TCY}jhghxGn!Csk2;g0Xs%1s)=7MxbJat z1oNv_Ye?l-WVOyPcaeX5h+NMj*EP#$;(MXhdX%cwmq9)yZr53@Qx!$7!zQ9k{{T|% z5B~GM9rssSk?-Ta=lx%KW#P)@N8rD!mcwkyTy3@Pr|5gN6}gG|p2gd`<@@m4ip=Mm zIPR~oA{X%f5!_#9MQV88iTiVxpN#KItky1t$z@jSjSA2C%ZdHvRx7+$ zF8&cz>5jBon-ndNv?BNNj~$9Z2Ux8ys=EWFl^tkBmho@yd;}~Hup(dPBR43+Fh=Dw3 zTdj8^rQAi{#vW>0Hsby;EAlGudvU+SioAgPo(FR@*Fq~2X9{YrYplp4yeAIVE`J-} z3#`_11$6-qLFIpB;uow|txLaPMON}HHTyYMOTF+JQY^!x|RU6xi9FKR-`HBlQ%YT6^HCE(cyzIFor>pyv6&cC^ zJS%V`^dIhfzM4a>&x41mfX`cz=a`lfJKu`*Gwr)MGJUDldWb?{p4EDis`@-D@&o3g z98QP+yV5s!{enbdii_%s7kVH@<^CFd*YM4t!t_B+^$Jqa7nQ72uP?FU~K+ z1YOItqwvdNK*IUNQP^WFma10p4P4v6#W>5pilB1GS=~DQDx~9O<0E)*S{1SHm*;CczBs_5d@bk+7mK^>mRSKmo&c{PIXpO!b_!n1hN&fb!L8_#60u%f<&a z10I+q?XL-R37idTI2CZ(uE(&4^QARN!^@U$8HX6VQSGDDspFC`%rrYSHebT}d1oFM zu9Mg$n`si+A&MEkr06wF^Zn160^!uz6CpOCCgreaJY$kN;No0OC(cp6Wz!U$3(Y&y zX9PRfjfXpq_G7XgjAYmW3YCp=mh+q`WvFg;u020D3@)uLQQ0Tl@RFqP*zMhnBPd0* zb$?B=>Kd|xCx~Oxl+gqt6tdCPg)nS=|7-mC16zKG`i>>jaM|*Wd?pTI4E9svwj3ZA_k}>cjh|pC_Cer2u=Dm~{q^1g zv%oKG^$TM>0F-660YaYm<3ezby9&;NK|Pb34ybK0^^vm)=R}n29aI194YFaxxH_57 zm2=*L*XE3A3hsNcG2^r$D`(u?$FdoY)W{t`dgz{apl!}rX$m~oRPTb6EU zhn+|c(u~r7rP4*m8Y*)z(^IDrjD^F>pJ`@TOnJtiIXmzFe19hAlZwa}$E()LUm*eN zn5tW#XqXqPV(O{IDyNl0E82K=`5rl_-A|G=oisfJ0rF?kh8Y@4hO=yu(p&XlMJlgM5fQUd`Bj6R-6J8U& zVQ|Td1F=?i06EH%JN`qf9t2(}3yl-!1M2_}x_gTFMSTm4(>uh<tyf2}mvx`TNP5V!T>9w2HA&2G$Fr;GpL`e%x@6VT1w7v%^7PBo)a)Posrdd6XT z%DER(tKkyAo&lGEvOicM`SkMRlyGEw!@+`eU;(i{Lt(AdQ95KjIv#QJf$+rs@X*sU zhBi1)z)>7t-mo`Cu0`#RJx(vh~lP|B|%?f z4M5hEB*X3#Z%|K0lh#9Sr#V@C{-x(PFSv2OBlHLAJVv(T=If2VbiK3%_W^_6>qb&( zf}@zv@XGzCSv}~62`%GFMEc9@FG2cMn6_!NJ%P>~$Et*B|M2f79%cmn&-gTJB^Sh? zKB>AJ$VFNhur5?w7*&zszmXlo4>G=kSwv5B4<_!F2U}9MmII5`k#=r;-dYsH%a(5` z(l_Ylhkb&GI&XPvwE(#3WgAGGKhyUQs4<*j<9`Wm?&eDv9Pcap3UTkpDx`o&5;sf7 zIXBM5Cn3fmsOh8Z^8#=|Vut#yr6JsWo>;|MKo}e#25>(BQu&Luf8CB2RZ})P1t0E3 z=*otnW4>Gui_7@>r-5^c!FeS6Q1LGTf|7ssjl0diI%fF~_!o2YkCJ~)Yhe?CcVj1I zd6yKthx6|Hq=W6!VbAz>5r8PZ71Mv1w}p09@l526$8RhC{Oib1PoJG?zUc~|Y`lzF z$6%tcVg%8@OHPLFHl>gtAMF&@QS8dRnLh#j7zX)Kuu_5oD04)!52%Prr=8<__Fa~ zIcC82*5;gWke({dkwKkrU!={~m+T0Dmy*wZK0rPPfI-iLt7Klw)iBNv;C+|=saeB2 z8_9Xu_z*6#W&&S@s>RNTH5KuSq2BU}D#0#_p&zu2bNqGOUwpRC--JB8Y<#31o^e{3 zWJz{EY}UJ=6A?mX5+qJ_>1H!X3{uH*ij(FGr@w9IjFTab3w7mnr&5M8oReP`yDxRB zqN9;Bqc3T_6A#cMA^P@AJdqwrR0@qx#!rP~o8_GHb`96Svkg3mrM*Z%Ag)XH!Gq=+ zz7Jll&TniiPkvvm%Fl6%Ymb}xSzG5@h4OgW_((mVZe!VeuHH8JQvajqFl=6zdggOA z!R6KXE?Mz;=`31iu7&M;p^f!~xal98ZpARMZB7XmUjnIl0Vw;i*f(gyxKCjDJUsI2 zIl0RLd(W~L#RXR8JhFl0SK~y|$k0iRnuP9R--%uhFJ_;eMp%TIA`<=VT!8>%?ayEx zdD-%f{AxZo=xli|AVuqRnNw6fDWlBeEtk(I1ALh`!5Ir<2IK2Oa={{U`i)c({GJ%Q zYy8g3#jkd>_+1T8C&&N5g?RJB%Z=k;9lnGxQ8T}l2iKck+N+5-*ZV@I<4aU0(-SAl zl;1+;wAKEQ-6tzL8aOt}<~`eeMrZZTXTLS1_}!@U8M>Q%P=i(O{Ntkl#1=l#3Bnp% z5tGzB<&>(xmIBmNxAqm`bta70S|6yehh+`Wq)-J|O$#rR?3svo_3t8RJLWAPrAaBk zJ32!f#s2WbE9|oq)3HtK(xhPr{x@Pn$D;%S>2sGG zHC%5!C^yJk?(+X}z5t4efQSD{@?Rj7FHvr58cxAyBU; zRzUxs2Y(XUj~5S=>dHYkpcRmVe~B26EC*T!$^p&!Gg`OEjcKPwpVR)}1wA76%53t! zav2My0)ij8<-DV)h)@f3yRtui%DEB6E4yeo-g4GB$z9?+@v;mdv7pe6TQliB`c=tY zBauMaT`1dQRB}6VPsud#<=k!q$3`|@9{F2(hRH87m<9!5HDY}#q5A?q;J0WSyv86MYsB|?SgKnLOMr5x79E0KHX9%+tj| z7O$Ls;r#W((iy%ElMlv}K|az0w@5vubM$rxdLLU;jxD80mP|%vfe2^gnqEWjA^Uw( zo=FcmGUqW^tA7L_l%aTs(8A0dp#7^L6LlcyF#TVL@~Hn4Vg^Db)PG&6gg#OJPDg*h zw^HM0%0<N1%rp7FeraCm{M1pu4|F!lav7RXsI=hNWB!w0KLLMQaGJ5I;Ilw1}#Q zA9FLJw^N`)pqBsRKdrH!8p64|1^86y>gk^VFQPNJP?U$_6R6LP;qf}<<&&$Y?OPR7 zHjybQXA%s-o{n4v&B+_*=TEa9h4>W)1TVj8KNy)`S|L{w>KTAa`75bVl5Xf^>S_G* z`Tw)8=4JjLm0k+mwhO)VL$rob=%sg_-+jH*h_e5ydMOU7@1Z{L$FePLhmMMFRV#Ku zw*`>eQPA!8&+R_lx>5Fjm2Mef#2)GMyR!DXp_`G{9DTmxiDC3L@;pqRAE)$Cy1h~A zxjXuNKxN6%=LbnB=q~iRvFGFULfp~n^Kz7zqtC;)Yki($&p+8Wf<51eECuYiV-fnh z8}_`Yc|R7d#dfLZk5cqarCG4oj=vO4DyUDhdj2gcm>fM{OA-{;^WXRb;Td_bshn^@ zk7t@!Y7zG6`5PE6*|bjdd=>xS9X)UC@xe-w<qe*Y; z8+OU=L_3WGfS2(zOa|PnKeKIG z3C0Qb%(2+y4pWd#IGpQ~63ZgzQyQ5d9PWY03%sAL`|YK3XMS$6wR}Fc9J}f6;3^8) zWjqQOeYrZm5ATyHInRxe5qMHZgS8oN8{1{KF+8@S-nx_J!fzFt!H{$fAWi@S;y^{V z$D|m(O1xW*74vwt5$NIEV{Qdx{1t#h9_7>F5|3fDG?YUWPRK_4!Y7=^<@t7a%AZ(7 zx>hR3^HyXbyPTCpLn-Yz@bGA?X>cg|u{@S*F1B}GUizIMp1Nbjb%fqs5`mCo(iEiQ z#uYd^T6ri;&3Bh{J>8~hG_C8Bv&}$~nJDfZDb9f19fD$wDD0i~qt$r6&^lF*A7T;b z-Ba;9s36kV$O%#`!6rPaL^i!jIaeJy0eWY)hG+U28#JQa;rKK7Bws;OoTi1Suyi5E0BJjwRuf|z26JHXSVa9o|e2g!~w7hKj7QPt$ zx%5-Q@S=YDp0Gy4!*u5XtW-08$b5WQgu!PP@reT;(FZq=0}Z7A&}ew^ap&*Vd2QsG zndWpO5o&W$q0~8#twsM*HCgeg5PgWBki&W9a8rKSsM6ng|9FjWA-JrAsi(x{bT*6r zVpTctFBF#p^~1f*0?x@#jfaCpS7$-2+b)hj+m*NZ=I!V9Ab=Fx&n>A77-_wP$c^B? zFuF_pp&||y{7>kDj!wJy8+p!)16h=J{@G&Apvx{F(4ut0a{@c*+zdso^a%BafkpcA znHTDx7k3c@vTodk8Wa8gF|KWpg-SN^^kg)8Xg~3z6nzWzUzCrY!+tLF;Un-_`F+g3 zX6@g|p_Q5M1Sq*|{Y&v5WYS{$nq5C2>+nq*GWk$nw>@AVv&yUPzi#}s%hs8F&HnMX z8#aAqVR>vc`s_`YVv>QBFxcRwYcrl+o^>>t27n0_~RKaD%1 zMb{f8%zC5i5RjeSw_xCtieH8B_p_dUXz`4m z0mE*uCuAP#9B!H8MlX5~EQQY>Jr2!@t>K|3C6)lYCU2M(*^XF$6h}(icS_G@4$d?? zIXVqX^?Jw>jo(ULL0jV~cBn)`zTEUGG~WkftR^|w)r;L9kvQ82!9K`rMkSP$gu~}& zwtW?Gy66<2DHUu|?QO({`$3?u&Bktg3;RsPj>wf8;vxLz@F4n9(`MlC{+Pv=L-@0P zbFMjJ`H57E8a8;$4`SnQQoCg(T$Dn+T4sXI%Ma$v7&`}GZJh`D($fWUJ;Z|c+b$ui ziRhrylm%N3^qd|HTOf}C+l)-{5*Ix<)R&0o7z>j}`gzvZGp}DL-fLPAkxL|M{<(nk zvopWBEPdmx(X<&&JN*s&;MHKyxetljlscB&r8IJ09j79RI~=8=_L#k_T2DetEZb}F z@Z5I7^^w9qz0X>%UO6>VRIil%TCZa~07pKX=3M1Ve?q}$z4H5+v+xf3OY{rZm#1Pe zCH4MaavDEt(Md3J%Bgy5ysuNkGq7yH;I1kn_e~%A)hX5h=1TxrFCoD&boN5lo`t_K z=3SMqt^geBys*Hy2qYkk;5Ri4+KEmVtdp{0`6%y_cRcfQ#v2~nTI8RB1>jZdYU{~JgFxLz9TLAm7V~agT9Tutjj(IfPHlaFa_i_XT0Ep4WMUXLtHFI zU`gYT^sc8RJw5GQ#arCVLi75@s&8F^4bX!a;58v~XUfat3)0ujhc2B*KIe^M-CYvc zk`XwP^_-LY3u0&Mire}Z^3OPY4rbtI=TX>O?qip#<)lnw83Sgb!c}xj+FAZvHLi#q znw1~c^B{b5Kd0*Xn1$mi_i|4K$ggw0H@Q_AV!I^=7aGv zX7-Mzwm+)8Og+9eN+O)69#C{>J|wqX_Wzm=D&D9AFY@@EtokDI3F)XIIQ(#o}r~aJ8OM60v|p#M!qc z)l4%UUjjJztvDsZ@O}^D#UuC*{5t}SW4y3`6K6OF_+l^xdC;Kd>b}wx0WSe(tpUBy zD}ICz{?s3==!B|>o?*LS9gRJDbPkQUPsol}w3sxZ6Z~n}7{M}DRsfE)W8MFRy$mnU z1v)LrI;2a!!#ZGBXbPd>d)m1hD&NC%ZC}O@%E~!$_t?48Z|Cl3O^6sti08@)0ic2c zzg)eBLl~_0?$-ZPrv3%s>~8(C#aex>?dz_|eJ*L5UJ%|%WrOt#@v z;=4)@iTBfO$aGeuohQ*FXhPV)Qp%2Hf_u!ruK}LRzb*}D_v!Fi4Mx#n;V$5ek`Br5 z6{kbrKMT+yZ7Dhw!+(_JmVLi?xibotTVJ5u9D6~Qd-vz~43Z1)lYVm8dL;CdwuVO; z*5{kBy@HUa^!>!a^)AsHsgMDf7iI5qVw5A4wsFOwnwt~9jWkx z9WYA|1`fv?g6^slB|X#NBu{&clQNzgfr2l!Z&AFKxpdn{V-bs?nUR33a)+2pSS%S+ z%)jF9`#kNqZFaeAZ?xF%hKAAN_bg-1MK5GHmx$c)VLc}E| z&x_<4q**BX&lF{AO)v^}2?}}aV#&ax6PhLy_yO$8TETOJYhQl&e{L&UMzpp(q->+k zcB%GE%oc$N@ebV}Usc9i&Q6(L-&a3v`znqnU6qgGWapJQf2F*ilvcjNE?n z^>7g82o{q-Enf8vuO3cLQgFa&(c`q=d2j47J6H7r#tuw=Xv^kM?9!k#qOW}yaPslt z{GKw8p8cc(qV!={!!iC1wiRBUb?VBV{ySbGX4=zDSgZetcZe%QjP@MN`!7C}8~L=I zq=h)u`6KEonJI&<-;ZVO_p2FPSil$J!#N1XU6qiaXcAN4_A|yvuxTdHJ~Who`&3;1ZQ zF-WRn6HCw)MV5_a7Xh&?%{z(V95eIRGpN!Ctsh<|p9|rDf3V zoP?3Jo`+2a6uvyBo0p9b@%5m%^a?4qiWD=U#<(eGbIvHO$WeB6siOqq5q2(cVO0GD zYJ^<^+yZ65r5t4koPXTm>JgU3=HubIb5ExlPlh#K5dh<5<0E{B17aZngW=A=-Q#`s z2Fpz0gZ4a);JIEeHzvB@>Uf)t%I3U>o4hq}r!b$tUQ}R|ol1ZA`sm*u0 zX$FyQW@#1R^?6gxEv-%U=v3Rn*71Krvbm+Rw^^5Ll)LaYt9H{i>+(VTdEy$Th+Cgo zbIW*ZB~J|lPf9u;kl7$e2}Rxc6%2q~&vPC|{>wfB`SYBbbK*^V`Dct*K{;~S`WJHK z`sGFk=Wf6us%eF)tXw6oV~A_4e7xcxT9I5fzBM1PUJ&L@(^@P`hKchM{-6{N{1iu{ zpIwiKC{FB3gufjB(_}t87yfQ|$NP#90q3XOM5Mo_tQM&$GFn{AC^Zi-PErcPm#uGh zzh003^uI%&MS#PK1%EbD#WdLh&Y!TU3jIQRDZ1(A^{nFPs%g0x}RRw>;$5pUR<5-N&8%s^;sYR{LE6>;>Cy_Q+!vL8rG1C;))WhgT& zyJpcZSfc4oP4MVnp(nCrRF(kANgSi7VRU|_Q;Tk;+2qTk3yR8=KZv3vc7*AHAtJBtiL$^d z-)x1PFcL^JeuTvGz zCQocHZG?>zOZW@(kr|TzE9Ii2d&PMV77_96*6BHD;$`DQxnugk&n0~c)34L%n~S6e zvyDI2T3zZl{Hntp|Miu;Z1t-Jt00*Zgxhj9VzjO zGY8vV(oWEqt$!g5a5@@&9sD(FCVIZasYYK(y;*P4v$5c^ z@p1JuYB(EtxR!jT9QMq(4qZ9U2(xx4V?(z>_@N%lkk_q8%Y~z;$IW*z76R;0?PezU z1?o1Vt+kUdNf1U4Dx>g7MK26GCt7M=E``&KiT_G|;cEU+(Si4-P4V8shY2B9^{BEd zSKq_~Pnum|eP*EH&|40s+;KaWUPd2eqZC$^w&Sgj^P!l+ZY}MUSk_ggUHDboKC2Wn zqN_^d`o97ErZF|hciiA`Mw?2{=cG=P!mrAIUn$eih~8J4(f{$dT{UZVUnw_Mr0AF6 zw*=nD8EyBKGB49}SHT%=t))yqBidS8uG3cHSHZqV^390eQySL)arf8wH>soUDXr7* z7UEZxcaJnNGNds>p9ErUV{8#w?jkmX$iLC7T1yFv$yCcKgL+U= z&NvS@$s8%BOfyA>t*}vgDtHahbq!?u6*8))8^I2Y>*t_RR-w~y%-a7W?}Pn?t6`fr zVW+-Ge97U|THQPz6ke53??Myj@!5Ia{i-P|yz=2*4_R~vPIGb&2Xd~;7IK=m5E4+r z4Jcq35bitS<4KrLzdSGGAdMOi9pf3gQE3dmujH8fM&!#eO$F#Xm#` zud$baJPb|w)gE9h@J0Wlp@6V{y_ zNI=gX4iS&yJiD#nxCtP!R&#gE@YJ;JMAxLNgW+)#v)!ADsB+?*B7&?Z1F5PMX2 z4==E5!0^xpmK>%9oKOFVn4-V!-md634JGih@zHqFtcILisNB&vfbcGIYENjirCLx^ z)m{ygj=TvWKuP-2qBLo8h?`_<(E_RCRf0aEh)Ecy`rFE%R;KY;r5m@44@eznVtsJL zdutS*GXGZi4@quz z>GIck>MMFo4QmwrfqJ-Y8G4TN3_rBnTC43Iq+!LTJQMcs#P)X9ooj$~cMH z+cbZ8>V_3(QbJQAp)WXBLONsX2ppF!-{|lo+m~RCKUPVAHX(6?iWzedW2_Y>nTfTGgN+1#ODu1jn zUd>sdy+fv3O=C_7VE;B|C|Dlj}{r@=Q0aIq4DuSZT?d{4j}2jC@99&&3IlsL<7 z81GANEy6dYhivV@K^y-Nd)&W<+VHO7R^ngMLwMUXX10i?+pnEq76DOL)nx;G-6o-La$Y zzhty_RR6Y7+fn83D!JhJl6*B6`#8}*+KvjNGMUOhh&LYWHs{~QGHI3HP^KpY=F?-w zxWUO_V3q7$tDB7A$2lWj=w4m3mHV5HKiBFVR}OnvZxpIlxT!TPC=?&QI6IH}!7Z{FT>B?>KmX%7`N==R&}v=!ZjFbE>)e|?MSo2y&0Kq^o&a7s`2rF_vB$3Ni(7zhlcFRS5GM@Sr_&-zj1WCpEa9_$AXvFOLv;6vd zKSyp6Mk1-^XkXB@?a-(4y)hs*l29T`Yl}~bz3%4-KcWI??PiM@7!pvd{AWm+|cCcfR4}q1)0+ zcSWEiF_jFO$rSR6KdJ-*_t+kQu{ug<;sKhsxx z|A+ZEHh9Y)wZ6-&A(4vfyX%iAs_#nHj;!xyago_5hw$lp~wV(9re{9PQ-3;6-1)4zPKyua%uggk#R7JpYM%JA{}yBLI0h|aJ* z_-tu^*U6H3^o`cvHI|~y?e7Lf;d1`&8@qY^-JMwcrTw1;&t?BO_g(y5BKKW>zX;zy zqQ4thTbO4`H%^GMzO1rkEgS@TnUEN&#g)VMt2bh7PU37(!=D9MyexbKF7lLKg7SI@3v)cA z+|b_@UU}u1x8U%#(3OW_s7gANHbfu#>%?f=V>pb4kB|$72MPEEjoUmVfsO-9+b0mW zC-4wEy?-E3Gly3)zhfo( z+>&6^V??Xj;`k=ea<=bO6Sac&=3RIWk7k>LANiX^Nt0(6_&qZykW1&;jE}r5`CrJ? zdG-q=8np!0=V=x4?EG@BJiA}#+1-z`XfEzt3Qg5{b^&|?G1OFoo@|ns6v?xpIdWP0 zuPcuVt*j$HQm{mxodxtl{#f~zFFdK@j-PJSlgpR?4f>#il@PWi9id1SsW0gPGLSs1?eYB$*l2liIbHvyrtu$ObGO~3m#imJWlovpm#=;^|o(f9}>tnU_Xp; z`ef`S6=$}`6Jz7V-_=i~_VIWL4_!osR<7X#I>%x39`P&}m`FPLq>R4Q%=iyY_%1Ja#n)N!iU(ls((iBf07$h!x&Z1Q{osa(4hjq!?S(rhCwkK=qWl>`0Ha87~v0ZL8pmt zOU|ZmBQMA@xKo~<%ZRQtXl^l(mWg!#@AIc=x0obhl12uCc4)@O-sCR`mpL{ z*U{b5zCLL0ygi$hkwBZq&y8mj%9?ms;P-4de$Rz9X;*?Su3yOYKbiSQ4qT@n?ID%i z1uC8~+`vGLIuzvuER*ks?jrvz#M+e0gK}WbzU3n7bR4$&~ffl@8ln*iub*|bD5;i|1pfPsCCGYm{wnOeD`EMRvSGi4V z7bf$52dqq~de`Cn^JhN_|5r09K`k*tk*wX}KkT(AAJ?#$=3|!>_40Aewnh2aqv*kr zl`uY?hfUGOW>I*!2wKZ*(b+_=;!i|x4fr2w!>KeTe{0ju-I7w8lIPs~Q0W9aE!p*y zz=)v?Dq}hU29_z#&tkhDC_{jyoFuXNcWU3DN3~yY;OEjRjI|NiORcY=dW=9q7_v>ogE=*lpI22P8P9ax34z=|0;mc=lC z4cqgB!q--S=4HwMQm->EpwMk@1yh{_ry7XZ4>ddakt8tp;5#*AP}Eeu&;xFitO(t#Wa6e{P@!>-h*^)OA9^`-me^{`zjI-L=<^Z$q* z#-H~|=h?~Qq=&CB{=cP%gMLbFoRXq5C(*;hfv~&3{WJJZJ**dTZ=oLAi`97~J%2JI zeaf(d+P=-c*}eLAnm<32%lvL~7=L-~)?}QKaImgtBIipO_~v((cmH1foXT@`wK5(| z7i`84z56oVd}MC?(>Gr){AaPdjJ>=Cl%eXU^^E)bI=(%fQLaf7?yBO*qEX7gh%)hwVeoB5B#J z7QX?PAJHy<$voKm6uQj8s=>42ev!HITgq%+f^F51uJKWN{cP;rikpo5rW`+aOwp74 zxyLGNbmce^;AZzVN#5SA^VT*k;K65daxpO*ue;kjYQFcEK`Hn$)c7J2!j3bs$fRIy zHALTo_3tejuBpcYOp&+4pHM5O;n4uP0di))9GZ(zYj5CqPIZy;U|K9MPIeCp)6T#Q zR4}GjvCvsBzn5Ae@7n(MUCqK_!(KV=STFj{H3*;q>}x}G#RPujOFe&9z6>Lo>=b09 zjBUuQefLVVA+?07>@P1c5+-p?8_@!Ua4`wdLg44TEcCA|2-_1uW?!aEmYS@7TFGaM zZb*=iqOSm*0zPE-C(-{GF8*HD`iqGt-tmqDopH1npxQtF4){Jer0Scx7arlV@L_!> z4{qIA=|Q+#fXbkpbV4pvc~848@0PpZ%aqT|ujBkKSwMv)ENwgBXLHI!6%<$HyOH8> zkUzQR6LM`Kco73SvNIXZX@n@ zV$Kx=5?RHQu>BqM6e~Jfio+?$kLJntn=sKi2`qs`R{^L2DV&B^WnX};){+qo4BXLp0ex{ zn|#SLzlQzS>TRWOyhpx;>=^B;txkuTMBqK?&=!tvAKJ{Q;O{T+Z^LY(zUbKC*AI^d zf3?r;EW)pM;HRF*`CHQIp9kcPgV%kbsQiBD$nP1q{JO>j|Ip&_R~z^*Jne?xSRB6W zd-yfaJf=S#lEa@a)S1VG`*hb|(E}3ZAVce;X>E6OB60G?T$a9Z^x^GOpQ#Z|7yh=J%2i=C_OC(?*03@=@}i|ONzs7H*n9{0=WAXhudl3 zZsUR5us&Zu=&y`^3_rHTe(eHiPR_60yS>-1b>r8u>;LD9%45*bcfhCJ@+jnwDI>%g zH4dc5GqR0oPb?_4pL-WyEw-QgjpvVMKleMfp1bs!)1Jzj{oJp5;qDc`z4z!ZjAlRg z26z@%>rnc{Zo=9%gqZyO+$**Gb_LC}D|6Al-FfE;jP5Nq5^1L2a%6?4y__CYdSHBn zh4SJ@&=)$hKWQB66DPv8HE9GHuLgCwa`m6W`m@FBZ!c0mHkLRT%`+VNcrm81E)I!Y zn0L;4378}`CJU1>UA~Y$Xg)}OD|tc7>mFT@c&W=9{u%oFQYxZxXWt$d-C_McVH=*Y ztm9WdgJ?j%S^_VYlU0BAi3s)TJQBj-RoWl!bwE)&88UV<@l$R)Nv_TJ1H{$%fkJ#E z9(i`uv&qA|Qg)Q)tHtc-aTQ z$2@8Ln|^W&pR~R|X>nT0_82d+63_bvwRm)Y!XrvQ4J~F~iP6t`-|xD6%+X( zTc^IH9#Q2Lw*vtSH`JXz9U|x_+mYa_&>sn;_4`Hr?S16Y358n)G{x?2Yux&Pe~6+5deso9ycsaxaBA5w6$e3i;PO zeuv-6<9CHFPguMxe1zZa%E-v?YSd}?U8o+GbNu*?{DQV|i?^;)e!PdT7W3mBXBYJ2 z(cVA3e)TPzj*M>**F7WJ`(paFC;l=m`KY+=easMZcr#NHnZjrH9?z~GO^g}9Q!7A7 zf?SsVOA?|eTNJOiV+HYo^LNHmkB;{C{d3>hKfB=3Z3Rhu-~Q68I!~|y9|)44ljb|e zNQtfKz~`7Nk#Y|eeTem7{;;C^7auO}r`>w92n}BQtgktG(@>(E)*D&ZC3#)_+e&X- zeE?=0q(Z}CUA!!Oq+ZGEv=W8wf6sda<~_6uedjX%Z*pPsk$S)j{FHWVi~+FvT@Nn{ zjnlaG`-^BqW6?S{WhBX|&e-ZNDbB~K|P(!+PNEgtBt<}ewZ#(!0h0ntp5et7+ zoCC>-bC&iD=)xpIwSX+IL_Q}Qgs_t5e#Fw-U6(8?8jzEp}!r5Q#~GefA#=&5l;Zf)w;@^wA4m)DWME%z%rxeku{ zWG>pZ^mprh5IE;F6aSF&W+)?fmJ!^^x$aRHU!AW)gvA73p!CPDkYPLATw4g`i) zD|*-lHhm#1@1jS>b5DvUvN$TSmix3|E~y}h_SB34EZ|I^caU=OM6)$J(tIjvOa}rn z5#kxyrwU+$wFDSrbvMvB!%FQ&FKg!| za4i5(iPNLD!%nbi6n;U^yIEY$4vW<*`slI$38ShP{BYW_WApQ0If4A``F&YGUu7o0 z9YB7k8o&@vbXKQ74&j@UEv7z;N3b`%M~5LiuY#uZRY9qlBabc4g(rU8^v@yvL%%ES z7v1`%;@l7flZ$g_O!UUNdQEJnhRg8~zuj&{`%&Xki)v{B!L4YD7>}X)t7F8?{H6vC zXClh*vhbk}<@U;xoT9?M_h=j>-lS_EZF_6u4n_0(29w`EytO;O4~&kk(DHU73EI+I z6{OANOTG6g{^!w$xM5AA3UJwAZtE3OF0RWhM>V`Gd=y`NdESxWeqWEn7xJF(@#0_8 zN^;xLu~I4WV{xGA4R3=II{Cy)GyW4jcS!sGMgLZhX%yMWh%2#zOV|2OuT9l29`|R1 zN1nJJoJ^w2=66oM^Xy5UeGTKkRs5vR8J^V||(tl0-a^_1ynt>TF0%Evn zDj=e7Z%)UxjX)#Xu?R~^zJss#wcsl`0#&#qsBRAY5`J&Qu4vK3qDIWAf`*9VJj}?8 z{nL1OMfU>Cw}ApNIG_7=wBwBFk?6V4&cGgaM#V0_7%L@}isc@jeWoflC-LZQlyXqW-!5PtW=Tu>V{dPF&nVYvwcxq1K4-I_f zGn=Cw(MFuc7)?YQnWvD&_Ewl0Nlhg%UY7h1z^?eRho}hK5YcnjnDopvBU~D9hh}p& zXPh9c-za@#CA?hc9Z23X->?7SAh_?+e|^4p>K+A0K~eY-rZUy+gr)m%cY)@xI}K*) z+gG_krBql1gywd}G`E>|G0$t!aM@n>`)TG_x}B}Y&%g|`2z$v=G9w*;_AwY@-_8rU zf%{RC9S?&Bs)ya*g4}9m|3k)dPP}S@*6&~udJ5PP)Uk*iSwOHa$SNQ?w;g@&SYtQLg8?T_|4=hXgVtg)7?{>8} zLd&ni1L}Gf88Q9UoW#I`$M!=vF`zQDKlQrg;LN`>b{qq@#$GHGajuRD#OcEf-3TX_RgPPZ1N-p?bso@y? zHgH`2Dzx$t0#X}zVheAqzhZIF3)-ngzJ`iB4D{R1Wi5h9o_YO +jH1(X7t0ye=>;&_WdRm~u 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

nOtU_Fr4>0 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%0A-l=a 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 3xrt;73vZdk>p9I< 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 %N%tAzgdiVwS{qXMo zX&Hqq&!(vhjo9S3TK?dp@TXO|OZ`?JUic_i!s-Lpu-y10ZkbtxZVx+<5A2#wY|-^Z z|9f|CzV3{Df2H!E>**kJq21GoQ<9Jx@A)2loLZ6|Q2ake{1ov%i8ntfmy__5@MFT! zKlr+JnMqLeo+f@Ml6n3Me-?fazDoq99@=xWgrKnddH4!=KfGEO;CwjXlNC|@ zlX58`K1lq%l23KMsOuDGv0C@im!`D&P&e{*_fP9})O7g(88BBeTafE8c?|hD@*kHZ z8Gog(w=n^@WGMC#$?`iZ3_e>|gnABsOoW4%amDG%qaTvq&5t5%}Ea1k`Q|YDr zPA94)|Cs6X6({E-J_etnf$2>-EYzFhP>%0?$$*?8QvQ9| zscy?$-%;%!z7GBs$mnrGRkHj=?+Fv1KAxe9ou`ex{T$ODW%Y3%R&Je|Ehi?}v?9V&k^OaLn719Bg^VdpzKIu=JcJipK z1DN%Y8SDGetS`%KAv9yQpid-~e@QPob3Abxehi-5JjtK5hcob_@ZU4%=>fU!Wt|`y z89VATPV%vA75!!BbmA+bt;WxPPBymW$dF(1v5t6ohIZl_0%|^#T8DAvV^i+PB3U9V zm^tgww*cgPJBYop2e}SO2gh}=D0RG5VjXfA|2;+-^$arCb(X&-n#^pYXJ!1F{IlMNrO@Ds}bJ{rPI- z`ZMHY@K~ng>_$BCuNJvDaw>i7$@x^AvyJ~-^!1;3dFEHm-z80cqSpsM1m7eCeTLLe zzVB{TJL3Ow;+_4>eVc-;uaNms^t7wM|>^u zb;P%dg1R0sR5bUmeZ_S9%vHD^Y^Dn}hdQ5q==G!b4bfBMx(XT9Nh3Hw0;-9Hi8_H? z!5`AkB>R!nx~l8^BcEBXk$z<6`B#*4zZWfO^DF0X`HfsZ5AkgGLIPgrIoHoai_Q42 ze?eC7YzY~At=Jp=WBO$ezfT)RDs z0ZY1FFI~g<^l;`lOWO4c_yKs;AFBFH-;a>*`#}2r#gd$DX?Gh{`wgQXd}KQDw~|oC zc%9Wsb3Jnu7H)+=wkjp2% z4~m>>*9?PgKgA?Vik^N->B%uWNbIm&^@HozQa?#^j{ zzZox|h97`u`jh;L{2BNmD{o??+!k_!H4guTaMTw@PAW|Oty=2WJyZ>#Lhb8 zBY$qj>6%vUp&UL6Un-os|M8GjQ|Ear@kfcTka$&(W<68&TM(S*(gz$7e~{ZD^+-9J zaRlq_W?zvWN3a%?F^*sh)Z>~8+1XsF8gD&=y|KT@?AKNO!;ivqTPXPxe%U&2`PJ|u z&oCqT6ZsPO3HVngS>3*Nz)!+Ip2n;84=?W|xli(^o`dn7rId@*K(Z*Olw;M0ikjFz zhP=F+WTnWPpYSK)C;xJK#y+0Y@cxgnZX@IAtOB2`m_s>d_*eb$=|p7~0g79V|9!{x zIFH*Cr)ii{2U~J{581)rGDKIriTWO#xlXbkz5(9dU)93bxp-;Ut?L=+PL2l}knRexRbR2#XUTn$zXU6F)lSn|9(<$Pezs}SXd(Rkq?)m8j z_&ns_EC$R^(pkntxB&js!flpx)EcjBYgPB())5~k{x=e@`Y(0=QT1Q<(`}M9x=p&A zy~%*y?1s4b(~W-br&uQxee;uc(FZ>Suhy59T{X^7c4f;5Rfb)yAa+h7KaPB-u^}M* zY536b%vw11$KfZ0SN)F~XUO93$Mn^X#&0Ha(#Dn-;Ln#?Czkv%ZtKgcIP8?}u0Yp>Mk^l%*Ba zeUIbAlQi*D(#FNkW60-!oqkLVnBO|^1iZZ4=V9S!$HqU-lS4Ak)a!vQneK_bGw2PW zw?y>JPwXvZVQUcnUg4BI&S$euXzj&vgS3<6GNB&-pf_s$qdX7zdhF?`{NF*m^NrNH zwLDKD_1q2bhd*o5yU2McU-hs)Ymst z{yZZ4bPh{>XIyXD{u^Wgk+#5CUyTdVm3CEv{sj6*#1GZ3)OB6Xt6tl#!bG(q*Kle& z@rQCT!{HeshEPWyVWNq}mub;A4PGL6i&ZvYrZ%n;z}f)6Bo@JWo0^e(L-uzTnJs;@3i??+?vq-9i=|X$jJ9T9M0pb~;fb^``nu zx@_OGdZ<~N!(xa|Q_P6n$B-}l`E=s*Limbh`I2kz-X%{m>a**9BKHJxV=qAN406$5 z@QyEKuSDA`d{EijlJidWB)r&LR!ILmd1<-z$c-TPH)8K0>z;Urn{rzjTI_`jIbVKx zX}Lb+Mv?mqbevXid(uu$AQyUWI>F^E`4j$BA^C%kCRyEno`H|U%dk)8ck)D}$X|dT zg}*^~^Amnq5%mrK5=#ol-)i`A555F`4E|GT^3ra0z(;>&_OaP^qaQ<2_8uaBhG@rc=yLcG_$Ne9jSJ|vT;l@YJ6+=-eK}Becc5SWUzz@hpWW~wc&4AS zZgzCRJ$k*Z4?YTCC_JY|v&|eq(K}9jKk@0~W69qW@V)RVfA;?OPJMog-ZR7xdgxt% zKMGIr$oh?HvYn=96TRgOpht;+t;CC;Y)F&ycpdy0{6~dX{YbUm?=`Z($C|w9JM>bK z_!maL?$^9)PvqsEt88b~(P|uZkoaNZ?>6zWh-ji!zK;kBk(L!8oO<#R;UxG z6UN?piRXG{wlGOZ#h)gA0DU#iH|L!cxeP5Q7a&hFgiK;rkLNr?@^y;%{lxc6yz-+gcXWa8pgz-u z)aTJz|!WE zDaTX9PZGaZ$J0Kf)oV}0?iu2%uQ@;Cd69)7{DW85N73ac?P)oD1AMy>rakqu7UXVE zCCJ4-cRr&Zk}}=_AB7J}zSa3-=G*zHZDc&I#{!(`GB@P-w%KDzlb`r;O#J)&dA$!% z`5}*_)vBf0EjbnH9FTH8gupIqX^vA!zJ19*%@V-Bs^*+YyVghGy z3I|GaHfJ_2Y)O5e#9sB^pV#Z$s$7!G)apEZn)t;FpVIgBiAP28XW>KW-6#b6tz-wX z*ju`p`i58M2jirjl(M}JNj@k2sZrY-|iL=kYV=$z#q#a@;?e!P0SuF?AffN56DlzxRluG4m+qel za5=9^ke~Q6?=t1s{)FEFKMtRMeG|SLe$0dKgCF(akHN>`Mc4l1_@t3vVo6Z=(?(v3 z-~NO@13!WtH@}d^IqbnNhaZCfJ!=FMJL`=6A{Sq7sO^V}4|(v9!56~6)RpcD_yTzM_3)IDe~C-}86)rJFTm$}q`Rz=^)PsMJ6R1Mfd8q> zehK`P2fqV;^egA}xX9>8`{{=FKYl)O-eso`-g)A@-e-^|e++&YeyL0TB>a#Ee;R%e z{uM6yGe$nW99AH+kQ=cg|FFn&pSzE(SNVs12NubLBgTgGkE@Y$zIs0K5#c(`{M6SZ z6JB**loP+7`1JE#^uq8l_;-k&od?S1Dn@;h{z2l$h(DAb&qLDO8ro(ZSWVn<2atpM@WWzmwy%>m=h5 z*?-E!l9i7V_7}^#J%=Kt)}2;Y)1RUD2_fiz&HA3}`9r(D=HpgS!OU$p=FXnv`yuQV zj-S`>+uPdbll#>y?#YUYou;UAJ%(Hyx%7U8Q`k8PKLW4Xk-8qRoNm@_L#gWl4|ipB z^_y~-q-8K%)~u<;ptF6WS}Ohjqw>esn(ZoXC|PT3oO9PU!bl z6sq@C=uJ9AOFe{<_y72Oa{ji1GL?4m5PUv-A;(e=2Ym0c)vfd%BfgsWMirmI9+ve=89hHvg1pR;c4!uz&=LQimh^s_+5bzsISW4q|8uzjxZ1JWKgKxD zyq~EgcfT4%do*Od0w?xLYABCqIiI9s@v_HRVC?aL(*g#s9?P+2pe6Nt1be-|KA-s8 z+5Ah{E0Oz@e=ZBWGb=KblXX{?XWerSO8dJ&I^!44Cm0r}c{D>W#+v%M0%_;VYgu1- z-t_n6D}CM~@1T(yV|bd}?^KTbDDu}y{i=1)x95&5&}-M+P**b%sh4i##{N6AUL?If z(T86k^Dw;+RyM%$e1UqMiS&qeII8ORB=SQGE@a&QmGk&Cyx(^r@k@@Ky43oITGTN6 z*4Gnt0l7)!epfnd@|S)eO})oPc1gZh_Z75MB*?AtK>S_LgnxA5g~Zo6*5~g=hQiFb zr2VsrfZIfRlQ_}K_-jQzy68g2^+EW9@DUd;_462f1AKv$=bh3&WW8~Lx#KVK|Bt;l z0ef>y`?&8utxDArYKcAQR8Ry}p=eZ9YMTsIsbW&9LM^dQs3oWhicm`wGqFz4c_+p) zv1g3&Mj1kli9NMV?5U-K((k(S|DTWNygYp}zHjDx-}g8s$IfO^S5OGecij2X)-Ta%tMQLO8^G|-r#h{-`RYC9bIV&zQ@Ip-2F1av}a8F zQnyXsk8FSTHopD6x>HO%vGS6o(-Ci9U&#C(o%`j$y>OLRyzafhfVFhk09Lr{DjH#t@5LKziKD7uU?D&@sY`ko4i%sdc3*)2bdRh3DbU{dq3FA z{j|yap3eCL-Cvq?zX;PlgH`8dZKR?fFzYoH1I=Yu;ZQsV4|8Fq)VUz!{+tPlXX}_K~`Q}Y$o}8Gc zG55tiPFnVMuT{gJc?RL`k9SO+hN-g->zv=k4{waS@d4(IS2wj8`~j1wL|@x9pblkh(FO`{C7I^A7DN}>uY_6GTz(zxchr77d(wh-r6*EW!6v*zT^^DW=_L+Iy?##;@uSzqgOLJMN2&uV#Lhn_KrI)9yFp?(8N;kgZWOKZk_&RR9eLm)15db&0?r_F?zJ6$LziAJdes=pIrajn8`zfY9&`bMl z)9%jCu5+ttch}2qf7rBpdue~sw0nAK|H!nv`@^m?;1Kir%^d%B`+BCm*-QHf)9xNG z_Ur0>OnbeT_Nk`5)=Ql;O?$PM_Nz>LrI+@3roC+1hj5>`SkL@>g84hR4ekB*!}n0! z_&X-<&ey!`VY~}(8X9%u0}jRd%KL`q`)=L8;OEANns~yjoBNn#o=4kfndVmpU2FFr zYvMT*54#P$99L6KytIt|BTSc>Cf+dd6W#tlJkGU0>y@`d#}1w*Ke}1%aUVAQf~zlk zUay&W+{D9fhhFBj#KhAk-hO^DkJIhnj_3Q8?s2`|VP^lE_$qFH-rV&VVcHv}eVp57 z?$o$L++f-r)83w6dtLbc zvEO}d$@h$TKIYEr8IvD3`D?mG+Q)(W8+5q2<9x(;dq4MRAMi`Fe@wp}+2+Enx1MRQ zoAyoJhIYN~!=k;NJDYgZ#M|f3ZjQOR&yy2Odtl8a`2D*deqYD^P^kNRt?v2AnI^Al z@>X*v**+gJCmB7j57hH@NW6dEJs~7Z=CNDIa$A#JN=XaUU{!P1kbLX{s+?+O>_>S&Ew&!Kuitc%xck`{39C^M-o0-8Aop8R?)U%Q)5_i2=bay!xHD-9KJRYdpX7Y%`0iKS z?z~n%+-#r8lVidy=e7?w?S9kV^YOrKA8Xouy|f=<+P%HBpJLiQrhP@XFmG<1*{0o{ zpL>|d&E2kBP5S`T{=;=Z%==#bFX(5khS^@1Crtc!^S6ik_cO`u?K1JM@7-`a{*HeM|XU{5sov%#Le5GJ^Dww<3mlnVB+n^2kC!GJKV1CcI$UWbf5NL+*rPU zb<42RAAffPj|c93^H$UUKr_DqUraczdyf61?QL-TyW2V2jPv{6Pw)vK?KQcE?woYPQqFySjSB z`+wKH&cjXo;<)+SFFosncN_OH@o%OqS$b#B_-^J8bllp#neFX7#pIoNg!vmf zY94dC=W&&Ze_`V0bgjoc4{XQXaqczot)?zn`n>x>QMSWer?&qSgWEZ7H#hG!llS)% zmMnFzKd$l)@^t69>ptK}v#zNnOSf>Jn516+VavHmZk?efzJd9hP$|34bX{j3lXtxN zTTSin<#pG&tb2WqHSvY!Z!(?e9{3V>=RI}B?)kXmU1jn%pJN^`+y{)Fd0)4uWEye2 zJZ$nj*DYDP-GCl>{kIz67IU}jH4|U=MzfA8eqeWeiHRS0(~_mP_V3yMH~nS1*PG@z zFWmK!gu6vmFdJj0-JP-eQ$=T z6F2B_+)nL|Pc?xzOG+r1s`-_JPpFXnZ$xgQVMpvQW- z+p=N%?%b~PjHz?lQ%mss1>N&}w7ZV`_cPX>zhvoA=J9>NmObk9KfJ4*F#(t_sly5gP9z6U3Nak{Oz#nlBFM+pMSW&{-b-m^_DmDetyZ)zq@tz=~?H6 z?mF&xGfkbL=5Li9@2>yBD-JZjsJ}wj7*poSt{3IKKzF=(Chr*YH_Uc&^CIS}O)I$P zKV83fbHZo|E$1&R^UG?@Shd<&kFpnSb^X#!|i!^Ntu*;%I@B5 zwtsiNNBbr`>6W~ymd~{Oe!9GuSQ{R8hjH4ktqtdGXOXdowSo+PC(5!{(>>`r)=qyF-_G$J;3!e|w-c&6}$3Z5TO{97j$hr;(?Tv&d`6+sXUMC&`z{_sGTM zz^yRun&dEYBsq?pNKPY9BWIDLe2-jA4%~+0lf%f7 z!e3?d1LBljKX}d*otr;PxD!97c{L$B`4sY2<0-EbkKeo* zY;IpOQ2rcTUpoJz0B%`(;Z9w}KUCb2l<)gu8!sf5^tXXfa*=PK>7tF=4VXb)H(+z`jP=jZq~{i3m#J3VjSYjyvm z<(}(wJZE{+a#`=KIEZ(y?$73K)UVg^@D19#6Zu2IinsDQzf#a%{=N3%DVMe@ZPfnX zoR<$wmfdsi^4&VGZ0DI2H!u1Joma5DY`N*8Zh?Ek%9EC>pplvt_us4g+xZzQp1se? zzh8TU_cyoB%)ejzC%?o?$g7aihv2D4L8lA`{tOnM0Gk`&c$4Ey=&qf6tNnMlP5--K zTg-p8PqYUI>?WZ$v)mt}*ou1NmY4ROb^9s}tABbqT~8G^QtJ>84(z*srbE2mAs$-3 z@A}ye@kWPu*wc6YT!*+kj+Bqb{YUnztYdvGUBBeho?Tmel=)hBRVg|dLyKs;|V*?D$Y-B53{vlbn@)+($Xg^)2JHQ{pyBym7 zsdOTaXNhN?K>N{YJnv4r08C#4=1GZvWA)GdljGK`em`~GlTOm}Zgm(pbbwxuIv#{0-s9O25KEl!jU9WaB=96NA*-hqCblke?OC5>->W8?5ov!jZ-SHVe#C!H% zJ{r^Gr7SO4UOE^1%aa2e*MiZ@zyjGk3iI|Rz$h6co6L(`j(%~rr^zyzCtH`GPL_4c zWR3BLmPC6%We$vi7FWdcOglz4E*Au1DVEt;0FUMDsd09SAdHHzL;^Se4-XNP- zpud;#3fsFM=j8s!_9`Doh4M}ir6;9@YucDY}NINuW6%hvtB`@w}j_$KMc z4?CXh5SR1qMTxgF_qE>HReZ@Ei(c6G@aX6&`+Im^F7HcA9>!~q7QcL_`JS^6TX(Pe z!JOA*FiYC=6Hgqfx1;q-?X|e}j^T@DYfvk`_ zGH(pIH!1h0EbEoY%CAtjL3-F;CF??Ko-z-itgG?w5Afc)TMu^}|GaSR2yAzL8kjmt zuY=SP)=$)N|M}X3Gqr~<&@Od^*$(kWhj?UG-}OBgc8F*Cjwd?A0~ht(KX7s1@l1z! z5yN!{GY4$?me#*kL-U+IFRi- zzv^COvB#~z`<3qu+$ISvgLwaWL{zgyGBV>gvke)M=xl7iO*#MX z#}2WZFhAL@8LR)-o(s=7Wpwyv-M+Q|sCi4&R@qAg^C-Gx={$y|8B(`6? zjJWi_vqOBo6;IrS?ehMv@9j%janFD0{G8>{mvy{sdFEXm_r9mS^o925m)hm^M&T?R zr!}%g26;XjCZpE*shqE7m@nt6a=x2newxgZavofy*Q|Nj$A#R#zGfh}SZ{}&FUOCx zi}So`zWA2AulM0wBi9+7Wxf1YsGIy6Y)%`dw~ff7-TD4;p36sGmKz;jACDJbpUcOK^T4&q&Bz_e zewIV{ikDu-k*Ynx6d;E8&-1O3j zPoEfF`$_$G?C!ts%$0ur`>XykI+fJ(tDUGlagz3y<(ZRp+~;1*x5uqaFQ1C`Tna4D z)OmpmwafEvi_gP>3$VY7v-!G(ulpK29_00%JTKRI9HdF-eDwE|c`{DQ{XD{YDYD3T znXHm^vPt^*IyOL-xjl(Xv0c77di(T#HNRhRi;g#M*X}$3mws2jG^{art5tXP^!S{@ zU3Q7f{kZrz`qe97Yd)BH8Vo%HdS3)9WbJS8_$y%SRWSNG7gV&A#LH4)NM&efQ5U?mOP> z5O-RA_iucw<9YYu+kM@>LtM^t*5>1ZeV!x7KT3Ja;s>^GUyd%a&a#Hee&6>z%IdGL z{J4tG+5N|jJz6sT`i{p3^c^pCh^JQ4{o^ZZuUXz>YV9ARLv((D-dF?eo;AUzF2dvK z3#2?wd$?cZ@mn6ZLu{{+4N@MjW3x~%M3%@L>AMi|7Cl9eku|bJ`k2?^I4OFK3^6Z9 zwxnMM<7CMI*(9rEl-nI7lVqAKGS5rTN;@gXarR0)pV`N8mh0?U3+o;9ff+B(gT`Ef zdG1BZ`A&9SUhoa^2UfKH_>^~q1w~K z;GRu&d(ra97Km5K+Hjp;-coyWYq&QE2FW{SW1as%K19mqU=%%e;nhUiqmy&)yE%Zu7l*_jXR>7@aTm`mR|L8FxUW_AAKU!jLjnhH@Ibh~|#%FS_;@fh0n8i%HqHS9w}HX=VBss!H*8$Hzt{a^8|GFy7z`f)I>&(i6j+@B zR?Y=|v%t{Bj9&`ouLR}zl>4zf&OS9qKh74eLVji|e9vP(zgH>!QaAP;uic5b?*Xv- zBpCi1+qdq$t|z)@d%O3)O3x?pCi=;IU$!163kx~UJ7DB}uu0}Vpp)%EdihV*=M%;v zAEI9`sqLmhhj{Q~-Cyc|Cj~#zacLIDJH+#gbbqP8CU;c!GaZ+@!e)oK)EmrtvCsRi zSLzV2e5w0O{askUwphnyp2E;qea9Q$>$uea1?#tPbr&i3BgPyYe?JPaA+)@XOZ}hq zM?&1A<93~Lhj?*C-M_M`_S$ONW&8s3+WT zwFfrPF7rB@^9oyWd)$17xXf$Q9`g#DpOYKwabufmmwB|W4Q%pb0Uc+#Zj?I2Wgc6w zhr2%RH@IqB>AI1T+GQTUF}dz7y@QUU^@snLHBNF@-7hyzdv#BEZZ9yn4_G9fec>^( zKsx)eoec1CI6@}Kudl=L(Z%CLUI+QJXpfRfGP5JTHA1+qdmNI%y-NJhyFnG@%J%KZZSvqd@wz~u-FAE@1X5IhxQze!;8P@Pvh4DN}8 z!6{&w3?2@T9l<>7bzM4vcA1CgSnavvwTF^$?}@s-XnFJ`9dBBmJz2+tr)aNQo;+2@ zy{Bm}S|0tCjyEljq!2HXvi;H1t$vng&(QJU4DD6RlV|F9g&sOfx7RFBovq`(bF`N% zkEM0INcW$s+sl^6&(m?|eC;uMg5OImUyu7um28oT8_*shV`N(VQ^d3MJXs{mWQuuJ zdVyZ2H%aG4-hW9y86+E@a6a@HnIKbSM#%gey+DSVs8gnA=~cRS5#n{atV5IT{F?J5 zTg(s8LuC9j&X*n|n_U0aOub*^cooJjK)ggsyG`G$zUw4A#H$_RxuJL+(fkdzXP49Q zJR|c6UWoBy8Bm^w<@e|tY|meWc;aF(ehHYJ4f?WRgUnnDujjz{T(EXCnD{E%p2DB< znAbz(3OB*K$RXsnjDJCXK)y|`%e+m0&~qo~`yCjXm1xgz z8`hEa5~iGAsQ7&5Jx)GA-b3C+-a-!Hyk&mzBF2s14c5pO8T$j;Q)G_J+=F(RSJCpC z<<7mxkKU*IW$uUP{s@*!VB{e%_9$2>gEF4)aqZGBOm>J@I>f^xaQwDz#&O}h1q_kz zK9X#H^8HGS7o73>R^AIg$;h}4`%Pk=eC{AzR=;WtS=QZt>h1wf$X^*_G zJ@J9|qUCkVJs;})0KM?BZkPQgzyDkMRL5n13hQ6%cUesI_PXVb?{qx5 zRC}l^(w<7DKPdBRJc8qXBQ}`Fjkx>RQFQ-^X^)#{pmyok{d(1Wi`jjNuRjtdtQ&c-mZn`mzi)$R<_?%hwdaG{i`!@~Z>zn&o%Z1N+QTEY$990nL%Kb=qxSSp z+H<3{7k1WO-bH(QwDv++dt!|C@*diQduoqFwC64Fafr2ll;@34%>#pbYjwzvkJt4p zduw<0(_a0#_WUojClAn`ouEBBQG4MF>+;X| z-!;Ew&3l`k^EQuw$#eg2%zIhevt7^aaRxfx3;w;^v%MP6=d@=1YsT9_)r~v8%ulP^ zb7yq>WJF*;!>TL zx=efKa_zaS_QDm~OIK>I%+X%EN_*pK?asB@y*cfH>$HdFYL8s6J$8fk#Esfhzt*1l zjrLq#d*LSSrJJ=^ZqZ)5ReR$$?XBCj%lDsnI6Kih5SMndZ`-%(U1*QY)BUBNP|ic; z^Xq(veCKz4*DG4_Xi?`kEYIAd<8{krp2EoeIzLm=UVBix?-A{RN419@(;g{nkNrt| z;&JV%KWooCp*{B(?XmyX9(YQ7Yrgi%Gum^{YEM+Pho0>HJUsKf&I?<4?s4P(lXm<3 zIrqX(>u;am#$Nns{Wszcx94S_e+FLq*VMJo16zOp*VMJo_bM;{YwFtPZ@E|hHFfRt zuEgvAn!5IRQRa=GR@Xic$-Vj0`rGFf{)OmYdSBP6e4t(K56e0p?el`@$LJsZ1gwzx zPk&n79`B>M_scF%Q}?f1-f5oJ`Nx3BB3;k_nf6ZgdR`CD%+Hgt`o};2Y4y6VuZ72< zV8!ZR{Sx)UUx9&dz}gb9@g11$H@^MIk?#V%1Ht4Vu(~1`^n&?S!OR+&pD;6?%Z4V19@mp-1Sl4zeyG#$${J=n1-SDaK7nJ$i9(s-5_zwM>^wjro=PoeE@x1g5<9>RH@gTjyc$i*eJW7{!kacM>KhAiI z`ANy={!Y_V4(?}JdY+z_{+D3hMS7id=Aqq7mf6ow_xD5HAU#MA)5G*AJxPz#qx2*_ zO;6MF^ekQ0q0IIY+dW;FNBDP`Z-8E>N9ei#LOelF{2rd7*XS8~yoh*??%WM8&`b0x zJ@W^|>+}}ANsr!xxYM8egYKnQ>3+KRUgQVqQM#;y91mf}Q;f&y8M>&`j2Gx> zdWoK;SLj80jb5cU=mFMm(S3B!eVBiU?xV-(0eXcVqBrOfdSW@uKSs~c6Ozy8O<9)~ z<0;0gyuWAY@ghv_+b zlwP36=_PuSUZJ<>HM(ao#%s`h^cFop_msE}bRS*TA;R`B+aoKYZknFuel64Ubl(H0 zTcjuHWqO6~@Oi=iAo9KR6g^3=(u;KOL&%r&!5BTYnC3taOaWeZYyeR$%JhnE@ zQ%huY9e8p*Ft!2M+7Qfb1bQ|BQ$xYx&%nkou(>JN3V^ZAKsg__S?mz^Zr*qQM2C2# zLtMV6n6F@6?C&WCw!rw&;b5KgYz5De<*k_)1XJ69o^8S4c3_!oj9}jOV16X?b^v1` zut9ovVjfu;#k`%t^e&)xS1>dhl=tyGT=$vZ`xVHe?BV>Zi zkOi_rHb~EIs23oUW8sMi7~cnsMZxFCYRbB@lJe!_T% zc&S5NzVFz08utUwGhl$Uzn3WE%J&_|Gf%$fC|p**Wqsc5f9}-K@QAdDC*=Ejm9$FWsiw^96Y54zNH*?u3`f*j?}n8Jq`?l1Z}ld$fD+0p)w! z&p(Uf@@evM@%`F{5MtatHq znD2Sy>Ey}ebn*ytGAZ-$9J*iokhy~GQdi=UM=_tkV_<|#kQuT-R>5K_J`-=8kqQ{lM5XE2{AnIyAhk!(GOJX!ZC ztk?BC=KBqO5&0qcHYwkWUqF|6$hr?=9jPmE|H~LR`wAF*6^y?IdfxzR!Z+cbgNKqt9`#{bb*=vV0i$T z90-P%2ZJ6kJ_xLMLGK!1o%E~)5Bfk^|49pY{F8f;W5`kDcI0q!V{%<`2sxPi*4pke z$IYyb@$>7D>w=Z_z}Wh1_k*(jQ&_j_MIQh3MdXL%+vKa{0#epj)_)M|NL`87H{(3E z09#~eOL$`|u(&l?2!ge3!0?V>W*0EFE0`V)7Q&#c|I3`m0&+h2IQbBH4>^y#nY^By zLtaA8AZ5EkyJ1{s4CvdP91Di`0IQ^LJY3d)A?uy@Hy;1wiR5(h2y!xc04ej3^}mSi zQdi=!{W*^Vz~lt5cpw-*2n@tP|0FPaFj$%bI@7=^**XgDKN^(vpY#%se{wH!3^|J2 zjvP*IOs-1~AqSJ+TH9UZxT#|>es(%}ELb`Yj2zGQ6G2)3DXiP|cOL)rMdXL%+vKa{ z0#epj)_)M|NL`6n&)_`H1RG@FYM}5LIhf3Xxhp_f|Cc$B z1>}74aq=PZ9&#ReGkHBZhrEQGLCSUouEe-a(sLEub2S*e1}u}Fxo}zkg{*g8jmJNE zA~~Hrf}BhqK*~I1{V!s>)RlPf7L1#}6%5}7CT|D*1+XE!1Ma&EO#J~Y-4AB|2o_6V z?Ez5Mf6~i5{>i<_G2|$6J90R=F}W@|gd9wMYi)PpL5v%C2n;_=KEnAt3bx4b<8WF3 zDXiP|3XgyKBJxA>ZSqxe0V(S%>pzHfq^`tMPh;HXGhp_wVC7lPrwWFj2SYD_i3MQw z70~x4*dV@^SJZ@*Z*?c{6!EIfuN2oI%QVRXA?;ZH!-dhkO^T zz6Zwt!S)Y8S^tHsciyW!{>c-`>EsdQWbyz~<{|5U5!sb->uSBj4Mpgl9q<;up)_)4?cD>HypT3CvkbIkbm0Uo|`pWtbVjZa~@%Vb2 z$NC(91F*CqnAivmZVU!C0b@hK@)n>c2-ZkvTXNpM0Erh`fiKN8U_c zPtGAPA!m@XT_uj29)a<5+mj=~@(y4$#P(63tp7sRJMRr1|Ky3}bn*ytGI;Z!B!fqoC`M31AQ|=S^t+g zj|Jp>@^SJZ@*Z*?c{6!EIfuN2oI%QV6*zA40*s%TMP3LNGhp~4w$BD-{TH&{c?)^` zlP8kX$s@?g72L)QNywo6@!SFYwft_AC)|2lYeE||L>%-#T&Zv+Fkfyq0-@SR}d zE-*Wf&g&&idW*+DxfeNx97S$N4ktGz*CmILgUN5L?e_l;<2Fd=_i(2O2JQw+q;nr! z)_)4?cD>ExpT3CvkbIkbm0Uo|`pWtbVjZa~@xY@PH}@DADuanXfw4b>{wKijU)Wv& ztIvVn7r{E|c?ll;JJ@~va~=!G`Q+o|L*zZ=Jo0ApdU6hV2|0t5?J9HJbPeNYUIl%x zf#KJ|D(PDYm-S!Bdgr~ve+C9xVC*~4>Ds4#9u(;hw#EDxSq|5K^VeYI7V-`-^E*)bhwp=D9|BW<0^|P;R-OTiFM!FH!BicL{R3<^ zz`}>*Ct&3>F!?no<5s?B`*QoXo8rrpD}WU*=>tRSgVH}g4Bpxbtd0Z=yMnbnz{b8{ za3a_|3@jc6R*nY!$AS4I7&sM-oCV6bnVIn7Y_M?|n7|RUg7G`R?*8|}1CN1` zr@+JlF!mZ)c@Hc!LI1a4ZaI7o(pnyD37_h!C zm^uKI{@#i3JefEM9*luavN#EzI2iOz2FqmV5O|i9?*o_ly#wc|OWQ++Nk3U!fVjNQoaXVrq@Y_pJVyS6d5L?WSo@msYKqzxLGpz z9z01l$iP3)o+s;Mtbz6%>3ts_B@4gAdRE9%93Gnj%Kl4Ro~M_|2I)N<{eonaOp;l$ zNqUc9J{cvGqi`LcF&|>SCz0~Jm1JI)ERt2yzZ?2r!G7D2JCWy+-+X}jQn$(ezNvcq z6PD-4qW<%&v%*KHvoR^-txA`5tg}w)NYt0@Jc)V7kTRdZG~{K;s2s^Ky* zAp_IVo*^4#sCB*J?coje1oogAnST>)OnIGOxf{Y>-_v5;kk!&{mHD~cv$C4U7>8} zAo%X!{bYP$XZx;~>JV>P z@j_K^*X^7~!ThD`yzk`Xzi}Zhn{$WzCdzz-pddT|Z*y1L1NU%W*0$&j-a} z$V+SrN?y)#X&1IS#A5+nPx=YVRy@6#&JS!3&yLXT&RFfWgS7|Z+FM6zm+fDH6NyaI zahabmpVaZliQ03sw6`wQ9-ON^dYg7I756oDerb{R$Y5v~>in>y# zHei4GvCZIM?b#LKrIkS6DqvX0AXTGzMhRjqhvTb&=bJUc?i%R6ch zhP8*sX)o@hUH-1o*Vf-Pl6L#=9n~l5{@y9tWqrE;&dA|9Zf}37Lp*e}?l1M_?}vns z(Q&(ed40sj$vQ83n)Z51yUat*qcf-LxIK@i6;E*$2f0n@TXlZeH05y$1c?F zo1;DXYwd+QwI_bBy};+A?bJFCaQ@xx-uv`CA`fbBKBhhVl=kck+RHWVDIPx;s_p7t z{eEHo_nqJ*}WA;!+u!!O}+gYZvO>L?)i9Ut_JG3FAv?@|CKzPJ=@!Fwu2i| zU8uLe{FZiXZIAyOI^M9nM`ruS@cTO7j^{eW<@yYnm9QrZWQAPTbr$6M4DT~fuFD`? zR=;IkpTTMB?TCD#J@%#LUu!Q9#r#uOfF82U*Ee<2;rE(?WQ2^72~w_uBj1B6u>D8Z zA!K`lY>{&PHo2~wTt7~(E7$#frmt`WCCC(+A#-GbERhvbKF4a&11;2xkn(+#7(GGC zbqh1}99beOWP|j5jk+OHu2UGJ%XJD<^dea$<$8oox?GRY`wi;K^#^103|Sy$zm@26 zeZMBX`+GFsqF#`UlCnOsUP-oR$vjyk%cOlBtvcJiOE?Z0C6i>9l2m!hxo(qO zuPOK)>P5*UnI(&)tb?pejqP%Mz!u&2J?e!>xn7`L7f{wg)>+m)$NUmmBjtL5ExN3? zXDP<brPs+O>GVTAFX<<{ zuOmp8>jcK>Nit1lNm++Hy-1eHD(UIMxIQvKhR6sRBNJqb%#b;pg^CG%vNtnu-tPM39%>;B30_~bf$ay`Dt0L&*v%Kb_H-m~1_ za*UVA8rdRK%b`wztdI@T!|UM%$OxGrGh~6RkS)@)JoguwAw3?>pKOsKUawBpAx@X; z-lges-Mc(pu6rlfyQ{NZu6HNbxs&VL$#w1IdUmq^<$88<9Xq*xom{t0u2&ZtjQPuT z>EwEJ5k8N{NV!g~JpVP=?q3=G<$J+NdYa6VvJQE=yl)}rCz0>){GI(C3@z2q=aMIs z{_=T9wnKiiLtN^~=QnX@q72n5C12imsdUH>^!w-P$>(d?4*AUvahadIj~46dd;C&| zxYYXvPtg7S`>vPn5SMzpuwJ7>eq=!3<4L{2tXJ%mzg*w-5*^|)-kKb*_D|-2$D=7c zugLzVCX84sof+&2e)3?cT1uaBbYb?e<@+soQI;FYlj8zPQ|p$}3== z@;U22`}u2R74-9MjqjD)pU--td$xzTcpW`2$+yRet&V!-^}+bYV0IfYJRZy^z|7^K zcMcf33Y6`tUkwjmtJ@pb!E@K^_SmoKH-X7pz|igBPhFqtUFcW18%*2}%KRD+YOg*7 z4?YZf9s%o*ftknI{sic+fGx88S9qWbmRtRY7M%us#%wYzF!_XIv&|v9z_0Cq}@- z+v|3#n-dzP0Q7ADgFGrqP$OM@o3uJ|Cke*{vCqPEX1X-4N z5_!RMz}7Wj@_sP3(+2Y3yi%DM&1DvWaC}9=RGh;%63QTDXTq4FI(+( zdgC9g+W-S(giMebvOreI2I+a9^CD$lG0W4Imn?5s?)w0BLu8CBe~fl{eIc(ml6+pv zlm4~ve3B%~q}PY`I9VjCWR%aFd9p73)pg^CbML8cg(X$ddG6!q;C&y&p0qcI(ssYj2=rr2lIGfC@A|i%e*34B_k2^lRPi$ z{E7YFx9TLBUnOJX(Z51^_kzdB%---%3ot}x$i)6= zuadq4;H?Q@>Oe40Hpu8fXb;7}1X&^*2ctbb87z{{A@IPVV3YJ629J~BIJ`_Y$lw&T z=MD$cM}S4rnFV(KBX>X5sp+np`x$k+&=WQ*ni*GZm zPl!C>sjs(qaidc+lC| z-%aEd3rLw~nd8JS#<*27a0%x{#%4241}=rCNtx%-TVg$hhtnsM z6UcqZG2|$61i2+C^Q>{4)MXgAL545qyvSr0UME9Wz_X;xbJeXdPvHvm{^Syl|0VeW z`8N3)`8QJL+2A;tD=}`1jLzY_$n;f=lhLc;1ybhu0Ouq81N|=YR`N#jO7aqNCV3Vq z^K`DkczM!$Ej&TC$XpKX-s>1A%cRV6%GOv<;lcC+$bHB?$eqaT$l>JANSUW^F2*g9 zf$QOE(t88ENCs|XoUD;D&p|=VQ`klSmg9aweoVeazDmAG{*{z@27irlt7P~$@EjS) z!z*O?CdSDoDf7IW^Ag@kzlFSkyqdh2JfA$1Je8DrMsCKq4Kj8Myhw&`h1bdGZSVr= z+zyv{PTB_RDcqmFH#wHvh1{0hf*eY&Ps%)F9H&Jlev5I-WV8Tpl8HMQCw+J7dG^~D z^Avu=@jfR%BHtxnAs3L(kbfa%o=J}5y$j=I$U2#vhj!oZz%1Dy!~dn{c?ahyyqSJI zc@=pnc^)}~JcT@tlzHYjPU!a-uSj}|@EjSw8(t#4e}E@Q+3&yD4(lo0i@rO#Gr2vv zIk^eB9=Qf7^DJ|m_&pf6N(S!byvW#n@Cxa_AD$v*o?o-R@H6^{NJx^wNeix>v$ue1CJbyOk8Rz+voS)g0*H7{7k#E0#Ds|}Zdj#{f>xw5k z#H$_R!ADU)N+!t+DdX6zcZi1`>wDhv`YALL>k=bV~*G0PDaTj znI(&4jjuxn?SOTAklcyfj9i<1oSaYINghH@C66IbCeI`1khhR>93=i5^Db1t7MYw6 zFFgZBpJm>2V6FFTOeRRFpQRVcD%rB~s{dfU1}Klqc|Km&$tv&fX?mG-*zV!+ zDUZv3?$0=x-3j~GL;A=7nIPkzVIIL<4sLHs>n!x!W)vvfm-!rd;;ApRhnOF@nEfsS zV{FecKlmlLn+z|8S4jE1g1@%g{rQFaJ8SMu;_^Hvj;Q&4*st`wq+M9(5O-RA_m6dm zhrULC&o^L-l<{p=JH!Lu_C23;hj^_+JhTM$b7c5Cc%78_dcN25NLU{3H%U_4^mb{l zTVCw1SA$??n{c`jukApDhSDcOc#_37Mvl1t(WRvu=u0M|c zUhXG986?AGll1P!^&#UCtY?|@kB7I&{9f?D-e6=OP_8HY;26|nIc|9TZgB#*=kZpFy_;$Q75&eRbz`((v?=Ud_OE3}#D^nSt20BN9B~s?? zpN{tMv0&mjuu6JPh6jE{roaf9ATwlG|bQf486Z7C@()k^{N#_3x9xH;LyTQyKzy|5L7v3bj_ra57 z>V7(}KixGB$MFiJ9OunHBClEkQxAaY2X+4)*l$m(f9PT4HOSf{@a&^(CuQBskD)zM z2BkglC++FS>CfnP&tJ8tEss8{;}y$u&*`|gsy#t(TJ5Rlb)L*y7^&%a({lgII$nE2 zd+tr`70bg5b-ZMG)AGdII=^nY?;Raay{ElpdF&rLUbVdWzK$n9&|bAX@}Z8GKhhrh zSbNg)%BMOWX=*Q6?q8(iDa&i0>v-%7?Ip{DU+Q?q^1@=oD_?=(7P$nBeFs*_(D(45 zgV&+aeqe?4cfsX&%hA34(H-5A*x;?nE_UJ0`pcl-L>D8Dw z1Zt|qU7+4{Lo5I5Zu(mmv z+yabk2{y^lws2X;y5+u|5HFIxQSc;LA^khEoh*}b9@*gejGyO8MV@EK`BgcC$Lqkg zV3O}E_{PFRWRlF19@g>g!Tw~L@e&`u3#6Q{Rq1uo*%ST!WQ2^7DKbMA$Py{%gEe}C z^h8kCM~27<86#6z!^&ulFhW`!_6i4%Kn#CzSeyWz>%zru$bdZ&)sMg;L-1^WNtlitG9%%d3`4U7^%Z zETg{va9uxddC79AE0p?`Wz_df)%7!$=Pj4ILa85!_P##NBX#}cH0>G7rLIuwXO>aF zc9gCcOK6Yy@%pTN@kLWKX~kt6p^VpB#(1ftd#}F|3&?nK{py;PFXIShyu>ehU%&dX zdc4$e+NF+A>XnvJFMYi3U$84Mol|vO z>I$WPX&LqXr|JHA%agy-ac@d{_;l?R%Y!p?Jj%!KG9TybWRvvqaVtb-$OPFSD`bTC z;{aJ8Go**dZG)bmN5~3UAbmVeLZm#uXXpj8Mz%+Dk@9@sqSr{@0XUvy zJp%LyS-o7ZV==2eaE129TpW*2?aB4Dhu7C$vfRIgjz@-T zFI(>4PRC1@`$p(^*7E8|9nb8by=i$Oq~ncUwHHTg4}`VH#%NFNuDxn`WUP+M>ym@P6PYgJhUYaDPSiz{`v{^bI*Fa5&vYZ z=x6JEyK#5@5%@gydFILMP~o!r$@AHuLolA?OWpea%lT$GkDq#dxybmw*H7mA0OwmJ zWxj? zZo~bw5xE+<0-0vsE#$pqnS7gEMD{-n;|w8X9WvIuq+KZc)&I-hkHgw9USGtjE8p)b zu>E~2-smu{FRIs1<|9mYh|B#o%z4L2na^#LyRMCIFzCCx-}vqHHwOI!FJj%|yuY4n zZLi$_mesFj&8KO(%v%_kptsL|p!S^Qk%>CqvRu9ouzMW)X&drzQpOD)r0c{icP8n0 z((=G$9j{m(Jw(Tw8(?Ys^SHIIE7Lqe=U1m|Z=ImMnADy)QG4_x?S)gd$4=88NNIP@ z)LyhadzOwz&w(dNxnD2h@$(_q|7r3L@;dT^DcE11k*|=?kT;Nbk~7H3OAs%FglaG01V6`F9e&y47_j=c`+Ef1eEXfymC0U=L1q+*ZF5N|58xC zXS0ZT^T`LvJIT4^#pF6ip#Ey4)X!dqx~a>-coy_r0p`fSmGBH%AU$)??py`7$mTWh zWRCr=1H-3d9$p^T@w4D*GEW8>5A*pjPBzIj>E+|JGXr&k^yV4xI+-W4WRZDQdYUYg zNit3r&qO`PdOR%A9UhnReUl(POhzRx{l)qC-sJpCY_E|GvdMk{9K52rU zA~R%;ERZF#Le@zCTv>AA7*xV-=9XU9s1e0lziUx{^>=Mgz>eR+%* z`mG)}Z@I6aY;k_&HB-8azzO=RZ;La}m$b3uJ|?kqxp%`i??B=K+jcBx?`BGf#tohe2!l-J0$Y zuXTuL%DR5*3GKBfwI}~ud$giG@RWAne7J}2&&zee#hatCDdI_PnQXt8>)<4?Uh!kV zI@iz7_A)(4m(Nwh^r-YFlVpSSOV41Q`M>JN!DpHG9GI%=e%~*}O}2}=H2pmC z8ZUsE7s0~c!2C;KtOm-C&b+K$+J#Lko_h_G~^0=|A&nGLN>HdMw zwYL^)kA0E5u0y=Vcx)i*l!VK}YouooJRn>F9wlYm@L;ry z$LVFOUE;#nis)Bd2@I|bX2{Yi@T3>alAhJzF;eb_N$x+{k4<`D2zeA$ox8R@48@&OsxlRkiqrg*$qHvLoi6D$T}JKBVHjx8^KGY ze`9!L6Sk8LGB_0N(Vu~3vPp)9p*>HAH-#6;Xn_65*kDwIM+yaaY2cr|g3;@QK&z!6~nNH9GOERo)$7$@rqc<30=nGWX2!m;qg zaiH&bFnIzPN`h6gej+@75*RrdY>>fI;AJv!D)UJ1Y4GH)z)%XTl8w{hg)_kD4EmX1 z@+{DEHt0JCtdZ$7JbNDKJ)d#1ITK#G0IZX#S@28-^jrj1$;QR-;w4~>OwMNhWnh!c zUJkEk!SWSg`bscx73jShERxQ(@H&~#!K2rKO)@%{{YdZi@W_o|=+|JG^!*0z&4Y=X zz{t&DiENObThJaNV`Q52-HLdTtdq`dXb+N6GDUiCN4!ARN$0m{50Ej^DKMX`lg=H? zCu5}Z|B&_`aB5ZQ|NmuXGIJeCB+Za9DoNDE*oYMqH5ePlMq`>cduwav~izs@n533`$gjg(clB3 z4QTE`v_B-8g65z#sQs|m{ZP*%!tqB%1OFEF7DcPj!ehe8$3=Zlh$fyC4L&96eOj~% z%|8Rb670{4`koVQKx5Afr=XD+gsqoEYfw)aaZt}I!gXl>tHR;eMFVe$M&A?-RlskF z2HzH~L$mLo{aw*4wDcbQ-WQF3AXKf)zwzZ8yr1^d^c1*pF+oP&D45l%rH(CBxF`(CvF2T}V+QEyW2n~GrGKbh+L zN&J1d-|{o=M2Sym+_8cx^l%eC%5Ne$Hx0|I8aPnC(&=T0QP603!zK<`&q9q0ZuHD_B#A4V8-!tleN(wpL0>&*W7sb zq_y8a^*^&#yXyESrfkBv;4hN5@vCTI4VhOyM_-6}9Cw4v<3o79xDWW&>!tk$v|kDS z4EiLV!@dAL56?d@Mf`J!n-AW1zJ9#w$P@cbpBFx-<#Sa&XDy#9@q7-;=d?NFxh$X8 zR?%MP^I2#Gbyd)R0_=z8J7u0YkI`P8gM)OguB3Biu+H{yovl8d?NK^cR@J%c(>Xj= z=K`4TOG`Ko6~m9?p#~=(*!;1Ab&+k<^CZE1 zzMnJfMKIUv^;kdCZ<2Me4Riq&{fz@pgPsR{0rrED=W)!_JK(o(l)MjNU7X41`50io zU+OPGYf%4%5*J2%75(t@fZ{lP+@W=Zqfm4H$eb7EX+0iWe^meaVh=<6q5QoRHS`z9-`8MVZd-}l2iJjV z(9hsM9=tV_aaH8uy0!y)eSWZSYiVEmW;veBHxfJrItI$m8JM?@XxTb&N}np`(shd>MoH{xDV}hqun}P{Jq;rKOAQq z^Gkckuou7;XmtmPk4_QwjG1FW2j-;qxMnD{`gSIX_cK&@Pe*c7@Gx0jW*E1L9m#=rU zr*3cEPo<5W>mtK-f#VUn!^nHF+&6{(DdV;8)a~^J!j+2nHSQL!Az$ns-QPY(@&ust zi`=XGMeY|4eSrSYmblP^x*v}VHGL=i;O}`z_ium$A4%T+1>zrlSodQ-YVln0E41@N zzYQqgKTXX`{OQo2VV{S2m;q&fzDM+WlHfAN$M>C$M|Hp8Iq_zS$B>`-sBw%VhWG7;P1$)J?`yUto^b?}qw2aFSW(v-e>QY zxCgKvM`B+0LHp(y7xPw)yczfhU(oxbKQ)H+(?3`GOWrRUd{8uv_8jtgz|5aB@`rFA za?nE(&wdh!tGw8{o)Y4??n2CiczdB9A2*o&QU9;w>qmdAw`}B3!0vffucL(eIFF?_ zbURqLElC3^m%!JIcL>*F~6zv%JaUv*|2 zHPOaiYGb$lEBSrU*l(@-3&Ah@RIFJ-4BU89IEeN|m=`Kv|D#WfpU0Bl-<5ZXraMH7 zouWCsUoYc+Fw-UN%}$r`PaXFB0P#z8i{^X4wrB&&{Dq>dqtXguUq=E0khc@1r;*Hr@hx03cW zv<3}NlJ8IE)`t9SQpP`PK;KitC3j8Oa-38{nL?&J=Kf+!` zTmt>k&zda#+w-KqD)Lm(PCq{HcpmooP@V@R#Pjc}Sx-v7G}`;21!#I3>6iJfZFSBV zywndrGz`0cJ3T&PZ~~mde%?Cj2yd^)Rl&S}_M<<(Ut}G$^9y6#KWF3pf9x_De_;nb zKjZjnmBT!-F3*%@`>)M9aQ&$xj{W)2Um5LTs2>`Fy~_HaS*Qhj9RB^g=yf!96K4JV zR3$x4Z(kR6(vQ0r8@r2Nd=EV@=ab6!>E!U<;va~%jw_;WzR%7Y{*iqoz8}i`f6(cz z`-!%(=iAureOu?x<2d9Ezr-`Lo@g(ED~4ZWKgnN1o&uQTtUZnM+-UbApLc(~zBJl1 zxGwc0K6tt0VZKC6k1K&AGo-x&jm!i?BL@lRp}~WN%h2E~;V3lpcj-61xm@4;TZwwm zUcXuFF);6wtEe||xa8w}SX)RuUq8LL&tN|Pk$=vgb;XX-{kfh)lUHhXnLb*#FRcSV zRNL5tiPrJal8nEM@#hTxD&BYI@P5F;`y~taA^ped`T2Xa`2K~zPb+)8?$-cEPLTG{ ziK2X6jU#^+8b3vk&z_}o;9_u2##74Zc5~huLuNFa`sazCZ9EUPE|K=^rJ}yeTIWl) zv4^gZy0W<6D?KZ0Un3evyAR5Fh#<~-0r9wBt3Y`_61Y*XuVAn_{_vHOuY^3coAvnA z?K+$BA)McN)K`VppOd_-pW_U@DD4?2=Oa4*A$WUnjcJK<0B=au@75 zjFWZNpVRxJ|BCRhTrK@_JhAte?azA5{Jg%TaUYe&^`alwpAyg0Jj-*wvRIA=l9>`n>Doa_h6A%HS(?w z=JU5_asG0iqd!S~1spfdTMg|9w|M>}5FdI;U!R<(%#vk~cd${{AcOnBeE(d-`B^ja zu^y@qe!PA~e$o5q>lpk~@n6NB|6MfUk>|^q;i5e6`8f)e^X2IizXX)?&htLGir8z= z>L}sx>Y{vIue>bt7w}0t$75>XTJbBFMfv$@9GrkXYvf^E4t~MWdOuNv|Ijbu^3aCS zUu=w?kKgZk=Q^pA`@DLu7v}tVLlT!ndlB{LCg}O9Xy<-3KL7q1ud8cAN20%Dz=L1K zJYhhdiF#gsPd|$OL+~#netG-GIKHun<377S#Bu&|s3&3c%l&HeUXl8^uBdmMveUuu zjXD3)eaq`!d+)X%*CYRU&KK-6&^{N+e3`BE{;CGkk6J-|c#<9$2XlS-(0|VG<2>y2nj8<- za|!Zty#}ye*{`YTHuf6q_D#}{XKTIQ0GRucxNnL3@S=vl2m8~wo_@Yz+3RU}zvm^2 z_|j7nSDP;yMV=(MaHF&r*&hZTd0pDMk1e^4J|6Dl@ocNN2f=CNjTv@(d-1P9>o_jl zH|E(v&zA!8eD))65cS6}-^-haVp#HJjlAaZZNTn@KVP5X><{f`9Jz=(a)w`Y4SABX z5aXPkl6mF2<2=@kID1EZ9@q~x*2Z3FWA{vHoj=jW&V6zftdqN;tdH|oKzq4OzQ9gW zPZ-KPrdBSU(QIP>T-O_8J6kd|jaKck+GHpZ}M=I526;$gpn%A2Ti=k^ac0My85AL7gb;ZYrKP zOowvaW#E^GmZ2H=<)NOlW&XI&u76Lxj^bWAn{|2jZf&=tV$a_x{bc_sy7W28L3(@< zTs;`=hlnn^MdGMuJ}vxL=!$s%_%Qq)haLpwyo6@yd0mLR9_#3N_zy$-JK#0IOTepu znb(IptwSY$JT6*2Ef49&{h*j?g6) z@p}cj4%%5)8tsKic-{tk@*L@peg*i28Go*B&w!c7m)7lkUm7vmli+^j%AFXhk z)ISxv2!1DlPlvM3s*yi9SL&!jz3>m6r`N~(gzMju{&+p124`M>Sof^tlmB`5h=oVS z0~z+m`=hH6$9g*6mONa)G4vNZU-}K=^(+l$K2y05F?)yP<32*`LcRXj#ln1_6+j~P zQ-$5kPiEXKG?3Q=^SMX{~KaxAy1zVO~EN&wPCUyE(?qb;9FK`y#A2?h|Fa zd0Y!dJ?x+P_#B(_(?3DZ*U&q%E;#?Cd-ZWGts4VjUe*zRNcU$u)q95I=YB=&Vcnm{ zF=@0jp2~jt`$LL2-h93Czoh4lm4$iz^}H)}B;V5gn4jvw>maYo-gk6=<_jQS@qOLS zJXGHYsN>lg&88T*2=!IPo}aW8LSC_7cwrqrEXs#?>&|Sr0Xd>q8X&oW~ichx13hWrdyo`pP~pH!gnruCwmF zXUmP5C-H?|FWaf5Hum_3a{lHqkJd-RS=7OC2ENq$34En9`=h4Y*e&CHd&gLpQ_w&2 zRomoCtb=*S`rx`qWBtd`&U{?o4`KYgzE0*mz_A2-#fbORTaQ14c}yC9Nt`D+qdkp& zg0NQ%d*~bKFM;c8&r8W*vz{7`ci=}O4)bhYS5Jrk)|eL;=II#dKE}F@ z8hQH-HtVsG--GKN?cOzHUZO@j?bHJ7mFMLC>D~wAd>;3p=n~XH7MriNQ?fo^WGXZ%`ZoC1Dbu5)e`pr1{wbPyXn=Z0#*7vn`MTl5c*@Yw=Q5t<^_ysu zH-_=@dn(>XC7=1dpFH|Y&lNk@VZ0>Fd5)~2kAuf4k2*`M>vnyVmgV!cwpUOuk5g&1 z?jOYW9?Z{GSO?c#e4HMaUPrjHv1lwP%Ka0^ej($u@Sp!nVdmraZqgGaj(%Rm@q03{ zEp>Yl&(k@s6#Qdb>3;kkWRQ0BZyq-u&%h)-J`4XG;(6YMx6}PRyXkBh|M59T{wu5l ztd~?okK_J3&mMYvz+fZ2Roheib9?J?rXS~x-zVbthP?aeabY|+=X0_gzAwY$kplC3 zP@W6)cpKy7_m86g*6ksDAIGeZoNZ%Y`aBB(ji)5P?^?MZsa_)*0$b1+l>52(+>!f1 zYd8;BNAelTOExw1wH(iAQM79KCrhp4`F$7bF^R9V@ee-RI$x%Zy$*Znxz>67&x^eb z<$Uw^^+sP1yZ=Se0yOnf>%19^vu60&FSm(nW3L*|m22pyVZ=q=mU&K>TleSNQl6{w zId$-HiK`oN4LpCPUkrY=g?j#IUE+gK?lVliqWeW&73OpDIQAhjzvl_b!}VK$zlHx8 zNB=tN3B0cNQv_FWe^fK<%tz&Oc;*eGj>sE&UOwMtT>LsY4>LGVD%ejs5ApO1y(xJ- z7101R3yr@e?P+K~)cdxy=b?PATLD}6uR;53GJmmmB#w4di?Ao(ZS7ZXWB0$;IzIT6 z)WgqJ_&t&M`+8jP1K|ez>tGB21**C~+o}8;#E8Q3EqxArTcZtlk^82@!<@4d7 z(T;AG3cr_N=F1szUffTYjrOI9@B`0-TQLsnJDD%~(f%0he1AfF@W)v5$MU-p$Iq?! zeT)+9^soLT{$x`#-%Fkh>PSE%X!k++emwQ7o{#S*ij0RppChDxTeg1&@89`8zTP!M zD=h+h0?Io0e8Xq!{&9n~WD4qS?5P#>d}e$VcKbP*FYd3l2I+Aruy-YC&*1waUc~YH z4a^fCs>hdC)|u-e`LgtT8+Ag$z^u<>^t%d}>+h`>rS1-6{nc^bH2X@iH@+5iAwC|Ee%a4{MnCl9IQad5 z%Eo%VHr6M<4^-Pkw=@4RBR^j^XdeQ50{Qs8qWETdzF<(8al;X38{hZJBTohMQ$ZZu zts>4xvZ>w)dcUSU344y?hvtnqt`ELnW}RGjfr+jA;rz3o@)o*(U`w6NI(eTH!1~Cv z@#nhw6xWL@q0GzrIi6aZeBrI6KJSmR{&@ZIPtxnI8_fQw?3d>Q>kK0A$wr;r-!)Yz4W-!zB;om zY8ml?{dB*u!Stu*+Snt=YwfS+WjxjUri{n`i|Eqv8*z0!e`ns@0eapd;uGjM5!3Af z%#Rm-7Ut6jjbc9855G@SKs&!@Q$~LKFg<@hDQu31{ghAA{rQ|Tj{L!sbvx&WnuR@l ziul#J?y-*2Tu&HJ?o>Tr?04B$%zS)KZGO)t{hAzy<$d3!^s3mCXX^R+eGY!FC2!b$ zi1R=LXX)`7gIOoF*2W$_Tk^4=B>IV*qxVw+`_Gm32*w)&v%eIW`8e)|;m7?75Bw(c z!uxmXS@Sdfjm#PwUpwfq3E#hv_%HJ((x~?wiHjkg`zHCloxohZ{w$e)mvlM(u5$cH z*BfI#c;9vU$j-B_NI%AYt@HGJOWW}Suj>WOOV02wTp;nhZZbagx{QP03&~xm_rvvO zehK;!bN)iaz@zvebB7Sxa!ucKkG8K1da{Q0`W>jpoU&HY2q$M?@GAQAoezRi=>{k>NRd#@4=LV0}o zx@cW3_863Q-f!^ugmFF3!Ot8IIS4=d8oizd=8N`_VJ{lYd{ov^MgG{edVcy*`MS*g z@!U_JxlxbH-mEj@sr5E?Z@yrvdmueI?DJ)+ld=3#%iHhzsZ z_Q<2H`^nX19{4#z=^fz)=EK7CDDK0q8Tpd%4?o_zA09tGzvO;%KKJK7^SqJAtS^WD zyf_~0-}98-Kkv`zpLfaUF1e?5KVILqb;%J3!_R(3_cMLU!d&y`w>knZ6myP#3 z<*MWjgOgwzTK)j*3w89P9~+$QkmD49MxcJ!)9`2g6>$9}z5dcGI-7O-UTtk>UVbkt z`kL+^K|P!&>kZvrHQ4Mw_@?e}+S3?!wvAr{evLMM(L-dNL@KTO^>)hq2XUNAU_Uqr zP8i2A^R}Ls_ajyK+g*~Ed8!}i{=urw=6qyf4_66y!c3unI*4g4ZnvS&7jTJwl+5{1dxn{9~cdqAqGL+L^Bmd&9v{?E6TrtIOLrUqC$jF*Shwwq`py-Nw%S=iJX* zH~hI@+mHRei8b|k&wniS*Nt}XTDl+Wp(bIkVEhs6>!v+!Fx#ocHg+Bl|Jp_!cwasj z>wwPzsPCNgkJ|j51`oM?wT~~DX-ztx{e{guG(fpe|4iiN{_4lUydLD*s~bCxS`JlP+0 z_T2X`@GN+K$bVP9I5qp^yO#EAVSl{YA9;D_O$qb5yu8U*<#mE}4PMTCyz$v3*L^-Q z_0~JJPhNa)VCJcI{l?Jm|1~a!{+BoZ**5dQY1><8^y>L*YE^acCXwoaYAG)AZX&&%^r> z<|(7D`o_9nU{m41W_mmOp|Zas#$|1;`^T_P+Y60N(CtO^AB4R;QMWU`0J|Uk)V9$5 z5@=7sFR+zv=kega`5^quA>A*wway$THH~@;*nbfRH=t3pbDsG<0`~8Py@>l&?)&ym zGy2`#U={!k+p>;gZT$Ruw9ZpUo-*cx$HUrNj|=Rtvr&%4`N*{KiyqKAPloe@x_Dl2 zUeh!5c<&*?eBRIflYDOISwZG02tTuKGUqef#xHiL-aq51g*Nsa_V0M(t@9+>*!jHy z?z1-c#dAM=2IJ4A<@&?^D@Oh_{yqu!r;olz{P}k-^2kFwmE(?o1%K@0E@EFd_nC*e z&-(;@+&oTR#Mccw^HU=yN<8<8C(vIdspqYoq%-5Gp_5zN>&V-0_?5w|+utket8q%} zd?n;dV;;CqznaqHxNo2H6+K6{2hJ5vLOC8&ZPZmY{nC0qGtRrBj3;jRWx%Dma-56s zt6*L9gEKge+@D^btM_NFv$xKXe7vtIBM;XXm34C7gRJvvJwN@Z{Cug@#;?BGq0NwQ z&X;3&5p_f2Gw_iiZbp#2!+I}b{G z{AN8b+o^p2b2#GWVZZPhV9s|5dCcQdx<&G{j?n|}343m;{E?kkSo z-@1-`8$0XlKw|C}<@=HTf}TJ8fX=LkT5et2=S%%p)(7uvdA}P#d=>NN z<9;G2-$z*w>-igx>CC#Rk;hxxD{bt7CtAnzy21NL^L6UyJ7v5HjL#Y*=M!I_sI0fp zra#Y!N)w_R~y<(%z3eWK$c+TZ1NF z(CY}jsIwWLZDX&uv9taK7}sQDe6f|}xTGuRpv_GG7?|`k}1H{zlJZ`m^5Lce-EY2c6A%3jEmG&c7S^DaK{S(|#-J zHSOj&`FSdjYaDUhZx+J-#v0l~zv%VFU{6E2AF|Sg=VvG&ZVT6jidKin@h>ATyMpdt zhMoDVZrvUkEX@0*0Q~J?x}Q0IzHerG%ztq6N9JKY;o*9oDmXk`>MlTS>JnL>_R4x( z-76d(skgI#DnD1|K1uFZ%o}m$b=rJCk^WWc;Psixet5oz;pgpZT^H92<9U3!&xPxr z`(AUnu5ce_a#cNl#HTa!QcI|-hUbd0p}0<9eaiRX%_-dQ@Oq==&TS)!pdgHtow$#Vx z-%4lJNiD&i-(LJ8nD>HL#_0n`C+m4CIIi4}6~ekC+7YS8H?>V&xNqe3h5H4|MqCp65jh@HgS$&V)jdVIE_28q*t>Nd=DHl6 zm-8buQjSv$%JoQP9p-hQAO01iUyjq?Cwc8?>$=Rmv;Be z85j3a@%IjXiuSiGscRwlQ{+7z?Hq4pAG2X9VPS^oUYefWIWV{TDU(-fx}Sdi5q$NzWf(s zp5`zg1`^s=@1NtN@;Lq z+PMoA9iZD;Czb2i8YRae*2X`4pybOzE$qumL92DFlNsU{g|a_W^KI+f{uA~38>i}Q zbZ1pls2_jVdp`2;yhxub_R2+~wTngT8BsGIIXthmy&v}A-^DMM6HVSKn!BrYe4~v$ zl5ZWKhrPH!{Oo%~y$^``9u-2K7EMuyo9{yzW^@1EbUzH5%^cjx_@?|&OBaJ&#PkR>xsEfsD`}D+nG8$)bT<3r=iGjLKI(-=KG5S*_*{nj4N6tr9#|wC zM?60V=I8i{Pjr9#bDhn)`2N@&C(m!z8K~=dYCq^~<_-PW+Fom8H?MPC=W{V`ULSb> zn8kH8{8Q_GIWEpy-tg!5QaGMJ+;8IZRqh94zKz`;(mFrq?;AYNKZDQRQ8evUw2y%w$3**7v_Edd=g^)< zd&Q`S@q^)aH|GT%>Wt|yEEw{1z zN3@P-eRv<5z8CPfd{dFOF{AUlIMWe^dFsx$cvEzBO9sOSZAs*K8fn>j>)zul48rI}wok zlm5I9G5bsXMf&6CE^CjLakCz34t{amA2-0XoBD@-_&LS6KR3SBk*aHpB*xFY;jQ(!FzoEFZrJ(x6YYHdZ*8aN;d7xm$agR5 z=eSJ!1NfYY_WY@{WC&yBcm;-uR>nY)FT97|uOIe0;$l$W8WNXA9t(a^a2~p}pS|_G zdBlg;lspN&)>i)i+w(c|Vm#Ke0CcDeQxc8}*fpIPMql;`5mBo2~0G-@lljk4BM)?<1%jCx0&t zuV?%`mh)Mt=>79L^W3&F-&7tq&pWz5`=K)a=jFu5|Bvy^!~V+{ZyD=}=L%>iIzYc)j5Bpd{MqU$3_AFTAL=y@2OTaePj}afZSCysGe# zo+tXT&a8*Z`@+m6@;-eD`r-VVcD_HRo#!j_<=gaUf6}_1SQ~p0G63c0 zXqC_Oemr03%zCK_*vn9UUR3!~k82prcxnWn(~(UrwX<6o4?lN9f~dh}-f|nepP$c| zfnc7e{2c0fm(;=IoN5!#>thPX!TLs@H?!L^{Njcm*Aw^cWe3WAOl$|y&{Wan=c4BI zaO=Be9rHO{<}Wf1UI(eH$1_dxkWG!Zv77yy&%2Usp6?Xf+WqB2jVO@7wr!hPKw zyuW2U?H;sWV%qm?J@4r@_G%k@aIe<+S>Gbmb(k@~w0khVDTY1ME*#<&fVuy>&kN^FH0)U-!=%%sQy?)8)Fr{gceY`(^6@Jzw!) zotcN4{6_4#S)xTK&lBFidk+(P1L{4Zb>1TE8N7cBAKBW!A9lVU<$ZD$_sP6p_Wf1Q z6Ixr&SMCR_@ckkN7{L2JzRydYrpGUR--Y*a0le=D{X_TTd{J|4>{eFdeNe`k`hR_& zn#Xwa7#H6M7tMZPU-~{4<162(k1M%YcrZ38`2M=z@Gm^xIzIZu zviq+iZ~W=j@t$Y&cpkqp=E?V5>-Z%7(4W7o`}cpKvpIgN+S<-}^^B8s%I5~LHgRRt zQ#Sl~{h&R)Nbf(4&jWlY)QjW$hq}?g`dC*4bynKMCI6%MYvyMi6JRK}@eh0``6|%# zN5aXEMH8QhW}wL$7;5%U=KbIh+^4y)&ye?n_AipBjywh22k`qtkx#|We5Ud`$@Y93 zfAfA}$NS}aox4iyRIL?ta{l(klFSfCJaevGCF*Vc1UO{~g z!;gPopn>mY`@YcUA#AYOFYi12xIef7^FhDdpNzM0{V?x0ng3_xKackz=z#XO(B83* ze&5+>)4vb?6~vdm)W=_iy#c%ZwQesP%yCl#b@8u$CmQ}q)Ys7S(4T5vPwJST)c-Lq zfa6hX6Bquubv?N@_C_0fWJ&A%{cY^LKJfQ*`f$DBe3{C1QN;Kc8|yOpC*x!5%6d8j z%6^!CD%QtLW8Ib8^J8;wKyR`@m(yRe#g_@BgpP z9QRWFy|q2s#?Jc3uP5`{0cHODpN!9895)#8w$=RDo$3CdDfpKWUorfB>q}jA*u5Qk zKGr`Kelv~!L*M{3+NsC;x^y-RWd3=~52au7PsUq_d)%mx`KxH3yn%k*EVs$;AJDq~ zR2zE{bw#M%dOp^-0QNCPeHJ(ad!|Q^ucAE1(mp7k$8ogD#v zerb=veugo=+@H*!L);i6f1^!&6>()~X+?cJ8Mn@y7b@#N2K}C4^iO*T?TZb2txf(S z{1ec^K)oL3UjX~#|lMqVncLh z9JSEK&i<>&zu4&CGqiR7cpG~R`8?3zFg+jpAHT88&*Mh_IdBA;9InTQR@Ry0re@pN z>uv0;ZyxHK3}t@Wb7=2aj=hNX#fIItiHtjd_TmVAJj{O#?33Zo{w;8Vc}ME;G1xP( zhx&B8y^79D^WukC8$0VOqMsX#`U-90J)>Ip&;0X{cg&_TU#v6UCO!uL4B~^U>isc) z5q^t}`mNP;fA&jdyv2BCrkfFO~T%5O?H0VeBB&o|cQ8c)PXaV~c`FrMTYl}aRO9A!vLt_EMK3-?WQNv#O zJz3*J(%*E{@d|V%+fm1JXrBh11LbqU{tYpnO+@*7SZMcdD(!V>d^6pTpZjvZW(fJc zLGfeV{ivt3rPN(Uoq5AAFj0?VJeBjx{ptKY{`@<|H6y-?{?a&3JYMBVdOys|-;2e( z5yTa?*8PLX8{b;St0xah#td{L{!&#QNdi*<=5qo%Q(I9$@&_pv>!IJ$veL z`MtqWQL|32-}t_I9M>t2Zyj~V*}vh>_04fK4%G9tn>WrwV74B|adN&nPWuSmFM6b~ z?30E>ijDBp;8@(s4eo_hZ_*9@8)Cez}Fh=5gffgy&V=KY;pp zJ*vH?+ski)w~=+mdE<2>@s{py_RIO?x(mOf`zPNMu0T1Drq(c@{5vyT|DpHweAy3# z*)Qwiyp}QE9F%!Oi}gH~FTvfxmsv?seo^DBx52a0B( zkwL;dZ|=r?Jr3o0lZRhF&ae1jiSrH-O+vjxg-g)XFyX*(QTEfZt*qxU+ljKD4E)N_ zz{SC{e`|v1t~ztLU;2fh&hD6}71g)*=2OYuuU zi%|P3X^%it&@%LmkHzl$8u8E^l=*AmU|sxD&=Qn>RL?i)7s~c5xMH;XzJ)(D1IKlQQt|l2#xJ5%yq`UubujP zwiy~)H`7$UZ(_bmI^O&-d!A?s+JO4cmv-+3qDg45z0-o@Zu4c^V*h{010 zo@Vgw2Jd0;o(At_@ZJVT4c^D#=?3p>@O}o%Z^yPQu9pK0yL_wffA*MRpJDJ!gAX#8 z-vVKO+(km>T{T%=?f%!lyc+$FXB+tsGgw}A|L1>%VdpQVV}C~(_M;6>7<`Pua|}M# z;NuKF-ry4qKGEQ$!6zAfvcabq{8xkjX7H&7^YaAGPs*^LZtxifpK0(}2A^&4IR>9= zaN6Lx2A^l}`37HL@P!6nWbnlXXAGWa@FfOcYVc(SUvBW<4gQD0S%a@I_)3GXGWcqP zuQB*qgRe6DU?>D$$@B;=vXz)V@KWy+L20v=>zYQ)L{FuRy8~lX9Pa6D`!A~3f zjKL*?pEdY7gP%9}1%qES_$7m1Hn?o?LW5s1_*H{nGx&9b-!S-1gDVEVW$@buzhm&b z2ES+U`v!ktaMj>N1}`@FKL&qj@J9xJZ15)r*9`vD;Li;H+~6+^{?g#D4F1~Sy20NV z{H?*?8T`G$KN$R@!9N+?F!*PKml*tu!M_^(o5BAz_;;|4=V5g`SRj96@V5qkXYlt1 z|6uTs2LEJm!{DC{USjYs2LEdCZwCL@VBqf@FQ#MZ@AGmQ^V4B)r@>tY4=}jf;2wi* zgI6%P*WeWmb{jm<;6VnjWUvRkJc+y%Z<>ub_Wu8R~mg+7r+s)bkqJp=D^`b!lJTIAa)B7FvONF^(uS11&=9P#?wqHq`rrQsS_7@K|DXR|Xl4GN|7F$B z11wMT|6Q&wms_0_XILpUbshNM!Pd6ctmgl=({wwFd@ww%rS|2`ytKcbKBD`RN^lIk z02~274Gx2=;1KvHa1h*kp41-z_ksQ3^}s&xmS8V9c+VVfi3U};Kt@M-qXQ# z@P*(S_*!rkd>^<1ehyp)e*i9lzXun=E1Zwx3tkPJ2X6%K2k!{Zfe!>{!6$$-;0wWN z@J-+p_z`dt{02Ayu7l&?&I_d882B&XD0mfc1YEjD{KMdjG5!#E6Zi+gQ^5i7;b1@b zY_Jb}9oP$g5bOcJ2DZUpfi3U~7fOANpdA0z!F6x|Tmy%|Rq!-$1$+p&3_b;10$%_w zg0BM?!1sdl;Ag=7;CI0}@aNzxcnLTI?zu?Dmj(|7r@*7ZN$>{X1b9nu9J~`a2Hpo8 z1s@8IfKLR6!54r-;H$ww@B*+O{2bT^{ut~9{{r@a-51MvZSbmK3%m)qv6&q2?ZI{M z-ryQ|7PtyN7F+?J4laW)2A9CsfQ#VU!3FRG;5_&la6kBUa1Q(*a2EUxI0ODKI1OGg zBlD30d%;QYn&1R@V{jb24LAm#29APffFt0e!C~;;pdm z_JS9JJ>d7iHuzJp1^x}(!0X?zc``p2&O5aE`nMW5yo0=6t_yBV5uOP4>?Aw|902bF zj)3Ff1o%X727C@UwWH*_3|s`y2ixd>0k{zs{~|a5|ApWj@>jtH@Ymon_-Akp+M}VW?G2k3{eQ+H-5uDmZ^6dn!fcFD8z{i8VyNdrg;5hgS#)IzwM|Knc zN5QF-+|Rs7engJ%yWkx76L22<1Goyl{~XN6=-JKn(Q~P==Mu@+2QFg$tPf7W9s-xa zyMwKxq~3$Ub$kv!8|?W_>`8DSBK@5SF7GOQ5jeG*@YUep))Id=xUiM*3$#xX{upd+ zBm6BmceHTlWf(7b2)H~)?5lyR`^tQ;3%2f-dNu>6YT~~=xN@lQfwaekPXfna&wvv+ z9@l__De=D*?1%pY;2Q3KUjk=Fi2u9bh*$U%a31}COZ#lG7k@dtdEBj;GM?XQpD*iS z=;bm$`A@~aeh=2my5jG>SJ(#*gG1mXI0nvvQ{XZ<2e$5$d_`~oTm{F#)_T(aIMkOo zQ+N|_47>w4v%lE)0H?MSj)6T>gipFk`cIuCd>+n^*lIE#3HV3$6nhd}1gF6Hjm3Te z8TKswVZRw%20sk0f?osI!JmMwO(ehT?^3S^JQ!U4QI1#7DPp(27aj|HVyuj3ea4Rw zo&XM=D*n5I>!%CP1bfdAJ_hUupAL>5CibhrvEzjA1jljy{u`VaC;bn+N$M?66n-A| z0Or2}_N^lJkHBS|4?lw~)NlVo@`X^(NN@za4!Ax|>YD&g?;$*e@p}r-00;LHK7sMz zOTe|g#XcY0hzdUhwx)-(RLvZ12 zd42c_oCi0+nG>a+?klC9B3_S%fJ3++^MO+s{|4Y1I0TN&l6rPw{K3L8a17V)6Tsz- zWIShplL@KkB5-kUv1h@7{e=Gs4ow&S7q|?544m6n>}9YIya=3u|L3&tBmO^;qr#oI z{#L<*!DaAj-~f1Sa0t8!I0Bvwj)8XrC&2rGE!1-;*aJQuT!;TTU>{!p{|-*UegilI zz6+cKKLXB!p9dGgZ-L90|HX{Q@%a**+EeDM0rtQ?;A&Z4)xE?%7@ULuD&Qh`E&78u z1Y3yT3hV<<0msna9^e#s1~>#h25ez`r_zpmbHOq2<=_= z{k@B5zhBOepBaCEuziipR~ekc^&)`dTLg!|Rd57s{Y&Cw;FXathx>~$;0#{>$Fo21 z)?nXWQcslrX}O*p22O)d0jKsB|GD7!xpF?|z{zuj?*T_(e~IznFTnla-fLw%z6T}$ zaIk-_~Rzd-U`0Iq}k!QKnS{uDR__G7*?;0U+?PJ*l8 z{~+GJNb)TK2f%}`lktYrVqYCxzFv4eaACgiL~#Bl;T^&Kw+QbI&fY3~C^&t)@QL8$ zKZVZ)$L|up92{F9JRcmrNBC}V{yyQyz@CEeLU8>-;YHxeBf{T;OmJ;IqJ?%f+4r=fQV?eSa5w5u5?P2Dbho_8K?= z{uNvW51udM31!89EpQGz5o}!{_6Rrzo&_#~PX_z06#t9CDe#TpD)<3#=qmAl37i9e z2)3>k`x0;r?730uFM`(s`>?*Y0H?syz!j{IS>OV$U#Ea$xIdf=F5&(=3-+HP_1pqZ z;{DNs;NnSQe;%AZLHIpz4e?)t3zNjYBHqtMd~!cB99-F5?CXG|rwLC0m%vlN7V4c2 z4xqk6z^St&{#3AiqRit(;OaW^Jp5X434A>`H$>uZ1BZOV_k#oA$G|D@bKnS`H@pST zKQFJJ1$iG@)8hGWKrS39#U2p`i$D4xp!}GuGz)|pYum|tQXM+Ra zlfgmo1>pQ>8SizBA1C!+LtaO?A8hR?$Mb%0JuLhbIP{a`D}y5=#r_UBcdF$36kPqA z@K4|v>;rC*`KW>igFUB-{}^y&ZQ&reJYM>r%6RZ0;5sSts(INaAv*3n$PJr1BVg6HTct8 zWPW!A`+VZRH~B^BcNRGIlJIfh6!f)Dpi$^d=n>Eppeg8i(0@Q*hTa0b8G0M^9_anhBJ_FatI+qLA3?u_E`fHx zAmdyaIvN^)PJnI)U3{7NN5IpeM?zE3%b~YI?}t7GeF^#;^i}9TQP-Q`#nA7d1F)Wk zLzj2_xi4&a_R9v#d9=~XG9LO>Jkma4Iqj2{(;hb3nSZL${sQ{l3+>#W#`Y(0ez1Lq zZMK=<^KUzA=Ij|q`8HmE^Yu4cZ=<#42WyA$Honc)A0JqMy!8jS4c8kV5WfwVW!!MX zF5!WAu-lATQ*TS{{#~ z=g>cc8;9px9`6zJ=pVz4!*7FI)idVVrT+NfbMIxlW4uQ%qCY<<9n*4spZ^*C>zB!R zUmCLP4rG2lS*HW@S-eI3?`WC-w;k!9xLy1gbH}RDjpUy=hyJm=_@`Ge9D(A0=6w3s z9}xfJTh9NkPtrf}kof=F(*LH9m-^#_(dC@}nE!7+r+*6mBbQx1{43wkpC6RB&cDV_ z^ydfZ>$J>2;5Yj7gZ7nM`oGc9iQ{WMD)aMC_p$?I{tsH0{`u#`KihIX-`J7lAx!y+HNPp`i@$YZB-nM$0{`pVE|Mcbf%k^~pNAwSUCH~1# zs5}^I{_uLs`FeO-7tf#Gc+>ycmgAp%IsG$uqxU4bGezd>s5|K&!yBmsS{{#Q3-m9J zk$RqP>A%j~^v~dpL9FHR*#BGl*Z(57nb^8Tx9^}C$oY0@741BKWi8I*YU=O zU$`=Rk^CKd(LaHW5|^|b@4fre-}9N&lV8sIaF#)bHT7cpoBhlBx&AWRi(g4Tzb&4B z$LsO_W*}JVPu$1&`i~NSGvduK@&Bnt|J?85f7@~{NaFwIs@<4>zEOT~teII@{1;wC zf6tb)n}#!5u7~~pN&j3({39*vFTF*7zOlc5+2!DRdRc@1c{~_+k>6M_;-voR>-J#0 z{2=STmg{rqZ2I$qS$@I7NN>q{`1o}Cn|A5{lzFsA@WIhLE!X1)SJOXmpv>ReAv3eE zthW&x*ce~zI`RJ}j!$)42|T6cdf53m#(VHV?uN_m4)Z_lWco+ozgbKFV^Z|bz(3w{ z{BO>qzjc$0XP@Qde_!3X<9^?DvC8RsKsoNCZfV$n`tY6Z z1i=?S`>f7{Go0XzUy4SU^+47Y7cg4LAwA`;aaRaKfxTsZqI?sBB$h z?`@Lpo~5#Ots$gl#HU8twWhj9wg%c=>mHz@2c2kjt>?rJnqhUVKg;>yAggPGInED< zSY3g?IX}#{y2fwr{E)D^HoR2*V0HeYzSz{Y(dsJ0O4-h?Ess!x?4C1iyw$aplhv8t zIny?@x+V$PiZ-&kLP8!z8(Upl3waf7Vs%Xx@+sQX>e@!guV^!?Yg?g!qM+5aolsEG z=2qACLLv7k)o<4hLgDT?+pAi_PW2sQBZ^clI|}WgNYye$D5^-+vXjt$ic~E-3&j+v zT6PgSxO>jFD(9~0X3n@Gm2)?tgd&wQB9v65a!z%qb8O0`P$iuvn08QQ-CZ!_a(6pZ zxreiYJI7{SZnuMb3ii9)LmX_L6rE!WF1Odgy~SE`xmR?LNa<&vC($vWAs)wqUv2{k!`1UDsiPm2UU>PUgdX>J_SU zY_;2cbFac9)^jcjV{6^+z8<(lIvRcCrnaAhw{p z)5*D&P{=(<4QjyF;u&^#s;kq0ZG|H4tDM5Z;u%#}Am^O*9H9&||H+J8yT)NK`3cBA_ zC3T;bYlelo51Ns%y3fA3Nn!Vhkg}b7pBkGw(cPBH)_uWs&79Hhna5b&mt58yPt1L> za_PQdUbB+8dplT(_)VLccAi6%cuLOqpglL2RMC?&G)#kchao0&Z-U;dfXSQ z$c_!xY+8#w?%B?9-cX#M>~Y_|gTjr)TIzAH>tvsBrOMDbw%p_X(utiYSm|*e;qKuM`Ip}d;v9rR6V9IuP3{|+tnN4fj zc8_vm_Y}<7?vjK1I5$J;I%~ThIZEL{f>+z_$DB2C=$q=_&apY$eU!5lE?A3X6?dVct9JrRVusW|+i*}`JnrERsV2VoE*`XGi=R)VUu=8K4D9=T5 zhuGsRPuq4@j=DK~O4aE(MO7FYuc1%DOLe$oG^g(z#Y$bey8mLLPTU zB^@wE$SW7fHRY1%lZ)qCyv%;9E{FsCk~7deYX^*TI_nr4RF%BqOwuehh5_q1Kic-5 z$~5c~)!?%2L)6d1ojj+jA69-;*_A^;$pCxM!*{4Q_j7a9lsqC6WVt7+13BnXp)PeZ zHs~Q|T1Pl%(x88z>->0)^W$Sq$`OaEx&}S7oAaadba>D+PTYu9)uI^moa111KBFQA zz2NjS{8rV_t!7J#7-08qvZ^BYT=m?vcT?v_b?j7aW7SXIiO!I2RP)n2!3h~YMIHRf z>IaGSe5BCddxmoXl{5ZKp7G8Vt@kXsvfAA<<5ut4&cK~lwQ;JR-gBIj&UtCLOO3Pl z+)tb2Q{6h*ZQEH*BYRYUulHt`W9)NYdU|hhA%9;pe}B`Y4(KY!9ecFZd#g*5dRB4z zyUisXdR4ld%HRp9h2rgg#Cc7U7qUlLta=1%b^lu~kG8zB6ouT~$Euf-$K*QgaSvBh z-u?KT=0KdhU#q+WJiU(|!JNJSX3n?Og6l2H!cmvJdsP>`kL}>BWWSpKK<|r{r78on-ZvIcw{wPJ0((NbX(KqUwD`$k$wmy{|e6)r+Po>qPZa=h~{9 z-q)NTN1d$>Q}5=kAJoqy-&eEX?>*MFt2(GMsmCpy)UDK6-Fv)CUMlUrxlWfSxSVT? zI&OUzt1CzEi7w~LqYhl(u=N!tT{|?RbY+(&-ePIuoz&s%-4X}H?sJZA z?^aDuC-Fv3Ka+sYv^uqo@;b{T)U0z=U+-jBeQDlpmgc=py@&7JwrNtUpzl0qR#9bC7m2Gz}uF6YuI^D<>= zH_pYXcc-Q0AL~@MbJNr5X7_0dcX7#~cFOXf|M^7ccTcsF&v-)SKYFgd7AgyGL`oJ05OqXNx zb@d+HJi0@UQV!OT=T!oAAE5j?hJ;leokRYndg!u7ouj6%_b}J$%4?)cU44ALN4Tz0 zAoU%&w7%Q7QhrA@O-_BzW3b+%m(F5yO(b0NRiJaQYXxqM3{X6nLbp`SCUh4Wzf%JLV(mtD)iOZWN)u)PhMmdeT)XDdEm-F+;M^qW! z-mEL6h9uEf=+Rd;O)6S0GFR~;qmupXB)C;gj=%R>mvc)g39i!<u;b1U8LTvZ3}B^Oo8y`73392K(N(A@0%FaJk{Jso}*}nbJwU2 zUiX|?$614C9@ez^+_$RagAZOw-A1XallwV!Asl?T+^MUVP*wlnqlAL)i&j>2v`|RZ zHe3~9+s=LBK-)g_4MihvQs=ZCckYy%uYdMz=UK^!fa=0-zOA!7FRCS2=$Y=^GCMbp zJ^K!DmaMuRY2L5zFZb)V+^-)X_v;?_-&De$1BJZqdsNPz8RF@4ryQCoHotqa8h6h@ zLIL+vY6bKhEEIIlSBIqMP@#}}!mf&D%Y231f89mV;m#eP^SI$SRT%E-qwYP_6TqH? zlo@lcp@!LWjL^aEH=LAngyQagr_58G8^w;XN4UGyt5MHsLJ9XZj_oWdI_bX3p|hP* zoaYPfL)AR@oFkZaxt&{pp0wPos^<&6>X`S;6{~u_;M`dBoG;d#%l(#Pz0etly8m>! zpHb7gF+JnB>#7H}Qn%$z!ieVeJpHf+3WVw2Bs z^=!Bv6U42hF=_a}EQRzCzW?X%{JEIIY9~e5%k@}`P zydya0>YL&46mY+*FYfS8;JmBvXoq)pInNKBCry20&Q!c>vwHPr!`1hTGsh9vW6l1b zbXlX1REK-my`F>`hj-Y6&Xl+>RR0WnNM^@!pWtMCSSH7It52S+VMRIG&dXn1`P#O# zEQUKb`OdhS%gbqX)ip=O`$=UPzM7myw)=av z=!Q4nPLc`pDS93kwFXVMk`2W~@6DX;wtAF&Kx>dLD zty|SyRozux4Rm+W12jW7&D=6JGBtzPARvk;AP9;m&NzZ7h%+b}P>hHZM59Da;(*v{ zj6*a|aZEJEAu%Qzq9!rX#P|E1eQr?=e&7Fl|Mk{;>%Z1xExOJ=d!N1c8SlRP>~k&} zJl$KMZm}>rFWpC=Tx-b+PBkvr(Xi*r({Ybdx}RV^2`Jeqp6oV=~5Cx_J=f z;3XoqmR$M^)Ec`GD@b~vlxvHfi{?oW5@>4dTMWwd;Cj@OUJWh<>7fG6jD3JnmTnO) zb7FsH9fk>Re(VX())4|NigE8DJyM{hv16&(=<7Al6|wJ8vsS^ajGam7U>Z4kLCI0k zaRS0m>AIJqo9s<&<|*uw#8+sY5$S2eE6^7nb!`_;R_r0R#&m(gv3bPJ5Xg_+mNgpLpv$J#sq|Xy*P;5RW94$}_T=ryo%sh;)#Fc35SbE|4 ztmxsG0qJ8Sx&f_NUv|R@5Qr`c#|9C%Odz}vTt(!G6HqGAANtNupL|3YaQFeU&9eY6 zfgFtIN{6_y!&v9@gnJ@(2vs;=G%Abzk*%{@plmG6&RQds-D2e&j28=(i#ePa>z>j& zHpG5Ttu7I$IrciGuNSB#wt~1z1!|3DIdCo$s4ey@YIeCm?XmCSDV4rLpgER3fE{qv zde-e8V7jHRdxdrDO+Buc7O-OPa581}|8#D2w5Y1e+KVvSVtpB!SCzMiMV>AFYYZ;hhqSIdp5 zTBeXqW7T!(8BDA}o!XM8(jL@~+T<1DsI_7rqCoO$G5;{yu^1&cM)ded#AXq?MsV5K zGU%7wB#oJiJrB0Y>jbKcVL#VOnvv8XCgoN!KAU5Aq1wrt1!{?{!<48@S1V;-34$JUQv;$6ZPmXBWwNy)W$y@3fCM!dgD=|)s3-HNUIuj} zhD7#lpgsYrXKb*BMl$^uVtyTJL)xkjq4%@D16iahAp2d2WLEvh=$Y&vfa;q^{XwI8 z{t!B6KMt`6tol)C|LkWVJ1kH3SpnH!3>mjL)f?CqJqcvGf`FtJPoZf-x1jEq1}H#+ zsz=>JHvn~89(9AD8q}8%uZ{!9Hv=3X7VF9P3bn+hBe-W88EUD`F<|u?N5m&!S8Z9n z*~sb>7Qnp)>J!!mai{9fx>|h|y;^F#78Y!K|K1!(4V~qxM%9D8I7X?xCU|vs8FeGo7Uv-@tejf7g zBmpNyK=4Aq>sB>l|Gbf_IWX~WhnAUMNfTbtNDh*73MdokiV=3s&P&)GP&oO zU-g-N6mTQ<&mXw}#QM*e6^8Ut48So#IRfwz2SSvF8`Y6mfz&s)+F;6jX?|(`sVTLV zHTFT+qM&F)gV7&5_9Uf&|5kCiuhWfXzaVv)Lcs@PUw>Ecg&IUZ; zULzrNru7Xff*BGzkMqku|D_^p!Xx{zT_C*x`(}|f@hyWLREP?l=2~rm-s)x46Q%4g z&|7HaJ=CUaSXm}!X0rL+3RTo@u#x(84YPhNSPG?nUBj&3#efew$x@YJ_Ss8-29Gr5 z**|&ZP?bSyhHB>2IDyq28&<(_svua0Q{!KdHx#Qk3C!Gv_Xhxt9t_J#Z}i2leyvfS z9UM@b^cshHFI~X1gJWuweo%zm9(;6zHdwhP*W!6laTNCml$v}Zekzt3;8xVQ;(PQH z0&^M3ZZg34F`FyCZ-Dnv%Zi%~FdEbq+XP6{nZCWwvZh#*xrA2i_#Oc8>W>;%>=Yoq z1g{%U3(+%BJGE)I5Y2^*(%bn)i4sYyf2DT_F!dxfeA-vEtAOgj<1tg~p%WE0XK3I| zy#-yE3@JTz)ueaW7|nWCdv?1yvp1dwG#P0)?%p8+nAf_}t5jJa!6`bh$+yX9a!kK-%=yJCKB}0dF2MoCO$_YFKfVDf?hhW!hj74dg;6_25e5yOXqbpU`v8t zIwo01D>9sm(J^}Ch7{VOwdc`H7lC`^o%6vrStZA=@RtPc>~nR;7u=Gf?hgr zh+3uL^(sLxoi`fGI`JD+f?hhWO?7B~n^l5dI&YGJx2XiZblzkG?@$SP>AWch-lY=s z(s@(WN4orjDnT!uH%)6#FI|FOI(Wc-bx3a~Ft+-lfaA_VE5tYxSg({GjmYKr(76cGm)uee(rDG)0A0RNMysDd z84gnYLK)4G(9R-w!Y_UT$C4g zfNv4Nt^r=1i}}$_+aR-`U=6wS)e3Gf9Cj6OnvZ_(^3wsNVav6GQ{`CzsP5SSs!p_2 z6ZO&nH=k8M;_jo!fRSRfOCfwG<*sMn2e zJ3(Vw-Cs1cuYuO8R^@nD;nnOtlUvk#39^NYN)>_k-wfsh(EnTW2D_jUt*$`4y);G);EF8O*bNoF{O5b8Pp1$h5WNjejnt&Ao=bEmYb_{ z;bKwKL#Kh}F+(#6G=J4Jvs9aI!r&?ZEB8qOpArZp|I_eSbEx~K01M3i63{vmSeetM zbxf-SHo|hWqIw%Vb?d-!3R41_NDa?q4Ic!UYcR!F!^@2ZXCi-w$v+PH+{U72XHqkC zOYW2cX^0Tfwv6A-br2pIX52il`W46X~8t^(4SrhMmijcGa?X-`bkKO>1}k=MyI^*WiRo|vZp z(3JmE)AWy2OJd_-b?&~K5<8iuUT4$PhiOV(Vq%(J!sI^FG`7z)jV-`jh&)ZxGKyQzrS;cidW}N*s_F)09P`FimMtc-zO&G;I)K?>kM? zfj}0Rris8b9gfkI>};AQjcIxgq`@>z8q-w3MADe10%nt+Lu;4}0_Kv&G!?KRX-rcA zo0G;g6|f~~Oj7|{lg2a^uq|m!QvutPmr_v92%3{Lrs>(74Yl)=#x$i_6{=mD>};AQ zJDa9SW17noUF}+!rYSK^U1OTENjx!4rFAS%OjBtb*W2GT z<=}SQlQ2T!oC&N~sUD5U<@nIKcLlkn7^KlETAki^nx-Ty3#%?E4E^-4G3~KMf~8EQ z&)^b}J`!m={SN+y(?3K`Bz-s1PI@BJMd@KkyXl@tdzRfBKdSx(@XHKjvQ5!)R_$P1 zuI-05$|zrP`l-MXm1RVYn#?3(tj+{4)ue*;^HKABq!qdf<+{N8*UWd|o^U`|UDZ00 z4^th6>!9jmK2BxDCbke@r5EnH5&pEJz-twTFhW8 zFV`aG8`kF*h-ky}QyOY{frx;zgCb5Y6k*r!9bMOAULfK%ia1S+SZ!F}SRmrAyol2Z zL|)!Zx+|HV`qIwOFe~yk}T{T_A#c z*HVkM1tJ1UI+N8Ug(8Y-Rs|9{+(zx}P@foUAoR7@Yf$w3})426_91lRL zdK$O>P66V_f@q5niE(?C5Yf1e-OiO1C1~8n?l6EDw=ZZi$L0FiQ`JG4ct)uPYH3-! z6IcPQ@1b3djdv&<2(|HQBp6Yzi2u)Bp4|5t_`buotBc})Iq7}d5B71Tef8ldH86paNjsoU=jsoU=jsoU= zjsoU=jsoU=jsoU=jsoU=jsoU=jsoU=jsoU=jweC?&_18z=^FeW`W)#bgkkqT^*Npc z-i1EL%QU>t=SVy8|4E-?VA%avKF1AO{yv{$VA!!qjA19O6Bu^VI0qVbLs7tSxs+)W zj`d3E(TH4*51qR$$Q8qmF2e6N>_}*QjhH)d(*|fYk$fZNJD19JXvp;#psl)-jN2oQOFnj*`qwb& zjt4%W>R1=APb;$PnIs=wvd0h&xhVM!$Q`!`uw6%{J(-Np!5{uFXJ>wEgM#H9cZB}S z{=hB}{$_7tnPR2X^}tkUuV%4gwYw~Z8?#uknAJ5w&HkYQ^%8QrX~KVyu99^BBv~cm zLnLu5vi`+}x2m+KMvc@>8a%@W89xP|@7-Z*Rcme|$xY45>1G?rX1gVBS=|Ry!O`sS z&j5nqubCl!$5zAWngWJbhHLH5_K47L*_Z*?+y7(?r?C0k9Jn&bC;VECQ%P(hn z8WHuHg9a5WfgTSS`iIPK&&SF0WG)XqN920G?ZipbT`ZgLR3=B;@*6DTKWbFa6pJ@6Rcqs;& z$!K|9I=8<2AeMLmqEALGtIyXAsEL{`TE0Qxm%xdZ8XOO^wq}{7-Xv}#0jm5KRsIbi ztMOv8S%+DHB}B&hI?C%gko8{AQavq_T&j};n7m9Ur;^}uoxG2^S1_rk$d%;YQ_tS3 z^lUl#MEJ(9*2$9=WB))Wt;TW|TM5%KFM1_KchgP2lI*M|?P64ErJ7CSJlbCx>04;8 z4uUD$Pj_cp&*bUg*sNz&TCqc)1l&(AN8*MY44wPyX;!XVemP++F00{N3F|Jd(C}w~ z2e84q$bxX#K&~AtjVczFN!6f6;*D`oE7F7S1XBMQavxH4S;Sm$Lt_gPL!UxIwYMxW z>R*G=*cAmihNE9qV_bN4=|{_0XE=h-E}#O1YSsAe0UnVb93Fd(9&-$}s!=s)kYU#X z_aS8V*q>m?_krnx@XjH0MJ;CHF(hte;yEO~W`a8@ry{31~660;pm1B>w}14V9g1WJj%>u9K6mQ{QKrrDr*FRMgmul1)bL*c>zd8gHEFK{TF>O8 zG`t1yNIvuCDL(XGB>HkrV}bkBai)VUOB|9j4S`^P)Hn(iHfiHY02qfKP*4&$Lg&a1}t*zTVblQ%KXx9U{rc*kf8=a5eUQkym{DYe!)ZAvc{_a zus?1Veya_is|)zuNq#}bK7Or*{DP;rWsOsZbM)MSh)~1hngU*9)d!Szm(tT>o52Kc z?$rKYkTzbo_g%V%=-3Iey~dY4cp&(0mqH6pv?jEpd1E_@04Oynw)#SFn{$~CfR;56_>jdjCB}a-4ofcm7r`B}_2zEaLosUL1IS-~73x14#lPe7 ztI(i1L=;?p6&iX1aymyz!JL3QWZ&gip@~;9r{MCdP}?@0qc6YG7f*#2UW6PIJ9QnC zym%_K=ols$a1mO33X&1Gv!BI8Qhf%L?h>{<`{}6sP@qq;(@Y(}PCjwwp6!gjNB;SG*@B(&HA;#pk2ZRH65& z=(TMSRm>emx0K_^54+WGfi$MC?}!y#-{IEaPFK0U!>ywR+Gpj~{|ia+S$VIFhA8c` z^4|X&lI&4#MtUDU!wR8Cxf$twBv4FmMtYypXyS{YzP`il!A2rp5Wvh9Q zZD5i z5GK(e(2cQ9Wq)A{GLFs}#v&z408c?e%DVba3}+3;k@W6GLGSV~x^uA%FgMEc+G|;H zw4jIHwVZXgq6}xqz4&!5!Ns6}au7@Ij>|4e>pL-=I~0)_&Oql*W%y?_{~a2I9xLbR zZD*$vripUO`+*XHS+Ls)4sI)kem49lr>4y3J%O@}!45wrBi@w>)*(Vq%Qdc0Ieiu67 zXrB5AfK>7Hd=+^^g>#0I`RitQLxppunt{?#CBqvkoU_y%4Q4aEp~6|I-bERgYI5qZY?O#MjHJZ|Q4Okih}rX*wDP~nU=AS+4TvRD=^r&a4&k#i1Km*n}5 z&GY3A70x(~LY*@-7@hIz3jC1o$*j%<^*s${tuE}HE*nYX4#wXucS1t;VYb>t#e;7U zGf91hgs49`FNVPZ&Xm0Rr%|)1nv!A|gybBeq~WRlYO2p0Dx7I*2l-~58EPn$$?%2> z=P;edkk9aj3TI}X??qTIommE?186G>XL&<~bA+-`zN_3&;mlK;$W0H>qw`wwh6?8x zjbdZ)h6-oCQ7e(*4HeD;#j|Lb1YkZ1sgjZS^8@_v#^s^J%KnyBTd0Vu3_FW-@5b~E z6)}B7MT}A8p_sm*A|^LfWO+k{bAtK_%A^&lo^wuAgD^-$zvX%TcteGAl15QK-caG3 zoNq-vCRV6nGP$`PI<0T0a5k$q@};+QE`5VWp|ni-8-pniW*f+0Cz`Cm`M%e zpYAW@&E2#?c$CIpGy}sCc813rD*R<)J~VsO-#gaEvTNN3`pu~r$Gc>$jWf+4JAFcGYWr#t^Fa{;w zrnIe!OAIoML5WW?@HUlMKzOo&cc=_wP~uYzyh~*mgA$*r?qQc91|`E7l=w8QJ;S3j zj6sRFt8=w{Y*kb<1||N0Y*oY`W|QcxiufbaIIgd&^_JWcCgBe<-`)3p93+K!wIJWcCgCs3Wo z)3p9(ff{7^Z9=%xpHi259-a}ATAEEWPGnrF4JTFzL3SOyxT=44I z0e!mng?~zwvgK4yfb%s-%rJm80lE4BifXOq5Ky=3TKE1>Uzaak8+CLhsD#kRN#9%T zHFSR~px+AmdKglwcO^RNG*&S{t1c*Qsz|BNQp*7<_>g$Syo>UU{QZE-0CKsTTmrOe z>dfWefp{?+F7G9DrZUu@5R)G2kGmA3^kiA zpo4EqmeFihs)QEd3J{s#+maoN0hr+1lAQvSjKxg3PKf9oh;6z|i0BdVwn)HBtnR4*OskV2>fo3r<~C;(QANmrqC;{?FY;Nm~4 zlr^pilgoM!ni>bgO~BB>Km&aLe>{`i`Q^RPs^Gu zxI*Y>_;C)(0_*6zuyHvX@(XUTEP9PP>mXaNlvQ-YUiG=;reA@*f>&U#<~Zc*_g=4l zBa*%j!i~PdgIN07%IN$5(F>qlTN(ZEMexG|T3=fk{YW6WwlexDLeBN-uJ5X}Z(=(I z@4XA4w0{Yeu^&J!{q;H-!a(z{)Xo|nAoH)1<~MJ{x?U2cYpyI-?XDo zvs{vI+R^7oAaB~y=P4)t72qt|FQsc$;ua6?2T0#OSv-VER0z5aMk>0Fea1KK;$bXO zk|^GD0)AuL#~|ymVMwy}e5)+(pdj>@yj2!IJ|0MIl9jAoNey_#RHFao_*<&2vt)^y z16|8#oh1{BQwF@sXq_d~sw*@Fvocy|$&3LLWwg$c0%V?b?s|?syM(ZqDZNT=jODQO4z&T~K&XP6idi;cH z=anz#B)M!Q78`QbC0Z%WZb(ZX_{sVakBq^hHmTXqqcL?jOjMiDQ zzrsr(tfMumjMiClfZ7h;w9d+Coh64To(ZxMAzVi5EIC?vV8cL?GFoTJHpSt_E2he5 zoh2t3c$+Gtb(WlL;2o-r)>(3jfp@7gT4%|rsvYXlIxC}fmYk-wr*&3F>nz!>9@O$- zouz4=B_HrtK!I%XVK#}rVk-HFw2oXcmE0|jBUel%jUR*7*)b^KxEvO+AuWB@$xJsq zHGtE(&mf_5OD$htF_r2z7OkqUm`YVL$zjMVrczaNb;HUPQ>l7^va zZ1tk3e$8RI0B)a>Z1tQ6RZuD%B*ATrrjEcdph&u9!+Sx1djg zE2dKY1!~n-Or-`&Ik{pgHAo=2Vk$LQxX2Y#si6YN6;r7e;UZT|rG^Pku9!-V5J;|= zN{tjqu9!-V=BgX2l`E!Ft%8#)rcwuUBJ)il#w(^$;{;r<&`qn+P5O$d)D(7!udkR& zO&fqQsP7L-wF@V?Vk$LVAh}{HHA5h|Vk&i*K(P$2m`cqQK(3fd%@Rnim`cqSNUoSl z9WIbuF_oGlkX$j9Izk}1Vk&i{Kn)pQF_oGtkX$j9I!d7C46m3<%@atjm`WWjkhx+i zb<9kRE?-|Um0E}|jmQ;KsblBr29ztNQYXmjC09(PmI;KFkXKBlP8^9+K0R>rQzygY zEmusXRsBC=@7YMDs`UVBIf#iy*)H+#2 z<%+4)B?8G6Q>pa=$rV$nO9hfErc##)Bv(wOE*D6ym`YtCkhx+ib=4}?OUwDbxne5yJ<(XMm`ZIH$kiRcMF6>CDs_WEa>Z2YMuFstsnk}1%oS6qo9058 zudkR&ZTmL`^NOj|Ez*o~#Z+p0z9VQEr*8cf%jhenQuiJLa(%^AYFAK(S4^dTBy!}6 zsnmS}$rV$n`{fa5u9!;w*aZ(?Uon+>^+NLF6;r8SNg26fD)pMIP8bZlVk-6e9MF}^ z6;r9tld$LX6;r7%=}zM!#w(^$e`Affoa-y5Qh%qi`75SU|KNP%;v8FuL74iAqcVTR zRO+7`Vwk>i#Z>BF>=iq>Vk-4D^#s zxk_N%a9RHw@#}5sVp*$0-XCGqtPXo!`Qv)uht0J*;VmXE=gnhghvgk!f#222yE4n) zkT(MP%DW3hA@5n>!rpk~xK>3mimQborJjI4-r}+_L<1G)D0-k!2nIeE zJ^Ovq4waly#CLlF-0WQl1HupO&q{paW*2F#inGY`1V}gseJm1A2x$p*RO*BfM@pB^ zpc>MYR(1WQNS_#DUsf+TbqV%3HBIhWR7SmQcdvSz1y^Z;8g9W><9x{dHicW=s}WuJ zs!g8wS9>}s--+mFsA3d;mo*!74(C#rJE_{c5muqgE2xfoKSG-7<1F=IgoCGh)qG}u z8sQguwAF}A{aE}hGW26{l~s2#Y3^`T@D0r~%==+g1M=y6sMl}zcR184+6%CLy}!dD zZZ_Z^IJB}uW1j)k^C(mPZ+-AKx7+}VkVF*Bq$aFD@7=7xHI6opRvW@6&F`PVO8pfQ z`sg;i#$kz;-iX9_fTcER_+r3~*P9YvU(5O_3P1`YHX3g=`8CLYUFRdVXHu}?-}EDc z9t|{$8I-Y>J+w>Y};FB!5CLzb`&trs9tU5TkCt+GYe`yo_LT4jrFl?ZsURc_SS z>45s~B+soHdj{afzZ$+r0ayigRN(@=vd&a3z0`Eio*pRLv%*L|0(G$J{>_p0ctizX zI1Rq6wg-IFzrm;nd;w2JnEE@idY(G8m1@PQCq>O)#!8FP-&5QjgUML#%KMlCn1%>-V4@+Ccr!n40tZ!3jz08empM9 zNjYTlfrc58EAaS!(EM0Sm0^>_vhE~wnx)d3*9U}_TPoxH1|{b-13GiTi8$)7IXwWl zAE*CHqu1r;S9N#Z$Ku`m8gOrbs3|~nNcE)0d9u85iz&h(#6Srd4_4z*riyGY-jR)b z&;H7MY~DlyH3jWZ&}wy?Ij8PcYK39&y!rhXq^S$RNk;YEdgvdCc5ZsqP`sm+!vHuc z=oYJP5BvNlO1)%g*0o5>??yqz-I6|NtDh*g`;Gx)B6yy9^D?e-;1aI`abJNZ$n)d0xGs_`Dj3=6pd9imEcw z{8EnrYY?B!dyVw!VbUXKp>pc!QcRwmz}^d}`Nv3njKpBl|HIHHV9MhmtEsvVwX7kn z$QVk}7PekMwt{4fLq7t;gPuly)ZXxiWm?^vn;!wJi*5tau$KWH2}Vt6qX}moYKnU& zObOJtn?2tEc8f`%3EWV1|n&h>GCAkw!(C=6>2*; zN^et&&u_b585(W@VNR}r2v3t#_o~M;AiG1q?N;fyXh}oP8n*6wN2xXzMys#atC%&2 zmPO9gYs*+^>AO)`^@r|gU_WMA|AEcXT#m%fgOK2*Tt^N=tMo%6G8~EFNc0|oc+ZJQ z{C&8vXkkZBA}Ze-5AN%YuK7;LcgqDbe$$l`W3F0VWX$mT1M zKWZ$h)Qrqwy8tZ!)O;HfcQLUUi8qkw$6;}^VQ{zkRlkog)Veu}uKb$R782w(YJbX+ zX<$Zn#~-Wfx zY7K|pfwteXe?@Ki#OpZ@BA>pKMw5arr3(0_>Fd7IKrDp0(Ux!H!d&; zYM2E^PsIL4ORH&_K^OFreh~k4r1Zj9=2u-DUPiuD>sG22AP!WErg?x(juJK~zLCYh z0B$deTO;P9CvD8;(F@Rbs$B~`$53Awl)B%3FA!Qf9zp}e0YY0TG{9c9uecU?28x>2 zE*>rVq|L8tv=4?7x>}nlAwV1;K@Y8OO|h66=<4SozTW7e^%08ep>^E^46Xes3x}3w zRc2Up4_N&o^k%^7pWvWbT{sb}_NP36RWHM0NWki)P%Rcft<|&Opjq{51FQWh4`4OQ zu$U6CdM$KP!0Hrm(5!Zn)&7*7SkaU_#LWMh=2u-E{vla$1ic0hO#$M-re+oH_>B zr}h;;i^ZwqZ>eL?Q_VuHE%!?ez^QmE==4d-v9D4wl9~EFP zJOKMf0ruttuwN8t@Zy0Q^hZ-f6W^MDtE@)PEX1tOrw4FbZm?{URF$r+XD{AwCS6p( zqFIRcJ)0YUP=K9w0QP4E*b@)HzGtv(&hH!SzUIXE$n961o^#A{`!;Ni#$yb?NAeR= z9FP0PlT9`&^#{rJ>}U2HxSI?S+a*%He?RXsSSmKuVEJZn77U_V5s%nJD7vu-fHsB^2;xVb>$`2hu{@l4gZRviU&xBoYEZx`tEVxE3zv#$A9kNnFB-a+y&gpHew zTuzI(qy}(q^$cFZ=+46_rzC6yb&T3(h-=2ni1{(3s~$C$b?}#Qq!w%iv6_Mh^iD(Q zz?X&dK7CmHLHJQkx%16$9cb0XC@&tu2el8d1DSo_gVClQ)}GARR8(<-DZ$`pHnO-R z-F_BM|J;OUm3rM#s}0Tf%`c;Oo&@vp+DZGm!?c<;Ub|>tcb+B0yDCqCijGT1)yw!@5P!BaMaCa zRou&#Ss%f5^q{R-hCkKE;HCP82z}nw$Kb76l2*+n0dCtqoFw5IXPGYgv;K>QHvsOd_X-3qn}PQUx&kIn z5G|LPUlk7Rs>591YyS!mX-B{&Cg>XYDH5ahFQPpIzX4_<9Refi9>D9-h9b*)wjNUN z=J<+*=t8p&Gg3DgY4-(E%R)UstECPBk(N4_2}->HiBbC((Nb>(rckPO_&jNtz61?a zBD9r^Ime$SKhE(lkQjoE8}Th-1S2+bU`wSy-0H(|% z5T{p$$Ai_UXQ29p2{b_q-|$~H1$bAest$#FKr_DGFM}@n4dvHJ44DsXr?(Ooea{sA z)cmSGp+ke>b7z_2w;?fVf64<`^_eJ@ZZW^AK6FFC%AIXkEka_{{*(u>8ev#W3RpFS zJ_=ZU7_e$R9IW=I?8J&Aa*tv0X25EA=-{4Eh9j~A9Q4@u7ZV&CW9NY9{zdfII3Ji! zV}pyzZw*t1wX4?9w_w~hz)aMG%>tIo&@wTp0PcVbd7&9c#gThf<}*;ZD!nAJ%jZ_KNlLmGOG$7 z0p$&{GOq%Y-ewrkSw2eg!{@1ib$A|OQzaOJjlrDd5S(p_pN8U#OmTV%&o#w4xKUgj z>1u%0cy|HOZTk_O54ER9Ha@UwQ`l+@x{Taj`0ogVZlGuWLm{Mvc)Xc~FQSs)=ZqV4{mDy^k8A4C{OX$giu_mo zi1`4S@`(AXe#CS;63fE3ri=K9+3)d!r(rW!{I4CAFnpWLFQ0}lgS|WrzwY!j{5p6V zj#V#aQ9M+nnoY6!=64n(t59#$XM)M$MyWN);p5;VxO68?W@=oKQe)L9CfkctQ26Jj z$Sq`YEts^B)A1(vJr}vNi;f}la|@Zb@T1B>PQnA#;YDjnwY`w4XTXQGv*LU(-3lVT zhdbJud?|JLm_j{!{`jle)YcU4EvJ_;8V|>N8GQE=@KdcR?Lek?JOx0hDLmer-YG!* z3=sWIh#0_Ivgs2ck^o)?Vxa_&_a^QT;1GV9L3L*|0zRM6VXihim|In^~>5TNJl@b$(EC8l;zZk&^WENXf$DZ$N0` zFA@X51?$kUMPNQn-G>*s>~N)M)M{@1tr==s1ze+ONky-d<^}D(LBoe`*TD~p`-__T zP__e*qfnweD++KEP}j9U|HITx(7$ZDiZ`Otj$4W!$F0EM=rLe0Q=JTS+&UY7rHb5; z+gHUy?*tK=?p@Ymg_3G;Gfr1SG`W@r$~4sqlI$F%xKmJon58yC#fqPVVB$f>EcGW; zr{bYJ_&g+6><+0f1Y1h*F$1=%`_R6LIOZ!FP4OLBIO~3!t#*S|IfBNgtIt6fdQe>l zO%x6KeQhMIc$oSlwCGZ%x4Vo)uR9lOLY}aNG`J<)He(NEYey z=k|1760E;lVb8cS49U30|I#U-Je&vw?z-RL*Ipt}!sYpMd-)w$dT{p3<@s~_{JCI< z<1X$aSS;)d1gdd){@h+gMR5MyEyZZCS2G%l=fZIQ+`e$L2AW+C6nl*j4sv<^+`dSl z7MJJG?TfFCvRJFf^XK;3EgEWb%UglFgcqRW{JCqP$?Yqy(LCpP3s14^YxwzsQ0;t| z=g;l!Y%`occX|HYzE=eB{Q0-Yw;4tsKJ3RxMsXB<6i9r16y4WH(fwwY^*@GS+wXJ~ zy`0QWf!8XM?PQn3#qbp8Ew-#a|IL zVgGma1i`@%Bgekyrl}}R?p@GHF55ZdK5Vt0WeEVG#b?aDR za|nJma^+(&-YYjEtv?pyy+7RyD>(%JI-AmbEXMmtAo*B~_vulZGJgo3Jrf)TVAy~3 zO3n>)2wtX%3H#UelCb|o2WWl|>B%SY2NiF{PaKEflVGktCgVLSQsrYZ-X4ME5Il7? zhv5H=a^?^`S(-!ezhF`h!Lyt>1W$tC5Ip51z687s2~h%{8z0QmW%^?>&JZTiVbExLf|pV5dioGND~?lXE(Q}0!GDV~ zoThRJewv=NIfx~9$7L6l1&82?Om829{5zH5pEif!rJS2Fhv0>2A|r?3MIetDN5G*- zAA+|Z<@z9t%AP=39)hieaX>$mk z1?7A;bt}gjWZ@7z(^(#Z{~*s77QF6CD{T(J6NOonHizIp)?gxS4#9KLBHs#%ulN*@ zWI)U$H5qLn>QBy#F^Av-_3?tlL-3@e`sNUP2XaOI->}WiA^0$e zvOENTE%};5@JwUKr|Ynm;1GPk*BpWukgL>JP^#P8;C+1v z-q(lVeTEd-z8r!tUx&32hu~8nEej68^F3PhTb|d?9D*l``k6!UK`ZJpu|i$1vDB|! zt2O~}xj6*SwBvFVJ1&)$6WnFNA^6`TOJr`!%QT1JiGoa&co?a2a|oX4vfvQ>Ks+m@ z^p?)0Z%{;`v`qOMm6`Hj_GdEKi6-MAcs^`}!Ofi+Y||)K*&Kp54ASNhyjhph<`BGe ze-7;V@o9Ys-tNM+A?4cr{(&rg2;OccojwF__a}!+tU&evu1@+8ygiWm=tJ=KAeQ3C zRqVkW^7;_GJ*)#s2>A+i(1+md)>}bVWDdd8$nfM4yy%BJIANLia|CkT=TO?8>tT>_ znUX{Bv=lG}JUIkkqH#G_4#D4}p$1nD!HW&k?8+f{fm&SNA?BZK>>KFDKy=5YL0}HS zvl+^QL-1$e;hQ#x;Au*7MwvtK&*}BjO`AjT0w&VG#gM`wcmcEN&rt}6;04U3%^`RJ z8`3;xg+uTHHm7T$3l6~x*plWkD;$Csur+-n+6IT<1#C;3L+}E&r!S?ToWagXn?vwF zhW?@2`Dt?q{t*o>O`AjTQlk}V9<#zBcmYpOcc8m)2>yq=>7yK8&?&Q@_*YH>GRPr#!DU@J z1W((MZv}D)UZ6Tx4#5l5Aj5yFOq6C<4#5l5;>sa-fm)$n8Y-DX@Jv=Ofq{zy;c72{ z+<650vXydu>X2;Y#Oz+f7X~$oQFu)hVicR!Q65brI0CK_M`fG0uL7aLI`+ z>>V(>4}jGt5b<+BQK*k{`1s}}SFIQL018NOn_dv`$R!E-cx|q!siDiLEyMtDVq4*Y?WhU@6)Ym5Hq{8$@l5l zw4RwYYTyD_KU%TB!t$#=n45vwTCkWXFd9lpEu?%;aS$tZ=O8_V2dZAoKVKPL+0r}pD@K%0YA2_lAU>SeOYbZs3Nr&m^x7wG0Cp1ojFdX)Q3c2AMFarwD-2cDpFNq{V zv-zIpEVV+jZ$$!+Oy|UW8ZQmqQQgpNS_zR{Xif;@g0yp3$k3WJUQ0j4lPNTZOMj#_ zbYzpEJ(7hCtx4xBdj;AubR;9a%~gXNQS5)|v$5x4+=k9yfnr7c06c&TXad;hpie{e z#98`|fY615nB*M+p*7zJwX4td7x;JV!>HBfhc)i!`0MG9-+JnKozsE8QCuSsdu1F_ zk*wXl1P$T80Wo$Bvrr-bU+6o#_FfIS{$fh369|owLj~>n-vAkN?Y>8#bo?yKZe-c` z0?Te%%*3&l-S1Q;j9&G-fY_=c?RA&bw+>7 z9!0Kf*;8i>u*cB?=MK!YrMj6hjHgDv}DfpUO`SoTGbQB=yGF71Y zfS}7E0xfb*9S5G%a26LlmjVLMLj_s^2t3;bS_ud|rxT*R0}xDS2)LdgxE?0p2IV_! z%9$LzJTvac2+k64hw@Vd^?cx=LqALKaKS#K{3?Qau-mn7D!-245rX|#`EO&W*?M@} zwO=X!J%V#N@*ybXb78iR67a#0Pv40>Prx@r{^tab7VxW({}n-e2OfWGH{1T{6f~c+ z30m3yIRqC7_?7LiCb-aG!~QC)WcINJ8}`={Tx75je{BN-w+b0P4rsH2u&da*u^%O@i9sdqIGVBu@ zupZd8A3HujS7h`7?nFH*vaf794vlZUS3~H)yV15L$!UIpzxU7FH zTqxl|g3I~6TL2A~Io;r&hI)mEvQ0v@&Hj9p2oDoni*J+XD1lo2VpJ+TMkw2S8w*o- zoIvgVjZ~~nDCc1D;hZhe9_7e%wu--f3|5sHKgE-g3kf~Sk;93g>hvf_mI##a=~0d> ze+g>gMari~ITCo3eR`B5fk)Y=M>!IBl<|EEZM#p8a^#98&2x?ek8ufrbLXk%i0E}}7<;eZa-Pf5I>yKWOm zO7@^kYtbAI691gBSpARW&?9-TLjfHnkn8jHzGyMY(Cy9{R?)KITKTNAWbsK>(el@@ z;S8(W-#ZL+C&NYs)Zlku^cJlUsJA~8gSY4uf%@uJEjmr0Car4G8GPihAeq7|AOK^&Sdm#v;I695p zkL94q-!c_oyMU`*KZO2^&P-|Sde`s9vaLAfX-ZfiVN^HXgR`x0m!M?dE+-IvD501ErO!zgLdqGUyQhfx5b33-Q6;<(en!@d^gd}`h&NM_a7 z_*=n=R>2e$qu>lH#cvpN(Hgk!5GWFHi+2x4p3h5h3`YEbPN>KJ1gEW7RijqD5S$g%9eZtu)$lyMO{{*i-J{%tE_ji ztoE)0Kclyn73Y(-H}vt=aUtO2iaRUbB`Y1sgi#PM!5HiKsh}tyjRH(k1D98ZP;EA zb2-5?;v$C(%tl4j(3`R2Y@u{>G?+GUXFK$lE=4O$-Nx!OvUvM{Z`4n9Pcc} z)es$5$-NwJrFtDY<8f(q(|bAIaMcs*p)ekiXFLVn>5ViU;#OWxaFnJbWA5d6qYcPr zrEb-D6j)xX)-#v$4py{Vh40urU+(32<1`AbT*q2jeN7-4Al?qRLQ*@?=YRlB&+0JjyE&UmwP$hECVLMXcG!ob1%m`LVbmF zjqK%k^VAjOrl-Wwc`dn@;~k?>Yz*$@c=L@~iAq{_-U9t)0`wl3j{%F!VEoyR|9VL* zv8sQ|sx4H+)rP%Ax_6U$FDI$@a*}#4C#m;xlCqamy$;p&PEhxtOgFuk(C^Qvur!dgZ2@&R zy_e%%tJdUYZpzEl%fxjW#c2p$Tm*ZWpnC_VU?-Za!TY|VnJZPkxif=p8pSGeFUPwjU{J}u9B;b;vz6S-@oqKUp9A~Xz+Ug= zMD$)x%#HNB7DBpmHbt5_n!9o@B+{SDUL0#)WB`}Su75xaMFvuzuDA9_au7?!v6mAW z%pu>EawGbc1wuAa2ro2_wDQ1ziQda8okjEB;i_6XTNYKz=Uz_f9D!W_IaIrJ?p5V_ zs`=c@DP2HImNq2!a!MDj*SMU|y`0iTjhN3gq`8++}Uyogv)ULZ6V^!aWnC@Q-WxMH(x=e}M zi=j}-jk-+2>|m9Z!*xlxzN7%)-Ejk-*^0kf5#LtZ9pz+5Fa>M|7uY^dZ$ zU8aixn=83dm+5N2mdYHKo=i6bwpMbZE>mT|wn}c)WvUI>UU?}64Fhj()Kzk$E;B?;*6?~&$&I?qXmt>RatWp;C&l)m0z=s+f}=k|1)LP zaicEtK#9H&G4n8+#OD{&Gml8?SU$g)p4lyp83uY3>^pDt}DGxpgN!1b)}mH zYLFFftE`31KDX;iZx*P<=XPD`Hi259-X^GO|7{F1S8yTJJ9nkqnd`cvpswo<)PFfq z>(vsxeDIo-^~meNn^E}k(PII2?_S^=NY9nTzsR{`HK?uxJjB#aSppc*UgkG55BdK9 zhhE^|DY96ItX^c}>35oY0QP>}kbhE*D^x(;M_*Ahs}Bwq@_UJW19mE&1M@~TjN_mpWeqsCTU)t_Q2bKnq!(ecxBhz!?8}4>oA3 za*CjF$_$#|$br=_kfg@tSaOycMs*&gI_uQ@fb$`u&btt&9>%*K)mcY%Mjd0+Sx0qF z2h@8@PzVg)57hZ-UY)xN)Um({+U`@Q_ilrwHsu;ije5UTz_VQndG^PKC#vGvzsmzN zJp1{)v@cD;#o%|2@WW~6e@fdxwCc}>aHnEl&eV||(i}0s1_1qY1|Sc#kY_)VmnG#@ zEB4{$qL-Tu@qx3IIU=4qzzjnJ=omI3Ys(ECCIaAYh8)BQ%qwFb?Rak-!|CfFe7 zL0F)ZVrgCSuyand3Qh!eGuezdRgsm0>r5?7jgzy?#t!GYwvZ8&v{YT%+EpjiBYN<3Xb%B=K$#0g*8B8zpODzWh#bsp{*?kFiTFY6~ zvT-rA3~0YY%Q5H~oV#o`+@3PO$Dx?I*sz^Tw)Z1Pw49gM@=-%wpd}9_Aco^5g9-MW zspZ>--6FF4GuUY@7g5W4SRtbW+5@y~{R^5)<@T}xJbUHDtMx>3-QS{Q>pR4CH@FoB z*ZMQ&)|lL-CU*=&53Dy^qpaeq?(svl(V@OWlX#mC{l-F+4Wn7nb!x$dcsrd4Klf@_I7@o(l{Nm5{m1`U9!Bw8a%a2{p z^2LaEI2ol&f_R6LAl{)Qh<7Ln;vGtYc!v_~E_aG|Xa9kO^=WV}OM;vEEBT@>#e?-1WF-XUq?9VjaP9q|s;c$#uHO1uN9;I)oR zyh9(2%f=<%L2$Wvr+9~Wr+9~Wr+9~Wr+9~WF`kV1c!zkWc!&7@@eZ7`NfYnDR*BP_ z9ht#!TFl?L#5)i{)g|6RphR5a9V|S#;cSd|ig$=V0*fOb?-1`4?+`D=$`e`rENp>% zyu%_5G{?UnDu{Q8cZzq2OT5D|@N(^occ9NJRNEFWZ$-IFPRGIquU;I_WyCuit$CVw z2f7VHwe#bh;vM4q$2$x~rzB0h1II*M;vGid&7O@R@echpL?`w*kR(mK0|!aGQ@lgG zQ@lf*F7TqoBty6Bc!y*QL8SrAotI_E@CKbO=P54uL3Z#!L&9=@5vrf)EI= zY6K|taX~M4Hj?5UPU>igXgl4bdK^Wk2jhtQrO_Fm%M_5~f?kjNL6??j2*0WZ#tot& z{2D&a^rOS_YpXy(Pc|ILem(thjE0Ca8p7}MDl9%mL&O;k;rDw|V>^oCjE3+B2=UK~ z;*5sy2MP9>qBx@={9(LWfYA_fMnm|+1$?t8&S(gK>|2`idqr_ZL-><_tHF^C^yKh&ZDm{HxB<;Dc_Q(GdRC88iZ7 z!`wJ+34epM2BIO*%Y*qbxH5e%vrM1MEGsyd=^ey=h-AG{=i)ccbD7>~^Yyqm&t-b8 zL~t?SxlC_NFWp1jCA$#$nRP@KoXhkMZbObfml@j^aZ#)zE=t42)$Ert9dS`s5OGml zqn)LUxG1jUzJrdqD6any)JYw2QSwSJw0@is7bWlCWfm(&T$BV67jZ^hlmrnMaqbZE+Q^aaMka%yy#Q|n$xANdQ--HCll$T@k~$8{w}C`wBu!XGG33TOg=NGgEaPI-f{iI*83HBZ5|$xQR+jT1EJK$1 zAS@%^DJ(;;G2z}6CSe&H!QGay3?^N-45)GwmQjziwj^7T$es#32!4qcj<_Yemmx3C zNQjak5+cq>h?0CHM6p})2;04aGrQ!m2~2XsqC`hRROm1|9SKpvNQe?02~ojFh?0Ux zh?3_i$G;6@^eH4niHI8=%(XtwNQmeVCb1kqH=fwdyafeyBt&!=i}+l96go-DCUqo4 zbPbn#S%EGJRv@mw(Tn9dpd%roYgutVgL|Xu(REw|_#k5>MD&s!8p=T|xw|fhTNfP( z5xqkZ*_98<=$*>&@2dIl&?t0hH}2U*cPe3;=!RXv=ns?#yA^PizkS|Y}L=w?GeFC1*#{!;=got*Igor*)voon9A)+tvvmw%G zzYNMS5+eGds4bBY(U*c&V;u>t?KIP?psd{MGC-f z5P6l!E{udI8e#53IxUe9MO#c9^P4*L=+LQLY7}iXdSiDpjD#rKW;oZO-!hDZDB5l~ z6QbiXjD#rKVG4xII%$c7C>mvWB#SB@9V(uNVN^86c8Hrfo8(xLq+&)w6pgba-AdcK zRC1U!iJjHiq6y~CQ18T0FC!s}CJ76pAj3$AqJzwRkfh!XY|do!n2?oDSGub!=XC@m z;jkWEn<66wM9wG7_R_o+UZQKaIj&7zt5ysHsKytVTi<9bq00 zty~mZ$w-KzBZWn0FcP9DjD*NA5~AoR^CSwQ_n>?eQr>d>yo~?dI3X1~U4G4`EivSE z&o5dgy<0Ak5akjHQ7(}X@>SH8C(ItlIv_wJ_?KR(or7!DP`f_2Rv`#Wt1d|Mu@%bfv3tU!P zbd})(SgXIfqk{dyVv`vOQFKk9Kq3-~uC-)khLI3O*V*pRLVXk(b0Q%+Arj&#WTkjD zMH@JpQyK}uX|Gr!Avjg0G!laLq%;zOrHaEyh*XD2h^Ns88ws%iVkHs@Q96$ce~E-B zJwzu}C(cNS(gjMn@#oO&(uI{+mEanPGZLcoC@yHZeq>5@|6W#f#5C|&jgp=#rd zgeYC3&lL@E+F!a}so`-(LX>W>&m3^Tt1!rQxo+)*NQjGJQc5EsxUQG`pGHEYav~v0 zY$OC1_!%%77m2t=LMT-k*GLGJ%*J=2-33dOR~w&zb{8yF zsv)kC5K0Y?Yb1nHO>vEcP=B?=H4=g=(l8Q2pFtMHH4;M2TpZU(2&I5@2uA}StI?>KP=MN~Yj&T-=mim1p5ifBXu*X6MAxZY>GWTY{d<3n<< z2y$_Rw;U3gtV-gQeS9BEB)c%lX@G}BCad*|a^u8;P0F)wUJpM$3HPLAFXbiToOqJG zl`4;4g3e9WDpeUD35O@^l&XpoyCPYyR5rdF6JD~fQZ@1Csk5I_wei2AKlKO zwac?Kc1^^mVyq<_2BRK4PsC59mVrt&#ZQ_6YLJ#|i5~~|BnK-sJ^l>_Wpc<f}Scc!m_@%V0 zNqIZs+el5|TXC6NvNUv(lGsp&J>KXhIV3VUja^dm8N4$(IU|ba*?5e$wyGv4{s6r( zOR4<$5#-HQ%8kE4d*&$R7vPY{a=ubk@weF7 z3zW*nE7(nkDpeEb3xMQdO4SzdkjUghrTWIZ&RI&e#9yUlXDihj zzZ63zd5%&G@acjbaNcaTO%91nUc8TOtD_y4s0W-lBcGF(s>S&_MD{A>O2=QOgdabf z4ZU2cM4W&($t#p9kFV!=*{4(`kh*Bcm9lMtPb7)t{+C!W4~a}(qi%HK|70Vt4LgE| zL?*Ah334TJNM!QPEZ$AT`D~E9D=714y8dph$Bl1hL+(+^k5A@!zL%E*7DZ0vVOI9N zUs9hO5}ABuF7@${$mFY9276wq;WeF|Fc|jI7q8btuA&i~-6r|bdn~k^j{Ikpoy1xx z^)Xw-=^S_(AU~n8c!Oo)^VqCUdA)IRjxQniGmc6g5*hDDBR}U5!{wV7U(Vt31$zZ= z?DOK6)5TxXPH-bm7akIsjF=;l!5FhbEaT$e8e{e$BwUxPQrG1=rQ~E-+)}!k3qOf5 zD?LZwA3O2)U{LA#y3WH`##B?f=Q_Dk5^=_um0qB{$~a@pN-t7ZW#f!7E4^5$nmA+3 zO6@qQ)wSb3U1c`J8Dmy@wNk_5j4>>sML5PN$9Okq<*CwTTTLEy*TopV*2vrTzp~dK%qUeB|b%o%9?!C-pjWk6@!y zKceoXY)on_b63+4$D{h^k&^z);HYni?Me?Sf#&$zY}gPr0B>cfV5n00@ic}(dbl+% zem5o8unls-FQMgYsW$Ql$ff4?hC1xKz;9180>8aj5Kl9iE(<`V-h}E*R>sTwXkDiJ z(a449di)X5UXqf5;<~iWby=|F14!@9q@F-J{uxWwP&=J>6+E2j%fW}PkGrG>uu`5C z9{&)QWf}+L!r`<5Wt^wW@~f(WFpsULx zV9h0qM_GVU))3^FkqEN*4p}Q92#S|{pEk#gmMGyqIFeISPVa80vCH#$Cc<{tNhL4j ziKhB_tmI>`>K}qZUA{!B?>tyxJ~t+a&{#aH&EdaAE0F&RTHbHVD%A727;_sk`!8F8 zBPt_#$D&|l&r2r``0++a=I3>W&7e%5;uUjALZD-JqzF+IYD?S+qTxnMJOJYJoCe%x^MA?`uUX>fBz|X!cR?UD_GwGL4-&19MUJ=8 zlXxO9M4&Mzm=CQ?;XEBvm!db#$Xdr4BbZ7jF!?$1#w^AP#+=Xua=~hl0-|)nxfnw~ z06F&DIa>S$`+ZKw;-s7??0nucJLp z&Y(a|3QRB}dmi4&OKeXQ2hs7!nvD}u2bu+PCThbHt7<%?`=es2YJhw!a%6C(XJea{ zSp=EJwU$^(Vyh)KlQ`BA$CKD;iPK2DVu{@(-mt{wB;K;b^(200i91OA%@X&M_&k@0 z%vFC0C!R}m&Lz6#67{*nkX&M1E-@vSn3GE!kxR7Y5}R^~<8p~pbBXhFiHj`p5*v4! zC4NETDoeaa;s#56K;l+Qd`98{OXLj%@u($y5ms`rgPh-u&30ZFd3#z1jkcvZNpl<{U>f660;W;beoprrOsf?- z$^JbQdQ5enpsEe5>IUR#RU25<+aL!W|No$Tyy=Z9O{Fort<)X%Z|8N$KL^?;$OT?0 zH`}GioFG?trJ-9cC%sZNaKZ93(1UKV8t4W3ea~9G?KwEBpo&fDVa#1t<{tZ(A-<2G zvPq(>hoLev4+Z|f0xu%Y(+WP9Q{bN{a8Qt8cq8K#jjo$$=CF5uj#Fx^_-i@Ede$Kn zHOP=!aURiSm=Da~u;#FWpW44g>ydvEO6ZzHV`3*DbHdHEOz9n<8$Pfl?m^YNP=HOx zeQeOjHb1ZrBXYb%shZwE$+5wwmGzaNQP2O>b*(3NFx`sc*sb zf=3yJ0$Ij!m*2p*p&%H?U4Eky(|A%t(ldM~0G0-FpKo>Y;d~kcwM+91<8>hL7A)}I zy~_%4Avg6BxFOp`TQv1-_$^y)i95Q1=w*qu7`EBombeqEtZc0%{)M$~w$2h$Fjlkm zmN=GTeJ##)rg>`5;y)=U~$avr})&ST!&A!_yXjFe7taKg00x zDph2I(Z3{{b@h@|L4Of6_><&Qf$Q@3V6%;7-cyZSnTtk!-aFWAMvGJ5D03Q_qEAw` z;#t(k+Gm-OSP8Ok06b9_Y7J-7{^J>k(15_ z_h$)i?im7DL#_dOF(_*;n$GiauiQxGq#BR1YWKizd_zqZth-JggH_9#S4jaiBgs7LqAF@J?z1Iiw3V)&TRxfGidF~GQZ>UAMfsBs(JERH;_49=A< zDna>yqUlkTua&$b;L_ew_f|BZt~<4Vh15W?;v{rijda3Vlo%|X`Yh}j45&zF6z;5f z&IRzM-8AtJND~gS)!qeuv#1TW;K+2i@P9T<{C~b_Vh%>e|G+{14;1DjOYIzILK)}4f@}KgIpF@(`VM*dDP;)c*IvL2eM8|L?*<1|x-G(y`fx$hi4$f`jafMKw1-{8!*0AAun`aF9xd zaFC6nIfR28E@TJ?sbmNT$?ngAgH$qvgS=6=AsnQV|1~(sF2$@Ugo7kPcn%ySqdnn` z01on45&pjb4zk!z75_OLWLhNc<^+Xy`*34W zkjTh(WRy(*36}5Jslb4Fz+r+2@gf;z`>lA9ud_&q7pYW$7pc_$IbI|y(~SuqL%ZFW zz$D&2f)(IJGRj*Z8m~v9^V8r%U?~0&qVYxK{ihI(^m!$(xK5AV3i--*h{noxh{j58 zOi+l%%72GwWIY1W*ay1Q2tqVAfwB;dOk&!DZQT5j3(?3T0@1h}2`w8yG;*S~5RJji zz=+`3DLMmNh(0nmm5kJ)l$1cG^PqsAPa~_GSkXH8qW`O z#vTiFa$~~3K{T$0TmaG74(s?rP(~pd)$9PGG4Pr~G}ZjR}_{B^wiB zuQFL>AsV^CHWffLZUUiBJvwwMHzok0QE#bknnM;4jhutfZ)pqB$QcS9m$nd%tA)%u zsQ{w!p-}PYP%%TP0nun%mOh*0SVKuFwh)aLpaL}L#jE1haqU(NXzUj(34uw<*aF#!;bKhu!T|m4#?z8Zca_4l}2upT}=1fM`r&?Wc8K6xJ!z#Kndz)QNID ze4~mR69Cc3bSi*oTpE_XtYhiR4Ou9ylgt&yPBKtd1xD%?xQq~uTzYEtS9esfUs!Ci zg=n-2(%c{bh(&Ap! zh{n<-YlNo|jit*HSZ-l<5{SmqHM*i#h{n?ON-0ER=?1&nhXaPgh<1p^&)N2Nh(@{p z>BfZ0oQ(+qL?f5h-v-gB>-qqqQP=eWM59sxM59V(EkvX80*FSX0*FSX0*FSX0*FTS zR{+t-m14LtL0A9(y%3FRbO6yvQy4sKAsUqoAsTg28$vWHH-u?$s8cO%$kT>2vzgxv^AX47^zf|9jqyBk5thI9{HQP_>3(U`j% z;cOIeT@DKYV`RHzcrlmbLvsHa@9Ay? zr4pX*Mo_BUy9Aw^tW~Pg)7=P4Re8D_L8+{#yAhPC@pLzWQnjA$Mo_A+r@ImA#g+!I z!)^rcR9t1@ZUm2?GLwU}T#Ki>5tN$leS;Uq$swwxRnS_K!<3rq{T35>xEsOy3)?VK zd5b;WjiA&rZy0%Flv?TOZUlNRug6ADcOxiohu3j8f|sSCxw{d*i*B;J5!fZgb~nNz zd_M7XH-c(%Jl&0;RKBOX5tMShH)zisrR;75B@&+QMo_BU)7=P4ReHJ`L8&TFcOxj3 z^(t_UB@b1qM&JmNhba~8Mo_A+r@Il93U(tXHQ3YL2ug*!5q4p872Dki``J+4jo^s` z9k0V~1n*mSBdkKHV!IpRczhW1bT>kvL3bl)hX5s%K0jW02~T$;s72+T?nY3m(#yvL zmONP{t32I}pj6h=-3U5+)q1)cL8%5$cOxh@+|%6%N;P@98$qcS?^P_Jl4mQ`>gjF- zrNZ3^x3O(@H^RqkTZi2Up6*6ai}Q7eSR_-s8$nsVr@Il9N_e^(L8)?YJ;%#FrNZ3^ zr=zlByBnboJ{@|;qeGI{s2d&cTX!QkkSn&k5sqOQ-Hi~G(cK7IkL&4f1f_iMTX!Q6 zh_cx3M!22&bT@*QaXj6PptDoB8{rhll?J;J#$fg2>28Frb`sOw2y79jb5D08&{*z9 z@N_oS@Ro3X_>7~HyAeFyjldzs-3XrUMqsaSH-e|T5oo9EMyRs85r|C3-3W_m z%eU@Em;w%s7Pb`;{5m0kwAXHdZ0)EnP@8It*o4W#KMVPW%n zSv*^(w|M|Flo=&Z$Qx}v-?M-3f-W-`UvX;@O*Co;Mtfoth;>^KJw1w*9}cq5V)T<4 zL-HYzb?X})GnRMhw?WmPV^uu?L%Kl|jA2w${cSe?7swwM=EFM1&h`xq;Adl&Af#w- zGZw?i=zhh=ZSm;*Hduu(-kZTH#mDJd;FV5gDE)5a(Cn!+`&klV_Eg$g0SnaZ=_HQ^ zDP|u`voEE2zq0yW^u({#JOdMPaE8F0-cn1Jf(E(CFyw@@eI z9Cz8m=j149p%T73Gh4a7-v>4Q1HL&FYMcRPI{uiQX16W&wEg=UWX*{v-}ieqXPs7S z8aPs_S!%ajA1_&c_XRpqx?y~o=581=>o;t7%mu%K3uBS}HkNGQdX~J9d<37_%=!O0QSi8b1n1U7t3V&r~ zo%*c{+l5*>3hlPF_R8CyK;*Sk|4EMQx{k8H4;5Z^c)P+2ItqOf2=!fM-Nd%$nB{+A z+liA-^XS~KB?fD^mA=^i<(U5ls%vHE$k&`x{&);VeZV)J5b*-FI_d|Thby59p-lU2 z`G;)0OSfZ@KNXQo^>@k)tJrn?EJN3`!$Z}Vi zsG6B8J0;Zn%N*Gs2C{2&W#@;of6kHpdmwvquIzE4?B_YMT@d9ZHe8%5yCRfztuxp* zMiz?fjk&T{g|eM-z3<;b28$a=x$!a1hh-d#Dew*;~k zxw7r{o}VN8S|HmaS9Yg0$f>_7N7i5rOWPW9W&2seslPo(wqGDSJy*6RknI^<9ER6| zC|w-zaNO~;yee^&H?O(Jt=6aPUtX3&%(;{pq7pAz&MP?*L(LVG7>DR=n;V3mvHUQG z1y@cw+J%T2#<1Yj8h(8Oaa{z&r9&}Y08rVhC9PrVM^-eS3p3BVZo_elt`Y1 z5q}7=vOnD|sV@7=vO%fwy(3AIP zHHmgPCqJ~~clx$A*a&xLA(;Okou(Zdcrax0j5`P8I4>`{AA=&YAB(!! z;1y)#6`r1loZAw}8OF;iKR>!^{n1Y3*LXsS4L^%A`GqfHL`CjqPV+wIxY3yyB9S9t zbgbnL$tipeGWZf1oTeQ+(?57GleHGI<1( zxuK^kD7S$%NO@gSBx?8*)#CS7N75pa8=uV|$+y zf!Fa{Btxgj@H}kSeF?wb{38MF#&TXOQm;^1w9@O=2QKo7JM9JMZ2QEW_If-90er;q zmqWi-qZHhfMQ?gNKLIoDdVRN`bf@i(C+BQ;I?D0nob66a0p+ zr@aYEDekm4Q7Ofp_9iK%xYOQ2N-6HNH(9ABzY6tw%}OcmwAVuG`2~aLYdoz{VDCcZ@txD~XbGE%%r1(KY z&e`^6D{0T!_U0(L+xP{YV0ef-?el}I7oM~26L;DR&)N3*LD37(+4hM$?a5`pbGCir zPJ7`w+dgrpz3`lE{~eOyIotm4NrvZa`+p%Bp0n+LL^3>Q+y9JYc+R#@+-Wa7XWJ+4 zv=^SU?e8KPp0n)}ciIcj+4hM$?S`&hy>**}{II|$ zZkxBBaRJ1g_K7>~ZBTMop-xf3Whhe%)|T!8zOh7PQMBMxP)A(I@V-ADpx86L;DV z&e`^fJME8G$rhiu)BYr-T7BY9`#I-q^O{Wv?sR+>z2aXx9`nNNE~pIGuTR|R_Rdre z&e@KibQ6|9Y}G%=3UH@=;!ekdbGCiKB0c4HDb^%!>f)!~D^!c$xe1b|-&RH~t-ga^ zjGv<)H6^eze!*wbp2a?Kr{mXhuE*8u6L&hEbI$fCxG`aIr#U8k#htzwyF=&<4Xiv% zD1Mo5fk;9EE29fINc>|bVn#lULyzKIibM}r%JunOKf0V^=yu>vN7p8&W@lnUN-X#=Y-{UfT2l;+?~7grC5q~J{#XSX8h zy2s%+A$Ze?*6Wd$@spSpj2{MnC1x)W@7r+8;$C+`u52;J%dY&A>S|O1yy=qeyp6$a zIDNaMM|VhIQ1NScNzYL<19;Ou@uo}aXJkpQ8B^ociJ(x}2u7y87T zE*Y%cX9|7dO_z-P8ip|3(kI?@$tWe?DD>B&zLJS^Me{p_KJlhYrXD8b9}E5CNKRAo zLsW#ZT{44%g5j1v@uo{!mE7g}#G5XeOL!{)Yq&n~rc352x!d)LH(e6qP5Z=~E?Fwe zh93J|pLo+HZNI@U-jBOJ@uo}8`4FR-;gO zoPRKi5O3Ni-gL=s^~N(CtThlX?}MKJ7MiDTm%erfdfMaZ+hu|UU6Nncl|C!|7aHl5 z=3qgWb)SrUIeojVhP^IW&}BW3M{a_F(TVbxpFr9t7IgVd4L7&7aamB zz=HM}q*VUbGey#dTbA|WH7Mbh6&=DYi3OcJ{VW(ISkTG#$jf9q7IgC8u%MF`3z`j& zBx?``xbzz&Z4hQcV4?jkccZaBVWIutv~K?*QrRjnIPnn{+V7@R!rzTMo8MijN}X+c z>inA3nK*!j_6ZB^2d8z*6yVpfGL60@aFj$}`t?lW!!dq?=*wr2j=JR+eU88WpBmw* zi@EfpPZ>s8ehC?{O+z$YII(jPa&{imUcr4gHVWi6g7-@e3#!Gn! zBOQ0kA7YnDv}XBZDJG>FfsvMI&2oW}mT1j#fsvMI&GH-=>GJ1UPx3yPxfcnwCskSA z*ZdS@+NWXt%}i}YxYy&112WaLN3X9t_=xo4vNn^hsAlHOdLW@>=K#h=IcC%p*(&dm{#iiO# zC-Nk9UAYH35(m}eCvj^5?on#ZZGpb290uQ2!_je*DR?`-)FzrR5mm+?;Q~d<#2*dH zOu@|{{+O;uTwP}5!g|M_(3^I`C#-k;NxjnOl@jQJR~|ht(3yBF(8=i8L`PWf#1s4^ zo2bQrZ%F*~i?GZKK^aERCSJ6*%K_(!mx4ZL^laj1wnKcvdM931Dk~F7;uR{?=-JDV zlIYpQt4u~~6aQr7p?d1$ptiwu=O<*K|NSEN;-^X_WNt`&cD(Q^{a?_DpX-&GmB}aZ zg;F&#`6Rwnm(;=~93Vhl#&6^Ws{G1>l2m2FGp`_#mP^t%_A*OLf5+`9+-_#Y*7Z)J zlO1-6v|L5SCKv!!f5sG%NSJe>NFst0Bh33qcaezT#1=W3U5EM6;V>VIJ8WXB(Y2sP z1Shr`-X<|VB_cSn-S8%gOGzSv6FbZpA+t^wF3+-wQHH>as(5s$cp5IS#29O%W^QVT@@MfEs7Mj0>Q_6IaWHpQk zPUJ$B|C&B$L~vq;DTF%o=xlQd^)ezjfi2ibW9E~H;KbZeFC&5z^MW3Qm0u!5B7zf# znj=xBS|frJN0@(5n@ppNLMs^&oH$ZgbOs}W6CqT&L}G7R5C??L&^NG12-Cx#yE z%KM*<2u>_9Rn+mAuA`!ufwdO() zYTvrhK1Kv5)(eaFF(NpzA@t(e93mUdWhkij&4CTBI|Z~v1Sd8brg7Layz9C&+I6qS zZx@LOPF!gI1VZb)D6CU%3>OOvb)v*05R!=C#3hF5E)o%(*lUL3F-l8c*0J>E!a`}C z_OA%0eJJ}I72JZ+P@A~Q@R>;!T-{N@eqpi6j0jF#6DW{~;Ka3-tdxl0#C5j&vrs=8 z8mmV2N15vl(-IvVmjm1*KkSFuwZ~bgJMP8@l;Ckl0)^uZ9OM!x93RO0QzzUEI4MyxSZuKfx_|NEcY+bGzk=rH$8$9i3g#pB{GkXkP;{yIYjS% zj!y*h$O5HY|2bF`S$JVrxdMF#3P+COBNF;l5X>V>&J|wPzXgUymNjO{tM!Rs9$BML zs0}^?og?d&8txOpJhH()y}~cuVT9}QNhtCOX508vytTyLXxj&L17n7xD>)m>k4 zqP$vv0$fnARH+7E!OWE!?kkwNQceEI8IWA1u50m+KN!>+KJJ7u!}?&mz@Iw|tc_~s zVqd|`m0IR2n7L9beWI;|$GZC+z|4IGGgqT`_*YQ!RGJdOD>lCkE-yGu$uo>krxlz* zSwW-j5w>2@%42_H_kgPBYC zaJn7LT*8Ob(+%$zj8K#C;dDEgxr7g=Tg`h?|I^0l#_-|veF*_GPd`YP_yjXgKcwDq z{B2N`epsF3`UEpi=YW}?jRJTI#IQ*6ftBr&k;Yt(56S&!kXwdTIO^M-soH=rA%7oA zWV$fPX@KFwnQFbFT%X~?8F`TcFms>b!Xpj+3?I()RjS5k_;9A5QnfzAhco?^>gzLnI3q7=_>Pa^!dC`_;6;(LbQ_a_&6(MhAB1IXZUa?05kXh!ZwUl-eRBO!$&gKAf4QRKCyf;mmBMT>lN)Ge;>2AI{8GBH=T9I5SVFa{p1*e~40* zKEsDI^OdUd89tm@pj6hcU^gAARE^KKOPRxz((vKTLZ$lp3?I%Mu9SukXO2*6u+Q+} z%p#?1_;BXPT^L;n2_McZ+0TYDd^odolsM4w89tl|z|4Jy4`(`pnP=7#|0W^f!iAO;lr7;lxp!AKAbsQsaBui z!=aON^4e4pXNnah<* z_zWM;T%lCCzn48w;rcWXVa&+y^QJxcjL!-q2+!OSz?C%6$u z!iO^vb3ZboZdLVS+QRVRs;>5Jz7u&L`m3^2z=h_pK#}q{Yo{#yvty#1Qm#*u58>$($RF7~s@FBeIQSYF-jJIJXdVtI8BzPGMC3v_i2n~u-fJ(2FY7&%e5 zdfdJE>oc~jdc3@I#a)Sr<<%43mL?Lhyn6EQDMZBb>Hx9aCt`VZfLQJmvAlXJYvsca zip*fRr0Q+$pm&zlt3_sqMY7e0tPG1R=uqU)pa>Dms{_PxpNQqv3rlc~uehGsL@cik5X*gH%~pqqP#Wn(IdSYExFhB!&~Ls56TR>(LBK`gHx zG!t1q5zDIs#B$%Ef&j7HCt`VZfLQJmvAlW>+ki$p5h9jXuccbor6$+C2BVdpfW#! zOrND7nSjL4@TZ(Fuj}UF;iv$iI}sNyt6#E=1czgN+w%2HFNS2VyZea{(@x*sC=t2A z@al;4M4?)FNV{Q17R-K|VQk6ECNdTb0kJN5na_DnzeDT5c-2Ifgp60osNDxEOJ1Wg zr{9FW05@M@BBus2g)1o22UZoXpixfUng(>k*D&|Hkf|q1HYf_!GiJH#H}atD)O`>B z=^6#@IKkajESlFYR*=W%kY4rZk*bYI@-V&VYveVTEFi4f-2W^NW0AY9UmA zG}FT9`5YQ(W<;fhrWwp$y=m2qsC07ORI-=4CUPvx3C{Uau}xdD)MZN=ICGoj?p&mu zx)!!$Gm6|E7TKIrWOGiDqiqpF37hRPV_u;FUq^%*g;7?2G(y|A$Cz~Ldczr}1#pvJ zgo;~=*isoy;Am6Nrm_jHF+*_8s>u_i{()%rWS2q>eE(q61F9)<4R=P3c?e?KZ+Awe52btWjM6E++HmEWyTp$J#c}sUX>7xXGm(F<U?@MTB-lsa|1Ok$!^FC!^r_Q0)Z5T6N@1X8&GG??xwnbRC*0)11 zg1X;8U(vI;3L9DEPIM0_PEhq*HZNs*4-`B79>TQ}{lY}%L5de~^b20ZwLg(;xt@ET z${zSQUkA%skW=@5oKM@-fRFQO07uxzI>H9cW*ZN|#nAILT&VfC7`?sdRzM#%4Tt^Kn@ot4KgL)DDy8j3Bb$In`LT^Fm$rdMv%1A8NwkN z1QC`V*@i6i7J^{kf!NT$g1HU>>cieeqTmbuUOk*894i@=z-SfW=OH}eK;}r68|B#| z=Kh0-0#7XJd86gr0;n6q5t_9UyBDh&mB+!;x1+y?oeZuya^yDr8MzuiW6#6SxXYP) z__!PSXHgT6uK1DFFrL%GI7_@#1pbrJHBdBiB=U!oInOdT*}oY7!UUU_W1Tf&m;Gzz z7mPSCZ={PF$CmS_8b9Oe@M8`^VhU4Q7)!0V+�_mMeC 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%0Ae54{}BbFz9 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

@~c@Y;^&3}WRhKH|{7wf7k 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%0DawDN@7XFV5x)%hp&6zC=`AjN4U$RTXgi4 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 {wzUkC5>zDGse%)q%DZJjP`xGu?Q>y-T6*Air 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
%MmIBjC>8ILGaQ`vI2#F9*I3 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

y*q`+;7Duf8O!cdO;y$W( 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

O^+smo7`SWDKr0?R9ICN-#Pml4~>ul<$ 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%0AZuj;jndG|{Xx+|5?94bmOOa7fr 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

ET%Jy;^5-kjLWgdGP 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 literal 0 HcmV?d00001 diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs b/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs new file mode 100644 index 0000000..3cc1f53 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs @@ -0,0 +1,277 @@ +module Main where + +import Control.DeepSeq +import Control.Applicative +import Control.Monad +import Data.Maybe +import System.CPUTime +import System.Environment + +------------------------------------ +--- Requires the installation of --- +--- Parsec package, i.e., --- +--- cabal install parsec --- +------------------------------------ + +import Text.Parsec hiding (optional, (<|>), token) +import Text.Parsec.String + +import Data.Bits +import Data.List +import Prelude + +import Control.DeepSeq +import Data.Vector.Unboxed(Vector) +import qualified Data.Vector.Unboxed as V + +import Constants +import Date +import Genome +import EvalGenome +import MathMod + +import Debug.Trace + +------------------------------ +--- Parser-related Helpers --- +------------------------------ +signed :: Parser String -> Parser String +signed p = (char '-' >> (('-':) <$> p)) <|> p + +whitespace :: Parser () +whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) + +lexeme :: Parser a -> Parser a +lexeme p = p <* whitespace + +token :: String -> Parser () +token = void . lexeme . string + +readInt :: Parser Int +readInt = lexeme $ read <$> signed (many1 digit) + +readDouble :: Parser Double +readDouble = lexeme $ read <$> signed (s2 <|> s1) + where s1 = do bef <- many1 digit + aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) + return $ bef ++ aft + s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit + +readArray :: Parser a -> Parser [a] +readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") + +--------------------------------------------- +--------------------------------------------- + +findBestLik :: Int -> [Double] -> (Int, Double) +findBestLik pop_size log_liks = + reduce (\ (best_ind, best_logLik) (ind, logLik) -> + if (logLik > best_logLik) + then (ind, logLik) + else (best_ind, best_logLik) + ) (0, -100000000.0) (zip [0..pop_size-1] log_liks) + +makeSummary :: Vector Double -> Double -> Vector Double -> Vector Double + -> (Genome, Double, [[Double]]) +makeSummary win_genome win_logLik calib_prices black_prices = + let res_genome = ( win_genome V.! 0, win_genome V.! 1, win_genome V.! 2, + win_genome V.! 3, win_genome V.! 4 ) + res_summary= zipWith (\ price quote -> + let err_ratio = abs $ 100.0 * (price - quote) / quote + in [10000.0*price, 10000.0*quote, err_ratio] + ) (V.toList calib_prices) (V.toList black_prices) + in (res_genome, win_logLik, res_summary) + +--------------------------------------------- +---- The Monte-Carlo Convergence Loop ------- +--------------------------------------------- + +mcmcConvergenceLoop :: Int -> Int -> [Swaption] -> Vector Int -> [Double] -> [Double] -- loop read-only args + -> [Vector Double] -> [Vector Double] -> [Double] -> Int -> Int -- loop variant args + -> ( [Vector Double], [Vector Double], [Double], Int ) +mcmcConvergenceLoop pop_size num_mcmc_its swaption_quotes sobol_dir_vct hermite_coeffs hermite_weights + genomes_old genomes_new logLiks_old j sob_offs0 = + if j == num_mcmc_its + then (genomes_old, genomes_new, logLiks_old, sob_offs0) + else + -- select the way in which genomes are perturbed + let move_selected = sobolNum sobol_dir_vct sob_offs0 + sob_offs1 = sob_offs0 + 1 + move_type = selectMoveType move_selected + + -- perturb the genome population based on the selection + (sob_offs2, genomes_new', bf_rats') = + case move_type of + DIMS_ALL -> let sob_offs_new = sob_offs1 + pop_size*5 + rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) + [5*i+sob_offs1..5*i+sob_offs1+4] + ) [0..pop_size-1] + (g, bfrat) = unzip $ zipWith3 mutateDimsALL + genomes_old genomes_new rand_vcts + in sob_offs_new `deepseq` g `deepseq` bfrat `deepseq` + (sob_offs_new, g, bfrat) + + DIMS_ONE -> let sob_offs_new = sob_offs1 + pop_size*5 + 1 -- *1 + dim_j = truncate $ (fromIntegral genome_dim) * (sobolNum sobol_dir_vct sob_offs1) +-- rand_nums = map (sobolNum sobol_dir_vct) +-- [sob_offs1+1..sob_offs1+pop_size] + rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) + [5*i+sob_offs1+1..5*i+sob_offs1+5] + ) [0..pop_size-1] + -- create sobol numbers + (g, bfrat) = unzip $ zipWith3 (mutateDimsONE dim_j) + genomes_old genomes_new rand_vcts -- rand_nums + in sob_offs_new `deepseq` g `deepseq` bfrat `deepseq` + (sob_offs_new, g, bfrat) + + DEMCMC -> let sob_offs_new = sob_offs1 + pop_size*8 + rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) + [8*i+sob_offs1..8*i+sob_offs1+7] + ) [0..pop_size-1] + (g, bfrat) = unzip $ zipWith (mcmcDE pop_size genomes_old) + rand_vcts [0..pop_size-1] + + in sob_offs_new `deepseq` g `deepseq` bfrat `deepseq` + (sob_offs_new, g, bfrat) + + -- evaluate the new genome population + --(logLiks_new', _, _) = unzip3 $ map (evalGenome hermite_coeffs hermite_weights swaption_quotes) genomes_new' + (logLiks_new_th, sw_pr_th, bl_pr_th) = + unzip3 $ map (evalGenome hermite_coeffs hermite_weights swaption_quotes) genomes_new' + logLiks_new' = logLiks_new_th `deepseq` sw_pr_th `deepseq` bl_pr_th `deepseq` + logLiks_new_th + + -- decide which genomes to ACCEPT/update + rand_nums = map (sobolNum sobol_dir_vct) [sob_offs2..sob_offs2+pop_size-1] + sob_offs3 = sob_offs2 + pop_size + (genomes_old', logLiks_old') = unzip $ + zipWith6 (\ genome_old genome_new logLik_old logLik_new bf_rat r01 -> + let exp_term = logLik_new - logLik_old + acceptance = min 1.0 $ (exp exp_term) * bf_rat + in if r01 < acceptance + then (genome_new, logLik_new) + else (genome_old, logLik_old) + ) genomes_old genomes_new' logLiks_old logLiks_new' bf_rats' rand_nums +{- + sob_offs3' = if (j `mod` 16) == 0 + then let (w_ind, w_lik) = findBestLik pop_size logLiks_old' + in trace ("It: "++show j++" Best Lik: "++show w_lik++" Genome Index: "++show w_ind) + sob_offs3 + else sob_offs3 +-} + in sob_offs3 `deepseq` genomes_old' `deepseq` genomes_new' `deepseq` logLiks_old' `deepseq` + mcmcConvergenceLoop pop_size num_mcmc_its swaption_quotes sobol_dir_vct hermite_coeffs hermite_weights + genomes_old' genomes_new' logLiks_old' (j+1) sob_offs3 + + +------------------------------------------------ +--- Main Entry Point: volatility calibration --- +------------------------------------------------ +-- genome == { g_a, g_b, g_rho, g_nu, g_sigma } +compute :: Int -> Int -> [Swaption] -> [Double] -> [Double] -> Vector Int + -> (Genome,Double,[[Double]]) +compute pop_size num_mcmc_its swaption_quotes + hermite_coeffs hermite_weights sobol_dir_vct = + + let ---------------------------------------------------- + -- initialization stage: compute POP_SIZE genomes -- + ---------------------------------------------------- + sobol_off0= 1 + -- compute 5*POP_SIZE random numbers! + rand_vcts = map (\ i -> V.fromList $ map (sobolNum sobol_dir_vct) + [5*i+sobol_off0..5*i+sobol_off0+4] + ) [0..pop_size-1] + -- initalize the genomes! + genomes = map (\ r01_vct5 -> + V.zipWith3 (\ g_max g_min r01 -> (g_max - g_min)*r01 + g_min ) + g_maxs g_mins r01_vct5 + ) rand_vcts + sobol_off1= sobol_off0 + pop_size*5 + + -- evaluate the just initalized genomes! + (logLiks_th,sw_pth,bl_pth)= unzip3 $ map (evalGenome hermite_coeffs hermite_weights swaption_quotes) genomes + (logLiks,_,_)= deepseq (logLiks_th,sw_pth,bl_pth) (logLiks_th,sw_pth,bl_pth) + + -- run the MCMC Convergence Loop + (genomes', genomes_prop', logLiks', sobol_off2) = + mcmcConvergenceLoop pop_size num_mcmc_its + swaption_quotes sobol_dir_vct + hermite_coeffs hermite_weights + genomes genomes logLiks 0 sobol_off1 + + -- find the best genome and recompute + -- the calibrated and reference price for it + (win_ind, win_logLik) = findBestLik pop_size logLiks' + win_genome = genomes' !! win_ind + (_, calib_prices, black_prices) = + evalGenome hermite_coeffs hermite_weights swaption_quotes win_genome + + -- format the result for printing + (res_genome, res_logLik, res_swap_arr) = makeSummary win_genome win_logLik calib_prices black_prices + + in (res_genome, res_logLik, res_swap_arr) + +----------------------------------------- +--- Entry point for Generic Pricing --- +--- The only place where using Monads,--- +--- e.g., parsing Dataset from StdIn --- +----------------------------------------- +main :: IO () +main = do s <- getContents + case parse run "input" s of + Left e -> error $ show e + Right m -> do + (v, runtime) <- m + result <- getEnv "HIPERMARK_RESULT" + writeFile result $ jsonish v + runtime_file <- getEnv "HIPERMARK_RUNTIME" + writeFile runtime_file $ show runtime + where run = do whitespace + pop_size <- readInt + num_mcmc_its <- readInt + num_swap_quotes <- readInt + swaption_quotes <- readDouble2d + num_hermite <- readInt + hermite_coeffs <- readDouble1d + hermite_weights <- readDouble1d + num_sobol_bits <- readInt + sobol_dir_vct <- readInt1d + +-- let num_swap_quotes = testSwaptionPricer hermite_coeffs hermite_weights $ +-- testG2ppUtil $ testMathMod $ test_dates num_swap_quotes0 + + let swaption_quotes'= map (\x -> (x!!0, x!!1, x!!2, x!!3)) swaption_quotes + + let (win_genome, win_logLik, win_swap_arr) = + compute pop_size num_mcmc_its swaption_quotes' + hermite_coeffs hermite_weights (V.fromList sobol_dir_vct) + + return $ do + start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + let v = (win_genome, win_logLik, win_swap_arr) + end <- v `deepseq` getCPUTime + return (v, (end - start) `div` 1000000000) + + readInt1d = readArray readInt + readDouble1d = readArray readDouble + readDouble2d = readArray $ readArray readDouble + +jsonish :: (Genome, Double, [[Double]]) + -> String +jsonish ((win_a, win_b, win_rho, win_nu, win_sigma), win_logLik, win_swap_arr) = + unlines [ "{" + , intercalate ",\n" + [ field "a_field" win_a + , field "b_field" win_b + , field "sigma_field" win_sigma + , field "nu_field" win_nu + , field "rho_field" win_rho + , field "lg_likelyhood" win_logLik + , field "swaption_calibration_result" win_swap_arr + ] + , "}" + ] + where field k v = "\"" ++ k ++ "\": " ++ show v + +-- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs +-- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data From 24ecabf9ea7e1a5e5d0e9ac3308955f14b4fcefc Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 15:15:59 +0200 Subject: [PATCH 076/122] Port OpenCL implementation of InterestCalib. --- .../implementations/cpp_opencl/FindBestKer.h | 160 ++++++ .../implementations/cpp_opencl/GenAlgFlat.h | 349 +++++++++++++ .../implementations/cpp_opencl/GenAlgKers.h | 297 +++++++++++ .../implementations/cpp_opencl/MainKer.h | 223 +++++++++ .../implementations/cpp_opencl/Makefile | 46 ++ .../cpp_opencl/SrcCL/BestIndValRedKer.cl | 109 ++++ .../cpp_opencl/SrcCL/CalibKers.cl | 467 ++++++++++++++++++ .../implementations/cpp_opencl/SrcCL/Date.cl | 147 ++++++ .../cpp_opencl/SrcCL/ExactYhat.cl | 314 ++++++++++++ .../cpp_opencl/SrcCL/G2ppUtil.cl | 231 +++++++++ .../cpp_opencl/SrcCL/GenAlg.cl | 313 ++++++++++++ .../cpp_opencl/SrcCL/Reductions.cl | 380 ++++++++++++++ .../implementations/cpp_opencl/SwapCalib.cpp | 64 +++ .../implementations/cpp_opencl/UtilGPGPU.h | 287 +++++++++++ .../static_configuration_template.json | 3 + .../implementations/cpp_sequential/G2PPorig.h | 90 ++-- .../implementations/cpp_sequential/Genome.h | 86 ++-- .../implementations/cpp_sequential/Makefile | 3 + .../cpp_sequential/SwapCalib.cpp | 15 +- .../InterestCalib/lib/include/Candidate.h | 114 ++--- benchmarks/InterestCalib/lib/include/Date.h | 14 +- .../InterestCalib/lib/include/EvalGenomeInl.h | 142 +++--- benchmarks/InterestCalib/lib/include/G2PP.h | 234 ++++----- .../InterestCalib/lib/include/G2ppUtil.h | 182 +++---- .../InterestCalib/lib/include/GenAlgUtil.h | 44 +- .../InterestCalib/lib/include/IrregShape.h | 2 +- .../InterestCalib/lib/include/KerConsts.h | 6 +- .../InterestCalib/lib/include/MathModule.h | 120 ++--- .../InterestCalib/lib/include/ParseInput.h | 12 +- .../InterestCalib/lib/include/WriteResult.h | 16 +- lib/include/Utilities.cl | 36 +- lib/setup.mk | 2 +- 32 files changed, 3951 insertions(+), 557 deletions(-) create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/FindBestKer.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgFlat.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgKers.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/MainKer.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/Makefile create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/BestIndValRedKer.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/CalibKers.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Date.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/ExactYhat.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/G2ppUtil.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/GenAlg.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Reductions.cl create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h create mode 100644 benchmarks/InterestCalib/implementations/cpp_opencl/static_configuration_template.json diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/FindBestKer.h b/benchmarks/InterestCalib/implementations/cpp_opencl/FindBestKer.h new file mode 100644 index 0000000..acd8124 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/FindBestKer.h @@ -0,0 +1,160 @@ +#ifndef FIND_BEST_KERNEL +#define FIND_BEST_KERNEL + +#include "SDK_stub.h" +#include "Constants.h" + +class FindBestKer { + // Assumptions: + // 1. the input array, `arr' has `size(arr) >= N', + // 2. the result arrays, has `size(r_ind)=size(r_val) >= LWG' + // + // Computation is split in two stages: + // - one that compute at most LWG elements (denoting partial reduces) + // - a second one that reduces the resulting LWG elements in one local workgroup. + private: + const size_t LWG; + size_t GWG; + uint UNROLL; + + // inputs, i.e., resources not owned by this kernel! + const cl_mem arr; // of size `N', and `offset' into it! + const uint N; + const uint offset; + + + OclObjects ocl; + + // res_ind and res_val have at least size LWG_FB + const cl_mem res_ind; + const cl_mem res_val; + + + // resources owned by this kernel + cl_kernel ker1; + cl_kernel ker2; + + public: + FindBestKer ( const uint sz, + const uint off, + const cl_mem& a, + const cl_mem& r_ind, + const cl_mem& r_val, + const OclObjects& o, + const int& lwg + ) : N(sz), offset(off), LWG(lwg), + arr(a), res_ind(r_ind), res_val(r_val), ocl(o) + { + UNROLL = mkUnrollFactor(); + GWG = mkGlobalWork (); + ker1 = mkKernel1 (); + ker2 = mkKernel2 (); + + bool sanity = is_pow2(lwg) && lwg <= LWG_FB; + assert( sanity && "In FindBestKer: Workgroup size not a pow of two or too large!" ); + } + + virtual ~FindBestKer() { + clReleaseKernel(ker1); + clReleaseKernel(ker2); + } + + void run ( int& best_ind, real_t& best_val ) { + cl_int ciErr1; + + //printf("Before run kernel 1 (LWG,GWG,UNROLL): (%ld,%ld,%d)\n", LWG, GWG, UNROLL); + + // run the reduction for each local group + ciErr1 = clEnqueueNDRangeKernel ( + ocl.getCommandQueue(), + ker1, 1, NULL, & GWG, & LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + + if( GWG > LWG ) { + // run the reduction for the resulted local group + ciErr1 = clEnqueueNDRangeKernel ( + ocl.getCommandQueue(), + ker2, 1, NULL, & LWG, & LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + } + + { // Finally, read-back the histogram result! + ciErr1 |= clEnqueueReadBuffer ( + ocl.getCommandQueue(), res_val, CL_TRUE, 0, + sizeof(real_t), &best_val, 0, NULL, NULL + ); + ciErr1 |= clEnqueueReadBuffer ( + ocl.getCommandQueue(), res_ind, CL_TRUE, 0, + sizeof(uint), &best_ind, 0, NULL, NULL + ); + } + oclCheckError(ciErr1, CL_SUCCESS); +// printf("After enqueue Best (Ind,Val): (%d,%f)\n\n", best_ind, best_val); + } + + private: + int mkUnrollFactor() { + const int sqLWG = LWG * LWG; + const bool exact1 = (N % sqLWG) == 0; + const int unroll = ( exact1 ) ? ( N / sqLWG ) : ( (N / sqLWG) + 1 ); + return unroll; + } + + int mkGlobalWork() { + const int urolLWG= UNROLL * LWG; + const bool exact2 = (N % urolLWG) == 0; + const int numGWG = ( exact2 ) ? (N / urolLWG) : ( (N / urolLWG) + 1 ); + return numGWG * LWG; + } + + cl_kernel mkKernel1( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl.program, "redbest_ker1", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->arr ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_ind ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_val ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &this->offset ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &this->N ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &this->UNROLL ); + + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkKernel2( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl.program, "redbest_ker2", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + uint newN = GWG / LWG; + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_ind ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&this->res_val ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &newN ); + + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + +}; + +#endif // FIND_BEST_KERNEL + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgFlat.h b/benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgFlat.h new file mode 100644 index 0000000..c7d0d62 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgFlat.h @@ -0,0 +1,349 @@ +#ifndef GEN_ALG_FLAT +#define GEN_ALG_FLAT + +#include "Constants.h" +#include "GenAlgUtil.h" +#include "Candidate.h" + +#include "IrregShape.h" +#include "UtilGPGPU.h" +#include "EvalGenomeInl.h" + +#include "FindBestKer.h" +#include "MainKer.h" +#include "GenAlgKers.h" + +/** + * Printing Swaption / Calibrated Price / Black Price / RMS + * The result is an array real_t[NUM_SWAP_QUOTES, 3] recording + * for each swaption the calibrated price, the black price + * and the percentagewise difference between the two. + */ +real_t* makeSummary(uint winner, CpuArrays& arrs) { + real_t* res = (real_t*) malloc( 3*NUM_SWAP_QUOTES*sizeof(real_t) ); + + real_t rms = 0.0; + + fprintf(stderr, "\n\nCALIBRATION RESULT: best genome is at index %d: ", winner); + fprintf(stderr, "{ a = %f, b = %f, sigma = %f, nu = %f, rho = %f }, Likelihood: %f!\n", + arrs.get_a() [winner], arrs.get_b() [winner], arrs.get_sigma ()[winner], + arrs.get_nu()[winner], arrs.get_rho()[winner], arrs.get_logLik()[winner] ); + fprintf(stderr, "\nPer-Swaption Approximation w.r.t. Black Price:\n\n"); + + for( int i = 0; i < NUM_SWAP_QUOTES; i ++ ) { + real_t black_price = arrs.get_quote(winner)[i]; + real_t calib_price = arrs.get_price(winner)[i]; + real_t err_ratio = (calib_price - black_price) / black_price; + + res[3*i + 0] = 10000.0*calib_price; + res[3*i + 1] = 10000.0*black_price; + res[3*i + 2] = 100.0*fabs(err_ratio); + + rms += err_ratio * err_ratio; + + fprintf(stderr,"Swaption %d: {{%f, %f, %f},%f}, CalibratedPrice: %f, BlackPrice: %f, DiffPerc: %f\n", + i, SwaptionQuotes[4*i+0], SwaptionQuotes[4*i+1], SwaptionQuotes[4*i+2], SwaptionQuotes[4*i+3], + res[3*i + 0], res[3*i + 1], res[3*i + 2] ); + } + + rms = 100.0 * sqrt ( rms / NUM_SWAP_QUOTES ); + fprintf(stderr, "\n\n Best Genome RMS: %f\n\n", rms); + + return res; +} + + +/** + * Utility function: find the genome with the best likelihood: + * scans the logLik array and fill in the index and likelihood + * of the best genome. + */ +void find_best(const real_t* logLik, int& best_ind, real_t& best_lik) { + bool sanity = true; + + best_lik = -INFINITY; + best_ind = 0; + + // this is in fact a reduction, but POP_SIZE is + // not big enough to warrant a parallel execution. + for ( UINT i = 0; i < POP_SIZE; i++ ) { // parallel reduction with MAX + real_t val = logLik[i]; + + sanity = !( isnan(val) || isinf(val) ); + assert( sanity && "val is NaN in find_best" ); + + if( val > best_lik ) { best_ind = i; best_lik = val; } + } +} + +void find_best_GPU( + FindBestKer& bestker, OclObjects& ocl_objs, + OclBuffers& ocl_arrs, const real_t* logLik, + int& best_ind, real_t& best_lik +) { + bool sanity = true; + + bestker.run(best_ind, best_lik); + + sanity = ! ( isnan(best_lik) || isinf(best_lik) ); + assert( sanity && "val is NaN in find_best" ); +} + +Move_Type selectMoveType(real_t move_selected) { + Move_Type move_type = NONE; + + real_t prob; + Move_Type type; + UINT k = 0; + do { + prob = mcmc_moves_selection_cumdensfct[k].fst; + type = mcmc_moves_selection_cumdensfct[k].snd; + + if( move_selected <= prob ) { + move_type = type; + } + k ++; + } while ( move_selected > prob && k < CUMDENSFCT_CARD ); + + assert(move_type != NONE && "MOVE_TYPE == NONE is ILLEGAL!"); + + return move_type; +} + +/** + * Main Entry Point for Swaption Calibration + * The (out) arguments are in fact the resulted + * winning genome result & its likelihood. + * The array result has size 3*NUM_SWAP_QUOTES + * and records for each swaption the calibrated + * price, the black price and the percentage + * difference between the two. + */ +real_t* mainKernelGPU(real_t& wg_a, + real_t& wg_b, + real_t& wg_sigma, + real_t& wg_nu, + real_t& wg_rho, + real_t& wg_logLik +) { + uint FLAT_SZ; + short* shape = getIregShapeAdjusted( LWG_EG, FLAT_SZ ); + int * start_inds = getStartInd( FLAT_SZ, shape, NUM_SWAP_QUOTES ); + + CpuArrays cpu_arrs(FLAT_SZ, shape); + real_t *g_a, *g_b, *g_rho, *g_nu, *g_sigma, *logLik, *bf_rat; + { // getting the cpu arrays + g_a = cpu_arrs.get_a (); + g_b = cpu_arrs.get_b (); + g_rho = cpu_arrs.get_rho (); + g_nu = cpu_arrs.get_nu (); + g_sigma = cpu_arrs.get_sigma (); + logLik = cpu_arrs.get_logLik(); + bf_rat = cpu_arrs.get_bf_rat(); + } + + OclObjects ocl_objs; OclBuffers ocl_arrs; + { // Initialization of the GPU resources: + initGPUresources ( cpu_arrs, ocl_objs, ocl_arrs ); + } + + FindBestKer bestker ( POP_SIZE, 10*POP_SIZE, ocl_arrs.genomes, + ocl_arrs.best_ind, ocl_arrs.best_val, ocl_objs, 128 ); + MainKer mainker ( cpu_arrs, ocl_arrs, ocl_objs ); + GenAlgKers genalgker( cpu_arrs, ocl_arrs, ocl_objs ); + + srand ( SEED ); + srand48 ( SEED ); + + // initialized the genomes with random numbers inside + // their acceptable bounds => requires 5*POP_SIZE randoms +#if (GPU_VERSION == 2) + genalgker.run_init( ); +#else + + for( int i = 0; i < POP_SIZE; i++ ) { + real_t r01, tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[0] - g_mins[0]) + g_mins[0]; + g_a [i ] = tmp; + g_a [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[1] - g_mins[1]) + g_mins[1]; + g_b [i ] = tmp; + g_b [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[2] - g_mins[2]) + g_mins[2]; + g_rho [i ] = tmp; + g_rho [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[3] - g_mins[3]) + g_mins[3]; + g_nu [i ] = tmp; + g_nu [i + POP_SIZE] = tmp; + + r01 = getRandRandNorm(); + tmp = r01 * ( g_maxs[4] - g_mins[4]) + g_mins[4]; + g_sigma [i ] = tmp; + g_sigma [i + POP_SIZE] = tmp; + + bf_rat [i ] = 1.0; + } +#endif + + // Initial evaluation of the genomes! +#if (GPU_VERSION == 2) + mainker.run (); + genalgker.run_cpLik(); + +#elif (GPU_VERSION == 1) + mainker.run(); + for( int i = 0; i < POP_SIZE; i++ ) { + logLik[i] = logLik[i+POP_SIZE]; + } +#else + fprintf(stderr, "This is GPU only, GPU_VERSION should be set to 1 or 2 in KerConsts.h!"); + exit(1); +#endif + + // sequential loop that runs the genetic algorithms + // (takes a population and returns a population) + for( int j = 0; j < MCMC_LOOPS; j++ ) { + + // select which move to perform: BEGIN + // Note: this block can also be a loop (in fixed order) + // over the various move types + real_t move_selected = getRandUnifNorm(); + Move_Type move_type = selectMoveType(move_selected); + +#if ( GPU_VERSION == 2 && WITH_SOBOL == 0 ) + sobol_offset ++; +#endif + + if ( move_type == DIMS_ALL ) { +#if (GPU_VERSION == 2) + genalgker.run_mutate( 33 ); +#else + for( int i = 0; i < POP_SIZE; i++ ) { + mutate_dims_all( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); // default ampl_ratio + } +#endif + + } else if ( move_type == DIMS_ONE ) { + + UINT dim_j = getRandIntNorm(GENOME_DIM); + +#if (GPU_VERSION == 2) + #if (WITH_SOBOL == 0) + sobol_offset++; + #endif + genalgker.run_mutate( dim_j ); +#else + for( int i = 0; i < POP_SIZE; i++ ) { + mutate_dims_one( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i, dim_j ); // default ampl_ratio + } +#endif + } else /* if ( move_type == DEMCMC ) */ { +#if (GPU_VERSION == 2) + genalgker.run_McMcDc( ); +#else + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel modulo random nums + mcmc_DE( g_a, g_b, g_rho, g_nu, g_sigma, bf_rat, i ); + } +#endif + } + + // evaluate the proposal +#if (GPU_VERSION == 2 || GPU_VERSION == 1) + mainker.run(); +#else + fprintf(stderr, "This is GPU only, GPU_VERSION should be set to 1 or 2 in KerConsts.h!"); + exit(1); +#endif + + // mcmc_acceptance_rejection(); + // Deciding whether to accept or reject the proposal, + // obtained by mutating/crossover of the individual. +#if (GPU_VERSION == 2) + genalgker.run_accept_cond( ); + genalgker.run_accept_prop( ); +#else + for ( int i = 0; i < POP_SIZE; i++ ) { // parallel + // Metropolis: get a random U[0,1) for each candidate + // rand=N.random.uniform() + real_t rand = getRandUnifNorm(); + + // selection: dimensions considered independent + // acceptance = min( 1, N.exp(c.logLik_proposal-c.logLik) * c.backward_forward_ratio ) + real_t acceptance = std::min( 1.0, exp( logLik[i+POP_SIZE] - logLik[i] ) * bf_rat[i] ); + + // if acceptance criterion is met then p->p' else does nothing + if ( rand < acceptance ) accept( i, g_a, g_b, g_rho, g_nu, g_sigma, logLik ); + } +#endif + + // print best candidate for the current iteration: +#if (GPU_VERSION == 2) + if ( (j % 16) == 0 ) { + int best_ind; real_t best_lik; + find_best_GPU( bestker, ocl_objs, ocl_arrs, logLik, best_ind, best_lik ); + fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", + j, best_lik, best_ind ); + } +#else + if ( (j % 16) == 0 ){ + int best_ind; real_t best_lik; + find_best(logLik, best_ind, best_lik); + fprintf(stderr, "\n Iteration: %d: Best Likelihood: %f, genome index: %d!\n", + j, best_lik, best_ind ); + } +#endif + } + +#if (GPU_VERSION == 2) + { // copy back genomes + uint cur_size = 12 * POP_SIZE * sizeof(real_t); + uint ciErr; + cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); + ciErr = clEnqueueReadBuffer(cmd_queue, ocl_arrs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); + oclCheckError( ciErr, CL_SUCCESS ); + } +#endif + + real_t* result; + { // print best candidate for the current iteration: + int best_ind; real_t best_lik; + find_best(logLik, best_ind, best_lik); + + // recompute the calibrated price and the black price sequentially! + logLik[best_ind] = + eval_genome( g_a[best_ind], g_b[best_ind], g_rho[best_ind], g_nu[best_ind], + g_sigma[best_ind], cpu_arrs.get_quote(best_ind), + cpu_arrs.get_price(best_ind), FLAT_SZ, shape, start_inds ); + + // Finally, make/print the result! + wg_a = cpu_arrs.get_a() [best_ind]; + wg_b = cpu_arrs.get_b() [best_ind]; + wg_sigma = cpu_arrs.get_sigma ()[best_ind]; + wg_nu = cpu_arrs.get_nu() [best_ind]; + wg_rho = cpu_arrs.get_rho() [best_ind]; + wg_logLik = cpu_arrs.get_logLik()[best_ind]; + + result = makeSummary( best_ind, cpu_arrs ); + } + + delete[] start_inds; + + // Releasing the GPU resources: + releaseGPUresources ( ocl_objs, ocl_arrs ); + + // Releasing the CPU resources: + cpu_arrs.releaseResources(); + + return result; +} + +#endif // end ifndef + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgKers.h b/benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgKers.h new file mode 100644 index 0000000..d45486a --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/GenAlgKers.h @@ -0,0 +1,297 @@ +#ifndef GEN_ALG_KERNELS +#define GEN_ALG_KERNELS + +#include "SDK_stub.h" +#include "Constants.h" + +class GenAlgKers { + private: + size_t LWG[3]; + size_t GWG[3]; + + const uint lwg; +// uint sobol_offset; + + CpuArrays cpu_arrs; + OclBuffers gpu_buffs; + OclObjects ocl_objs; + + // resources owned by this kernel + cl_kernel init_ker; + cl_kernel cplik_ker; + cl_kernel accnd_ker; + cl_kernel acprp_ker; + cl_kernel mutat_ker; + cl_kernel mcde_ker; + + public: + GenAlgKers( const CpuArrays & arrs, + const OclBuffers& buffs, + const OclObjects& objs + ) : cpu_arrs(arrs), gpu_buffs(buffs), ocl_objs(objs), lwg( mkLWG(POP_SIZE) ) + { + //sobol_offset = 1; + + bool valid = (POP_SIZE >= 32) && (POP_SIZE <= 512); + assert( valid && "Population size NOT in range [32, 512]!" ); + init_ker = mkInitKernel (); + cplik_ker = mkCpLiKernel (); + accnd_ker = mkAcceptCondKernel (); + acprp_ker = mkAcceptPropKernel (); + mutat_ker = mkMutateDimKernel (); + mcde_ker = mkMcMcDcKernel (); + } + + virtual ~GenAlgKers() { + clReleaseKernel( init_ker); + clReleaseKernel(cplik_ker); + clReleaseKernel(accnd_ker); + clReleaseKernel(acprp_ker); + clReleaseKernel(mutat_ker); + clReleaseKernel( mcde_ker); + } + + void run_init( ) { + cl_int ciErr1; + + LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; + GWG[0] = lwg; GWG[1] = 6; GWG[2] = 1; + + // set the index of the next random number! + ciErr1 |= clSetKernelArg( init_ker, 3, sizeof(uint), &sobol_offset ); + oclCheckError(ciErr1, CL_SUCCESS); + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + init_ker, 2, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + oclCheckError(ciErr1, CL_SUCCESS); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + sobol_offset += (5 * POP_SIZE); + } + + void run_cpLik( ) { + cl_int ciErr1; + + LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; + GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + cplik_ker, 1, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + } + + void run_accept_cond( ) { + cl_int ciErr1; + + LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; + GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; + + // set the index of the next random number! + ciErr1 |= clSetKernelArg( accnd_ker, 3, sizeof(uint), &sobol_offset); + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + accnd_ker, 1, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + + sobol_offset += (1 * POP_SIZE); + } + + void run_accept_prop( ) { + cl_int ciErr1; + + LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; + GWG[0] = lwg; GWG[1] = 6; GWG[2] = 1; + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + acprp_ker, 2, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + } + + // IF dim_j > 4 then is a mutate_all! + void run_mutate( const uint dim_j ) { + cl_int ciErr1; + + LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; + GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; + + // set the index of the next random number! + ciErr1 |= clSetKernelArg( mutat_ker, 3, sizeof(uint), &sobol_offset); + ciErr1 |= clSetKernelArg( mutat_ker, 4, sizeof(uint), &dim_j); + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + mutat_ker, 1, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + + sobol_offset += (5 * POP_SIZE); + } + + void run_McMcDc( ) { + cl_int ciErr1; + + LWG[0] = lwg; LWG[1] = 1; LWG[2] = 1; + GWG[0] = lwg; GWG[1] = 1; GWG[2] = 1; + + // set the index of the next random number! + ciErr1 |= clSetKernelArg( mcde_ker, 3, sizeof(uint), &sobol_offset); + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + mcde_ker, 1, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + + sobol_offset += (8 * POP_SIZE); + } + + + private: + + uint mkLWG( const uint Npop ) { + if( (Npop % WARP) == 0 ) return Npop; + else return (Npop / WARP + 1) * WARP; + } + + cl_kernel mkInitKernel ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "init_genome", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gene_ranges ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkCpLiKernel ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "copyLogLik", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkAcceptCondKernel ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "accept_cond", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accept_cond ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkAcceptPropKernel ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "accept_prop", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accept_cond ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkMutateDimKernel ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + uint dim_j = 7; + + + kernel = clCreateKernel( ocl_objs.program, "mutate_dims", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gene_ranges ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &dim_j ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(real_t), &MOVES_UNIF_AMPL_RATIO ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkMcMcDcKernel ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + const real_t gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM); + const real_t ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO; + + + kernel = clCreateKernel( ocl_objs.program, "mcmc_DE", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gene_ranges ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.sobol_dir_vct ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &sobol_offset ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(real_t), &gamma_avg ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(real_t), &l_ratio ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } +}; + +#endif diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/MainKer.h b/benchmarks/InterestCalib/implementations/cpp_opencl/MainKer.h new file mode 100644 index 0000000..39368db --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/MainKer.h @@ -0,0 +1,223 @@ +#ifndef MAIN_KERNEL +#define MAIN_KERNEL + +#include "SDK_stub.h" +#include "Constants.h" + +class MainKer { + private: + size_t LWG[3]; + size_t GWG[3]; + + CpuArrays cpu_arrs; + OclBuffers gpu_buffs; + OclObjects ocl_objs; + + + // resources owned by this kernel + cl_kernel ker; + cl_kernel ker_red1; + cl_kernel ker_red2; + + public: + MainKer ( const CpuArrays & arrs, + const OclBuffers& buffs, + const OclObjects& objs + ) : cpu_arrs(arrs), gpu_buffs(buffs), ocl_objs(objs) + { +// LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; +// GWG[0] = arrs.SS; GWG[1] = POP_SIZE; GWG[2] = 1; + + ker = mkKernel1 (); + ker_red1 = mkKernel2 (); + ker_red2 = mkKernel3 (); + } + + virtual ~MainKer() { + clReleaseKernel(ker); + clReleaseKernel(ker_red1); + clReleaseKernel(ker_red2); + } + + void run ( ) { + cl_int ciErr1; + + //printf("Before run kernel 1 (LWG,GWG,UNROLL): (%ld,%ld,%d)\n", LWG, GWG, UNROLL); +#if (GPU_VERSION == 1) + copy_in_buffers1(); +#endif + { // run the main, big kernel with local segmented reduction for each local group + LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; + GWG[0] = cpu_arrs.SS; GWG[1] = POP_SIZE; GWG[2] = 1; + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + ker, 3, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + } + + { // run the second segmented reduction kernel + LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; + GWG[0] = cpu_arrs.SS; GWG[1] = NUM_HERMITE; GWG[2] = POP_SIZE; + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + ker_red1, 3, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + } + + { // run the third regular reduction kernel + LWG[0] = LWG_EG; LWG[1] = 1; LWG[2] = 1; + GWG[0] = LWG_EG; GWG[1] = POP_SIZE; GWG[2] = 1; + + ciErr1 = clEnqueueNDRangeKernel ( + ocl_objs.getCommandQueue(), + ker_red2, 3, NULL, this->GWG, this->LWG, + 0, NULL, NULL + ); + ciErr1 |= clFinish( ocl_objs.getCommandQueue() ); + oclCheckError(ciErr1, CL_SUCCESS); + } + +#if (GPU_VERSION == 1) +// copy_out_buffers1(); +// copy_out_buffers2(); + copy_out_buffers3(); +#endif + } + + private: + cl_kernel mkKernel1 ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "eval_genome_main", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.shape ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.swap_quotes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.ci_t1cs_scale ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.new_quote_price); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.scalars ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_SWAP_QUOTES ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &cpu_arrs.SS ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkKernel2 ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "eval_genome_red1", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.shape ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gauss_coefs ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.gauss_weights ); + + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.ci_t1cs_scale ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.scalars ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accum0 ); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_SWAP_QUOTES ); +// ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &POP_SIZE ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &cpu_arrs.SS ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + cl_kernel mkKernel3 ( ) { + cl_kernel kernel; + UINT counter = 0; + cl_int ciErr1; + + kernel = clCreateKernel( ocl_objs.program, "eval_genome_red2", &ciErr1 ); + oclCheckError( ciErr1, CL_SUCCESS ); + + counter = 0; + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.genomes ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.scalars ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.accum0 ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(cl_mem), (void*)&gpu_buffs.new_quote_price); + + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_SWAP_QUOTES ); + ciErr1 |= clSetKernelArg( kernel, counter++, sizeof(uint), &NUM_HERMITE ); + oclCheckError( ciErr1, CL_SUCCESS ); + + return kernel; + } + + + void copy_in_buffers1() { + cl_int ciErr; + size_t cur_size; + cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); + + cur_size = 13 * POP_SIZE * sizeof(real_t); + ciErr |= clEnqueueWriteBuffer(cmd_queue, gpu_buffs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); + + oclCheckError(ciErr, CL_SUCCESS); + } + + void copy_out_buffers1() { + cl_int ciErr; + size_t cur_size; + cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); + + cur_size = 4 * cpu_arrs.SS * POP_SIZE * sizeof(real_t); + ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.ci_t1cs_scale, CL_TRUE, 0, cur_size, cpu_arrs.ci_t1cs_scale, 0, NULL, NULL); + + cur_size = NUM_SWAP_QUOTES * POP_SIZE * sizeof(real_t); // need only to write back the quotes (not the prices) + ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.new_quote_price, CL_TRUE, 0, cur_size, cpu_arrs.new_quote_price, 0, NULL, NULL); + + cur_size = 8 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(real_t); + ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.scalars, CL_TRUE, 0, cur_size, cpu_arrs.scalars, 0, NULL, NULL); + } + + void copy_out_buffers2() { + cl_int ciErr; + size_t cur_size; + cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); + + cur_size = NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE * sizeof(real_t); + ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.accum0, CL_TRUE, 0, cur_size, cpu_arrs.accum0, 0, NULL, NULL); + } + + void copy_out_buffers3() { + cl_int ciErr; + size_t cur_size, offset; + cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); + + cur_size = POP_SIZE * sizeof(real_t); + offset = 11 * POP_SIZE * sizeof(real_t); + ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.genomes, CL_TRUE, offset, cur_size, cpu_arrs.get_logLik() + POP_SIZE, 0, NULL, NULL); + +// cur_size = 13 * POP_SIZE * sizeof(real_t); +// ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); + +// cur_size = 2 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(real_t); // need only to write back the quotes (not the prices) +// ciErr |= clEnqueueReadBuffer(cmd_queue, gpu_buffs.new_quote_price, CL_TRUE, 0, cur_size, cpu_arrs.new_quote_price, 0, NULL, NULL); + } +}; + +#endif // MAIN_KERNEL + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile new file mode 100644 index 0000000..fe484d2 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile @@ -0,0 +1,46 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +# FIXME - this should not even exist! +include $(HIPERMARK_LIB_DIR)/platform.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ + -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ + -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ + -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ + -D CURR_DIR_PATH='"$(MAKE_DIR)"' + +SOURCES_CPP =SwapCalib.cpp +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h +OBJECTS =SwapCalib.o +EXECUTABLE =SwapCalib + + +default: $(EXECUTABLE) + +%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< + +$(EXECUTABLE): $(OBJECTS) + cp -r $(HIPERMARK_IMPLEMENTATION)/SrcCL . + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + ./$(EXECUTABLE) diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/BestIndValRedKer.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/BestIndValRedKer.cl new file mode 100644 index 0000000..a495ff8 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/BestIndValRedKer.cl @@ -0,0 +1,109 @@ +/******************************************************/ +/********* FIND_BEST KERNEL and HELPERS ***************/ +/******************************************************/ + +inline real2_t OP_BEST(real2_t iv1, real2_t iv2) { + return ( ( iv1.y > iv2.y ) ? iv1 : iv2 ); +} + +inline real2_t reduce_best_warp( __local volatile real2_t* sh_data ) { + const uint th_id = get_local_id(0) & (WARP-1); + + if( th_id >= 1 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-1 ] ); + if( th_id >= 2 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-2 ] ); + if( th_id >= 4 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-4 ] ); + if( th_id >= 8 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-8 ] ); +#if (WARP == 32) + if( th_id >= 16 ) sh_data[th_id] = OP_BEST( sh_data[th_id], sh_data[th_id-16] ); +#endif + return sh_data[th_id]; +} + +inline void reduce_best_local ( __local volatile real2_t* sh_data ) { + // perform scan at warp level + real2_t res = reduce_best_warp( sh_data + WARP_FST ); + barrier( CLK_LOCAL_MEM_FENCE ); + + // gather per-warp results in the first WARP elements + if ( TH_ID == WARP_LST ) { + sh_data[ WARP_ID ] = res; + } + barrier(CLK_LOCAL_MEM_FENCE); + + if( TH_ID < WARP ) { + reduce_best_warp( sh_data ); + } + barrier(CLK_LOCAL_MEM_FENCE); +} + + +__kernel void +redbest_ker1 ( + __global real_t *arr, + __global uint *res_ind, + __global real_t *res_val, + uint offset, + uint N, + uint U +) { + __local real2_t locred[ LWG_FB ]; + + arr += offset; + + real2_t seqbest = (real2_t) ( 0.0F, -INFTY ); + + uint i = get_group_id(0) * (U * get_local_size(0)) + get_local_id(0); + + + //uint B = min( i + (U * get_local_size(0)), N ); + uint B = i + (U * get_local_size(0)); + if( B > N ) { B = N; } + + for( ; i < B; i += get_local_size(0) ) { + real2_t cur = (real2_t) ( (real_t)i, arr[i] ); + seqbest = OP_BEST(seqbest, cur); + } + + locred[ get_local_id(0) ] = seqbest; + barrier(CLK_LOCAL_MEM_FENCE); + + reduce_best_local ( locred ); + + if ( get_local_id(0) == get_local_size(0) - 1 ) { + real2_t res = locred[WARP-1]; + res_ind[ get_group_id(0) ] = (uint) res.x; + res_val[ get_group_id(0) ] = res.y; + } +} + +/** + * Assumes we have to reduce exactly one local workgroup. + */ +__kernel void +redbest_ker2 ( + __global uint *arr_ind, + __global real_t *arr_val, + uint N +) { + __local real2_t locred[ LWG_FB ]; + + uint th_id = get_local_id(0); + + if ( th_id >= N ) { + real2_t tmp = (real2_t) ( 0.0F, -INFTY ); + locred[ th_id ] = tmp; + } else { + real2_t tmp = (real2_t) ( (real_t)arr_ind[th_id], arr_val[th_id] ); + locred[ th_id ] = tmp; + } + + barrier(CLK_LOCAL_MEM_FENCE); + reduce_best_local( locred ); + + if ( th_id == get_local_size(0) - 1 ) { + real2_t res = locred[ WARP-1 ]; + arr_ind[ 0 ] = (uint) res.x; + arr_val[ 0 ] = res.y; + } +} + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/CalibKers.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/CalibKers.cl new file mode 100644 index 0000000..46fc053 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/CalibKers.cl @@ -0,0 +1,467 @@ +// BOP is a generic binary associative operator, +// e.g., +, *, AND, OR +//#define BOP(a,b) ( (a)+(b) ) + +#include "real.h" +#include "KerConsts.h" + +#define TH_ID (get_local_id(0)) +#define WARP_ID (TH_ID >> lgWARP) +#define WARP_FST (WARP_ID << lgWARP) +#define WARP_LST (WARP_FST + (WARP-1)) + +inline real_t minR(real_t a, real_t b) { return ( (a <= b) ? a : b ); } +inline real_t maxR(real_t a, real_t b) { return ( (a <= b) ? b : a ); } + +#include "GenAlg.cl" +#include "BestIndValRedKer.cl" + +/******************************************************/ +/********* EVAL_GENOME KERNELS and HELPERS ************/ +/******************************************************/ + +/** Assumes global shape has the following layout: + * 1. flags, i.e., 1 if start of segment, -1 if iddle thread, and 0 otherwise + * 2. iota(n_schedi) + * 3. the swaption index + * 4. the size of the current segment + * Local shape has the following structure: + * 1. flags as uchar, where 1 denote the start of a segment, + * 2. cond as uchar, where 0 denotes thread is active, + * 3. index as short in iota(n_schedi), + * 4. swaption's global index as short + * 5. size fo the current segment as short + */ +inline +bool fillShapeMeta(__global short* shape, + __local short* sh_mem, + uint Nshp +) { + bool iddle = false; + uint loc_ind = TH_ID, glb_ind = get_global_id(0); // ignore global dimension 1 + short tmp = shape[ glb_ind ]; + + { // fill the boolean part! + __local uchar* shape_meta = (__local uchar*) sh_mem; + + shape_meta[ loc_ind ] = ( tmp != 0 ) ? (uchar) 1 : (uchar) 0; + loc_ind += get_local_size(0); + shape_meta[ loc_ind ] = (uchar) 0; + } + + glb_ind += Nshp; + sh_mem[ loc_ind ] = shape[ glb_ind ]; // setting iota(n_schedi) + + loc_ind += get_local_size(0); + glb_ind += Nshp; + sh_mem[ loc_ind ] = shape[ glb_ind ]; // setting the swaption index + + loc_ind += get_local_size(0); + glb_ind += Nshp; + tmp = shape[ glb_ind ]; + if( tmp < 0 ) { iddle = true; tmp = -tmp; } + sh_mem[loc_ind] = tmp; + + barrier(CLK_LOCAL_MEM_FENCE); + return iddle; +} + +inline +short getIotaInd (__local short* shape) { + return shape[ TH_ID + get_local_size(0) ]; +} +inline +short getSwapGlbInd(__local short* shape) { + return shape[ (get_local_size(0) << 1) + TH_ID ]; +} +inline +short getSwapLocInd(__local short* shape) { + short res = getSwapGlbInd(shape) - shape[ get_local_size(0) << 1 ]; + return res; +} +inline +short getSgmSize (__local short* shape ) { + return shape[ (get_local_size(0) << 1) + get_local_size(0) + TH_ID ]; +} + +#include "Date.cl" +#include "G2ppUtil.cl" +#include "Reductions.cl" +#include "ExactYhat.cl" + + +/** + * Two-dimensional kernel: + * 1. the outer dimension is POP_SIZE, + * 2. the inner dimension is Nshp, i.e., an approximation + * (with idde threads) of the flattened parallelism + * of the loop of count `NUM_SWAP_QUOTES'. + */ + +__kernel __attribute__((reqd_work_group_size(LWG_EG, 1, 1))) +void eval_genome_main ( + __global short *glb_shape, + __global real_t *SwaptionQuotes, + __global real_t *genomes, + __global real_t *glb_arrs, // ci ++ t1_cs ++ scale ++ bbi + __global real_t *new_quote_price, // [POP_SIZE * NUM_SWAP_QUOTES * 2] + __global real_t *interm_scalars, // [POP_SIZE * NUM_SWAP_QUOTES * 8] + // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, + // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } + uint Nswap, + uint Npop, + uint Nshp +) { + real4_t tmp4; + + __local short shape_meta [ (LWG_EG << 2) ]; + __local real4_t sh_mem4 [ LWG_EG + (LWG_EG >> 1) ]; + + bool iddle = fillShapeMeta( glb_shape, shape_meta, Nshp ); + + real_t swap_freq = 1.0, maturity = 1.0, tmat0 = 1.0; uint n_schedi; + if( !iddle ) { + int ttt = getSwapGlbInd(shape_meta); + swap_freq = SwaptionQuotes[ (ttt<<2) + 1 ]; + maturity = add_years( TODAY, SwaptionQuotes[ (ttt<<2) ] ); + n_schedi = (uint) (12.0 * SwaptionQuotes[ (ttt<<2) + 2 ] / swap_freq); + tmat0 = date_act_365( maturity, TODAY ); + } + + real_t strike, beg_date, end_date; + { // BLACK PRICE COMPUTATION. + __local uchar* flags = (__local uchar*) shape_meta; + + tmp4 = (real4_t) (0.0, MAX_DATE, MIN_DATE, 1.0); + if(!iddle) { + tmp4.w = (real_t) getIotaInd(shape_meta); // i + tmp4.y = add_months( maturity, swap_freq*tmp4.w ); // t0 + tmp4.z = add_months( tmp4.y, swap_freq ); // tn + tmp4.x = zc(tmp4.z) * date_act_365(tmp4.z,tmp4.y); // lvl + } + beg_date = tmp4.y; end_date = tmp4.z; + + sh_mem4[ TH_ID ] = tmp4; + barrier(CLK_LOCAL_MEM_FENCE); + segm_reduce_plusminmax( sh_mem4, flags ); // ToDo 2 + + int last_ind = TH_ID - getIotaInd( shape_meta ); + if(!iddle) last_ind += n_schedi - 1; + tmp4 = sh_mem4[last_ind]; // the reduction result! + barrier(CLK_LOCAL_MEM_FENCE); + + strike = ( zc(tmp4.y) - zc(tmp4.z) ) / tmp4.x; + if( flags[TH_ID] && (!iddle) ) { + // if thread is the start of a segment + // write new_quote to global memory! + int ttt = getSwapGlbInd(shape_meta); + tmp4.y = 0.5 * SwaptionQuotes[ (ttt<<2) + 3 ] * tmat0; + // was get_group_id(1) + new_quote_price[ get_global_id(1)*Nswap + ttt ] = + tmp4.x * strike * ( uGaussian_P(tmp4.y) - uGaussian_P(-tmp4.y) ); + } + } // END BLACK PRICE. + + { // PRICER OF SWAPTION COMPUTATION + + real_t y0, y1, eps, eps_contrib, mux, t4, t1_cs_first; + { + real_t a, b, rho, nu, sigma; + { + uint tmp_ind = get_global_id(1) + Npop; + uint Npop2 = (Npop << 1); + a = genomes[ tmp_ind ]; tmp_ind += Npop2; + b = genomes[ tmp_ind ]; tmp_ind += Npop2; + rho = genomes[ tmp_ind ]; tmp_ind += Npop2; + nu = genomes[ tmp_ind ]; tmp_ind += Npop2; + sigma = genomes[ tmp_ind ]; tmp_ind += Npop2; + } +// + { + real_t v0_mat, v0_end, vt_end, baii, bbii, tmp; + tmp4 = bigv( a, b, rho, nu, sigma, tmat0 ); + v0_mat = tmp4.x; +// + tmp = date_act_365(end_date, TODAY); + tmp4 = bigv( a, b, rho, nu, sigma, tmp ); + v0_end = tmp4.x; +// + tmp = date_act_365(end_date, maturity); + tmp4 = bigv( a, b, rho, nu, sigma, tmp ); + vt_end = tmp4.x; + //baii = tmp4.y; + //bbii = tmp4.z; + tmp4.w = 0.5 * ( vt_end - v0_end + v0_mat ); // expo_aici + tmp4.x = date_act_365( end_date, beg_date ) * strike; // res + } +// + { + //bool is_first = ((__local uchar*)shape_meta)[TH_ID] && (!iddle); + bool is_first = (!iddle) && ( (TH_ID == get_local_size(0)-1) || (((__local uchar*)shape_meta)[TH_ID+1]==1) ); // actually is_last! + real_t muy, rhoxy, sigmax, sigmay, rhoxyc, rhoxycs, zc_mat, tmp1, tmp2; + uint gind = get_global_id(1)*Nswap + getSwapGlbInd(shape_meta), offset = Npop*Nswap; // was get_group_id(1) +// + mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); + if(is_first) interm_scalars[ gind ] = mux; gind += offset; +// + muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); + if(is_first) interm_scalars[ gind ] = muy; gind += offset; +// + tmp1 = sqrt( (real_t)b_fun(2.0*a, tmat0) ); // sqrt_bfun_a + sigmax = sigma * tmp1; + if(is_first) interm_scalars[ gind ] = sqrt((real_t)2.0) * sigmax; gind += offset; +// + tmp2 = sqrt( (real_t)b_fun(2.0*b, tmat0) ); // sqrt_bfun_b + sigmay = nu * tmp2; + rhoxy = rho * b_fun(a+b, tmat0) / (tmp1 * tmp2); + t4 = (rhoxy * sigmay) / sigmax; +// + rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel + rhoxycs = sqrt( (real_t)rhoxyc ); // used in reduction kernel + if(is_first) interm_scalars[ gind ] = rhoxy / (sigmax*rhoxycs); gind += offset; + if(is_first) interm_scalars[ gind ] = sigmay * rhoxycs; gind += offset; +// + zc_mat = zc(maturity); + if(is_first) tmp4.x += 1.0; //cii + tmp4.x *= zc(end_date) / zc_mat; // fact_aici + if(is_first) interm_scalars[ gind ] = zc_mat; gind += offset; +// + t1_cs_first = tmp4.z * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*tmp4.z) ); + eps = 0.5 * sigmax; + eps_contrib = sigmay * (rhoxy * eps / sigmax); + y0 = sigmay * KKK * rhoxycs; + y1 = muy - y0; + y0 += muy - ( rhoxyc / b ); + } + } + + { + { // save to global arrays, ci, t1_cs, scale, bbi, and + // store (aici, baii, bbii, log_aici) in tmp4! + uint gind = get_global_id(1) * Nshp + get_global_id(0), offset = Nshp * Npop; + real_t fact_aici = tmp4.x; + + if( !iddle ) glb_arrs[gind] = fact_aici; gind += offset; // ci [i] + if( !iddle ) glb_arrs[gind] = t1_cs_first + tmp4.w; gind += offset; // t1_cs[i] + if( !iddle ) glb_arrs[gind] = - ( tmp4.y + tmp4.z * t4 ); gind += offset; // scale[i] + if( !iddle ) glb_arrs[gind] = tmp4.z; // bbi [i] + + tmp4.x *= exp(tmp4.w); // aici + tmp4.w += log(fact_aici); // log_aici + + sh_mem4[ TH_ID ] = tmp4; + barrier(CLK_LOCAL_MEM_FENCE); + } + + { // finally call `exactYhat', and store `f' and `df' to global memory. + real_t f, g, h, df; + uint gind = getSwapGlbInd(shape_meta); + __local uchar* flags = (__local uchar*)shape_meta; + //uint n_schedi = (iddle) ? 1 : (uint)(12.0 * SwaptionQuotes[ (gind<<2) + 2 ] / swap_freq); + + f = exactYhat( iddle, flags, n_schedi, y0, y1, sh_mem4, mux ); + + if( flags[TH_ID] && (!iddle) ) { // start of segment + uint offset = Npop*Nswap; + gind += get_global_id(1)*Nswap + 6*offset; // was get_group_id(1) + interm_scalars[ gind ] = f; + gind += offset; + } + + y0 += eps_contrib; + y1 += eps_contrib; + mux+= eps; + g = exactYhat( iddle, flags, n_schedi, y0, y1, sh_mem4, mux ); + + y0 -= 2.0*eps_contrib; + y1 -= 2.0*eps_contrib; + mux-= 2.0*eps; + h = exactYhat( iddle, flags, n_schedi, y0, y1, sh_mem4, mux ); + + if( flags[TH_ID] && (!iddle) ) { // start of segment + interm_scalars[ gind ] = 0.5 * ( g - h ) / eps; // i.e., df + } + } + } + } +} + +/********************************************************/ +/*************** Main Reduction kernel 1 ****************/ +/********************************************************/ +/** + * Two-dimensional kernel: + * 1. the outermost dimension is POP_SIZE, + * 2. the middle dimension is Gauss_DIM + * 2. the inner dimension is Nshp, i.e., an approximation + * (with idde threads) of the flattened parallelism + * of the loop of count `NUM_SWAP_QUOTES'. + */ + +__kernel __attribute__((reqd_work_group_size(LWG_EG, 1, 1))) +void eval_genome_red1 ( + __global short *glb_shape, + __constant real_t *gauss_coefs, // [Gauss_DIM] + __constant real_t *gauss_weights, // [Gauss_DIM] + + __global real_t *glb_arrs, // ci ++ t1_cs ++ scale ++ bbi + __global real_t *interm_scalars, // [POP_SIZE * NUM_SWAP_QUOTES * 8] + // { mux, muy, sqrt_sigmax = sqrt((real_t)2.0) * sigmax, + // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } + + __global real_t *accum0, // [ POP_SIZE * NUM_SWAP_QUOTES * Gauss_DIM ] + + uint Nswap, + uint Nshp +) { + __local short shape_meta [ LWG_EG << 2 ]; + __local real_t sh_mem [ LWG_EG ]; + + bool iddle; + { + iddle = fillShapeMeta( glb_shape, shape_meta, Nshp ); + } + + real_t x_quad = gauss_coefs [get_global_id(1)]; + + real_t sigmay_rhoxycs, x, h1; + if(!iddle){ + real_t mux, muy, sqrt2sigmax, t2, f, df, yhat_x; // Npop == POP_SIZE = get_global_size(2) + uint gind = get_global_id(2) * Nswap + getSwapGlbInd(shape_meta), offset = get_global_size(2) * Nswap; + + mux = interm_scalars[ gind ]; gind += offset; + muy = interm_scalars[ gind ]; gind += offset; + + // x = sqrt2sigmax * x_quad + mux; + sqrt2sigmax = interm_scalars[ gind ]; gind += offset; // + x = sqrt2sigmax * x_quad + mux; + + t2 = interm_scalars[ gind ]; gind += offset; + + sigmay_rhoxycs = interm_scalars[ gind ]; gind += offset + offset; + f = interm_scalars[ gind ]; gind += offset; + df = interm_scalars[ gind ]; + + yhat_x = f + df*(x - mux); + h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); + } + + if(!iddle){ + uint gind = get_global_id(2) * Nshp + get_global_id(0), offset = Nshp * get_global_size(2); + gind += 3 * offset; + real_t bbi = glb_arrs[gind]; gind -= offset; + real_t h2 = h1 + bbi * sigmay_rhoxycs; + + real_t scale = glb_arrs[gind]; gind -= offset; + real_t t1_cs = glb_arrs[gind]; gind -= offset; + real_t expo_aici = t1_cs + scale*x; + + real_t expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); + + x = glb_arrs[gind] * expo_part; + } + + { // segmented reduce with operator plus the x's + + __local uchar* flags = (__local uchar*) shape_meta; + bool is_last = (!iddle) && ( (TH_ID == get_local_size(0)-1) || ( flags[TH_ID+1] == 1) ); + + sh_mem[TH_ID] = (iddle) ? 0.0 : x; + barrier(CLK_LOCAL_MEM_FENCE); + + segm_reduce_plus( sh_mem, flags ); + + if( is_last ) { + real_t accum = sh_mem[TH_ID]; + real_t tmp = sqrt((real_t)2.0) * x_quad; //(x - mux) / sigmax; + tmp = exp( (real_t)- 0.5 * tmp * tmp ); + + real_t w_quad = gauss_weights[get_global_id(1)]; + + real_t res = w_quad * tmp * ( uGaussian_P(-h1) - accum ); + + //uint GaussDIM = get_global_size(1); +#if 0 + uint gind = get_global_id(2) * get_global_size(1) * Nswap + + getSwapGlbInd(shape_meta) * get_global_size(1) + get_global_id(1) ; + accum0[gind] = res; +#else + // accum0 is put it in transposed form, i.e., + // accum0[ j * Nswap + ttt ] and is used in + // this way by the next kernel + uint gind = get_global_id(2) * get_global_size(1) * Nswap + + get_global_id(1) * Nswap + getSwapGlbInd(shape_meta); + accum0[gind] = res; +#endif + } + } +} + + + +/********************************************************/ +/*************** Main Reduction kernel 2 ****************/ +/********************************************************/ +inline real_t cauchy_pdf( real_t z, real_t mu, real_t gamma ) { + real_t x = (z-mu) / gamma; + return 1.0 / ( PI * gamma * (1.0+x*x) ); +} +inline real_t logLikelihood_cauchy( real_t y_ref, real_t y ) { + real_t LLHOOD_CAUCHY_OFFS = 5.0; + real_t gamma = ( fabs(y_ref) / 50.0 ) * LLHOOD_CAUCHY_OFFS + 0.01; + real_t pdfs = cauchy_pdf( y, y_ref, gamma ); + pdfs += 1.0e-20; // avoid NaNs + return log(pdfs); +} + +/** + * Two-dimensional kernel: + * 1. the outermost global dimension is POP_SIZE, + * 2. the innermost global dimension is equal to the local + * dimension, i.e., LWG_EG, which is an overapproximation + * of NUM_SWAP_QUOTES. + * Each local groups process exactly NUM_SWAP_QUOTES elements, + * and the rest of the htreads are iddle. + * This is taking a shortcut to implement reduce in a regular fashion. + */ + +__kernel __attribute__((reqd_work_group_size(LWG_EG, 1, 1))) +void eval_genome_red2 ( + __global real_t *genomes, + __global real_t *interm_scalars, // [POP_SIZE * NUM_SWAP_QUOTES * 8] + // { mux, muy, sqrt_sigmax = sqrt((real_t)2.0) * sigmax, + // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } + __global real_t *accum0, // [ POP_SIZE * NUM_SWAP_QUOTES * Gauss_DIM ] + __global real_t *new_quote_price, // [POP_SIZE * NUM_SWAP_QUOTES * 2] + + uint Nswap, + uint GaussDIM +) { + __local real_t sh_mem [ LWG_EG ]; + + bool iddle = ( TH_ID >= Nswap ); + + real_t lik = 0.0; + if (!iddle) { + real_t accum = 0.0; + uint gid = get_global_id(1) * GaussDIM * Nswap + get_global_id(0); + for( uint j = 0; j < GaussDIM; j++, gid += Nswap ) { + accum += accum0[ gid ]; + } + + gid = get_global_id(1) * Nswap + TH_ID; + real_t zc_mat = interm_scalars[ gid + (5 * get_global_size(1) * Nswap) ]; + + real_t nprice = zc_mat * ( accum / sqrt( PI ) ); + new_quote_price[ gid + get_global_size(1)*Nswap ] = nprice; + + lik = logLikelihood_cauchy( new_quote_price[gid], nprice ); + } + + sh_mem[ TH_ID ] = lik; + barrier(CLK_LOCAL_MEM_FENCE); + + real_t rms = reduce_reg_plus( sh_mem ); + + if(TH_ID == 0) genomes[ 11*get_global_size(1) + get_global_id(1) ] = rms; +} diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Date.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Date.cl new file mode 100644 index 0000000..7159857 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Date.cl @@ -0,0 +1,147 @@ +////////////////////////////////////////////////////// +//// Date: Gregorian calendar +////////////////////////////////////////////////////// +#ifndef GREG_CALEND +#define GREG_CALEND + +#define MINUTES_IN_DAY 1440 // hours_in_day * 60; +#define MINUTES_TO_NOON 720 // (hours_in_day / 2) * 60; + +typedef struct DDD{ + int year; + int month; + int day; + int hour; + int min; +} Date; + +Date mkDate(int y, int mo, int d, int h, int mn) { + Date date; + date.year = y; + date.month = mo; + date.day = d; + date.hour = h; + date.min = mn; + return date; +} + +inline +int MOD(int x, int y) { + return ( x - (x/y)*y ); +} + +inline +int date_of_gregorian( Date date ) { + int ym; + if(date.month == 1 || date.month == 2) { + ym = ( 1461 * ( date.year + 4800 - 1 ) ) / 4 + + ( 367 * ( date.month + 10 ) ) / 12 - + ( 3 * ( ( date.year + 4900 - 1 ) / 100 ) ) / 4; + } else { + ym = ( 1461 * ( date.year + 4800 ) ) / 4 + + ( 367 * ( date.month - 2 ) ) / 12 - + ( 3 * ( ( date.year + 4900 ) / 100 ) ) / 4; + } + + int tmp = ym + date.day - 32075 - 2444238; + + return tmp * MINUTES_IN_DAY + date.hour * 60 + date.min; +} + +inline +Date gregorian_of_date ( int minutes_since_epoch ) { + int jul, l, n, i, j, d, m, y, daytime; + + jul = minutes_since_epoch / MINUTES_IN_DAY; + l = jul + 68569 + 2444238; + n = ( 4 * l ) / 146097; + l = l - ( 146097 * n + 3 ) / 4; + i = ( 4000 * ( l + 1 ) ) / 1461001; + + l = l - ( 1461 * i ) / 4 + 31; + j = ( 80 * l ) / 2447; + d = l - ( 2447 * j ) / 80; + l = j / 11; + + m = j + 2 - ( 12 * l ); + y = 100 * ( n - 49 ) + i + l; + + daytime = MOD( minutes_since_epoch, MINUTES_IN_DAY ); + +// if ( daytime == MINUTES_TO_NOON ) return Date(y,m,d,12,0); +// else return Date(y,m,d, daytime / 60, MOD(daytime, 60)); + + return mkDate(y,m,d, daytime / 60, MOD(daytime, 60)); +} + +inline +bool check_date(int year, int month, int day) { + bool tmp1, tmp2, tmp3; + + tmp1 = ( 1 <= day && 1 <= month && month <= 12 && 1980 <= year && year <= 2299 ); + tmp2 = ( day <= 28 ); + + if ( month == 2 ) { + tmp3 = ( day == 29 && MOD(year, 4) == 0 && ( year == 2000 || (! (MOD(year, 100) == 0)) ) ); + } else if ( month == 4 || month == 6 || month == 9 || month == 11 ) { + tmp3 = ( day <= 30 ); + } else { + tmp3 = ( day <= 31 ); + } + + return tmp1 && (tmp2 || tmp3); +} + +inline +real_t days_between(real_t t1, real_t t2) { + return ( (t1 - t2) / MINUTES_IN_DAY ); +} + +inline +real_t date_act_365(real_t t1, real_t t2) { + return ( days_between(t1, t2) / 365.0F ); +} + +inline +bool leap(int y) { + return ( MOD(y,4) == 0 && ( ( MOD(y,100)!=0 ) || (MOD(y,400)==0) ) ); +} + +inline +int end_of_month( int year, int month ) { + bool leap_year = leap(year); + if ( month == 2 && leap_year ) return 29; + else if ( month == 2 ) return 28; + else if ( month == 4 || month == 6 || month == 9 || month == 11 ) return 30; + else return 31; +} + +inline +real_t add_months ( real_t time, real_t rnbmonths ) { + int nbmonths = convert_int(rnbmonths); //(int) rnbmonths; + Date date = gregorian_of_date( convert_int( time ) ); + + date.month += nbmonths; + date.year += (date.month-1) / 12; + date.month = MOD( date.month-1, 12 ) + 1; + + if ( date.month <= 0 ) { date.year -= 1; date.month += 12; } + + { // date.day = min( date.day, end_of_month(date.year, date.month) ); + int tmp = end_of_month(date.year, date.month); + if(date.day > tmp) date.day = tmp; + } + + date.hour = 12; + date.min = 0; + + return (real_t) ( date_of_gregorian( date ) ); +} + +inline +real_t add_years( real_t date, real_t nbyears ) { + return add_months( date, nbyears * 12.0F ); +} + +#endif // ifndef GREG_CALEND + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/ExactYhat.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/ExactYhat.cl new file mode 100644 index 0000000..c054fd9 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/ExactYhat.cl @@ -0,0 +1,314 @@ +// reduction with + +real_t to_solve( bool iddle, + uint n_schedi, + __local uchar* flags, + __local real_t * sh_mem, + + real_t scale, + real_t bbi, + real_t yhat +) { + real_t accum; + sh_mem[TH_ID] = (iddle) ? 0.0 : scale * exp( - bbi * yhat ); + barrier(CLK_LOCAL_MEM_FENCE); + + segm_reduce_plus( sh_mem, flags ); // ToDo 2 + + int last_ind = TH_ID - getIotaInd( (__local short*)flags ); + if(!iddle) last_ind += n_schedi - 1; + + accum = sh_mem[last_ind]; + barrier(CLK_LOCAL_MEM_FENCE); + + return accum - 1.0; +} + + +/** + * root finding by Brent's method. + */ +//real2_t tmp2 = rootFinding_Brent(iddle, shape, sh_mem4, scales, uplo.y, uplo.x, 1.0e-4, 1000); +//rootFinding_Brent(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); +inline +real2_t rootFinding_Brent( bool iddle, + uint n_schedi, + __local uchar* flags, + __local real_t * sh_mem, + real_t bbi, //sh_mem4[TH_ID].z; + real_t scale, + real_t a, //lb, + real_t b, //ub, + real_t tol, + uint iter_max + // (root, fb) : (real_t, real_t) +) { + real2_t res; + + real_t fa = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, a); + real_t fb = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, b); + + if( (!iddle) && fa*fb >= 0.0 ) { + res.x = 0.0; + res.y = ( a >= 0.0 ) ? INFTY : -INFTY; + iddle = true; + } + + if( fabs(fa) < fabs(fb) ) { real_t tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } + + real_t c = a, fc = fa; + bool mflag = true; + real_t d = 0.0; + + uchar ok = 0; int i = 0; + do { + { // reduce with && global termination + ok = ( fb == 0.0 || fabs(b-a) < tol || i >= iter_max ); + + if( ok ) { + if( !iddle ) { + res.x = b; + res.y = fb; + } + iddle = true; + } + + flags[TH_ID+get_local_size(0)] = iddle; + barrier(CLK_LOCAL_MEM_FENCE); + ok = reduce_reg_and( flags + get_local_size(0) ); + //barrier(CLK_LOCAL_MEM_FENCE); + } + i ++; + + // the loop's body + if( !ok ) { + real_t s; + if( !iddle ) { + if( fa == fc || fb == fc ) { + s = b - fb * (b - a) / (fb - fa); + } else { + real_t s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); + real_t s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); + real_t s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); + s = s1 + s2 + s3; + } + + bool big_cond = + ( (3.0 * a + b) /4.0 > s || s > b) || + ( mflag && fabs(b-c)/2.0 <= fabs(s-b) ) || + ( !mflag && fabs(c-d)/2.0 <= fabs(s-b) ) || + ( mflag && fabs(b-c) <= fabs(tol) ) || + ( !mflag && fabs(c-d) <= fabs(tol) ) ; + + if ( big_cond ) { + mflag = true; + s = (a + b) / 2.0; + } else { + mflag = false; + } + } + real_t fs = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, s); + + if( !iddle ) { + // d is assigned for the first time here: + // it's not used above because mflag is set + d = c; + c = b; fc = fb; + + if( fa*fs < 0.0 ) { b = s; fb = fs; } + else { a = s; fa = fs; } + + if( fabs(fa) < fabs(fb) ) { + real_t tmp; + tmp = a; a = b; b = tmp; + tmp = fa; fa = fb; fb = tmp; + } + } + } + } while (!ok); + + return res; +} + + +/*********************************************/ +/*********************************************/ + +inline +real2_t rootBisection( bool iddle, + uint n_schedi, + __local uchar* flags, + __local real_t * sh_mem, + real_t bbi, //sh_mem4[TH_ID].z; + real_t scale, + real_t a, //lb, + real_t b, //ub, + real_t tol, + uint iter_max + // (root, fb) : (real_t, real_t) +) { + real2_t res; + + real_t fa = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, a); + real_t fb = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, b); + + if( (!iddle) && fa*fb >= 0.0 ) { + res.x = 0.0; + res.y = ( a >= 0.0 ) ? INFTY : -INFTY; + iddle = true; + } + + real_t x = b, fx = fb; + + uchar ok = 0; int i = 0; + do { + { // reduce with && global termination + ok = ( fx == 0.0 || fabs(b-a) < tol || i >= iter_max ); + + if( ok ) { + if( !iddle ) { + res.x = x; + res.y = fx; + } + iddle = true; + } + + flags[TH_ID+get_local_size(0)] = iddle; + barrier(CLK_LOCAL_MEM_FENCE); + ok = reduce_reg_and( flags + get_local_size(0) ); + //barrier(CLK_LOCAL_MEM_FENCE); + } + i ++; + + // the loop's body + if( !ok ) { + real_t s; + + x=(a+b)/2.0; + + real_t fx = to_solve(iddle, n_schedi, flags, sh_mem, scale, bbi, x); + + if( !iddle ) { + if ( fa*fx > 0.0 ) { a = x; fa = fx; } + else { b = x; } + } + } + } while (!ok); + + return res; +} + + +/********************************************/ +/********************************************/ + + +/** + * Computes Yhat + */ +real_t exactYhat( bool iddle, + __local uchar* flags, + uint n_schedi, + real_t y0, + real_t y1, + __local real4_t* sh_mem4, + real_t x +) { + real_t res = 0.0, scales; + real2_t uplo; + + { // the first reduction (+,max) + bool is_last; short lind; + __local real2_t* sh_mem2 = (__local real2_t*) (sh_mem4 + LWG_EG); + + if( iddle ) { + uplo = (real2_t) ( 0.0, -INFTY ); + } else { + real4_t tmp4 = sh_mem4[ TH_ID ]; + real_t baix = tmp4.y * x; + + uplo.x = tmp4.x * exp( -baix ); + uplo.y = ( tmp4.w - baix ) / tmp4.z; + } + scales = uplo.x; + + barrier(CLK_LOCAL_MEM_FENCE); + sh_mem2[ TH_ID ] = uplo; + barrier(CLK_LOCAL_MEM_FENCE); + + segm_reduce_plusmax( sh_mem2, flags ); // ToDo: Fix this please! + + int last_ind = TH_ID - getIotaInd( (__local short*) flags ); + if(!iddle) last_ind += n_schedi - 1; + uplo = sh_mem2[last_ind]; // the reduction result! + barrier(CLK_LOCAL_MEM_FENCE); + } + +// CHECKING uplo + + if ( n_schedi == 1 ) { + res = uplo.y; + iddle = true; + } + + if(!iddle) { // adjust `up' + int lfind = TH_ID - getIotaInd( (__local short*)flags ) + n_schedi - 1; + real_t log_s = log(uplo.x); + real_t tmp = log_s / sh_mem4[ lfind ].z; //bbi[n_schedi-1]; + lfind += 1 - n_schedi; + + if ( tmp <= 0.0 ) { + uplo.x = tmp; + } else { + tmp = log_s / sh_mem4[lfind].z; // bbi[0]; + if ( 0.0 <= tmp ) uplo.x = tmp; + else uplo.x = - INFTY; + } + } + +// const real_t yl = lo - EPS; +// const real_t yu = up + EPS; + if ( (!iddle) && (y1 <= uplo.y - EPS) ) { + // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS + + res = y1 + 1.0; + iddle = true; + } else if ( (!iddle) && (uplo.x + EPS <= y0) ) { + // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) + + res = y0 - 1.0; + iddle = true; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + uplo.x = minR( uplo.x + EPS, y1 ); + uplo.y = maxR( uplo.y - EPS, y0 ); + // tmp2 = (root, error); //UINT iter; + +#if 1 + real2_t tmp2 = rootFinding_Brent( + iddle, n_schedi, flags, (__local real_t*) (sh_mem4+LWG_EG), + sh_mem4[TH_ID].z, scales, uplo.y, uplo.x, 1.0e-4, 1000 + ); +#else + + real2_t tmp2 = rootBisection( + iddle, n_schedi, flags, (__local real_t*) (sh_mem4+LWG_EG), + sh_mem4[TH_ID].z, scales, uplo.y, uplo.x, 1.0e-4, 1000 + ); + + +#endif + + if( !iddle ) { + res = ( tmp2.y == -INFTY ) ? + y0 - 1.0 : + ( tmp2.y == INFTY ) ? y1 + 1.0 : tmp2.x; + } + } + + return res; +} + + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/G2ppUtil.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/G2ppUtil.cl new file mode 100644 index 0000000..0f2a482 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/G2ppUtil.cl @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////// +///// Trivial (w.r.t. parallelism) Helper Functions for G2PP +//////////////////////////////////////////////////////////////////// + +#ifndef G2PP_UTIL +#define G2PP_UTIL + +//////////////////////////////////// +/// MATH RELATED +//////////////////////////////////// + +//------------------------------------------------------------------------- +// polynomial expansion of the erf() function, with error<=1.5e-7 +// formula 7.1.26 (page 300), Handbook of Mathematical Functions, Abramowitz and Stegun +// http://people.math.sfu.ca/~cbm/aands/frameindex.htm + +inline +real_t erff1( real_t x ) { + real_t poly = 0.0F, t, t2; + + t = 1.0 / (1.0 + 0.3275911*x); + poly += 0.254829592 * t; + + t2 = t * t; + poly += (-0.284496736) * t2; + poly += 1.421413741 * t * t2; + + t2 = t2 * t2; + poly += (-1.453152027) * t2; + poly += 1.061405429 * t * t2; + + return ( 1.0 - poly * exp(-(x*x)) ); + +// real_t p = 0.3275911; +// real_t a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741, a4 = -1.453152027, a5 = 1.061405429; +// +// real_t t = 1.0/(1.0+p*x); +// real_t t2 = t * t; +// real_t t3 = t * t2; +// real_t t4 = t2 * t2; +// real_t t5 = t2 * t3; +// return ( 1.0 - (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5) * exp(-(x*x)) ); + +} + +//------------------------------------------------------------------------- +// Cumulative Distribution Function for a standard normal distribution + +inline +real_t uGaussian_P( real_t x ) { + real_t u = x / sqrt((real_t)2.0); + real_t e = ( u < 0.0 ) ? -erff1(-u) : erff1(u); + + return ( 0.5 * (1.0 + e) ); +} + +inline +real_t erff_poly_only( real_t x ) { + real_t poly = 0.0, t, t2; + + t = 1.0 / (1.0 + 0.3275911*x); + poly += 0.254829592 * t; + + t2 = t * t; + poly += (-0.284496736) * t2; + poly += 1.421413741 * t * t2; + + t2 = t2 * t2; + poly += (-1.453152027) * t2; + poly += 1.061405429 * t * t2; + + return poly; +} + +inline +real_t uGaussian_P_withExpFactor( real_t x, real_t exp_factor ) { + real_t u = fabs( x / sqrt((real_t)2.0) ); + real_t e = erff_poly_only(u); + + real_t res = 0.5 * e * exp(exp_factor-u*u); + + if( x >= 0.0 ) { + res = exp(exp_factor) - res; + } + + return res; +} + +///////////////////////// +//// G2PP Utilities +///////////////////////// + +inline +real_t zc( real_t t ) { + return exp( (real_t)(- R * date_act_365( t, TODAY )) ); +} + +inline +real_t b_fun( real_t z0, real_t tau ) { + return ( 1.0 - exp(-z0*tau) ) / z0; +} + +inline +real_t t_fun( real_t sigma, real_t x0, real_t tau ) { + real_t expxtau = exp( -x0*tau ) ; + real_t exp2xtau = expxtau*expxtau; + + return sigma*sigma/(x0*x0) * ( tau + 2.0/x0*expxtau-1.0/(2.0*x0)*exp2xtau-3.0/(2.0*x0) ); +} + + +/////////////////////////////////////////////////////////////////// +// the first parameter `genome' is the five-genes genome used in +// the genetic algorithms that models the interest rate +// the second parameter is the time +// the result is V in Brigo and Mercurio's book page 148. +// \var(\int_t^T [x(u)+y(u)]du) +/////////////////////////////////////////////////////////////////// +//res = (v, bai, bbi, _) +inline +real4_t bigv( real_t g_a, + real_t g_b, + real_t g_rho, + real_t g_nu, + real_t g_sig, + real_t tau +) { + real4_t res4; + + res4.w = g_sig; //(g_sig == 0.0) ? 1.0e-10 : g_sig; // g_sigma + res4.y = b_fun(g_a, tau); + res4.z = b_fun(g_b, tau); + res4.x = t_fun(res4.w, g_a,tau); + res4.x+= t_fun(g_nu, g_b,tau); + res4.x+= 2.0 * g_rho * g_nu * res4.w / (g_a * g_b) * + ( tau - res4.y - res4.z + b_fun(g_a+g_b, tau) ); + + return res4; +} + + +/////////////////////////////////////////////////////////////////// +// the first parameter `genome' is the five-genes genome used in +// the genetic algorithms that models the interest rate +// the other parameter are times: today, maturity, and the +// lower and upper bound of the considered time interval +// +// the result is: x drift term in tmat-forward measure +/////////////////////////////////////////////////////////////////// +inline +real_t bigmx( real_t a, + real_t b, + real_t rho, + real_t nu, + real_t sigma, // ends genome + real_t today, + real_t tmat, + real_t s, + real_t t +) { + real_t ts = date_act_365(t, s) ; + real_t tmatt = date_act_365(tmat, t) ; + + real_t tmat0 = date_act_365(tmat, today); + real_t tmats = date_act_365(tmat, s) ; + real_t t0 = date_act_365(t, today); + real_t s0 = date_act_365(s, today); + + real_t tmp, res = 0.0; + + tmp = (sigma*sigma)/(a*a)+(sigma*rho*nu)/(a*b); + tmp *= ( 1.0 - exp(- a * ts) ); + res += tmp; + + tmp = sigma * sigma / (2.0 * a * a); + tmp *= exp(- a * tmatt) - exp(- a * (tmats + ts)); + res -= tmp; + + tmp = rho * sigma * nu / (b * (a + b)); + tmp *= exp(-b * tmatt) - exp(-b*tmat0 - a*t0 + (a+b)*s0); + res -= tmp; + + return res; +} + + +/////////////////////////////////////////////////////////////////// +// the first parameter `genome' is the five-genes genome used in +// the genetic algorithms that models the interest rate +// the other parameter are times: today, maturity, and the +// lower and upper bound of the considered time interval +// +// the result is: y drift term in tmat-forward measure +/////////////////////////////////////////////////////////////////// +inline +real_t bigmy( real_t a, + real_t b, + real_t rho, + real_t nu, + real_t sigma, // ends genome + real_t today, + real_t tmat, + real_t s, + real_t t +) { + real_t ts = date_act_365(t, s ); + real_t tmatt = date_act_365(tmat, t ); + real_t tmat0 = date_act_365(tmat, today); + real_t tmats = date_act_365(tmat, s ); + real_t t0 = date_act_365(t, today); + real_t s0 = date_act_365(s, today); + + real_t tmp, res = 0.0; + + tmp = nu*nu/(b*b)+sigma*rho*nu/(a*b); + tmp *= 1.0 - exp(-b * ts); + res += tmp; + + tmp = nu * nu / (2.0 * b * b); + tmp *= exp(-b * tmatt) - exp(-b * (tmats + ts)); + res -= tmp; + + tmp = sigma * rho * nu / (a * (a + b)); + tmp *= exp(-a * tmatt) - exp(-a*tmat0 - b*t0 + (a+b)*s0); + res -= tmp; + + return res; +} + +#endif // ifndef G2PP_UTIL + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/GenAlg.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/GenAlg.cl new file mode 100644 index 0000000..508a5a1 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/GenAlg.cl @@ -0,0 +1,313 @@ +// Various Kinds of Regular and Segmented Reduction +#ifndef GEN_ALG_KERNELS +#define GEN_ALG_KERNELS + +real_t getSobolNum( uint n, __constant int* SOBOL_DIR_VCT ) { + int n_gray = (n >> 1) ^ n; + int res = 0; + for( int i=0; i < SOBOL_BITS_NUM; i++ ) { + int t = (1 << i); + bool cond = ( (n_gray & t) == t ); + if ( cond ) { + res = res ^ SOBOL_DIR_VCT[i]; + } + } + real_t rres = ((real_t)res) / ( (1< 0.0F ) ? (backward_range / forward_range) : 1.0F; + + // assign p' + real_t diff = amplitude * r01 - semiamplitude; + return (real2_t) (gene + diff, bf_fact); +} + +inline +real_t constrain_gene( real_t gene, real_t lb, real_t ub ) { + return maxR( lb, minR( ub, gene ) ); +} + +/*******************************************/ +/********** MUTATE DIMs KERNEL ***********/ +/*******************************************/ + +/** + * One-Dimensional Kernel: + * Dimension is POP_SIZE (LWG = GWG) + */ +__kernel void +mutate_dims ( __global real_t* genomes, //[13, POP_SIZE] + __constant real_t* lub, //[2, 5]. i.e., [lower,upper] gene range + __constant int * SOBOL_DIR_VCT, //[SOBOL_BITS_NUM == 30] + uint sob_offset, + uint dim_j, + real_t amplitude_ratio, // = MOVES_UNIF_AMPL_RATIO + uint Npop // POP_SIZE +) { + uint gid = get_global_id(0); +#if (SOBOL_TRANSP == 1) + uint gidr = gid*5 + sob_offset; +#else + uint gidr = gid + sob_offset; +#endif + uint offset = ( Npop << 1 ); + real_t fb_rat = 1.0F; + real2_t tmp; + + if( gid < Npop ) { + gid += Npop; + for(int i=0; i < 5; i++) { + real_t lb = lub[i], ub = lub[i+5]; + real_t r01 = getSobolNum(gidr, SOBOL_DIR_VCT); + + real_t ampl = (dim_j > 4 || dim_j == i) ? amplitude_ratio : 0.0F; + tmp = mutate_helper( genomes[gid-Npop], genomes[gid], + lb, ub, r01, ampl ); + + real_t val = constrain_gene(tmp.x, lb, ub); + genomes[gid] = val; //(i == 2 && val == 0.0) ? EPS0 : val; + + fb_rat *= tmp.y; + gid += offset; +#if (SOBOL_TRANSP == 1) + gidr += 1; +#else + gidr += Npop; +#endif + } + gid += Npop; + genomes[gid] = fb_rat; + } +} + + +/**********************************************/ +/************* Crossover MCMC_DE **************/ +/**********************************************/ + +inline real_t getRandUnifNorm(real_t r) { + return r; +} +//Returns a (pseudo) random integer in [0, ub) +inline uint getRandIntNorm(uint ub, real_t r01) { + return (uint) (r01 * ub); +} + +inline +real_t perturbation( real_t gene, + real_t gene_k, + real_t gene_l, + real_t r01, + real_t lb, + real_t ub, + real_t gamma1, + real_t amplitude_ratio //= MOVES_UNIF_AMPL_RATIO +) { + real_t amplitude = fabs( (ub - lb) * amplitude_ratio ); + real_t semiamplitude = amplitude / 2.0F; + real_t perturb = ( amplitude * r01 - semiamplitude ); + return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); +} + +/** + * Crossover + * One-Dimensional of size POP_SIZE = LWG = GWG + */ +__kernel void +mcmc_DE( __global real_t *genomes, + __constant real_t *lub, // [2, 5]. i.e., [lower,upper] gene range + __constant int *SOBOL_DIR_VCT, // [SOBOL_BITS_NUM == 30] + uint sob_offset, + real_t gamma_avg, // 2.38 / sqrt(2.0*GENOME_DIM), + real_t ampl_ratio, // 0.1 * MOVES_UNIF_AMPL_RATIO + uint Npop +) { + real_t r01; + uint gid = get_global_id(0); + +#if (SOBOL_TRANSP == 1) + uint gidr = gid*8 + sob_offset; + uint rinc = 1; +#else + uint gidr = gid + sob_offset; + uint rinc = Npop; +#endif + + uint offset = ( Npop << 1 ); + + if( gid < Npop ) { + uint cand_UB = Npop - 1; + r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); gidr += rinc; + uint k = getRandIntNorm( cand_UB, r01 ); + if ( k == gid ) { + k = cand_UB; + cand_UB -= 1; + } + + r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); gidr += rinc; + uint l = getRandIntNorm( cand_UB, r01 ); + if ( l == gid || l == k ) { + l = cand_UB; + } + + // proposal + // gamma: integrated out from the adviced Multivariate Gaussian with Gaussian target (Braak, 2006) + // random.uniform: is it supposed to be Sobol or such ? Does C++ rand() works? + // gamma = N.random.uniform( gamma_avg-0.5, gamma_avg+0.5 ) + r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); gidr += rinc; + real_t gamma1 = gamma_avg - 0.5F + getRandUnifNorm( r01 ); + + for( int j = 0; j < 5; j ++ ) { + real_t lb = lub[j], ub = lub[j+5]; + + r01 = getSobolNum(gidr, SOBOL_DIR_VCT ); + real_t val = perturbation ( genomes[gid], genomes[k], genomes[l], r01, lb, ub, gamma1, ampl_ratio ); + val = constrain_gene( val, lb, ub ); + + genomes[ gid + Npop ] = val; //( j == 2 && val == 0.0 ) ? EPS0 : val; + + gidr += rinc; + gid += offset; + k += offset; + l += offset; + } + + gid += offset; + genomes[gid] = 1.0F; // TODO: fix + } +} + + +#endif // GEN_ALG_KERNELS + diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Reductions.cl b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Reductions.cl new file mode 100644 index 0000000..f9026a1 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SrcCL/Reductions.cl @@ -0,0 +1,380 @@ +// Various Kinds of Regular and Segmented Reduction +#ifndef REDUCTION_KERNELS +#define REDUCTION_KERNELS + +/*************************************************/ +/*** Regular Total Reduction With Operator AND ***/ +/*************************************************/ + +inline +uchar reduce_reg_and_warp( + __local volatile uchar* sh_data +) { + const uint th_id = get_local_id(0) & (WARP-1); + + if( th_id >= 1 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-1 ]; + if( th_id >= 2 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-2 ]; + if( th_id >= 4 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-4 ]; + if( th_id >= 8 ) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-8 ]; +#if (WARP == 32) + if( th_id >= 16) sh_data[th_id] = sh_data[th_id] && sh_data[th_id-16]; +#endif + return sh_data[th_id]; +} + +inline +uchar reduce_reg_and ( __local volatile uchar* sh_data ) { + // perform scan at warp level + uchar res = reduce_reg_and_warp( sh_data + WARP_FST ); + barrier( CLK_LOCAL_MEM_FENCE ); + + // gather per-warp results in the first WARP elements + if ( TH_ID == WARP_LST ) { + sh_data[ WARP_ID ] = res; + } + barrier(CLK_LOCAL_MEM_FENCE); + + if( TH_ID < WARP ) { + reduce_reg_and_warp( sh_data ); + } + barrier(CLK_LOCAL_MEM_FENCE); +#if 0 + if( WARP_ID != 0 ) { + res = res && sh_data[ WARP_ID-1 ]; + } + barrier(CLK_LOCAL_MEM_FENCE); + + sh_data[TH_ID] = res; + + barrier(CLK_LOCAL_MEM_FENCE); + + res = sh_data[ get_local_size(0) - 1 ]; + barrier(CLK_LOCAL_MEM_FENCE); + return res; +#else + res = sh_data[ (get_local_size(0) >> lgWARP) - 1 ]; //sh_data[WARP-1]; + barrier(CLK_LOCAL_MEM_FENCE); + return res; +#endif +} + +/*************************************************/ +/*** Regular Total Reduction With Operator PLUS***/ +/*************************************************/ + +inline +real_t reduce_reg_plus_warp( + __local volatile real_t* sh_data +) { + const uint th_id = get_local_id(0) & (WARP-1); + + if( th_id >= 1 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-1 ]; + if( th_id >= 2 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-2 ]; + if( th_id >= 4 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-4 ]; + if( th_id >= 8 ) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-8 ]; +#if (WARP == 32) + if( th_id >= 16) sh_data[th_id] = sh_data[th_id] + sh_data[th_id-16]; +#endif + return sh_data[th_id]; +} + +inline +real_t reduce_reg_plus ( __local volatile real_t* sh_data ) { + // perform scan at warp level + real_t res = reduce_reg_plus_warp( sh_data + WARP_FST ); + barrier( CLK_LOCAL_MEM_FENCE ); + + // gather per-warp results in the first WARP elements + if ( TH_ID == WARP_LST ) { + sh_data[ WARP_ID ] = res; + } + barrier(CLK_LOCAL_MEM_FENCE); + + if( TH_ID < WARP ) { + reduce_reg_plus_warp( sh_data ); + } + barrier(CLK_LOCAL_MEM_FENCE); + + if( WARP_ID != 0 ) { + res = res + sh_data[ WARP_ID-1 ]; + } + barrier(CLK_LOCAL_MEM_FENCE); + + sh_data[TH_ID] = res; + barrier(CLK_LOCAL_MEM_FENCE); + +// res = sh_data[ get_local_size(0) - 1 ]; +// barrier(CLK_LOCAL_MEM_FENCE); +// return res; + + return sh_data[ get_local_size(0) - 1 ]; +} + +/*************************************************/ +/*** Irregular, Segmented Reduction With Op. + ***/ +/*************************************************/ + +inline real_t segm_reduce_plus_warp( + __local volatile real_t* ptr, + __local volatile uchar* hd ) { + const uint th_id = TH_ID & (WARP-1); + + if( th_id >= 1 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-1] + ptr[th_id]; + hd [th_id] = hd[th_id - 1] | hd[th_id]; + } + if( th_id >= 2 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-2] + ptr[th_id]; + hd [th_id] = hd[th_id - 2] | hd[th_id]; + } + if( th_id >= 4 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-4] + ptr[th_id]; + hd [th_id] = hd[th_id - 4] | hd[th_id]; + } + if( th_id >= 8 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-8] + ptr[th_id]; + hd [th_id] = hd[th_id - 8] | hd[th_id]; + } +#if (WARP == 32) + if( th_id >= 16 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : ptr[th_id-16]+ ptr[th_id]; + hd [th_id] = hd[th_id - 16] | hd[th_id]; + } +#endif + return ptr[th_id]; +} + +inline void segm_reduce_plus( + __local volatile real_t *ptr, + __local volatile uchar *hd +) { + // 1a: record whether this warp begins + // with an ``open'' segment. + uchar th_flag = hd[ TH_ID ]; + bool warp_is_open = ( hd[WARP_FST] == 0 ); + barrier(CLK_LOCAL_MEM_FENCE); + + // 1b: intra-warp segmented scan for each warp + real_t val = segm_reduce_plus_warp( ptr + WARP_FST, hd + WARP_FST ); + + // 2a: the last value is the correct partial result + real_t warp_total = ptr[WARP_LST]; + + // 2b: warp_flag is the OR-reduction of the flags + // in a warp, and is computed indirectly from + // the mindex in hd[] + bool warp_flag = hd[WARP_LST]!=0 || !warp_is_open; + bool will_accum= warp_is_open && (hd[TH_ID] == 0); + + barrier(CLK_LOCAL_MEM_FENCE); + + // 2c: the last thread in a warp writes partial results + if( TH_ID == WARP_LST ) { + ptr[WARP_ID] = warp_total; + hd [WARP_ID] = warp_flag; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // 3: one warp scans the per-warp results + if( WARP_ID == 0 ) { + segm_reduce_plus_warp( ptr + WARP_FST, hd + WARP_FST ); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // 4: accumulate results from step 3: + if ( WARP_ID != 0 && will_accum ) { + val = val + ptr[ WARP_ID-1 ]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + ptr[TH_ID] = val; + hd [TH_ID] = th_flag; + + barrier(CLK_LOCAL_MEM_FENCE); +} + +/****************************************************/ +/*** Irregular, Segmented Reduce With Op. (+,max) ***/ +/****************************************************/ + +inline real2_t OP_PLUS_MAX(real2_t a, real2_t b) { + return (real2_t) ( a.x + b.x, maxR(a.y, b.y) ); +} + +inline real2_t segm_reduce_plusmax_warp( + __local volatile real2_t* ptr, + __local volatile uchar* hd ) { + const uint th_id = TH_ID & (WARP-1); + + if( th_id >= 1 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-1], ptr[th_id]); + hd [th_id] = hd[th_id - 1] | hd[th_id]; + } + if( th_id >= 2 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-2], ptr[th_id]); + hd [th_id] = hd[th_id - 2] | hd[th_id]; + } + if( th_id >= 4 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-4], ptr[th_id]); + hd [th_id] = hd[th_id - 4] | hd[th_id]; + } + if( th_id >= 8 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-8], ptr[th_id]); + hd [th_id] = hd[th_id - 8] | hd[th_id]; + } +#if (WARP == 32) + if( th_id >= 16 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MAX(ptr[th_id-16], ptr[th_id]); + hd [th_id] = hd[th_id - 16] | hd[th_id]; + } +#endif + return ptr[th_id]; +} + +inline void segm_reduce_plusmax( + __local volatile real2_t *ptr, + __local volatile uchar *hd +) { + // 1a: record whether this warp begins + // with an ``open'' segment. + uchar th_flag = hd[ TH_ID ]; + bool warp_is_open = ( hd[WARP_FST] == 0 ); + barrier(CLK_LOCAL_MEM_FENCE); + + // 1b: intra-warp segmented scan for each warp + real2_t val = segm_reduce_plusmax_warp( ptr + WARP_FST, hd + WARP_FST ); + + // 2a: the last value is the correct partial result + real2_t warp_total = ptr[WARP_LST]; + + // 2b: warp_flag is the OR-reduction of the flags + // in a warp, and is computed indirectly from + // the mindex in hd[] + bool warp_flag = hd[WARP_LST]!=0 || !warp_is_open; + bool will_accum= warp_is_open && (hd[TH_ID] == 0); + + barrier(CLK_LOCAL_MEM_FENCE); + + // 2c: the last thread in a warp writes partial results + if( TH_ID == WARP_LST ) { + ptr[WARP_ID] = warp_total; + hd [WARP_ID] = warp_flag; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // 3: one warp scans the per-warp results + if( WARP_ID == 0 ) { + segm_reduce_plusmax_warp( ptr + WARP_FST, hd + WARP_FST ); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // 4: accumulate results from step 3: + if ( WARP_ID != 0 && will_accum ) { + val = OP_PLUS_MAX( val, ptr[ WARP_ID-1 ] ); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + ptr[TH_ID] = val; + hd [TH_ID] = th_flag; + + barrier(CLK_LOCAL_MEM_FENCE); +} + + +/****************************************************/ +/*** Irregular, Segmented Reduce With Op. (+,max) ***/ +/****************************************************/ + +inline real4_t OP_PLUS_MIN_MAX( real4_t a, real4_t b ) { + return ( real4_t ) ( a.x + b.x, minR(a.y, b.y), maxR(a.z, b.z), 1.0 ); +} + +inline real4_t segm_reduce_plusminmax_warp( + __local volatile real4_t* ptr, + __local volatile uchar* hd ) { + const uint th_id = TH_ID & (WARP-1); + + if( th_id >= 1 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-1], ptr[th_id]); + hd [th_id] = hd[th_id - 1] | hd[th_id]; + } + if( th_id >= 2 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-2], ptr[th_id]); + hd [th_id] = hd[th_id - 2] | hd[th_id]; + } + if( th_id >= 4 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-4], ptr[th_id]); + hd [th_id] = hd[th_id - 4] | hd[th_id]; + } + if( th_id >= 8 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-8], ptr[th_id]); + hd [th_id] = hd[th_id - 8] | hd[th_id]; + } +#if (WARP == 32) + if( th_id >= 16 ) { + ptr[th_id] = hd[th_id] ? ptr[th_id] : OP_PLUS_MIN_MAX(ptr[th_id-16], ptr[th_id]); + hd [th_id] = hd[th_id - 16] | hd[th_id]; + } +#endif + return ptr[th_id]; +} + +inline void segm_reduce_plusminmax( + __local volatile real4_t *ptr, + __local volatile uchar *hd +) { + // 1a: record whether this warp begins + // with an ``open'' segment. + uchar th_flag = hd[ TH_ID ]; + bool warp_is_open = ( hd[WARP_FST] == 0 ); + barrier(CLK_LOCAL_MEM_FENCE); + + // 1b: intra-warp segmented scan for each warp + real4_t val = segm_reduce_plusminmax_warp( ptr + WARP_FST, hd + WARP_FST ); + + // 2a: the last value is the correct partial result + real4_t warp_total = ptr[WARP_LST]; + + // 2b: warp_flag is the OR-reduction of the flags + // in a warp, and is computed indirectly from + // the mindex in hd[] + bool warp_flag = hd[WARP_LST]!=0 || !warp_is_open; + bool will_accum= warp_is_open && (hd[TH_ID] == 0); + + barrier(CLK_LOCAL_MEM_FENCE); + + // 2c: the last thread in a warp writes partial results + if( TH_ID == WARP_LST ) { + ptr[WARP_ID] = warp_total; + hd [WARP_ID] = warp_flag; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // 3: one warp scans the per-warp results + if( WARP_ID == 0 ) { + segm_reduce_plusminmax_warp( ptr + WARP_FST, hd + WARP_FST ); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // 4: accumulate results from step 3: + if ( WARP_ID != 0 && will_accum ) { + val = OP_PLUS_MIN_MAX( val, ptr[ WARP_ID-1 ] ); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + ptr[TH_ID] = val; + hd [TH_ID] = th_flag; + + barrier(CLK_LOCAL_MEM_FENCE); +} + +#endif // REDUCTION_KERNELS diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp new file mode 100644 index 0000000..7bdd251 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp @@ -0,0 +1,64 @@ +/****************************************/ +/*** Translated to C++ & parallelized ***/ +/*** in OpenCL by Cosmin E. Oancea ***/ +/*** from an original OCaml code ***/ +/*** (sequential) by LexiFi ***/ +/*** and a sequential Python implem ***/ +/*** using a different genetic alg.***/ +/*** by Christian Andreetta ***/ +/****************************************/ + + +#include "Util.h" +#include "Constants.h" +#include "ParseInput.h" +#include "GenAlgFlat.h" +#include "WriteResult.h" + +int main() +{ + real_t wg_a = 0.0, wg_b = 0.0, wg_sigma = 0.0, + wg_nu = 0.0, wg_rho = 0.0, wg_logLik = 0.0; + real_t* calib_arr = NULL; + + printf("\n// Running GPU-Parallel Swaption-Calibration Benchmark\n"); + + readDataSet( POP_SIZE, MCMC_LOOPS, + NUM_SWAP_QUOTES, SwaptionQuotes, + NUM_HERMITE, HermiteCoeffs, HermiteWeights, + NUM_SOBOL_BITS, SobolDirVct + ); + + unsigned long int elapsed_usec = 0; + { // Main Computational Kernel + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + calib_arr = mainKernelGPU(wg_a, wg_b, wg_sigma, wg_nu, wg_rho, wg_logLik); + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; + } + + { // writeback of the result + FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); + FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); + const int Ps = get_CPU_num_threads(); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + + writeResult(result, + wg_a, + wg_b, + wg_sigma, + wg_nu, + wg_rho, + wg_logLik, + calib_arr); + + fclose(result); + } + + return 0; +} diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h b/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h new file mode 100644 index 0000000..864bc1c --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h @@ -0,0 +1,287 @@ +#ifndef GPGPU_UTILITIES +#define GPGPU_UTILITIES + +#include "SDK_stub.h" + +/************************/ +/*** Helper Functions ***/ +/************************/ +bool is_pow2(uint n) { + uint c = 1; + while(c < n) { + c = c << 1; + } + return (c == n); +} + + +struct CpuArrays { + // size of the shape array + const uint SS; + + // shape of the irregular arrays for one genome + short* shape; + + // [13 * POP_SIZE] = + // { a, a_p, b, b_p, rho, rho_p, nu, nu_p, + // sigma, sigma_p, logLik, logLik_p, bf_rat } + real_t* genomes; + + // [ 4 * SS * POP_SIZE ] + real_t* ci_t1cs_scale; + + // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] + real_t* new_quote_price; + + // [ NUM_SWAP_QUOTES*NUM_HERMITE ] + real_t* accum0; + + // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] + // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, + // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } + real_t* scalars; + + real_t gene_ranges[10]; + + CpuArrays (const uint n, short* shp) : SS(n) { + shape = shp; + + genomes = new real_t[ 13 * POP_SIZE ]; + ci_t1cs_scale = new real_t[ 4 * SS * POP_SIZE ]; + scalars = new real_t[ 8 * NUM_SWAP_QUOTES * POP_SIZE ]; + + new_quote_price = new real_t [ 2 * NUM_SWAP_QUOTES * POP_SIZE ]; + accum0 = new real_t [ NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE ]; + + for(int i=0; i<5; i++) { gene_ranges[i] = g_mins[i]; } + for(int i=0; i<5; i++) { gene_ranges[i+5] = g_maxs[i]; } + } + + void releaseResources() { + delete[] shape; + delete[] genomes; + delete[] ci_t1cs_scale; + delete[] scalars; + delete[] new_quote_price; + delete[] accum0; + } + + // genome helpers + real_t* get_a () { return genomes; } + real_t* get_b () { return genomes + POP_SIZE*2; } + real_t* get_rho () { return genomes + POP_SIZE*4; } + real_t* get_nu () { return genomes + POP_SIZE*6; } + real_t* get_sigma () { return genomes + POP_SIZE*8; } + real_t* get_logLik() { return genomes + POP_SIZE*10;} + real_t* get_bf_rat() { return genomes + POP_SIZE*12;} + + // get the shape of the irregular array (for one genome) + short* get_shape (){ return shape; } + + // get the start iterator into arrays ci, t1cs, scale for genome i + real_t* get_ci (int i) { return ci_t1cs_scale + SS*i; } + real_t* get_t1cs (int i) { return ci_t1cs_scale + SS*i + SS*POP_SIZE; } + real_t* get_scale (int i) { return ci_t1cs_scale + SS*i + 2*SS*POP_SIZE; } + real_t* get_bbi (int i) { return ci_t1cs_scale + SS*i + 3*SS*POP_SIZE; } + + // get the start iterator into array-expanded scalars for genome i + real_t* get_mux (int i) { return scalars + i * NUM_SWAP_QUOTES ; } + real_t* get_muy (int i) { return scalars + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_sqsigx(int i) { return scalars + i * NUM_SWAP_QUOTES + 2 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_t2 (int i) { return scalars + i * NUM_SWAP_QUOTES + 3 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_sigrho(int i) { return scalars + i * NUM_SWAP_QUOTES + 4 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_zcmat (int i) { return scalars + i * NUM_SWAP_QUOTES + 5 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_f (int i) { return scalars + i * NUM_SWAP_QUOTES + 6 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_df (int i) { return scalars + i * NUM_SWAP_QUOTES + 7 * NUM_SWAP_QUOTES * POP_SIZE; } + + // get the quotes prices for genome i + real_t* get_quote (int i) { return new_quote_price + i * NUM_SWAP_QUOTES; } + real_t* get_price (int i) { return new_quote_price + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } + + // get the accumulator for the irregular array for genome i + real_t* get_accum (int i) { return accum0 + i * NUM_SWAP_QUOTES * NUM_HERMITE; } +}; + +/**************************************/ +/*** OpenCL related Data Structures ***/ +/**************************************/ +struct OclBuffers { + // Used for BestFit reduction (size LWG_FB) + cl_mem best_ind; + cl_mem best_val; + + cl_mem shape; // [ SS * 4 ] + cl_mem swap_quotes; // [ NUM_SWAP_QUOTES * 4 ] + cl_mem genomes; // [13 * POP_SIZE] + cl_mem ci_t1cs_scale; // [ 4 * SS * POP_SIZE ] + cl_mem new_quote_price; // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] + cl_mem accum0; // [ NUM_SWAP_QUOTES * NUM_HERMITE ] + cl_mem scalars; // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] + + cl_mem gauss_coefs; + cl_mem gauss_weights; + + cl_mem gene_ranges; + cl_mem sobol_dir_vct; + + cl_mem accept_cond; + + + void releaseResources ( ) { + shrLog(stdlog, "Release oclBuffers ... "); + + clReleaseMemObject( best_ind ); + clReleaseMemObject( best_val ); + + clReleaseMemObject( shape ); + clReleaseMemObject( swap_quotes ); + + clReleaseMemObject( genomes ); + clReleaseMemObject( ci_t1cs_scale ); + clReleaseMemObject( new_quote_price ); + clReleaseMemObject( accum0 ); + clReleaseMemObject( scalars ); + + clReleaseMemObject( gauss_coefs ); + clReleaseMemObject( gauss_weights ); + + clReleaseMemObject( gene_ranges ); + clReleaseMemObject( sobol_dir_vct ); + + clReleaseMemObject( accept_cond ); + } +}; + +struct OclObjects { + UINT dev_id; + + cl_command_queue cmdQueue[16]; // OpenCL command queue + cl_context context; // OpenCL context + cl_device_id* devices; // OpenCL device list + cl_program program; // OpenCL program + + cl_command_queue& getCommandQueue() { + return cmdQueue[dev_id]; + } + void releaseResources ( ) { + shrLog(stdlog, "Release OpenCL objects ..."); + clReleaseProgram ( program ); + clReleaseCommandQueue( getCommandQueue() ); + free(devices); + clReleaseContext( context ); + } +}; + + +/******************************************/ +/*** Filling the OpenCL data structures ***/ +/******************************************/ +void compileGPUprog( OclObjects& objs ) { + char compile_option[1024]; + +#ifdef MAC + // Build the program with 'mad' Optimization option + char flags[] = "-cl-mad-enable -DMAC "; +#else + char flags[] = ""; +#endif + + sprintf( compile_option, "%s -D lgWARP=%d -D TODAY=%10f -D LWG_FB=%d -D INFTY=%f -D MAX_DATE=%f -D MIN_DATE=%f -D SOBOL_BITS_NUM=%d -D%s -I%s/include -I%s/include -I%s/SrcCL", + flags, lgWARP, TODAY, LWG_FB, INFTY, MAX_DATE, MIN_DATE, NUM_SOBOL_BITS, + REAL_FLAG, + HIPERMARK_BENCHMARK_LIB_DIR, HIPERMARK_LIB_DIR, IMPLEMENTATION_DIR); + + fprintf(stderr, "compiling like this: %s\n", compile_option); + objs.dev_id = 0; + cl_uint nDevice; + build_for_GPU( + objs.context, + objs.cmdQueue, + nDevice, + objs.devices, + objs.program, + objs.dev_id, + compile_option, + "", + "SrcCL/CalibKers" + ); +} + +void makeOclBuffers ( CpuArrays& cpu_arrs, OclObjects& ocl_objs, OclBuffers& ocl_arrs ) { + cl_int ciErr, ciErr2; + size_t cur_size; + cl_command_queue& cmd_queue = ocl_objs.getCommandQueue(); + + cur_size = LWG_FB * sizeof(real_t); + ocl_arrs.best_val = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2); ciErr |= ciErr2; + + cur_size = LWG_FB * sizeof(uint); + ocl_arrs.best_ind = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2); ciErr |= ciErr2; + + // for the main kernel(s) + cur_size = 4 * cpu_arrs.SS * sizeof(short); + ocl_arrs.shape = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.shape, CL_TRUE, 0, cur_size, cpu_arrs.shape, 0, NULL, NULL); + + // swaption quotes + cur_size = 4 * NUM_SWAP_QUOTES * sizeof(real_t); + ocl_arrs.swap_quotes = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.swap_quotes, CL_TRUE, 0, cur_size, SwaptionQuotes, 0, NULL, NULL); + + // gene ranges + cur_size = 10 * sizeof(real_t); + ocl_arrs.gene_ranges = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.gene_ranges, CL_TRUE, 0, cur_size, cpu_arrs.gene_ranges, 0, NULL, NULL); + + // sobol direction vector + cur_size = 30 * sizeof(real_t); + ocl_arrs.sobol_dir_vct = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.sobol_dir_vct, CL_TRUE, 0, cur_size, SobolDirVct, 0, NULL, NULL); + + // acceptance condition + cur_size = POP_SIZE * sizeof(unsigned char); + ocl_arrs.accept_cond = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + + // GaussHermite coefficients and weights! + cur_size = NUM_HERMITE * sizeof(real_t); + ocl_arrs.gauss_coefs = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.gauss_coefs, CL_TRUE, 0, cur_size, HermiteCoeffs, 0, NULL, NULL); + ocl_arrs.gauss_weights = clCreateBuffer( ocl_objs.context, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; + ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.gauss_weights, CL_TRUE, 0, cur_size, HermiteWeights, 0, NULL, NULL); + + cur_size = 13 * POP_SIZE * sizeof(real_t); + ocl_arrs.genomes = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; +// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.genomes, CL_TRUE, 0, cur_size, cpu_arrs.genomes, 0, NULL, NULL); + + cur_size = 4 * cpu_arrs.SS * POP_SIZE * sizeof(real_t); + ocl_arrs.ci_t1cs_scale = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; +// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.ci_t1cs_scale, CL_TRUE, 0, cur_size, cpu_arrs.ci_t1cs_scale, 0, NULL, NULL); + + cur_size = 2 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(real_t); + ocl_arrs.new_quote_price = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; +// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.new_quote_price, CL_TRUE, 0, cur_size, cpu_arrs.new_quote_price, 0, NULL, NULL); + + cur_size = 8 * NUM_SWAP_QUOTES * POP_SIZE * sizeof(real_t); + ocl_arrs.scalars = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; +// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.scalars, CL_TRUE, 0, cur_size, cpu_arrs.scalars, 0, NULL, NULL); + + cur_size = NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE * sizeof(real_t); + ocl_arrs.accum0 = clCreateBuffer( ocl_objs.context, CL_MEM_READ_WRITE, cur_size, NULL, &ciErr2 ); ciErr |= ciErr2; +// ciErr |= clEnqueueWriteBuffer(cmd_queue, ocl_arrs.accum0, CL_TRUE, 0, cur_size, cpu_arrs.accum0, 0, NULL, NULL); + + oclCheckError(ciErr, CL_SUCCESS); +} + +void initGPUresources ( CpuArrays& cpu_arrs, OclObjects& ocl_objs, OclBuffers& ocl_arrs ) { + compileGPUprog ( ocl_objs ); + makeOclBuffers ( cpu_arrs, ocl_objs, ocl_arrs ); +} + +void releaseGPUresources( OclObjects& ocl_objs, OclBuffers& ocl_arrs ) { + fprintf(stderr, "Releasing GPU Resources ... "); + ocl_arrs.releaseResources(); + ocl_objs.releaseResources(); + fprintf(stderr, "OK!\n"); +} + +#endif // GPGPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/static_configuration_template.json b/benchmarks/InterestCalib/implementations/cpp_opencl/static_configuration_template.json new file mode 100644 index 0000000..00bdffb --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/static_configuration_template.json @@ -0,0 +1,3 @@ +{ + "REAL_TYPE" : ["float", "double"] +} diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h b/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h index 5f324a4..1e11294 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/G2PPorig.h @@ -8,10 +8,10 @@ #include "GenAlgUtil.h" -REAL to_solve_orig( const UINT& N, +real_t to_solve_orig( const UINT& N, const IntermElem* tmp_arrs, - const REAL& yhat ) { - REAL accum = 0.0; + const real_t& yhat ) { + real_t accum = 0.0; for( UINT i = 0; i < N; i++ ) { accum += tmp_arrs[i].hat_scale * exp( - tmp_arrs[i].bbi * yhat ); } @@ -25,20 +25,20 @@ REAL to_solve_orig( const UINT& N, void rootFinding_Brent_orig ( const UINT& N, IntermElem* tmp_arrs, - const REAL& lb, - const REAL& ub, - const REAL& toll, + const real_t& lb, + const real_t& ub, + const real_t& toll, const UINT& it_mx, - REAL& root, // result + real_t& root, // result UINT& it, - REAL& fb + real_t& fb ) { - const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; - const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; + const real_t tol = (toll <= 0.0) ? 1.0e-9 : toll; + const real_t iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; - REAL a = lb, b = ub; + real_t a = lb, b = ub; - REAL fa = to_solve_orig(N, tmp_arrs, a); + real_t fa = to_solve_orig(N, tmp_arrs, a); fb = to_solve_orig(N, tmp_arrs, b); if( fa*fb >= 0.0 ) { @@ -48,22 +48,22 @@ void rootFinding_Brent_orig ( return; } - if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } + if( fabs(fa) < fabs(fb) ) { real_t tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } - REAL c = a, fc = fa; + real_t c = a, fc = fa; bool mflag = true; - REAL d = 0.0; + real_t d = 0.0; it = 0; for( UINT i = 0; i < iter_max; i++ ) { if ( fb != 0.0 && fabs(b-a) >= tol ) { - REAL s; + real_t s; if( fa == fc || fb == fc ) { s = b - fb * (b - a) / (fb - fa); } else { - REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); - REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); - REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); + real_t s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); + real_t s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); + real_t s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); s = s1 + s2 + s3; } @@ -78,7 +78,7 @@ void rootFinding_Brent_orig ( mflag = false; } - REAL fs = to_solve_orig(N, tmp_arrs, s); + real_t fs = to_solve_orig(N, tmp_arrs, s); // d is assigned for the first time here: // it's not used above because mflag is set @@ -89,7 +89,7 @@ void rootFinding_Brent_orig ( else { a = s; fa = fs; } if( fabs(fa) < fabs(fb) ) { - REAL tmp; + real_t tmp; tmp = a; a = b; b = tmp; tmp = fa; fa = fb; fb = tmp; } @@ -108,29 +108,29 @@ void rootFinding_Brent_orig ( //return BrentRes(b, it, fb); } -REAL exactYhatOrig( +real_t exactYhatOrig( const UINT& n_schedi, - const REAL& b, // scals begins - const REAL& sigmax, - const REAL& sigmay, - const REAL& rhoxy, - const REAL& rhoxyc, - const REAL& rhoxycs, - const REAL& mux, - const REAL& muy, // scals ends + const real_t& b, // scals begins + const real_t& sigmax, + const real_t& sigmay, + const real_t& rhoxy, + const real_t& rhoxyc, + const real_t& rhoxycs, + const real_t& mux, + const real_t& muy, // scals ends IntermElem* tmp_arrs, - const REAL& x // output + const real_t& x // output ) { // ugaussian_Pinv(k)=1.0e~4 - const REAL k = - 3.71901648545568; + const real_t k = - 3.71901648545568; - REAL up = 0.0, lo = -INFTY; + real_t up = 0.0, lo = -INFTY; for( UINT i = 0; i < n_schedi; i++ ) { - REAL baix = tmp_arrs[i].bai * x; + real_t baix = tmp_arrs[i].bai * x; - REAL up_term = tmp_arrs[i].aici * exp( -baix ); + real_t up_term = tmp_arrs[i].aici * exp( -baix ); tmp_arrs[i].hat_scale = up_term; up += up_term; lo = std::max( lo, ( tmp_arrs[i].log_aici - baix ) / tmp_arrs[i].bbi ); @@ -138,8 +138,8 @@ REAL exactYhatOrig( // CHECKING uplo!!!! - const REAL log_s = log(up); - REAL tmp = log_s / tmp_arrs[n_schedi-1].bbi; + const real_t log_s = log(up); + real_t tmp = log_s / tmp_arrs[n_schedi-1].bbi; if ( tmp <= 0.0 ) { up = tmp; @@ -149,20 +149,20 @@ REAL exactYhatOrig( else up = - INFTY; } - const REAL yl = lo - EPS; - const REAL yu = up + EPS; + const real_t yl = lo - EPS; + const real_t yu = up + EPS; - const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; - const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; + const real_t y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; + const real_t y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; - REAL res; + real_t res; if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) else { - const REAL root_lb = std::max( yl, y0 ); - const REAL root_ub = std::min( yu, y1 ); + const real_t root_lb = std::max( yl, y0 ); + const real_t root_ub = std::min( yu, y1 ); - REAL root, error; UINT iter; + real_t root, error; UINT iter; rootFinding_Brent_orig(n_schedi, tmp_arrs, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h b/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h index a99d977..c7ce807 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Genome.h @@ -28,28 +28,28 @@ * Genome min/max ranges and proposed initial values (not used) * { g_a, g_b, g_rho, g_nu, g_sigma } */ -const REAL g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; -const REAL g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; -const REAL g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; -//const REAL Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; +const real_t g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; +const real_t g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; +const real_t g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; +//const real_t Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; /** * perturbing a genome; requires one random uniform number in [0,1) */ inline -REAL perturbation( - const REAL gene, - const REAL gene_k, - const REAL gene_l, +real_t perturbation( + const real_t gene, + const real_t gene_k, + const real_t gene_l, const UINT i, - const REAL gamma1, - const REAL amplitude_ratio + const real_t gamma1, + const real_t amplitude_ratio ) { - REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - REAL semiamplitude = amplitude / 2.0; - REAL r01 = getRandRandNorm(); - REAL perturb = ( amplitude * r01 - semiamplitude ); + real_t amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + real_t semiamplitude = amplitude / 2.0; + real_t r01 = getRandRandNorm(); + real_t perturb = ( amplitude * r01 - semiamplitude ); return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); } @@ -58,7 +58,7 @@ REAL perturbation( * contraining gene i to be within accepted bounds! */ inline -REAL constrain_dim1( const int i, const REAL gene ) { +real_t constrain_dim1( const int i, const real_t gene ) { return std::max( g_mins[i], std::min( g_maxs[i], gene ) ); } @@ -66,12 +66,12 @@ REAL constrain_dim1( const int i, const REAL gene ) { /** * Helper mutate function: requires one uniform random number */ -Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int i, const REAL amplitude_ratio ) { - REAL forward_range, backward_range; - REAL tmp_min_max, tmp_max_min; +Tuple mutate_helper( const real_t gene, const real_t gene_prop, const int i, const real_t amplitude_ratio ) { + real_t forward_range, backward_range; + real_t tmp_min_max, tmp_max_min; - const REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - const REAL semiamplitude = amplitude / 2.0; + const real_t amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + const real_t semiamplitude = amplitude / 2.0; tmp_min_max = std::min( g_maxs[i], gene + semiamplitude ); tmp_max_min = std::max( g_mins[i], gene - semiamplitude ); @@ -81,32 +81,32 @@ Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int tmp_max_min = std::max( g_mins[i], gene_prop - semiamplitude ); backward_range = tmp_min_max - tmp_max_min; - const REAL bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; + const real_t bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; // assign p' - REAL r01 = getRandRandNorm(); - REAL diff = amplitude * r01 - semiamplitude; - return Tuple(gene + diff, bf_fact); + real_t r01 = getRandRandNorm(); + real_t diff = amplitude * r01 - semiamplitude; + return Tuple(gene + diff, bf_fact); } struct Genome { - REAL a; - REAL b; - REAL rho; - REAL nu; - REAL sigma; - REAL logLik; - REAL fbRat; - REAL padding; + real_t a; + real_t b; + real_t rho; + real_t nu; + real_t sigma; + real_t logLik; + real_t fbRat; + real_t padding; Genome() { this->a = 0.0; this->b = 0.0; this->rho = 0.0; this->nu = 0.0; this->sigma = 0.0; this->logLik = 0.0; this->fbRat = 0.0; } - Genome( const REAL a, const REAL b, const REAL rho, const REAL nu, - const REAL sigma, const REAL logLik, const REAL fbRat) { + Genome( const real_t a, const real_t b, const real_t rho, const real_t nu, + const real_t sigma, const real_t logLik, const real_t fbRat) { this->a = a; this->b = b; this->rho = rho; this->nu = nu; this->sigma = sigma; this->logLik = logLik; this->fbRat = fbRat; @@ -131,9 +131,9 @@ struct Genome { * done for all types of crossover/mutation/etc */ void mutate_dims_all( const Genome& orig, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { - REAL fb_rat = 1.0; - Tuple tmp(EPS0, 1.0); + const real_t amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { + real_t fb_rat = 1.0; + Tuple tmp(EPS0, 1.0); tmp = mutate_helper( orig.a, this->a, 0, amplitude_ratio ); this->a = constrain_dim1(0, tmp.fst); @@ -166,11 +166,11 @@ struct Genome { */ void mutate_dims_one( const Genome& orig, const int dim_j, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO + const real_t amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { - REAL fb_rat = 1.0; + real_t fb_rat = 1.0; - Tuple tmp(EPS0, 1.0); + Tuple tmp(EPS0, 1.0); tmp = mutate_helper( orig.a, this->a, 0, (dim_j == 0) ? amplitude_ratio : 0.0 ); this->a = constrain_dim1(0, tmp.fst); fb_rat *= tmp.snd; @@ -200,13 +200,13 @@ struct Genome { void mcmc_DE( const Genome& orig, const Genome& gene_k, const Genome& gene_l, - const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), - const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO + const real_t gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), + const real_t ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO ) { // proposal // gamma: integrated out from the adviced // Multivariate Gaussian with Gaussian target (Braak, 2006) - REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); + real_t gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); this->a = constrain_dim1( 0, perturbation( orig.a, gene_k.a, gene_l.a, 0, gamma1, ampl_ratio ) ); this->b = constrain_dim1( 1, perturbation( orig.b, gene_k.b, gene_l.b, 1, gamma1, ampl_ratio ) ); diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile index 14669d4..b2cc929 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile @@ -19,6 +19,9 @@ default: $(EXECUTABLE) %.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp index 84d002b..b29ba4e 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp @@ -11,6 +11,7 @@ #include "Constants.h" #include "ParseInput.h" #include "GenAlgFlat.h" +#include "WriteResult.h" int main() { @@ -45,17 +46,17 @@ int main() fclose(runtime); writeResult(result, - wg_a, - wg_b, - wg_sigma, - wg_nu, - wg_rho, - wg_logLik, + gene.a, + gene.b, + gene.sigma, + gene.nu, + gene.rho, + gene.logLik, calib_arr); fclose(result); } - return 1; + return 0; } diff --git a/benchmarks/InterestCalib/lib/include/Candidate.h b/benchmarks/InterestCalib/lib/include/Candidate.h index 336e1d5..4916ef2 100644 --- a/benchmarks/InterestCalib/lib/include/Candidate.h +++ b/benchmarks/InterestCalib/lib/include/Candidate.h @@ -27,28 +27,28 @@ * Genome min/max ranges and proposed initial values (not used) * { g_a, g_b, g_rho, g_nu, g_sigma } */ -const REAL g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; -const REAL g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; -const REAL g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; -//const REAL Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; +const real_t g_mins [GENOME_DIM] = { EPS0, EPS0, -1.0+EPS0, EPS0, EPS0 }; +const real_t g_maxs [GENOME_DIM] = { 1.0-EPS0, 1.0-EPS0, 1.0-EPS0, 0.2, 0.2 }; +const real_t g_inis [GENOME_DIM] = { 0.02, 0.02, 0.0, 0.01, 0.04 }; +//const real_t Candidate::p_ref[GENOME_DIM] = { 1.0, -2.0, 0.5, -0.3, -0.5, 0.1 }; /** * perturbing a genome; requires one random uniform number in [0,1) */ inline -REAL perturbation( - const REAL gene, - const REAL gene_k, - const REAL gene_l, +real_t perturbation( + const real_t gene, + const real_t gene_k, + const real_t gene_l, const UINT i, - const REAL gamma1, - const REAL amplitude_ratio + const real_t gamma1, + const real_t amplitude_ratio ) { - REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - REAL semiamplitude = amplitude / 2.0; - REAL r01 = getRandRandNorm(); - REAL perturb = ( amplitude * r01 - semiamplitude ); + real_t amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + real_t semiamplitude = amplitude / 2.0; + real_t r01 = getRandRandNorm(); + real_t perturb = ( amplitude * r01 - semiamplitude ); return ( gene + perturb + gamma1 * ( gene_k - gene_l ) ); } @@ -57,7 +57,7 @@ REAL perturbation( * contraining gene i to be within accepted bounds! */ inline -REAL constrain_dim1( const int i, const REAL gene ) { +real_t constrain_dim1( const int i, const real_t gene ) { return std::max( g_mins[i], std::min( g_maxs[i], gene ) ); } @@ -65,12 +65,12 @@ REAL constrain_dim1( const int i, const REAL gene ) { * accepting the proposal */ void accept(const int i, - REAL* g_a, // genome begins - REAL* g_b, - REAL* g_rho, - REAL* g_nu, - REAL* g_sigma, - REAL* logLik + real_t* g_a, // genome begins + real_t* g_b, + real_t* g_rho, + real_t* g_nu, + real_t* g_sigma, + real_t* logLik ) { g_a [i] = g_a [i+POP_SIZE]; g_b [i] = g_b [i+POP_SIZE]; @@ -83,12 +83,12 @@ void accept(const int i, /** * Helper mutate function: requires one uniform random number */ -Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int i, const REAL amplitude_ratio ) { - REAL forward_range, backward_range; - REAL tmp_min_max, tmp_max_min; +Tuple mutate_helper( const real_t gene, const real_t gene_prop, const int i, const real_t amplitude_ratio ) { + real_t forward_range, backward_range; + real_t tmp_min_max, tmp_max_min; - const REAL amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); - const REAL semiamplitude = amplitude / 2.0; + const real_t amplitude = fabs( (g_maxs[i] - g_mins[i]) * amplitude_ratio ); + const real_t semiamplitude = amplitude / 2.0; tmp_min_max = std::min( g_maxs[i], gene + semiamplitude ); tmp_max_min = std::max( g_mins[i], gene - semiamplitude ); @@ -98,12 +98,12 @@ Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int tmp_max_min = std::max( g_mins[i], gene_prop - semiamplitude ); backward_range = tmp_min_max - tmp_max_min; - const REAL bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; + const real_t bf_fact = ( semiamplitude > 0.0 ) ? (backward_range / forward_range) : 1.0; // assign p' - REAL r01 = getRandRandNorm(); - REAL diff = amplitude * r01 - semiamplitude; - return Tuple(gene + diff, bf_fact); + real_t r01 = getRandRandNorm(); + real_t diff = amplitude * r01 - semiamplitude; + return Tuple(gene + diff, bf_fact); } /** @@ -112,17 +112,17 @@ Tuple mutate_helper( const REAL gene, const REAL gene_prop, const int * I took out the evaluation of the proposal, since it should be * done for all types of crossover/mutation/etc */ -void mutate_dims_all( REAL* g_a, // genome begins - REAL* g_b, - REAL* g_rho, - REAL* g_nu, - REAL* g_sigma, - REAL* g_fb_rat, +void mutate_dims_all( real_t* g_a, // genome begins + real_t* g_b, + real_t* g_rho, + real_t* g_nu, + real_t* g_sigma, + real_t* g_fb_rat, const int i, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { - REAL fb_rat = 1.0; + const real_t amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { + real_t fb_rat = 1.0; - Tuple tmp(EPS0, 1.0); + Tuple tmp(EPS0, 1.0); tmp = mutate_helper( g_a [i], g_a [i+POP_SIZE], 0, amplitude_ratio ); g_a [i + POP_SIZE] = constrain_dim1(0, tmp.fst); fb_rat *= tmp.snd; @@ -148,19 +148,19 @@ void mutate_dims_all( REAL* g_a, // genome begins * all population. Memory coalescence? * Requires POP_SIZE random uniform numbers! */ -void mutate_dims_one( REAL* g_a, // genome begins - REAL* g_b, - REAL* g_rho, - REAL* g_nu, - REAL* g_sigma, - REAL* g_fb_rat, +void mutate_dims_one( real_t* g_a, // genome begins + real_t* g_b, + real_t* g_rho, + real_t* g_nu, + real_t* g_sigma, + real_t* g_fb_rat, const int i, const int dim_j, - const REAL amplitude_ratio = MOVES_UNIF_AMPL_RATIO + const real_t amplitude_ratio = MOVES_UNIF_AMPL_RATIO ) { - REAL fb_rat = 1.0; + real_t fb_rat = 1.0; - Tuple tmp(EPS0, 1.0); + Tuple tmp(EPS0, 1.0); tmp = mutate_helper( g_a [i], g_a [i+POP_SIZE], 0, (dim_j == 0) ? amplitude_ratio : 0.0 ); g_a [i + POP_SIZE] = constrain_dim1(0, tmp.fst); fb_rat *= tmp.snd; @@ -183,15 +183,15 @@ void mutate_dims_one( REAL* g_a, // genome begins * Crossover * Requires a vector of size [ POP_SIZE*8 ] of random uniform numbers. */ -void mcmc_DE( REAL* g_a, // genome begins - REAL* g_b, - REAL* g_rho, - REAL* g_nu, - REAL* g_sigma, // genome ends - REAL* bf_rat, // fwd_bwd_ratio +void mcmc_DE( real_t* g_a, // genome begins + real_t* g_b, + real_t* g_rho, + real_t* g_nu, + real_t* g_sigma, // genome ends + real_t* bf_rat, // fwd_bwd_ratio const int j, - const REAL gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), - const REAL ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO + const real_t gamma_avg = 2.38 / sqrt(2.0*GENOME_DIM), + const real_t ampl_ratio = 0.1 * MOVES_UNIF_AMPL_RATIO ) { UINT cand_UB = POP_SIZE - 1; UINT k = getRandIntNorm(cand_UB); // random in [0,pop_size-1) @@ -207,7 +207,7 @@ void mcmc_DE( REAL* g_a, // genome begins // proposal // gamma: integrated out from the adviced // Multivariate Gaussian with Gaussian target (Braak, 2006) - REAL gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); + real_t gamma1 = gamma_avg - 0.5 + getRandUnifNorm(); g_a [j + POP_SIZE] = constrain_dim1( 0, perturbation( g_a [j], g_a [k], g_a [l], 0, gamma1, ampl_ratio ) ); g_b [j + POP_SIZE] = constrain_dim1( 1, perturbation( g_b [j], g_b [k], g_b [l], 1, gamma1, ampl_ratio ) ); diff --git a/benchmarks/InterestCalib/lib/include/Date.h b/benchmarks/InterestCalib/lib/include/Date.h index ba21834..39beace 100644 --- a/benchmarks/InterestCalib/lib/include/Date.h +++ b/benchmarks/InterestCalib/lib/include/Date.h @@ -74,12 +74,12 @@ bool check_date(const int& year, const int& month, const int& day) { return tmp1 && (tmp2 || tmp3); } -REAL days_between(const REAL& t1, const REAL& t2) { - REAL diff = static_cast(t1 - t2); +real_t days_between(const real_t& t1, const real_t& t2) { + real_t diff = static_cast(t1 - t2); return diff / minutes_in_day; } -REAL date_act_365(const REAL& t1, const REAL& t2) { +real_t date_act_365(const real_t& t1, const real_t& t2) { return days_between(t1, t2) / 365.0; } @@ -96,7 +96,7 @@ int end_of_month( const int& year, const int& month ) { else return 31; } -REAL add_months ( const REAL& time, const REAL& rnbmonths ) { +real_t add_months ( const real_t& time, const real_t& rnbmonths ) { int nbmonths = static_cast( rnbmonths ); Date date = gregorian_of_date( static_cast ( time ) ); @@ -113,15 +113,15 @@ REAL add_months ( const REAL& time, const REAL& rnbmonths ) { date.min = 0; } - return static_cast( date_of_gregorian( date ) ); + return static_cast( date_of_gregorian( date ) ); } -REAL add_years( const REAL& date, const REAL& nbyears ) { +real_t add_years( const real_t& date, const real_t& nbyears ) { return add_months( date, nbyears * 12.0 ); } void test_dates() { - REAL tmp; + real_t tmp; fprintf(stderr, "add_months(min_date,1)==48240 : "); tmp = add_months(MIN_DATE, 1.0); diff --git a/benchmarks/InterestCalib/lib/include/EvalGenomeInl.h b/benchmarks/InterestCalib/lib/include/EvalGenomeInl.h index 6adc3d3..360ce9c 100644 --- a/benchmarks/InterestCalib/lib/include/EvalGenomeInl.h +++ b/benchmarks/InterestCalib/lib/include/EvalGenomeInl.h @@ -9,28 +9,28 @@ /** * MOST IMPORTANTLY: GENOME EVALUATION By Pricer of Swaption & BLACK PRICE */ -REAL eval_genome( const REAL a, - const REAL b, - const REAL rho, - const REAL nu, - const REAL sigma, +real_t eval_genome( const real_t a, + const real_t b, + const real_t rho, + const real_t nu, + const real_t sigma, - REAL* anew_quote, // [NUM_SWAP_QUOTES] - REAL* anew_price, // [NUM_SWAP_QUOTES] + real_t* anew_quote, // [NUM_SWAP_QUOTES] + real_t* anew_price, // [NUM_SWAP_QUOTES] const int N, short* flags, // [N] int * start_inds // [NUM_SWAP_QUOTES] ) { - REAL rms = 0.0; + real_t rms = 0.0; bool sanity = true; // expand the irregular arrays - REAL *irreg_arrays = new REAL[8 * N]; - REAL *gbai, *gbbi, *gaici, *glog_aici, *gci, *gt1_cs, *gscale, *ghat_scale; + real_t *irreg_arrays = new real_t[8 * N]; + real_t *gbai, *gbbi, *gaici, *glog_aici, *gci, *gt1_cs, *gscale, *ghat_scale; { // map intermediary arrays - REAL* ptr = irreg_arrays; + real_t* ptr = irreg_arrays; gbai = ptr; ptr += N; gbbi = ptr; ptr += N; gaici = ptr; ptr += N; @@ -43,32 +43,32 @@ REAL eval_genome( const REAL a, // BIG KERNEL for( UINT ttt = 0; ttt < NUM_SWAP_QUOTES; ttt++ ) { - const REAL mat_year = SwaptionQuotes[4*ttt + 0]; - const REAL swap_freq = SwaptionQuotes[4*ttt + 1]; - const REAL term_year = SwaptionQuotes[4*ttt + 2]; - const REAL quote = SwaptionQuotes[4*ttt + 3]; + const real_t mat_year = SwaptionQuotes[4*ttt + 0]; + const real_t swap_freq = SwaptionQuotes[4*ttt + 1]; + const real_t term_year = SwaptionQuotes[4*ttt + 2]; + const real_t quote = SwaptionQuotes[4*ttt + 3]; // adjust temporary array const int beg_ind = start_inds[ttt]; - REAL *ci = gci + beg_ind, *bai = gbai + beg_ind, *bbi = gbbi + beg_ind, *aici = gaici + beg_ind; - REAL *log_aici = glog_aici + beg_ind, *t1_cs = gt1_cs + beg_ind, *scale = gscale + beg_ind; - REAL *hat_scale = ghat_scale + beg_ind; + real_t *ci = gci + beg_ind, *bai = gbai + beg_ind, *bbi = gbbi + beg_ind, *aici = gaici + beg_ind; + real_t *log_aici = glog_aici + beg_ind, *t1_cs = gt1_cs + beg_ind, *scale = gscale + beg_ind; + real_t *hat_scale = ghat_scale + beg_ind; // new_quote does not have to be computed all the time, does it? // it can just be computed once and indexed into an array ... - //const REAL new_quote = black_price ( TODAY, mat_year, swap_freq, term_year, quote ); + //const real_t new_quote = black_price ( TODAY, mat_year, swap_freq, term_year, quote ); - const REAL maturity = add_years( TODAY, mat_year ); + const real_t maturity = add_years( TODAY, mat_year ); const UINT n_schedi = static_cast(12.0 * term_year / swap_freq); - const REAL tmat0 = date_act_365( maturity, TODAY ); + const real_t tmat0 = date_act_365( maturity, TODAY ); - REAL strike; // new_quote, + real_t strike; // new_quote, { // BLACK PRICE computation - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; + real_t lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; for(UINT i = 0; i < n_schedi; i++) { // reduce o map => in local memory - const REAL a1 = add_months( maturity, swap_freq*i ); - const REAL a2 = add_months( a1, swap_freq ); + const real_t a1 = add_months( maturity, swap_freq*i ); + const real_t a2 = add_months( a1, swap_freq ); // Reduction( lvl: +, t0 : min, tn : max ) lvl += zc(a2) * date_act_365(a2, a1); @@ -77,49 +77,49 @@ REAL eval_genome( const REAL a, } strike = ( zc(t0) - zc(tn) ) / lvl; - const REAL d1 = 0.5 * quote * tmat0; + const real_t d1 = 0.5 * quote * tmat0; anew_quote[ttt] = lvl * strike * ( uGaussian_P(d1) - uGaussian_P(-d1) ); } // END BLACK PRICE - //const REAL new_price = pricer_of_swaption( TODAY, mat_year, swap_freq, term_year, g_a, g_b, g_rho, g_nu, g_sigma); - //REAL new_price; + //const real_t new_price = pricer_of_swaption( TODAY, mat_year, swap_freq, term_year, g_a, g_b, g_rho, g_nu, g_sigma); + //real_t new_price; { // PRICER OF SWAPTION COMPUTATION - REAL v0_mat, dummy1, dummy2; + real_t v0_mat, dummy1, dummy2; bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); // - const REAL mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); - const REAL muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); + const real_t mux = - bigmx( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); + const real_t muy = - bigmy( a, b, rho, nu, sigma, TODAY, maturity, TODAY, maturity ); // - const REAL zc_mat = zc(maturity); + const real_t zc_mat = zc(maturity); // - const REAL sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); - const REAL sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); - const REAL rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); - const REAL sigmax = sigma * sqrt_bfun_a; - const REAL sigmay = nu * sqrt_bfun_b; - - const REAL rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel - const REAL rhoxycs = sqrt( rhoxyc ); // used in reduction kernel - const REAL sigmay_rhoxycs = sigmay * rhoxycs; - const REAL t4 = (rhoxy * sigmay) / sigmax; + const real_t sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); + const real_t sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); + const real_t rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); + const real_t sigmax = sigma * sqrt_bfun_a; + const real_t sigmay = nu * sqrt_bfun_b; + + const real_t rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel + const real_t rhoxycs = sqrt( rhoxyc ); // used in reduction kernel + const real_t sigmay_rhoxycs = sigmay * rhoxycs; + const real_t t4 = (rhoxy * sigmay) / sigmax; // for( UINT i = 0; i < n_schedi; i++ ) { - const REAL beg_date = add_months( maturity, swap_freq*i ); //scheduleix[i]; - const REAL end_date = add_months( beg_date, swap_freq ); //scheduleiy[i]; - const REAL res = date_act_365( end_date, beg_date ) * strike; + const real_t beg_date = add_months( maturity, swap_freq*i ); //scheduleix[i]; + const real_t end_date = add_months( beg_date, swap_freq ); //scheduleiy[i]; + const real_t res = date_act_365( end_date, beg_date ) * strike; - const REAL cii = ( i == n_schedi-1 ) ? 1.0 + res : res; + const real_t cii = ( i == n_schedi-1 ) ? 1.0 + res : res; - REAL v0_end, vt_end, baii, bbii, date_tod1, date_tod2; + real_t v0_end, vt_end, baii, bbii, date_tod1, date_tod2; date_tod1 = date_act_365(end_date, TODAY); bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); date_tod2 = date_act_365(end_date, maturity); bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); - const REAL expo_aici = 0.5 * (vt_end - v0_end + v0_mat); - const REAL fact_aici = cii * zc(end_date) / zc_mat; + const real_t expo_aici = 0.5 * (vt_end - v0_end + v0_mat); + const real_t fact_aici = cii * zc(end_date) / zc_mat; ci [i] = fact_aici; // reuse the space to hold the factor of t1_cs t1_cs [i] = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; // hold only the exponent of the original t1_cs; @@ -134,45 +134,45 @@ REAL eval_genome( const REAL a, assert(sanity && "Nan aici in pricer of swaption. Exiting!\n"); } // - const REAL eps = 0.5 * sigmax; + const real_t eps = 0.5 * sigmax; - const REAL f = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + const real_t f = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux ); - const REAL g = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + const real_t g = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux + eps ); - const REAL h = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, + const real_t h = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux - eps ); - const REAL df = 0.5 * ( g - h ) / eps; + const real_t df = 0.5 * ( g - h ) / eps; - const REAL sqrt2sigmax = sqrt(2.0) * sigmax;; - const REAL t2 = rhoxy / (sigmax*rhoxycs);; + const real_t sqrt2sigmax = sqrt(2.0) * sigmax;; + const real_t t2 = rhoxy / (sigmax*rhoxycs);; - REAL accum = 0.0; + real_t accum = 0.0; for( UINT j = 0; j < NUM_HERMITE; j++ ) { - const REAL x_quad = HermiteCoeffs [j]; - const REAL w_quad = HermiteWeights[j]; + const real_t x_quad = HermiteCoeffs [j]; + const real_t w_quad = HermiteWeights[j]; - const REAL x = sqrt2sigmax * x_quad + mux; - const REAL yhat_x = f + df*(x - mux); - const REAL h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); + const real_t x = sqrt2sigmax * x_quad + mux; + const real_t yhat_x = f + df*(x - mux); + const real_t h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); - REAL accum1 = 0.0; + real_t accum1 = 0.0; for( UINT i = 0; i < n_schedi; i++ ) { - const REAL h2 = h1 + bbi[i] * sigmay_rhoxycs; + const real_t h2 = h1 + bbi[i] * sigmay_rhoxycs; - const REAL expo_aici = t1_cs[i] + scale[i]*x; - const REAL fact_aici = ci[i]; + const real_t expo_aici = t1_cs[i] + scale[i]*x; + const real_t fact_aici = ci[i]; // accum1 += fact_aici * exp(expo_aici) * uGaussian_P(-h2); - const REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); + const real_t expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); accum1 += fact_aici * expo_part; } sanity = ! ( isnan(accum1) || isinf(accum1) ); assert(sanity && "Nan accum1 in pricer of swaption. Exiting!\n"); - REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; - const REAL t1 = exp( - 0.5 * tmp * tmp ); + real_t tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; + const real_t t1 = exp( - 0.5 * tmp * tmp ); accum += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); } @@ -182,9 +182,9 @@ REAL eval_genome( const REAL a, anew_price[ttt] = zc_mat * ( accum / sqrt( PI ) ); -// const REAL tmp = (anew_price[ttt] - anew_quote[ttt]) / anew_quote[ttt]; +// const real_t tmp = (anew_price[ttt] - anew_quote[ttt]) / anew_quote[ttt]; // rms += tmp * tmp; - const REAL lik = logLikelihood( anew_quote[ttt], anew_price[ttt] ); + const real_t lik = logLikelihood( anew_quote[ttt], anew_price[ttt] ); rms += lik; } } diff --git a/benchmarks/InterestCalib/lib/include/G2PP.h b/benchmarks/InterestCalib/lib/include/G2PP.h index e9d3b0b..bd9105f 100644 --- a/benchmarks/InterestCalib/lib/include/G2PP.h +++ b/benchmarks/InterestCalib/lib/include/G2PP.h @@ -12,33 +12,33 @@ // Root finder ////////////////////////// -REAL exactYhat( const UINT& n_schedi, - - const REAL& b, // scals begins - const REAL& sigmax, - const REAL& sigmay, - const REAL& rhoxy, - const REAL& rhoxyc, - const REAL& rhoxycs, - const REAL& mux, - const REAL& muy, // scals ends - - const REAL* bai, // babaicis begins - const REAL* bbi, - const REAL* aici, - const REAL* log_aici, // babaicis ends - - REAL* scales, - const REAL& x +real_t exactYhat( const UINT& n_schedi, + + const real_t& b, // scals begins + const real_t& sigmax, + const real_t& sigmay, + const real_t& rhoxy, + const real_t& rhoxyc, + const real_t& rhoxycs, + const real_t& mux, + const real_t& muy, // scals ends + + const real_t* bai, // babaicis begins + const real_t* bbi, + const real_t* aici, + const real_t* log_aici, // babaicis ends + + real_t* scales, + const real_t& x ) { // ugaussian_Pinv(k)=1.0e~4 - const REAL k = - 3.71901648545568; + const real_t k = - 3.71901648545568; - REAL up = 0.0, lo = -INFTY; + real_t up = 0.0, lo = -INFTY; for( UINT i = 0; i < n_schedi; i++ ) { - REAL baix = bai[i] * x; + real_t baix = bai[i] * x; - REAL up_term = aici[i] * exp( -baix ); + real_t up_term = aici[i] * exp( -baix ); scales[i] = up_term; up += up_term; lo = std::max( lo, ( log_aici[i] - baix ) / bbi[i] ); @@ -50,8 +50,8 @@ REAL exactYhat( const UINT& n_schedi, // CHECKING uplo!!!! - const REAL log_s = log(up); - REAL tmp = log_s / bbi[n_schedi-1]; + const real_t log_s = log(up); + real_t tmp = log_s / bbi[n_schedi-1]; if ( tmp <= 0.0 ) { up = tmp; @@ -61,20 +61,20 @@ REAL exactYhat( const UINT& n_schedi, else up = - INFTY; } - const REAL yl = lo - EPS; - const REAL yu = up + EPS; + const real_t yl = lo - EPS; + const real_t yu = up + EPS; - const REAL y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; - const REAL y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; + const real_t y0 = sigmay * ( rhoxy * (x-mux) / sigmax + k * rhoxycs ) - rhoxyc/b + muy; + const real_t y1 = sigmay * ( rhoxy * (x-mux) / sigmax - k * rhoxycs ) + muy; - REAL res; + real_t res; if ( y1 <= yl ) res = y1 + 1.0; // yhat is greater than y1 => 1 - phi(h_i(x, yhat)) < EPS else if ( yu <= y0 ) res = y0 - 1.0; // yhat is lower than y0 => phi(h_i(x, yhat)) < EPS) else { - const REAL root_lb = std::max( yl, y0 ); - const REAL root_ub = std::min( yu, y1 ); + const real_t root_lb = std::max( yl, y0 ); + const real_t root_ub = std::min( yu, y1 ); - REAL root, error; UINT iter; + real_t root, error; UINT iter; rootFinding_Brent(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); //rootBisection(1, n_schedi, scales, bbi, root_lb, root_ub, 1.0e-4, 1000, root, iter, error); @@ -101,47 +101,47 @@ REAL exactYhat( const UINT& n_schedi, // return res,ba,bb ////////////// -REAL pricer_of_swaption( const REAL& today, +real_t pricer_of_swaption( const real_t& today, - const REAL& sw_mat, // swaptionQuote begins ... - const REAL& sw_freq, - const REAL& sw_ty, // swaptionQuote ends. - - const REAL& a, // genome begins ... - const REAL& b, - const REAL& rho, - const REAL& nu, - const REAL& sigma // genome ends. + const real_t& sw_mat, // swaptionQuote begins ... + const real_t& sw_freq, + const real_t& sw_ty, // swaptionQuote ends. + + const real_t& a, // genome begins ... + const real_t& b, + const real_t& rho, + const real_t& nu, + const real_t& sigma // genome ends. ) { //SwapOfSwap sos = extended_swaption_of_swaption(sw_mat, sw_freq, sw_ty); - const REAL maturity = add_years( TODAY, sw_mat ); + const real_t maturity = add_years( TODAY, sw_mat ); const UINT n_schedi = static_cast(12.0 * sw_ty / sw_freq); // - const REAL tmat0 = date_act_365( maturity, today ); // BIG BUG -- was TODAY - REAL v0_mat, dummy1, dummy2; + const real_t tmat0 = date_act_365( maturity, today ); // BIG BUG -- was TODAY + real_t v0_mat, dummy1, dummy2; bigv( a, b, rho, nu, sigma, tmat0, v0_mat, dummy1, dummy2); // - const REAL mux = - bigmx( a, b, rho, nu, sigma, today, maturity, today, maturity ); - const REAL muy = - bigmy( a, b, rho, nu, sigma, today, maturity, today, maturity ); + const real_t mux = - bigmx( a, b, rho, nu, sigma, today, maturity, today, maturity ); + const real_t muy = - bigmy( a, b, rho, nu, sigma, today, maturity, today, maturity ); // - const REAL zc_mat = zc(maturity); + const real_t zc_mat = zc(maturity); // - const REAL sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); - const REAL sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); - const REAL rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); - const REAL sigmax = sigma * sqrt_bfun_a; - const REAL sigmay = nu * sqrt_bfun_b; - - const REAL rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel - const REAL rhoxycs = sqrt( rhoxyc ); // used in reduction kernel - const REAL sigmay_rhoxycs = sigmay * rhoxycs; - const REAL t4 = (rhoxy * sigmay) / sigmax; + const real_t sqrt_bfun_a = sqrt( b_fun(2.0*a, tmat0) ); + const real_t sqrt_bfun_b = sqrt( b_fun(2.0*b, tmat0) ); + const real_t rhoxy = rho * b_fun(a+b, tmat0) / (sqrt_bfun_a * sqrt_bfun_b); + const real_t sigmax = sigma * sqrt_bfun_a; + const real_t sigmay = nu * sqrt_bfun_b; + + const real_t rhoxyc = 1.0 - rhoxy * rhoxy; // used in reduction kernel + const real_t rhoxycs = sqrt( rhoxyc ); // used in reduction kernel + const real_t sigmay_rhoxycs = sigmay * rhoxycs; + const real_t t4 = (rhoxy * sigmay) / sigmax; // - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; + real_t lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; for( UINT i = 0; i < n_schedi; i++ ) { - REAL a1 = add_months( maturity, sw_freq*i ); + real_t a1 = add_months( maturity, sw_freq*i ); //sos.swap_sched1[i] = a1; - REAL a2 = add_months( a1, sw_freq ); + real_t a2 = add_months( a1, sw_freq ); //sos.swap_sched2[i] = a2; // Reduction( lvl: +, t0 : min, tn : max ) @@ -150,32 +150,32 @@ REAL pricer_of_swaption( const REAL& today, tn = std::max(tn, a2); } - const REAL strike = ( zc(t0) - zc(tn) ) / lvl; + const real_t strike = ( zc(t0) - zc(tn) ) / lvl; // - REAL* ci = new REAL[n_schedi]; - REAL* bai = new REAL[n_schedi]; - REAL* bbi = new REAL[n_schedi]; - REAL* aici = new REAL[n_schedi]; - REAL* log_aici = new REAL[n_schedi]; - REAL* t1_cs = new REAL[n_schedi]; - REAL* scale = new REAL[n_schedi]; - REAL* hat_scale= new REAL[n_schedi]; + real_t* ci = new real_t[n_schedi]; + real_t* bai = new real_t[n_schedi]; + real_t* bbi = new real_t[n_schedi]; + real_t* aici = new real_t[n_schedi]; + real_t* log_aici = new real_t[n_schedi]; + real_t* t1_cs = new real_t[n_schedi]; + real_t* scale = new real_t[n_schedi]; + real_t* hat_scale= new real_t[n_schedi]; for( UINT i = 0; i < n_schedi; i++ ) { - const REAL beg_date = add_months( maturity, sw_freq*i ); //scheduleix[i]; - const REAL end_date = add_months( beg_date, sw_freq ); //scheduleiy[i]; - const REAL res = date_act_365( end_date, beg_date ) * strike; + const real_t beg_date = add_months( maturity, sw_freq*i ); //scheduleix[i]; + const real_t end_date = add_months( beg_date, sw_freq ); //scheduleiy[i]; + const real_t res = date_act_365( end_date, beg_date ) * strike; - const REAL cii = ( i == n_schedi-1 ) ? 1.0 + res : res; + const real_t cii = ( i == n_schedi-1 ) ? 1.0 + res : res; - REAL v0_end, vt_end, baii, bbii, date_tod1, date_tod2; + real_t v0_end, vt_end, baii, bbii, date_tod1, date_tod2; date_tod1 = date_act_365(end_date, today); bigv( a, b, rho, nu, sigma, date_tod1, v0_end, dummy1, dummy2 ); date_tod2 = date_act_365(end_date, maturity); bigv( a, b, rho, nu, sigma, date_tod2, vt_end, baii, bbii ); - const REAL expo_aici = 0.5 * (vt_end - v0_end + v0_mat); - const REAL fact_aici = cii * zc(end_date) / zc_mat; + const real_t expo_aici = 0.5 * (vt_end - v0_end + v0_mat); + const real_t fact_aici = cii * zc(end_date) / zc_mat; ci [i] = fact_aici; // reuse the space to hold the factor of t1_cs t1_cs [i] = bbii * (mux * t4 - (muy - 0.5*rhoxyc*sigmay*sigmay*bbii) ) + expo_aici; // hold only the exponent of the original t1_cs; @@ -191,39 +191,39 @@ REAL pricer_of_swaption( const REAL& today, } // - const REAL eps = 0.5 * sigmax; + const real_t eps = 0.5 * sigmax; - const REAL f = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux ); - const REAL g = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux + eps ); - const REAL h = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux - eps ); - const REAL df = 0.5 * ( g - h ) / eps; + const real_t f = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux ); + const real_t g = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux + eps ); + const real_t h = exactYhat( n_schedi, b, sigmax, sigmay, rhoxy, rhoxyc, rhoxycs, mux, muy, bai, bbi, aici, log_aici, hat_scale, mux - eps ); + const real_t df = 0.5 * ( g - h ) / eps; // AT this point we need: // scalars: sqrt2sigmax, t2, f, df, mux, muy, sigmay_rhoxycs, zc_mat // arrays : t1_cs, bbi, scale, ci - const REAL sqrt2sigmax = sqrt(2.0) * sigmax; - const REAL t2 = rhoxy / (sigmax*rhoxycs); + const real_t sqrt2sigmax = sqrt(2.0) * sigmax; + const real_t t2 = rhoxy / (sigmax*rhoxycs); // t2 * (sqrt2sigmax * x_quad) -> sqrt(2.0) * rhoxy / rhoxycs * xquad - REAL accum0 = 0.0; + real_t accum0 = 0.0; for( UINT j = 0; j < NUM_HERMITE; j++ ) { - const REAL x_quad = HermiteCoeffs [j]; - const REAL w_quad = HermiteWeights[j]; + const real_t x_quad = HermiteCoeffs [j]; + const real_t w_quad = HermiteWeights[j]; - const REAL x = sqrt2sigmax * x_quad + mux; + const real_t x = sqrt2sigmax * x_quad + mux; - const REAL yhat_x = f + df*(x - mux); - const REAL h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); + const real_t yhat_x = f + df*(x - mux); + const real_t h1 = ( (yhat_x - muy) / sigmay_rhoxycs ) - t2*( x - mux ); - REAL accum1 = 0.0; + real_t accum1 = 0.0; for( UINT i = 0; i < n_schedi; i++ ) { - const REAL h2 = h1 + bbi[i] * sigmay_rhoxycs; + const real_t h2 = h1 + bbi[i] * sigmay_rhoxycs; - const REAL expo_aici = t1_cs[i] + scale[i]*x; - const REAL fact_aici = ci[i]; + const real_t expo_aici = t1_cs[i] + scale[i]*x; + const real_t fact_aici = ci[i]; // accum1 += fact_aici * exp(expo_aici) * uGaussian_P(-h2); - const REAL expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); + const real_t expo_part = uGaussian_P_withExpFactor( -h2, expo_aici ); accum1 += fact_aici * expo_part; if( isnan(accum1) || isinf(accum1) ) { @@ -235,8 +235,8 @@ REAL pricer_of_swaption( const REAL& today, } } - REAL tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; - const REAL t1 = exp( - 0.5 * tmp * tmp ); + real_t tmp = sqrt(2.0) * x_quad; //(x - mux) / sigmax; + const real_t t1 = exp( - 0.5 * tmp * tmp ); accum0 += w_quad * t1 * ( uGaussian_P(-h1) - accum1 ); } @@ -258,20 +258,20 @@ REAL pricer_of_swaption( const REAL& today, //// Pricer for one genome: //// //////////////////////////////// -REAL pricer (const REAL a = 0.02453, const REAL b = 0.98376, const REAL rho = -0.82400, const REAL nu = 0.11830, const REAL sigma = 0.02398) { +real_t pricer (const real_t a = 0.02453, const real_t b = 0.98376, const real_t rho = -0.82400, const real_t nu = 0.11830, const real_t sigma = 0.02398) { //let genome = {0.02453, 0.98376, ~0.82400, 0.11830, 0.02398} in - REAL rms = 0.0, logLik = 0.0; + real_t rms = 0.0, logLik = 0.0; for( UINT i = 0; i < NUM_SWAP_QUOTES; i++ ) { - const REAL mat_year = SwaptionQuotes[4*i+0]; - const REAL swap_freq = SwaptionQuotes[4*i+1]; - const REAL term_year = SwaptionQuotes[4*i+2]; - const REAL quote = SwaptionQuotes[4*i+3]; + const real_t mat_year = SwaptionQuotes[4*i+0]; + const real_t swap_freq = SwaptionQuotes[4*i+1]; + const real_t term_year = SwaptionQuotes[4*i+2]; + const real_t quote = SwaptionQuotes[4*i+3]; - const REAL g2pp_price = pricer_of_swaption( TODAY, mat_year, swap_freq, term_year, a, b, rho, nu, sigma); - const REAL market_price = black_price ( TODAY, mat_year, swap_freq, term_year, quote ); + const real_t g2pp_price = pricer_of_swaption( TODAY, mat_year, swap_freq, term_year, a, b, rho, nu, sigma); + const real_t market_price = black_price ( TODAY, mat_year, swap_freq, term_year, quote ); - const REAL tmp = (g2pp_price - market_price) / market_price; + const real_t tmp = (g2pp_price - market_price) / market_price; rms += tmp * tmp; logLik += logLikelihood( market_price, g2pp_price ); } @@ -297,18 +297,18 @@ REAL pricer (const REAL a = 0.02453, const REAL b = 0.98376, const REAL rho = -0 void test_pricer_of_swaption() { - const REAL a = 0.02453; - const REAL b = 0.98376; - const REAL rho = -0.82400; - const REAL nu = 0.11830; - const REAL sigma = 0.02398; + const real_t a = 0.02453; + const real_t b = 0.98376; + const real_t rho = -0.82400; + const real_t nu = 0.11830; + const real_t sigma = 0.02398; // (maturity, frequency, term) = swaption - REAL maturity = 10.0; - REAL freq = 6.0; - REAL term = 4.0; + real_t maturity = 10.0; + real_t freq = 6.0; + real_t term = 4.0; - const REAL price1 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma); + const real_t price1 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma); printf("Pricer_of_swaption test I = 657.82158867845 : "); if( equalEps(price1, 657.82158867845) ) printf(" SUCCESS!\n\n"); else printf("%f FAILS!\n\n", price1); @@ -318,7 +318,7 @@ void test_pricer_of_swaption() { freq = 6.0; term = 30.0; - const REAL price2 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma ); + const real_t price2 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma ); printf("Pricer_of_swaption test II = 1902.97628191498 : "); if( equalEps(price2, 1902.97628191498) ) printf(" SUCCESS!\n\n"); else printf("%f FAILS!\n\n", price2); @@ -329,7 +329,7 @@ void test_pricer_of_swaption() { freq = 6.0; term = 25.0; - const REAL price3 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma ); + const real_t price3 = 1.0e4 * pricer_of_swaption( TODAY, maturity, freq, term, a, b, rho, nu, sigma ); printf("Pricer_of_swaption test III = 1840.859126408099 : "); if( equalEps(price3, 1840.859126408099) ) printf(" SUCCESS!\n\n"); else printf("%f FAILS!\n\n", price3); diff --git a/benchmarks/InterestCalib/lib/include/G2ppUtil.h b/benchmarks/InterestCalib/lib/include/G2ppUtil.h index fae53f9..0666314 100644 --- a/benchmarks/InterestCalib/lib/include/G2ppUtil.h +++ b/benchmarks/InterestCalib/lib/include/G2ppUtil.h @@ -5,34 +5,34 @@ #include "Constants.h" #include "MathModule.h" -REAL zc( const REAL& t ) { +real_t zc( const real_t& t ) { return exp( - R * date_act_365( t, TODAY ) ); } /** -Triple accumSched( Triple xx, Triple yy ) { - REAL x = xx.fst, d1 = xx.snd, d2 = xx.thrd, y = yy.fst, tf = yy.snd, tp = yy.thrd; - return Triple( x + zc(tp) * date_act_365(tp, tf), std::min(d1,tf), std::max(d2,tp) ); +Triple accumSched( Triple xx, Triple yy ) { + real_t x = xx.fst, d1 = xx.snd, d2 = xx.thrd, y = yy.fst, tf = yy.snd, tp = yy.thrd; + return Triple( x + zc(tp) * date_act_365(tp, tf), std::min(d1,tf), std::max(d2,tp) ); } **/ SwapOfSwap extended_swaption_of_swaption( - const REAL& sw_mat, - const REAL& freq, - const REAL& sw_ty + const real_t& sw_mat, + const real_t& freq, + const real_t& sw_ty ) { - const REAL maturity = add_years( TODAY, sw_mat ); + const real_t maturity = add_years( TODAY, sw_mat ); const UINT nschedule = static_cast(12.0 * sw_ty / freq); SwapOfSwap sos(nschedule); - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; + real_t lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; for(UINT i=0; i= EPS ) ? x : ( x >= 0.0 ) ? EPS : -EPS; - const REAL expxtau = exp( -x0*tau ) ; - const REAL exp2xtau = expxtau*expxtau; +real_t t_fun( const real_t& sigma, const real_t& x0, const real_t& tau ) { + //const real_t x0 = ( fabs(x) >= EPS ) ? x : ( x >= 0.0 ) ? EPS : -EPS; + const real_t expxtau = exp( -x0*tau ) ; + const real_t exp2xtau = expxtau*expxtau; return sigma*sigma/(x0*x0) * ( tau + 2.0/x0*expxtau-1.0/(2.0*x0)*exp2xtau-3.0/(2.0*x0) ); } @@ -69,17 +69,17 @@ REAL t_fun( const REAL& sigma, const REAL& x0, const REAL& tau ) { // the result is V in Brigo and Mercurio's book page 148. // \var(\int_t^T [x(u)+y(u)]du) /////////////////////////////////////////////////////////////////// -void bigv( const REAL& g_a, - const REAL& g_b, - const REAL& g_rho, - const REAL& g_nu, - const REAL& g_sig, - const REAL& tau, - REAL& v, - REAL& bai, - REAL& bbi +void bigv( const real_t& g_a, + const real_t& g_b, + const real_t& g_rho, + const real_t& g_nu, + const real_t& g_sig, + const real_t& tau, + real_t& v, + real_t& bai, + real_t& bbi ) { - const REAL g_sigma = g_sig; //(g_sig == 0.0) ? 1.0e-10 : g_sig; + const real_t g_sigma = g_sig; //(g_sig == 0.0) ? 1.0e-10 : g_sig; bai = b_fun(g_a, tau); bbi = b_fun(g_b, tau); @@ -98,25 +98,25 @@ void bigv( const REAL& g_a, // // the result is: x drift term in tmat-forward measure /////////////////////////////////////////////////////////////////// -REAL bigmx( const REAL& a, - const REAL& b, - const REAL& rho, - const REAL& nu, - const REAL& sigma, // ends genome - const REAL& today, - const REAL& tmat, - const REAL& s, - const REAL& t +real_t bigmx( const real_t& a, + const real_t& b, + const real_t& rho, + const real_t& nu, + const real_t& sigma, // ends genome + const real_t& today, + const real_t& tmat, + const real_t& s, + const real_t& t ) { - const REAL ts = date_act_365(t, s) ; - const REAL tmatt = date_act_365(tmat, t) ; + const real_t ts = date_act_365(t, s) ; + const real_t tmatt = date_act_365(tmat, t) ; - const REAL tmat0 = date_act_365(tmat, today); - const REAL tmats = date_act_365(tmat, s) ; - const REAL t0 = date_act_365(t, today); - const REAL s0 = date_act_365(s, today); + const real_t tmat0 = date_act_365(tmat, today); + const real_t tmats = date_act_365(tmat, s) ; + const real_t t0 = date_act_365(t, today); + const real_t s0 = date_act_365(s, today); - REAL tmp, res = 0.0; + real_t tmp, res = 0.0; tmp = (sigma*sigma)/(a*a)+(sigma*rho*nu)/(a*b); tmp *= ( 1.0 - exp(- a * ts) ); @@ -143,24 +143,24 @@ REAL bigmx( const REAL& a, // the result is: y drift term in tmat-forward measure /////////////////////////////////////////////////////////////////// -REAL bigmy( const REAL& a, - const REAL& b, - const REAL& rho, - const REAL& nu, - const REAL& sigma, // ends genome - const REAL& today, - const REAL& tmat, - const REAL& s, - const REAL& t +real_t bigmy( const real_t& a, + const real_t& b, + const real_t& rho, + const real_t& nu, + const real_t& sigma, // ends genome + const real_t& today, + const real_t& tmat, + const real_t& s, + const real_t& t ) { - const REAL ts = date_act_365(t, s) ; - const REAL tmatt = date_act_365(tmat, t) ; - const REAL tmat0 = date_act_365(tmat, today); - const REAL tmats = date_act_365(tmat, s) ; - const REAL t0 = date_act_365(t, today); - const REAL s0 = date_act_365(s, today); + const real_t ts = date_act_365(t, s) ; + const real_t tmatt = date_act_365(tmat, t) ; + const real_t tmat0 = date_act_365(tmat, today); + const real_t tmats = date_act_365(tmat, s) ; + const real_t t0 = date_act_365(t, today); + const real_t s0 = date_act_365(s, today); - REAL tmp, res = 0.0; + real_t tmp, res = 0.0; tmp = nu*nu/(b*b)+sigma*rho*nu/(a*b); tmp *= 1.0 - exp(-b * ts); @@ -178,23 +178,23 @@ REAL bigmy( const REAL& a, } -REAL black_price ( const REAL& today, - const REAL& sw_mat, // swaption.1 - const REAL& freq, // swaption.2 - const REAL& sw_ty, // swaption.3 - const REAL& vol +real_t black_price ( const real_t& today, + const real_t& sw_mat, // swaption.1 + const real_t& freq, // swaption.2 + const real_t& sw_ty, // swaption.3 + const real_t& vol ) { // inlined extended_swaption_of_swaptions - const REAL maturity = add_years( TODAY, sw_mat ); + const real_t maturity = add_years( TODAY, sw_mat ); const UINT nschedule = static_cast(12.0 * sw_ty / freq); - const REAL sqrtt = date_act_365( maturity, today ); + const real_t sqrtt = date_act_365( maturity, today ); // morally equivalent to `swap_schedule2lvl(swap_schedule)' but in map-reduce form!! - REAL lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; + real_t lvl = 0.0, t0 = MAX_DATE, tn = MIN_DATE; for(UINT i=0; i> 1) ^ n; int res = 0; for( int i=0; i < NUM_SOBOL_BITS; i++ ) { @@ -19,7 +19,7 @@ REAL getSobolNum( uint n ) { res = res ^ SobolDirVct[i]; } } - REAL rres = static_cast(res) / ( (1<(res) / ( (1<= 1.0 || rres < 0 ) { printf("sobol(%d) = %f. Exiting!\n", n, rres); exit(0);} return rres; } @@ -27,23 +27,23 @@ REAL getSobolNum( uint n ) { //unsigned int rand_count = 1; uint sobol_offset = 1; //11; -REAL getRandRandNorm() { +real_t getRandRandNorm() { #if WITH_SOBOL return getSobolNum( sobol_offset++ ); #endif double r = static_cast(std::rand()); // drand48() double d = static_cast(RAND_MAX)+0.1; - return static_cast(r / d); + return static_cast(r / d); } -REAL getRandUnifNorm() { +real_t getRandUnifNorm() { return getRandRandNorm(); - //return static_cast(drand48()); + //return static_cast(drand48()); } //Returns a (pseudo) random integer in [0, ub) UINT getRandIntNorm(long int ub) { - REAL r01 = getRandRandNorm(); + real_t r01 = getRandRandNorm(); return static_cast(r01 * ub); } @@ -54,38 +54,38 @@ UINT getRandIntNorm(long int ub) { /********************************************/ //========================================================================= -const REAL sqrtTwoPi = sqrt(2*PI); +const real_t sqrtTwoPi = sqrt(2*PI); -REAL normal_pdf( const REAL& z, const REAL& mu, const REAL& sigma ) { - REAL sigmap = fabs(sigma); - REAL res = 1.0 / (sigmap * sqrtTwoPi); - REAL ecf = (z-mu) * (z-mu) / (2.0 * sigmap * sigmap); +real_t normal_pdf( const real_t& z, const real_t& mu, const real_t& sigma ) { + real_t sigmap = fabs(sigma); + real_t res = 1.0 / (sigmap * sqrtTwoPi); + real_t ecf = (z-mu) * (z-mu) / (2.0 * sigmap * sigmap); return res * exp( -ecf ); } -REAL cauchy_pdf( const REAL& z, const REAL mu = 0.0, const REAL gamma = 4.0) { - REAL x = (z-mu) / gamma; +real_t cauchy_pdf( const real_t& z, const real_t mu = 0.0, const real_t gamma = 4.0) { + real_t x = (z-mu) / gamma; return 1.0 / ( PI * gamma * (1+x*x) ); } -REAL logLikelihood_normal(const REAL& y_ref, const REAL& y) { - //REAL mu = y_ref; - REAL sigma = (y_ref / 50.0) * LLHOOD_NORMAL_OFFS; - REAL pdfs = normal_pdf( y, y_ref, sigma ); +real_t logLikelihood_normal(const real_t& y_ref, const real_t& y) { + //real_t mu = y_ref; + real_t sigma = (y_ref / 50.0) * LLHOOD_NORMAL_OFFS; + real_t pdfs = normal_pdf( y, y_ref, sigma ); pdfs += 1.0e-20; // avoid NaNs return log(pdfs); } -REAL logLikelihood_cauchy(const REAL& y_ref, const REAL& y) { - REAL gamma = ( fabs(y_ref) / 50.0 ) * LLHOOD_CAUCHY_OFFS + 0.01; - REAL pdfs = cauchy_pdf( y, y_ref, gamma ); +real_t logLikelihood_cauchy(const real_t& y_ref, const real_t& y) { + real_t gamma = ( fabs(y_ref) / 50.0 ) * LLHOOD_CAUCHY_OFFS + 0.01; + real_t pdfs = cauchy_pdf( y, y_ref, gamma ); pdfs += 1.0e-20; // avoid NaNs return log(pdfs); } -REAL logLikelihood(const REAL& y_ref, const REAL& y) { +real_t logLikelihood(const real_t& y_ref, const real_t& y) { if ( LLHOOD_TYPE == NORMAL ) return logLikelihood_normal(y_ref, y); else/* LLHOOD_TYPE == CAUCHY */return logLikelihood_cauchy(y_ref, y); } diff --git a/benchmarks/InterestCalib/lib/include/IrregShape.h b/benchmarks/InterestCalib/lib/include/IrregShape.h index 9703fac..107e08b 100644 --- a/benchmarks/InterestCalib/lib/include/IrregShape.h +++ b/benchmarks/InterestCalib/lib/include/IrregShape.h @@ -53,7 +53,7 @@ short* getIregShapeAdjusted( const int LWG, } N = Ncur; - REAL overhead = ((REAL)Ncur)/(Ncur-tot_iddle_thds); + real_t overhead = ((real_t)Ncur)/(Ncur-tot_iddle_thds); overhead = (overhead - 1.0) * 100.0; // printf("Summary: Ncurr: %d, tot_iddle_thds: %d, overhead: %f percent\n", diff --git a/benchmarks/InterestCalib/lib/include/KerConsts.h b/benchmarks/InterestCalib/lib/include/KerConsts.h index ca3256c..94c84c2 100644 --- a/benchmarks/InterestCalib/lib/include/KerConsts.h +++ b/benchmarks/InterestCalib/lib/include/KerConsts.h @@ -32,9 +32,9 @@ /*********************************************/ #if REAL_IS_FLOAT - #define EPS0 (0.3e-2) - #define EPS (0.2e-4) - #define PI (3.14159265358) + #define EPS0 (0.3e-2F) + #define EPS (0.2e-4F) + #define PI (3.14159265358F) #else #define EPS0 (1.0e-3) diff --git a/benchmarks/InterestCalib/lib/include/MathModule.h b/benchmarks/InterestCalib/lib/include/MathModule.h index db7ecf6..55dc3c0 100644 --- a/benchmarks/InterestCalib/lib/include/MathModule.h +++ b/benchmarks/InterestCalib/lib/include/MathModule.h @@ -12,15 +12,15 @@ // formula 7.1.26 (page 300), Handbook of Mathematical Functions, Abramowitz and Stegun // http://people.math.sfu.ca/~cbm/aands/frameindex.htm -REAL erff1( const REAL& x ) { - const REAL p = 0.3275911; - const REAL a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741, a4 = -1.453152027, a5 = 1.061405429; +real_t erff1( const real_t& x ) { + const real_t p = 0.3275911; + const real_t a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741, a4 = -1.453152027, a5 = 1.061405429; - const REAL t = 1.0/(1.0+p*x); - const REAL t2 = t * t; - const REAL t3 = t * t2; - const REAL t4 = t2 * t2; - const REAL t5 = t2 * t3; + const real_t t = 1.0/(1.0+p*x); + const real_t t2 = t * t; + const real_t t3 = t * t2; + const real_t t4 = t2 * t2; + const real_t t5 = t2 * t3; return ( 1.0 - (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5) * exp(-(x*x)) ); } @@ -28,35 +28,35 @@ REAL erff1( const REAL& x ) { //------------------------------------------------------------------------- // Cumulative Distribution Function for a standard normal distribution -REAL uGaussian_P( const REAL& x ) { - const REAL u = x / sqrt(2.0); - const REAL e = ( u < 0.0 ) ? -erff1(-u) : erff1(u); +real_t uGaussian_P( const real_t& x ) { + const real_t u = x / sqrt(2.0); + const real_t e = ( u < 0.0 ) ? -erff1(-u) : erff1(u); return ( 0.5 * (1.0 + e) ); } -REAL erff_poly_only( const REAL& x ) { - const REAL p = 0.3275911; - const REAL a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741, a4 = -1.453152027, a5 = 1.061405429; +real_t erff_poly_only( const real_t& x ) { + const real_t p = 0.3275911; + const real_t a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741, a4 = -1.453152027, a5 = 1.061405429; - const REAL t = 1.0/(1.0+p*x); - const REAL t2 = t * t; - const REAL t3 = t * t2; - const REAL t4 = t2 * t2; - const REAL t5 = t2 * t3; + const real_t t = 1.0/(1.0+p*x); + const real_t t2 = t * t; + const real_t t3 = t * t2; + const real_t t4 = t2 * t2; + const real_t t5 = t2 * t3; - const REAL res = (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5); + const real_t res = (a1*t + a2*t2 + a3*t3 + a4*t4 + a5*t5); return res; // erff was: ( 1.0 - res * exp(-(x*x)) ); } -REAL uGaussian_P_withExpFactor( const REAL& x, const REAL exp_factor ) { - const REAL u = fabs( x / sqrt(2.0) ); - const REAL e = erff_poly_only(u); +real_t uGaussian_P_withExpFactor( const real_t& x, const real_t exp_factor ) { + const real_t u = fabs( x / sqrt(2.0) ); + const real_t e = erff_poly_only(u); - REAL res = 0.5 * e * exp(exp_factor-u*u); + real_t res = 0.5 * e * exp(exp_factor-u*u); if( x >= 0.0 ) { res = exp(exp_factor) - res; @@ -73,10 +73,10 @@ REAL uGaussian_P_withExpFactor( const REAL& x, const REAL exp_factor ) { // otherwise follows the real implementation //////////////////////////////////////////////////////////////////////// // N is the size of scales (bbi) -REAL to_solve( const UINT& fid, const UINT& N, const REAL* scales, const REAL* bbi, const REAL& yhat ) { +real_t to_solve( const UINT& fid, const UINT& N, const real_t* scales, const real_t* bbi, const real_t& yhat ) { if ( fid == 33 ) return (yhat+3.0)*(yhat-1.0)*(yhat-1.0); else { - REAL accum = 0.0; + real_t accum = 0.0; for( UINT i = 0; i < N; i++ ) { accum += scales[i] * exp( - bbi[i] * yhat ); } @@ -96,26 +96,26 @@ def bisection(f,lb,ub,N=50): void rootBisection( const UINT& fid, const UINT& N, - const REAL* scale, - const REAL* bbi, - const REAL& lb, - const REAL& ub, - const REAL& toll, + const real_t* scale, + const real_t* bbi, + const real_t& lb, + const real_t& ub, + const real_t& toll, const UINT& it_mx, - REAL& root, // result + real_t& root, // result UINT& it, - REAL& fb + real_t& fb ) { // IMPLEMENT THIS HERE!!! - const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; - const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; + const real_t tol = (toll <= 0.0) ? 1.0e-9 : toll; + const real_t iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; - REAL a = lb, b = ub; + real_t a = lb, b = ub; - REAL x, fx; + real_t x, fx; it = 0; - REAL fa = to_solve(fid, N, scale, bbi, a); + real_t fa = to_solve(fid, N, scale, bbi, a); fb = to_solve(fid, N, scale, bbi, b); if( fa*fb >= 0.0 ) { @@ -152,22 +152,22 @@ void rootBisection( void rootFinding_Brent ( const UINT& fid, const UINT& N, - const REAL* scale, - const REAL* bbi, - const REAL& lb, - const REAL& ub, - const REAL& toll, + const real_t* scale, + const real_t* bbi, + const real_t& lb, + const real_t& ub, + const real_t& toll, const UINT& it_mx, - REAL& root, // result + real_t& root, // result UINT& it, - REAL& fb + real_t& fb ) { - const REAL tol = (toll <= 0.0) ? 1.0e-9 : toll; - const REAL iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; + const real_t tol = (toll <= 0.0) ? 1.0e-9 : toll; + const real_t iter_max = (it_mx <= 0 ) ? IT_MAX : it_mx; - REAL a = lb, b = ub; + real_t a = lb, b = ub; - REAL fa = to_solve(fid, N, scale, bbi, a); + real_t fa = to_solve(fid, N, scale, bbi, a); fb = to_solve(fid, N, scale, bbi, b); if( fa*fb >= 0.0 ) { @@ -177,22 +177,22 @@ void rootFinding_Brent ( return; } - if( fabs(fa) < fabs(fb) ) { REAL tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } + if( fabs(fa) < fabs(fb) ) { real_t tmp = fa; fa = fb; fb = tmp; tmp = a; a = b; b = tmp; } - REAL c = a, fc = fa; + real_t c = a, fc = fa; bool mflag = true; - REAL d = 0.0; + real_t d = 0.0; it = 0; for( UINT i = 0; i < iter_max; i++ ) { if ( fb != 0.0 && fabs(b-a) >= tol ) { - REAL s; + real_t s; if( fa == fc || fb == fc ) { s = b - fb * (b - a) / (fb - fa); } else { - REAL s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); - REAL s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); - REAL s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); + real_t s1 = (a*fb*fc)/( (fa-fb)*(fa-fc) ); + real_t s2 = (b*fa*fc)/( (fb-fa)*(fb-fc) ); + real_t s3 = (c*fa*fb)/( (fc-fa)*(fc-fb) ); s = s1 + s2 + s3; } @@ -207,7 +207,7 @@ void rootFinding_Brent ( mflag = false; } - REAL fs = to_solve(fid, N, scale, bbi, s); + real_t fs = to_solve(fid, N, scale, bbi, s); // d is assigned for the first time here: // it's not used above because mflag is set @@ -218,7 +218,7 @@ void rootFinding_Brent ( else { a = s; fa = fs; } if( fabs(fa) < fabs(fb) ) { - REAL tmp; + real_t tmp; tmp = a; a = b; b = tmp; tmp = fa; fa = fb; fb = tmp; } @@ -243,9 +243,9 @@ void rootFinding_Brent ( int test_math() { // Rootfinder.brent (-4.) (4./.3.) (fun x -> (x+.3.)*.(x-.1.)**2.) 1e-4 == -3 printf("# Brent test: %f => ", -3.0); - REAL scale[1] = { 0.0 }, bbi[1] = { 0.0 }; + real_t scale[1] = { 0.0 }, bbi[1] = { 0.0 }; - REAL root, err; UINT it; + real_t root, err; UINT it; rootFinding_Brent(33, 1, scale, bbi, -4.0, 4.0/3.0, 0.0, 0, root, it, err); if( equalEps(root, -3.0) ) printf(" SUCCESS!\n\n"); else printf(" %f FAILS!\n\n", root); diff --git a/benchmarks/InterestCalib/lib/include/ParseInput.h b/benchmarks/InterestCalib/lib/include/ParseInput.h index efddda2..173356b 100644 --- a/benchmarks/InterestCalib/lib/include/ParseInput.h +++ b/benchmarks/InterestCalib/lib/include/ParseInput.h @@ -22,11 +22,11 @@ void readDataSet( UINT& pop_size, UINT& num_conv_iters, UINT& num_swap_quotes, - REAL*& swaption_quotes, // [num_swap_quotes,4] + real_t*& swaption_quotes, // [num_swap_quotes,4] UINT& num_hermitians, - REAL*& hermite_coefs, // [num_hermite] - REAL*& hermite_weights, // [num_hermite] + real_t*& hermite_coefs, // [num_hermite] + real_t*& hermite_weights, // [num_hermite] UINT& num_sobol_bits, int*& sobol_dirs_vct // [num_sobol_bits] @@ -50,7 +50,7 @@ void readDataSet( UINT& pop_size, atr_ok = num_swap_quotes > 0; assert(atr_ok && "Number of swaptions LESS or equal to ZERO!\n"); - if ( read_array(sizeof(REAL), read_real, (void**)&swaption_quotes, shape, 2) ) { + if ( read_array(sizeof(real_t), read_real, (void**)&swaption_quotes, shape, 2) ) { fprintf(stderr, "Syntax error when reading the swaption quotes.\n"); exit(1); } @@ -66,14 +66,14 @@ void readDataSet( UINT& pop_size, atr_ok = num_hermitians > 0; assert(atr_ok && "Number of hermitians LESS or equal to ZERO!\n"); - if ( read_array(sizeof(REAL), read_real, (void**)&hermite_coefs, shape, 1) ) { + if ( read_array(sizeof(real_t), read_real, (void**)&hermite_coefs, shape, 1) ) { fprintf(stderr, "Syntax error when reading the hermitian coeficients.\n"); exit(1); } atr_ok = ( shape[0] == num_hermitians ); assert(atr_ok && "Incorrect shape of the hermitian coefficients!"); - if ( read_array(sizeof(REAL), read_real, (void**)&hermite_weights, shape, 1) ) { + if ( read_array(sizeof(real_t), read_real, (void**)&hermite_weights, shape, 1) ) { fprintf(stderr, "Syntax error when reading the hermitian weights.\n"); exit(1); } diff --git a/benchmarks/InterestCalib/lib/include/WriteResult.h b/benchmarks/InterestCalib/lib/include/WriteResult.h index a263cdc..93c9453 100644 --- a/benchmarks/InterestCalib/lib/include/WriteResult.h +++ b/benchmarks/InterestCalib/lib/include/WriteResult.h @@ -4,19 +4,19 @@ #include /* Writes trailing comma and newline. */ -void writeRealField(FILE *stream, const char* field, REAL x) +void writeRealField(FILE *stream, const char* field, real_t x) { fprintf(stream, "\"%s\": %f,\n", field, x); } void writeResult(FILE *stream, - REAL a, - REAL b, - REAL sigma, - REAL nu, - REAL rho, - REAL logLik, - REAL* calib_arr) + real_t a, + real_t b, + real_t sigma, + real_t nu, + real_t rho, + real_t logLik, + real_t* calib_arr) { /* Hackily manually generate JSON. It would be nice with some proper library support. */ diff --git a/lib/include/Utilities.cl b/lib/include/Utilities.cl index 28fbd06..dff4d53 100644 --- a/lib/include/Utilities.cl +++ b/lib/include/Utilities.cl @@ -125,7 +125,7 @@ TYPE segm_scan_reg_warp( **/ inline void segm_scan_reg_block ( - __local volatile REAL* sh_data, + __local volatile real_t* sh_data, uint sh_size, uint sgm_size ) { @@ -235,8 +235,8 @@ void segm_red_reg_block_K ( * ASSERTS: * 1. ptr & hd are adjusted for each warp */ -inline REAL segm_scan_warp( - __local volatile REAL* ptr, +inline real_t segm_scan_warp( + __local volatile real_t* ptr, __local volatile FLAG* hd ) { const uint th_id = TH_ID & (WARP-1); @@ -265,8 +265,8 @@ inline REAL segm_scan_warp( return ptr[th_id]; } -inline REAL segm_scan_block( - __local volatile REAL *ptr, +inline real_t segm_scan_block( + __local volatile real_t *ptr, __local volatile FLAG *hd ) { // 1a: record whether this warp begins @@ -276,10 +276,10 @@ inline REAL segm_scan_block( barrier(CLK_LOCAL_MEM_FENCE); // 1b: intra-warp segmented scan for each warp - REAL val = segm_scan_warp( ptr + WARP_FST, hd + WARP_FST ); + real_t val = segm_scan_warp( ptr + WARP_FST, hd + WARP_FST ); // 2a: the last value is the correct partial result - REAL warp_total = ptr[WARP_LST]; + real_t warp_total = ptr[WARP_LST]; // 2b: warp_flag is the OR-reduction of the flags // in a warp, and is computed indirectly from @@ -330,7 +330,7 @@ inline REAL segm_scan_block( * 2. size of ptr and hd is [K * local_group_size(0)] */ inline void segm_scan_block_K( - __local volatile REAL *ptr, + __local volatile real_t *ptr, __local volatile FLAG *hd , uint K , bool warp_level @@ -339,7 +339,7 @@ inline void segm_scan_block_K( segm_scan_block(ptr, hd); } else { uint th_idmK = TH_ID * K; - REAL reg_ptr[SEQ_ELMS]; + real_t reg_ptr[SEQ_ELMS]; bool reg_hd [SEQ_ELMS]; { // 1) each threads copies its elems in regs @@ -351,7 +351,7 @@ inline void segm_scan_block_K( { // 2) now write to shared memory local_group_size(0) elements FLAG flag; - REAL data; + real_t data; data = reg_ptr[K-1]; if ( reg_hd[K-1] == 0 ) { // the sum of the last segm @@ -375,7 +375,7 @@ inline void segm_scan_block_K( } { // 3) perform the segmented scan for get_local_size(0) elements - REAL accum; + real_t accum; if(warp_level) { segm_scan_warp ( ptr + WARP_FST, hd + WARP_FST ); @@ -410,15 +410,15 @@ inline void segm_scan_block_K( inline void ComparatorPrivate( uint *keyA, - REAL *valA, + real_t *valA, uint *keyB, - REAL *valB, + real_t *valB, uint arrowDir ){ if( (*keyA > *keyB) == arrowDir ){ uint t; t = *keyA; *keyA = *keyB; *keyB = t; - REAL r; + real_t r; r = *valA; *valA = *valB; *valB = r; } } @@ -426,15 +426,15 @@ inline void ComparatorPrivate( // volatile inline void ComparatorLocal( __local uint *keyA, - __local REAL *valA, + __local real_t *valA, __local uint *keyB, - __local REAL *valB, + __local real_t *valB, uint arrowDir ){ if( (*keyA > *keyB) == arrowDir ){ uint t; t = *keyA; *keyA = *keyB; *keyB = t; - REAL r; + real_t r; r = *valA; *valA = *valB; *valB = r; } } @@ -445,7 +445,7 @@ inline void ComparatorLocal( */ void bitonicSortLocal( __local volatile uint *l_key, - __local volatile REAL *l_val, + __local volatile real_t *l_val, uint arrayLength, uint sort_len //uint sortDir diff --git a/lib/setup.mk b/lib/setup.mk index d1a7026..abc1fa4 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -24,6 +24,6 @@ else INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include endif -CXXFLAGS += -DIMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION_DIR)"' +CXXFLAGS += -DIMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION)"' CXXFLAGS += -DHIPERMARK_BENCHMARK_LIB_DIR='"$(HIPERMARK_BENCHMARK_LIB_DIR)"' CXXFLAGS += -DHIPERMARK_LIB_DIR='"$(HIPERMARK_LIB_DIR)"' From f12dadf2822d3744a7118251ddbcb9089cd404a2 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 15:19:05 +0200 Subject: [PATCH 077/122] Change HIPERMARK_IMPLEMENTATION to HIPERMARK_IMPLEMENTATION_DIR. --- .../InterestCalib/implementations/cpp_opencl/Makefile | 4 ++-- .../InterestCalib/implementations/cpp_openmp/Makefile | 4 ++-- .../InterestCalib/implementations/cpp_openmp/instantiate | 4 ++-- .../InterestCalib/implementations/cpp_sequential/Makefile | 2 +- .../InterestCalib/implementations/haskell_lh/Makefile | 6 +++--- .../LocVolCalib/implementations/cpp_openclmp_all/Makefile | 4 ++-- .../LocVolCalib/implementations/cpp_openclmp_outer/Makefile | 4 ++-- .../LocVolCalib/implementations/cpp_openmp_naive/Makefile | 2 +- .../LocVolCalib/implementations/cpp_sequential/Makefile | 2 +- benchmarks/LocVolCalib/implementations/haskell_lh/Makefile | 4 ++-- .../OptionPricing/implementations/cpp_openmp/instantiate | 4 ++-- lib/setup.mk | 4 ++-- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile index fe484d2..3698123 100644 --- a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile @@ -27,11 +27,11 @@ EXECUTABLE =SwapCalib default: $(EXECUTABLE) -%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) - cp -r $(HIPERMARK_IMPLEMENTATION)/SrcCL . + cp -r $(HIPERMARK_IMPLEMENTATION_DIR)/SrcCL . $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) clean: diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile index f975376..0bc9d32 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile @@ -8,7 +8,7 @@ include $(HIPERMARK_LIB_DIR)/setup.mk INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include INCLUDES += -I$(HIPERMARK_LIB_DIR)/include -INCLUDES += -I$(HIPERMARK_IMPLEMENTATION) +INCLUDES += -I$(HIPERMARK_IMPLEMENTATION_DIR) #-fno-unsafe-math-optimizations -fno-finite-math-only #-fmath-errno -ftrapping-math -fno-rounding-math -fsignaling-nans @@ -19,7 +19,7 @@ EXECUTABLE =SwapCalib default: $(EXECUTABLE) -%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate b/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate index ee90c75..2e76ab2 100755 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate @@ -16,8 +16,8 @@ cp $HIPERMARK_BENCHMARK_LIB_DIR/include/EvalGenomeInl.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/G2PP.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/G2ppUtil.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/MathModule.h . -cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . -cp $HIPERMARK_IMPLEMENTATION/run . +cp $HIPERMARK_IMPLEMENTATION_DIR/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . +cp $HIPERMARK_IMPLEMENTATION_DIR/run . cp $HIPERMARK_LIB_DIR/include/Util.h . diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile index b2cc929..1b4da85 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile @@ -16,7 +16,7 @@ EXECUTABLE =SwapCalib default: $(EXECUTABLE) -%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile index df75451..5a66b3c 100644 --- a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile @@ -7,12 +7,12 @@ SOURCES = SwapCalib.hs EXECUTABLE = SwapCalib OBJECTS = SwapCalib.hi SwapCalib.o -GHC_FLAGS = -Wall -O2 -msse2 -rtsopts -i$(HIPERMARK_IMPLEMENTATION) +GHC_FLAGS = -Wall -O2 -msse2 -rtsopts -i$(HIPERMARK_IMPLEMENTATION_DIR) default: $(EXECUTABLE) -$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) - ghc $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) +$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) + ghc $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile index d7c9dec..ddba0b5 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile @@ -19,7 +19,7 @@ GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ -D CURR_DIR_PATH='"$(MAKE_DIR)"' -SOURCES_CPP =$(HIPERMARK_IMPLEMENTATION)/VolCalibAll.cpp +SOURCES_CPP =$(HIPERMARK_IMPLEMENTATION_DIR)/VolCalibAll.cpp HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h \ $(HIPERMARK_BENCHMARK_LIB_DIR)/Constants.h \ $(HIPERMARK_BENCHMARK_LIB_DIR)/ParseInput.h \ @@ -28,7 +28,7 @@ HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h \ EXECUTABLE =VolCalibAll $(EXECUTABLE): - cp $(HIPERMARK_IMPLEMENTATION)/*cl . + cp $(HIPERMARK_IMPLEMENTATION_DIR)/*cl . $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile index 55cb40f..fec72d5 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile @@ -19,7 +19,7 @@ GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ -D CURR_DIR_PATH='"$(MAKE_DIR)"' -SOURCES_CPP =$(HIPERMARK_IMPLEMENTATION)/VolCalibOuter.cpp +SOURCES_CPP =$(HIPERMARK_IMPLEMENTATION_DIR)/VolCalibOuter.cpp HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h \ $(HIPERMARK_BENCHMARK_LIB_DIR)/Constants.h \ $(HIPERMARK_BENCHMARK_LIB_DIR)/ParseInput.h \ @@ -28,7 +28,7 @@ HELPERS =PrepareKernels.h Vect_CPU.h Vect_GPU.h VolCalibInit.h \ EXECUTABLE =VolCalibOuter $(EXECUTABLE): - cp $(HIPERMARK_IMPLEMENTATION)/*cl . + cp $(HIPERMARK_IMPLEMENTATION_DIR)/*cl . $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile index f13edbc..119dd37 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile @@ -16,7 +16,7 @@ EXECUTABLE =VolCalibOrig default: $(EXECUTABLE) -%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile index 3743699..9f825b4 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile @@ -16,7 +16,7 @@ EXECUTABLE =VolCalibOrig default: $(EXECUTABLE) -%.o: $(HIPERMARK_IMPLEMENTATION)/%.cpp $(HELPERS) +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile index 618e7aa..6f5e944 100644 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile +++ b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile @@ -9,8 +9,8 @@ GHC_FLAGS = -Wall -O2 -msse2 -rtsopts default: $(EXECUTABLE) -$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) - ghc $(HIPERMARK_IMPLEMENTATION)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) +$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) + ghc $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) clean: rm $(EXECUTABLE) *o *hi diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate index 1617a61..009dae1 100755 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate @@ -8,8 +8,8 @@ cp $HIPERMARK_LIB_DIR/include/Util.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Constants.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Optimizations.h . cp $HIPERMARK_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $HIPERMARK_IMPLEMENTATION/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . -cp $HIPERMARK_IMPLEMENTATION/run . +cp $HIPERMARK_IMPLEMENTATION_DIR/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . +cp $HIPERMARK_IMPLEMENTATION_DIR/run . #$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data $HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk diff --git a/lib/setup.mk b/lib/setup.mk index abc1fa4..c064870 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -2,7 +2,7 @@ # variables will be missing. Set these to hopefully-working values to # support standalone compilation. HIPERMARK_BENCHMARK_LIB_DIR ?= ../../lib/ -HIPERMARK_IMPLEMENTATION ?= . +HIPERMARK_IMPLEMENTATION_DIR ?= . OS=$(shell uname -s) @@ -24,6 +24,6 @@ else INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include endif -CXXFLAGS += -DIMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION)"' +CXXFLAGS += -DIMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION_DIR)"' CXXFLAGS += -DHIPERMARK_BENCHMARK_LIB_DIR='"$(HIPERMARK_BENCHMARK_LIB_DIR)"' CXXFLAGS += -DHIPERMARK_LIB_DIR='"$(HIPERMARK_LIB_DIR)"' From 4f328ae95c14e8709b572d791fdeadc25bbf8619 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 21 Aug 2015 15:29:40 +0200 Subject: [PATCH 078/122] Renamed script to run LocVolCalib --- run_hipermark_CalibVolDiff | 9 --------- run_hipermark_LocVolCalib | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) delete mode 100755 run_hipermark_CalibVolDiff create mode 100755 run_hipermark_LocVolCalib diff --git a/run_hipermark_CalibVolDiff b/run_hipermark_CalibVolDiff deleted file mode 100755 index 173ca43..0000000 --- a/run_hipermark_CalibVolDiff +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -clear -echo Deleting all files in instantiations/CalibVolDiff -echo Running hipermark CalibVolDiff cpp_openmp_naive + cpp_sequential small + medium dataset, two times. -echo Storing all results in instantiations/ - -rm -rf instantiations/CalibVolDiff -../hipermark/hipermark instantiations/ 2 benchmarks/CalibVolDiff cpp_openmp_naive,cpp_sequential small,medium diff --git a/run_hipermark_LocVolCalib b/run_hipermark_LocVolCalib new file mode 100755 index 0000000..b79e650 --- /dev/null +++ b/run_hipermark_LocVolCalib @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/LocVolCalib +echo Running hipermark LocVolCalib cpp_openmp_naive + cpp_sequential medium dataset, two times. +echo Storing all results in instantiations/ + +rm -rf instantiations/LocVolCalib +../hipermark/hipermark instantiations/ 2 benchmarks/LocVolCalib cpp_openmp_naive,cpp_sequential medium From 722bb3f32d647bf6e739c90dd5d90435d6c6b474 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 15:42:27 +0200 Subject: [PATCH 079/122] Input reading fixes. --- .../implementations/cpp_openmp/Makefile | 1 + .../implementations/cpp_openmp/UtilCPU.h | 66 +++++++++---------- .../static_configuration_template.json | 3 + .../InterestCalib/lib/include/KerConsts.h | 10 --- .../InterestCalib/lib/include/ParseInput.h | 2 +- .../LocVolCalib/lib/include/ParseInput.h | 2 +- 6 files changed, 39 insertions(+), 45 deletions(-) create mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp/static_configuration_template.json diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile index 0bc9d32..a97de36 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile @@ -5,6 +5,7 @@ HIPERMARK_LIB_DIR ?= ../../../../lib/ HIPERMARK_CONFIG_REAL_TYPE ?= double include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include INCLUDES += -I$(HIPERMARK_LIB_DIR)/include diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/UtilCPU.h b/benchmarks/InterestCalib/implementations/cpp_openmp/UtilCPU.h index 4ed4ec9..096451e 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/UtilCPU.h +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/UtilCPU.h @@ -23,33 +23,33 @@ struct CpuArrays { // [13 * POP_SIZE] = // { a, a_p, b, b_p, rho, rho_p, nu, nu_p, // sigma, sigma_p, logLik, logLik_p, bf_rat } - REAL* genomes; + real_t* genomes; // [ 4 * SS * POP_SIZE ] - REAL* ci_t1cs_scale; + real_t* ci_t1cs_scale; // [ 2 * NUM_SWAP_QUOTES * POP_SIZE ] - REAL* new_quote_price; + real_t* new_quote_price; // [ NUM_SWAP_QUOTES*NUM_HERMITE ] - REAL* accum0; + real_t* accum0; // [ 8 * NUM_SWAP_QUOTES * POP_SIZE ] // { mux, muy, sqrt_sigmax = sqrt(2.0) * sigmax, // t2 = rhoxy / (sigmax*rhoxycs), sigmay_rhoxycs, zc_mat, f, df } - REAL* scalars; + real_t* scalars; - REAL gene_ranges[10]; + real_t gene_ranges[10]; CpuArrays (const uint n, short* shp) : SS(n) { shape = shp; - genomes = new REAL[ 13 * POP_SIZE ]; - ci_t1cs_scale = new REAL[ 4 * SS * POP_SIZE ]; - scalars = new REAL[ 8 * NUM_SWAP_QUOTES * POP_SIZE ]; + genomes = new real_t[ 13 * POP_SIZE ]; + ci_t1cs_scale = new real_t[ 4 * SS * POP_SIZE ]; + scalars = new real_t[ 8 * NUM_SWAP_QUOTES * POP_SIZE ]; - new_quote_price = new REAL [ 2 * NUM_SWAP_QUOTES * POP_SIZE ]; - accum0 = new REAL [ NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE ]; + new_quote_price = new real_t [ 2 * NUM_SWAP_QUOTES * POP_SIZE ]; + accum0 = new real_t [ NUM_SWAP_QUOTES * NUM_HERMITE * POP_SIZE ]; for(int i=0; i<5; i++) { gene_ranges[i] = g_mins[i]; } for(int i=0; i<5; i++) { gene_ranges[i+5] = g_maxs[i]; } @@ -65,38 +65,38 @@ struct CpuArrays { } // genome helpers - REAL* get_a () { return genomes; } - REAL* get_b () { return genomes + POP_SIZE*2; } - REAL* get_rho () { return genomes + POP_SIZE*4; } - REAL* get_nu () { return genomes + POP_SIZE*6; } - REAL* get_sigma () { return genomes + POP_SIZE*8; } - REAL* get_logLik() { return genomes + POP_SIZE*10;} - REAL* get_bf_rat() { return genomes + POP_SIZE*12;} + real_t* get_a () { return genomes; } + real_t* get_b () { return genomes + POP_SIZE*2; } + real_t* get_rho () { return genomes + POP_SIZE*4; } + real_t* get_nu () { return genomes + POP_SIZE*6; } + real_t* get_sigma () { return genomes + POP_SIZE*8; } + real_t* get_logLik() { return genomes + POP_SIZE*10;} + real_t* get_bf_rat() { return genomes + POP_SIZE*12;} // get the shape of the irregular array (for one genome) short* get_shape (){ return shape; } // get the start iterator into arrays ci, t1cs, scale for genome i - REAL* get_ci (int i) { return ci_t1cs_scale + SS*i; } - REAL* get_t1cs (int i) { return ci_t1cs_scale + SS*i + SS*POP_SIZE; } - REAL* get_scale (int i) { return ci_t1cs_scale + SS*i + 2*SS*POP_SIZE; } - REAL* get_bbi (int i) { return ci_t1cs_scale + SS*i + 3*SS*POP_SIZE; } + real_t* get_ci (int i) { return ci_t1cs_scale + SS*i; } + real_t* get_t1cs (int i) { return ci_t1cs_scale + SS*i + SS*POP_SIZE; } + real_t* get_scale (int i) { return ci_t1cs_scale + SS*i + 2*SS*POP_SIZE; } + real_t* get_bbi (int i) { return ci_t1cs_scale + SS*i + 3*SS*POP_SIZE; } // get the start iterator into array-expanded scalars for genome i - REAL* get_mux (int i) { return scalars + i * NUM_SWAP_QUOTES ; } - REAL* get_muy (int i) { return scalars + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_sqsigx(int i) { return scalars + i * NUM_SWAP_QUOTES + 2 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_t2 (int i) { return scalars + i * NUM_SWAP_QUOTES + 3 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_sigrho(int i) { return scalars + i * NUM_SWAP_QUOTES + 4 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_zcmat (int i) { return scalars + i * NUM_SWAP_QUOTES + 5 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_f (int i) { return scalars + i * NUM_SWAP_QUOTES + 6 * NUM_SWAP_QUOTES * POP_SIZE; } - REAL* get_df (int i) { return scalars + i * NUM_SWAP_QUOTES + 7 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_mux (int i) { return scalars + i * NUM_SWAP_QUOTES ; } + real_t* get_muy (int i) { return scalars + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_sqsigx(int i) { return scalars + i * NUM_SWAP_QUOTES + 2 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_t2 (int i) { return scalars + i * NUM_SWAP_QUOTES + 3 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_sigrho(int i) { return scalars + i * NUM_SWAP_QUOTES + 4 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_zcmat (int i) { return scalars + i * NUM_SWAP_QUOTES + 5 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_f (int i) { return scalars + i * NUM_SWAP_QUOTES + 6 * NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_df (int i) { return scalars + i * NUM_SWAP_QUOTES + 7 * NUM_SWAP_QUOTES * POP_SIZE; } // get the quotes prices for genome i - REAL* get_quote (int i) { return new_quote_price + i * NUM_SWAP_QUOTES; } - REAL* get_price (int i) { return new_quote_price + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } + real_t* get_quote (int i) { return new_quote_price + i * NUM_SWAP_QUOTES; } + real_t* get_price (int i) { return new_quote_price + i * NUM_SWAP_QUOTES + NUM_SWAP_QUOTES * POP_SIZE; } // get the accumulator for the irregular array for genome i - REAL* get_accum (int i) { return accum0 + i * NUM_SWAP_QUOTES * NUM_HERMITE; } + real_t* get_accum (int i) { return accum0 + i * NUM_SWAP_QUOTES * NUM_HERMITE; } }; #endif // CPU_UTILITIES diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/static_configuration_template.json b/benchmarks/InterestCalib/implementations/cpp_openmp/static_configuration_template.json new file mode 100644 index 0000000..00bdffb --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/static_configuration_template.json @@ -0,0 +1,3 @@ +{ + "REAL_TYPE" : ["float", "double"] +} diff --git a/benchmarks/InterestCalib/lib/include/KerConsts.h b/benchmarks/InterestCalib/lib/include/KerConsts.h index 94c84c2..2433360 100644 --- a/benchmarks/InterestCalib/lib/include/KerConsts.h +++ b/benchmarks/InterestCalib/lib/include/KerConsts.h @@ -17,16 +17,6 @@ */ #define GPU_VERSION 2 -/** - * If WITH_FLOAT == 0 THEN double precision is used, - * Otherwise single float precision. - * - * If you modify this flag, DO NOT forget to perform - * a dummy change in file `SrcCL/CalibKers.cl', - * so that the cached version will be invalidated! - */ -#define WITH_FLOAT 1 - /*********************************************/ /*********************************************/ /*********************************************/ diff --git a/benchmarks/InterestCalib/lib/include/ParseInput.h b/benchmarks/InterestCalib/lib/include/ParseInput.h index 173356b..9cde8ba 100644 --- a/benchmarks/InterestCalib/lib/include/ParseInput.h +++ b/benchmarks/InterestCalib/lib/include/ParseInput.h @@ -9,7 +9,7 @@ //using namespace std; -#if WITH_FLOAT +#if REAL_IS_FLOAT #define read_real read_float #else #define read_real read_double diff --git a/benchmarks/LocVolCalib/lib/include/ParseInput.h b/benchmarks/LocVolCalib/lib/include/ParseInput.h index 8453724..f15135e 100644 --- a/benchmarks/LocVolCalib/lib/include/ParseInput.h +++ b/benchmarks/LocVolCalib/lib/include/ParseInput.h @@ -11,7 +11,7 @@ using namespace std; #include -#if WITH_FLOATS +#if REAL_IS_FLOAT #define read_real read_float #else #define read_real read_double From aee27a568df08a9c59858eb778fda9d6ada6b103 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 21 Aug 2015 15:53:30 +0200 Subject: [PATCH 080/122] Fix this dataset. --- benchmarks/InterestCalib/datasets/large/input.json | 4 ++-- benchmarks/InterestCalib/datasets/large/output.json | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/benchmarks/InterestCalib/datasets/large/input.json b/benchmarks/InterestCalib/datasets/large/input.json index 92db00c..7093357 100644 --- a/benchmarks/InterestCalib/datasets/large/input.json +++ b/benchmarks/InterestCalib/datasets/large/input.json @@ -1,6 +1,6 @@ { - "population_size": 256, - "convergence_iterations": 128, + "population_size": 128, + "convergence_iterations": 424, "num_swaption_quotes": 196, "swaption_quotes": [ diff --git a/benchmarks/InterestCalib/datasets/large/output.json b/benchmarks/InterestCalib/datasets/large/output.json index c21426d..a82736c 100644 --- a/benchmarks/InterestCalib/datasets/large/output.json +++ b/benchmarks/InterestCalib/datasets/large/output.json @@ -1,10 +1,10 @@ { - "a_field": 0.325608, - "b_field": 0.001000, - "sigma_field": 0.009058, - "nu_field": 0.018683, - "rho_field": -0.083963, - "lg_likelyhood": 624.116935, + "a_field": 0.023511, + "b_field": 0.964110, + "sigma_field": 0.025390, + "nu_field": 0.142763, + "rho_field": -0.912444, + "lg_likelyhood": 504.367344, "swaption_calibration_result": [ [ 74.172585 , 115.320470 , 35.681337 ], From f996688a39f85c07986350c3d45c6d4a36761bc0 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 11:43:50 +0200 Subject: [PATCH 081/122] First few OptionPricing implementations done. --- .../implementations/cpp_openmp/GenPricing.cpp | 28 +- .../implementations/cpp_openmp/Makefile | 41 +- .../dynamic_configuration_template.json | 1 + .../static_configuration_template.json | 4 + .../cpp_sequential/GenPricing.cpp | 151 +++ .../implementations/cpp_sequential/Makefile | 35 + .../static_configuration_template.json | 4 + .../implementations/haskell_lh/GenPricing.hs | 494 ++++++++ .../implementations/haskell_lh/Makefile | 26 + .../implementations/haskell_lh/Payoff3Cond.hs | 1105 +++++++++++++++++ .../OptionPricing/lib/include/Constants.h | 11 +- .../cpp_openmp => lib/include}/Contracts.h | 32 +- .../OptionPricing/lib/include/ParseInput.h | 34 +- .../cpp_openmp => lib/include}/SobolGaussBB.h | 38 +- 14 files changed, 1910 insertions(+), 94 deletions(-) create mode 100644 benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json create mode 100644 benchmarks/OptionPricing/implementations/cpp_openmp/static_configuration_template.json create mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp create mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/Makefile create mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/static_configuration_template.json create mode 100644 benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs create mode 100644 benchmarks/OptionPricing/implementations/haskell_lh/Makefile create mode 100644 benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs rename benchmarks/OptionPricing/{implementations/cpp_openmp => lib/include}/Contracts.h (97%) rename benchmarks/OptionPricing/{implementations/cpp_openmp => lib/include}/SobolGaussBB.h (88%) diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp index 72e58e3..7d6695f 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp @@ -21,8 +21,8 @@ double* run_CPUkernel( const int& Ps, // allocate for Ps threads const UINT Sd = do_padding( sob_dim ); UINT* sob_glb_vct = static_cast( malloc( Ps * Sd * sizeof(UINT)) ); - REAL* md_glb_vct = static_cast( malloc( Ps * Sd * sizeof(REAL)) ); - REAL* trj_glb_vct = static_cast( malloc( Ps * Sd * sizeof(REAL)) ); + real_t* md_glb_vct = static_cast( malloc( Ps * Sd * sizeof(real_t)) ); + real_t* trj_glb_vct = static_cast( malloc( Ps * Sd * sizeof(real_t)) ); const UINT Sv = do_padding( scals.num_models ); double* vhat_glb = static_cast( malloc( Ps * Sv * sizeof(double)) ); @@ -31,8 +31,8 @@ double* run_CPUkernel( const int& Ps, { UINT th_id = omp_get_thread_num(); UINT* sob_vct = sob_glb_vct + ( th_id * Sd ); - REAL* md_vct = md_glb_vct + ( th_id * Sd ); - REAL* trj_vct = trj_glb_vct + ( th_id * Sd ); + real_t* md_vct = md_glb_vct + ( th_id * Sd ); + real_t* trj_vct = trj_glb_vct + ( th_id * Sd ); double* vhat = vhat_glb + ( th_id * Sv ); for(int i = 0; i < scals.num_models; i ++) @@ -76,28 +76,28 @@ double* run_CPUkernel( const int& Ps, md_vct, trj_vct ); #ifdef FAST_BB - REAL* traj = md_vct; + real_t* traj = md_vct; #else - REAL* traj = trj_vct; //md_vct; + real_t* traj = trj_vct; //md_vct; #endif // compute trajectory for ( int m = 0; m < scals.num_models; m ++ ) { - REAL* md_c = md_arrs.md_c + ( m * num_under_sq ); - REAL* md_vols = md_arrs.md_vols + ( m * sob_dim ); - REAL* md_drifts = md_arrs.md_drifts + ( m * sob_dim ); - REAL* md_starts = md_arrs.md_starts + ( m * scals.num_under ); + real_t* md_c = md_arrs.md_c + ( m * num_under_sq ); + real_t* md_vols = md_arrs.md_vols + ( m * sob_dim ); + real_t* md_drifts = md_arrs.md_drifts + ( m * sob_dim ); + real_t* md_starts = md_arrs.md_starts + ( m * scals.num_under ); for( int i = 0; i < scals.num_dates; i ++ ) { for( int j = 0; j < scals.num_under; j ++ ) { - REAL temp = 0.0; + real_t temp = 0.0; int k = i*scals.num_under + j; for ( int l = 0; l <= j; l ++ ) { #ifdef FAST_BB - REAL md_val = trj_vct[i*scals.num_under + l]; + real_t md_val = trj_vct[i*scals.num_under + l]; #else - REAL md_val = md_vct [i*scals.num_under + l]; + real_t md_val = md_vct [i*scals.num_under + l]; #endif temp += md_c[j*scals.num_under + l] * md_val; } @@ -170,7 +170,7 @@ int main() { elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); - FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); + FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); fprintf(runtime, "%d\n", elapsed_usec / 1000); fclose(runtime); write_1Darr(result, prices, scals.num_models); diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile b/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile index e690441..7447ebf 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile @@ -1,32 +1,35 @@ -include setup.mk +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ -ifndef ($(HAVE_GPU)) -include platform.mk -endif +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double -INCLUDES += -I../includeC -GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include SOURCES_CPP =GenPricing.cpp -HELPERS =Contracts.h SobolGaussBB.h ../includeC/Constants.h ../includeC/Optimizations.h ../includeC/ParseInput.h -# XXX what about the boilerplate in ../includeC ??? +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h OBJECTS =GenPricing.o EXECUTABLE =GenPricing -default: cpu - -# TODO need redesign, probably use different executable names (or -# standardisation of "gpu" targets across all benchmarks) - -.cpp.o: $(SOURCES_CPP) $(HELPERS) - $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< +default: $(EXECUTABLE) -# The GPU version is in: ../CppOpenCL. This folder is CPU only! -gpu: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< -cpu: $(OBJECTS) +$(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) clean: rm -f $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json new file mode 100644 index 0000000..14298aa --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json @@ -0,0 +1 @@ +{"NUM_THREADS": [1,2,3,4]} diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/static_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_openmp/static_configuration_template.json new file mode 100644 index 0000000..7742ccc --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/static_configuration_template.json @@ -0,0 +1,4 @@ +{ + "REAL_TYPE" : ["float", "double"] +} + diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp new file mode 100644 index 0000000..e52d301 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp @@ -0,0 +1,151 @@ +#define FAST_BB + +#include "ParseInput.h" +#include "SobolGaussBB.h" +#include "Contracts.h" + +double* run_CPUkernel( const LoopROScalars & scals, + const SobolArrays & sob_arrs, + const ModelArrays & md_arrs, + const BrowBridgeArrays& bb_arrs +) { + const UINT sob_dim = scals.num_under * scals.num_dates; + const UINT num_under_sq = scals.num_under * scals.num_under; + const int* sob_matT = sob_arrs.sobol_dirvcts; + + // allocate for Ps threads + const UINT Sd = do_padding( sob_dim ); + UINT* sob_vct = static_cast( malloc( Sd * sizeof(UINT)) ); + real_t* md_vct = static_cast( malloc( Sd * sizeof(real_t)) ); + real_t* trj_vct = static_cast( malloc( Sd * sizeof(real_t)) ); + + const UINT Sv = do_padding( scals.num_models ); + double* vhat = static_cast( malloc( Sv * sizeof(double)) ); + + // init the prices to 0 + for(int i = 0; i < scals.num_models; i ++) { + vhat[ i ] = 0.0; + } + + // Sobol number 0 is a vector of 0s. + for(int i = 0; i < sob_dim; i++) { + sob_vct[i] = 0; + } + + for( int i = 0; i < scals.num_mcits; i ++ ) { + + // Sobol strength-reduced (recurrence) formula. + sobolRec( sob_dim, scals.sobol_bits, sob_matT, i+1, sob_vct ); + + // transform the normal [0,1) to gaussian distribution [-inf, +inf] + uGaussian( scals.sob_norm_fact, sob_dim, sob_vct, md_vct ); + + // correlate the dates on each path using a Brownian Bridge + brownianBridge( scals.num_under, scals.num_dates, + bb_arrs.bb_inds, bb_arrs.bb_data, + md_vct, trj_vct ); + +#ifdef FAST_BB + real_t* traj = md_vct; +#else + real_t* traj = trj_vct; //md_vct; +#endif + + // compute trajectory + for ( int m = 0; m < scals.num_models; m ++ ) { + real_t* md_c = md_arrs.md_c + ( m * num_under_sq ); + real_t* md_vols = md_arrs.md_vols + ( m * sob_dim ); + real_t* md_drifts = md_arrs.md_drifts + ( m * sob_dim ); + real_t* md_starts = md_arrs.md_starts + ( m * scals.num_under ); + + for( int i = 0; i < scals.num_dates; i ++ ) { + for( int j = 0; j < scals.num_under; j ++ ) { + real_t temp = 0.0; + int k = i*scals.num_under + j; + + for ( int l = 0; l <= j; l ++ ) { +#ifdef FAST_BB + real_t md_val = trj_vct[i*scals.num_under + l]; +#else + real_t md_val = md_vct [i*scals.num_under + l]; +#endif + temp += md_c[j*scals.num_under + l] * md_val; + } + + temp = exp( temp*md_vols[k] + md_drifts[k] ); + + traj[k] = (k < scals.num_under) ? + md_starts[ k ] * temp : + traj[k - scals.num_under] * temp ; + } + } + + aggregDiscountedPayoff( m, scals.contract, + scals.num_under, + scals.num_cash_flows, + scals.num_det_pricers, + md_arrs.md_discts, + md_arrs.md_detvals, + traj, vhat ); + } + } + + + for(int i = 0; i < scals.num_models; i ++) { + vhat[i] = vhat[i] / scals.num_mcits; + } + + // clean-up! + free(sob_vct); + free( md_vct); + free(trj_vct); + + return vhat; +} + + +int main() { + LoopROScalars scals; + SobolArrays sob_arrs; + ModelArrays md_arrs; + BrowBridgeArrays bb_arrs; + + fprintf(stdout, "\n// Generic Pricing, Original Sequential Benchmark:\n"); + + readDataSet(scals, sob_arrs, md_arrs, bb_arrs); + + fprintf(stdout, "// Contract: %d, MC Its#: %d, #Underlyings: %d, #Path Dates: %d, chunk: %d\n\n", + scals.contract, scals.num_mcits, scals.num_under, scals.num_dates, scals.chunk ); + + double* prices; + unsigned long int elapsed_usec; + { // run kernel + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + + computeSobolFixIndex( sob_arrs, scals.chunk ); + { // do work and cleanup + prices = run_CPUkernel( scals, sob_arrs, md_arrs, bb_arrs ); + } + + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed_usec = t_diff.tv_sec*1e6+t_diff.tv_usec; + + md_arrs .cleanup(); + bb_arrs .cleanup(); + sob_arrs.cleanup(); + } + + { + FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); + FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); + fprintf(runtime, "%d\n", elapsed_usec / 1000); + fclose(runtime); + write_1Darr(result, prices, scals.num_models); + fclose(result); + } + + return 0; +} + diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile new file mode 100644 index 0000000..7808673 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile @@ -0,0 +1,35 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +SOURCES_CPP =GenPricing.cpp +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h +OBJECTS =GenPricing.o +EXECUTABLE =GenPricing + +default: $(EXECUTABLE) + +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< + +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + +clean: + rm -f $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/static_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_sequential/static_configuration_template.json new file mode 100644 index 0000000..7742ccc --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/static_configuration_template.json @@ -0,0 +1,4 @@ +{ + "REAL_TYPE" : ["float", "double"] +} + diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs new file mode 100644 index 0000000..e348336 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs @@ -0,0 +1,494 @@ +module Main where + +import qualified Data.List +import Control.Applicative +import Control.Monad +import Data.Maybe +import System.Environment +import System.CPUTime + +------------------------------------ +--- Requires the installation of --- +--- Parsec package, i.e., --- +--- cabal install parsec --- +------------------------------------ + +import Text.Parsec hiding (optional, (<|>), token) +import Text.Parsec.String + +import Data.Bits +import Data.List hiding (tail) +import Prelude hiding (tail) + +--import Debug.Trace + +import Control.DeepSeq + +import Data.Vector.Unboxed(Vector) -- for gaussian approx +import qualified Data.Vector.Unboxed as V + +------------------------------ +--- Parser-related Helpers --- +------------------------------ +signed :: Parser String -> Parser String +signed p = (char '-' >> (('-':) <$> p)) <|> p + +whitespace :: Parser () +whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) + +lexeme :: Parser a -> Parser a +lexeme p = p <* whitespace + +token :: String -> Parser () +token = void . lexeme . string + +readInt :: Parser Int +readInt = lexeme $ read <$> signed (many1 digit) + +readDouble :: Parser Double +readDouble = lexeme $ read <$> signed (s2 <|> s1) + where s1 = do bef <- many1 digit + aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) + return $ bef ++ aft + s2 = (++) <$> (char '.' >> pure "0.") <*> many1 digit + +readArray :: Parser a -> Parser [a] +readArray p = lexeme $ between (token "[") (token "]") (p `sepBy` token ",") + +--------------------------------------------- +--- Definition of lish-homomorphic reduce --- +--- requires a binary associative op --- +--------------------------------------------- + +reduce :: (a -> a -> a) -> a -> [a] -> a +reduce bop ne lst = foldl bop ne lst + +--zip5 :: [a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)] +--zip5 [] [] [] [] [] = [] +--zip5 (a:as) (b:bs) (c:cs) (d:ds) (e:es) = +-- (a,b,c,d,e) :: (zip5 as bs cs ds es) +--zip5 as bs cs ds es = [] + +--------------------------------------------- +--- Chunking Helpers --- +--------------------------------------------- +chunk :: Int -> [a] -> [[a]] +chunk _ [] = [] +chunk n arr = take n arr : chunk n (drop n arr) + +--------------------------------------------- +--- Sobol Quasi-random vector generation --- +--------------------------------------------- +grayCode :: Int -> Int +grayCode x = (x `shiftR` 1) `xor` x + +xorInds :: Int -> Int -> [Int] -> Int +xorInds bits_num n dir_vs = reduce xor 0 $ map (dir_vs!!) is + where bits = [0..bits_num-1] + is = filter (testBit $ grayCode n) bits + +sobolIndI :: Int -> [[Int]] -> Int -> [Int] +sobolIndI bits_num dir_vs n = + map (xorInds bits_num n) dir_vs + +sobolIndR :: Int -> [[Int]] -> Int -> [Double] +sobolIndR bits_num dir_vs n = + map ((/divisor) . fromIntegral) arri + where arri = sobolIndI bits_num dir_vs n + divisor = 2.0 ** fromIntegral bits_num + +lsb0 :: Int -> Int +lsb0 n = lsb0_help 0 n + where lsb0_help ell c | (c .&. 1 == 0) = ell + | otherwise = lsb0_help (ell+1) (c `shiftR` 1) + +sobolRecI :: Int -> [[Int]] -> [Int] -> Int -> [Int] +sobolRecI bits_num sob_dir_vs prev n = zipWith xor prev dir_vs + where dir_vs = map ( !! mybit ) sob_dir_vs + mybit = min (lsb0 n) (bits_num-1) + +sobolRecMapSeq :: Double -> Int -> [[Int]] -> (Int,Int) -> [[Double]] +sobolRecMapSeq sob_fact bits_num dir_vs (l, u) = + let a = sobolIndI bits_num dir_vs l + norm = ( * sob_fact ) . fromIntegral + in map (map norm) (scanl (sobolRecI bits_num dir_vs) a [l..u-1]) + -- this scanl is sequential (NOT parallel) + +------------------------------------------ +------------------------------------------ + +sobolRecMapPar :: Double -> Int -> [[Int]] -> (Int,Int) -> [[Double]] +sobolRecMapPar sob_fact bits_num dir_vs (lb_inc, ub_exc) = + let contribs = map (\k -> if (k==lb_inc) + then sobolIndI bits_num dir_vs lb_inc + else recM dir_vs (k-1) + ) [lb_inc..ub_exc] + vct_ints :: [[Int]] + vct_ints = Data.List.tail $ + scanl (zipWith xor) (replicate (length dir_vs) 0) contribs + -- this scanl is parallel (associative xor operator)! + in map (map (\x -> (fromIntegral x) * sob_fact)) vct_ints + +sobolRecI2 :: [[Int]] -> [Int] -> Int -> [Int] +sobolRecI2 sob_dirs prev i = + zipWith xor prev (recM sob_dirs i) + +recM :: [[Int]] -> Int -> [Int] +recM sob_dirs i = + let mybit = lsb0 i + in map (\row -> row !! mybit) sob_dirs + +------------------------------------------ +--- To-Gaussian Distribution Transform.--- +------------------------------------------ +polyAppr :: Double -> Double -> Double -> Double -> Double -> Double + -> Double -> Double -> Double -> Double -> Double -> Double + -> Double -> Double -> Double -> Double -> Double -> Double +polyAppr x a0 a1 a2 a3 a4 a5 a6 a7 b0 b1 b2 b3 b4 b5 b6 b7 = + (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0) / + (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) + + +-- same functionality as "polyAppr", but using vectors for constants +approx :: Double -> Vector Double -> Vector Double -> Double +approx x as bs = let seqreduce xs = V.foldr (\b c -> b + x*c) 0.0 xs + in seqreduce as / seqreduce bs + +smallcase :: Double -> Double +smallcase q = q * approx (0.180625 - q*q) small_as small_bs + +small_as :: Vector Double +small_as = V.fromList [ 3.387132872796366608 + , 133.14166789178437745 + , 1971.5909503065514427 + , 13731.693765509461125 + , 45921.953931549871457 + , 67265.770927008700853 + , 33430.575583588128105 + , 2509.0809287301226727 ] + +small_bs :: Vector Double +small_bs = V.fromList [ 1.0 + , 42.313330701600911252 + , 687.1870074920579083 + , 5394.1960214247511077 + , 21213.794301586595867 + , 39307.89580009271061 + , 28729.085735721942674 + , 5226.495278852854561 ] + +intermediate :: Double -> Double +intermediate q = approx (q-1.6) interm_as interm_bs + +interm_as :: Vector Double +interm_as = V.fromList [ 1.42343711074968357734 + , 4.6303378461565452959 + , 5.7694972214606914055 + , 3.64784832476320460504 + , 1.27045825245236838258 + , 0.24178072517745061177 + , 0.0227238449892691845833 + , 7.7454501427834140764e-4] + +interm_bs :: Vector Double +interm_bs = V.fromList [ 1.0 + , 2.05319162663775882187 + , 1.6763848301838038494 + , 0.68976733498510000455 + , 0.14810397642748007459 + , 0.0151986665636164571966 + , 5.475938084995344946e-4 + , 1.05075007164441684324e-9] + +tail :: Double -> Double +tail q = approx (q - 5.0) tail_as tail_bs + +tail_as :: Vector Double +tail_as = V.fromList [ 6.6579046435011037772 + , 5.4637849111641143699 + , 1.7848265399172913358 + , 0.29656057182850489123 + , 0.026532189526576123093 + , 0.0012426609473880784386 + , 2.71155556874348757815e-5 + , 2.01033439929228813265e-7] + +tail_bs :: Vector Double +tail_bs = V.fromList [ 1.0 + , 0.59983220655588793769 + , 0.13692988092273580531 + , 0.0148753612908506148525 + , 7.868691311456132591e-4 + , 1.8463183175100546818e-5 + , 1.4215117583164458887e-7 + , 2.04426310338993978564e-15] + + +ugaussianEl :: Double -> Double +ugaussianEl p = + if ((dp < 0.0) && (0.0 - dp <= 0.425)) || ((0.0 <= dp) && (dp <= 0.425)) + then smallcase dp + else let pp = if dp < 0.0 then dp + 0.5 else 0.5 - dp + r = sqrt $ -log pp + x = if r <= 5.0 then intermediate r else tail r + in if dp < 0.0 then 0.0 - x else x + where dp = p - 0.5 + +ugaussian :: [Double] -> [Double] +ugaussian = map ugaussianEl + +------------------------------------------ +--- Brownian-Bridge Implementation --- +------------------------------------------ +brownianBridgeDates :: Int -> [[Int]] -> [[Double]] -> [Double] -> [Double] +brownianBridgeDates num_dates bb_inds bb_data gauss = + let bbrow = update (replicate num_dates 0.0) + (bi!!0) (sd!!0 * gauss!!0) + bbrow' = foldl f bbrow $ drop 1 $ + zip3 (zip3 bi li ri) (zip3 sd lw rw) gauss + in zipWith (-) bbrow' (0.0:bbrow') + where [bi,li,ri] = map (map $ subtract 1) bb_inds + [sd,lw,rw] = bb_data + f bbrow ((l,j,k),(x,y,z),zi) = + let wk = bbrow !! k + tmp = z * wk + x * zi + in update bbrow l $ if (j + 1) == 0 + then tmp + else tmp + y * (bbrow!!j) + update a i v = take i a ++ [v] ++ drop (i+1) a + +brownianBridge :: Int -> Int -> [[Int]] -> [[Double]] -> [Double] -> [[Double]] +brownianBridge num_paths num_dates bb_inds bb_data gaussian_arr = + transpose $ map (brownianBridgeDates num_dates bb_inds bb_data) gauss2dT + where gauss2d = chunk num_paths gaussian_arr + gauss2dT = transpose gauss2d + +------------------------------------------ +--- Black-Scholes Implementation --- +------------------------------------------ +fftmp :: Int -> [[Double]] -> [Double] -> [Double] +fftmp num_paths md_c zi = map f [0..num_paths-1] + where f j = reduce (+) 0.0 $ zipWith (*) (take (j+1) zi) (take (j+1) $ md_c!!j) + +correlateDeltas :: Int -> [[Double]] -> [[Double]] -> [[Double]] +correlateDeltas num_paths md_c = map $ fftmp num_paths md_c + +combineVs :: [Double] -> [Double] -> [Double] -> [Double] +combineVs n_row vol_row dr_row = + zipWith (+) dr_row $ zipWith (*) n_row vol_row + +mkPrices :: [Double] -> [[Double]] -> [[Double]] -> [[Double]] -> [[Double]] +mkPrices md_starts md_vols md_drifts noises = + drop 1 $ scanl (zipWith (*)) md_starts e_rows + where e_rows = map (map exp) $ zipWith3 combineVs noises md_vols md_drifts + +blackScholes :: Int -> [[Double]] -> [[Double]] -> [[Double]] + -> [[Double]] -> [Double] -> [[Double]] +blackScholes num_paths bb_arr md_c md_vols md_drifts md_starts = + mkPrices md_starts md_vols md_drifts noises + where noises = correlateDeltas num_paths md_c bb_arr + + +------------------------------------------ +--- Payoff functions --- +------------------------------------------ +payoff :: Int -> [Double] -> [Double] -> [[Double]] -> Double +payoff contract md_disc md_detval xss = + if contract == 1 then payoff1 md_disc md_detval xss + else if contract == 2 then payoff2 md_disc xss + else if contract == 3 then payoff3 md_disc xss + else 0.0 + +payoff1 :: [Double] -> [Double] -> [[Double]] -> Double +payoff1 md_disc md_detvals xss = + let detval = head md_detvals + amount = ( (head (head xss)) - 4000.0 ) * detval + amount'= max 0.0 amount + in trajInner amount' 0 md_disc + +payoff2 :: [Double] -> [[Double]] -> Double +payoff2 md_disc xss + | 1.0 <= mins !! 0 = trajInner 1150.0 0 md_disc + | 1.0 <= mins !! 1 = trajInner 1300.0 1 md_disc + | 1.0 <= mins !! 2 = trajInner 1450.0 2 md_disc + | 1.0 <= mins !! 3 = trajInner 1600.0 3 md_disc + | 1.0 <= mins !! 4 = trajInner 1750.0 4 md_disc + | 0.75 < mins !! 4 = trajInner 1000.0 4 md_disc + | otherwise = trajInner (1000 * (mins!!4)) 4 md_disc + where divs = [ 1.0/3758.05, 1.0/11840.0, 1.0/1200.0 ] + xss_div = map (zipWith (*) divs) xss + mins = map minimum xss_div + + +payoff3 :: [Double] -> [[Double]] -> Double +payoff3 md_disc xss = + let underlyings (i,j) = (xss !! i) !! j + x3309 = ( reduce (||) False . map (reduce (||) False . zipWith (>=) [2630.6349999999998, 8288.0, 840.0]) ) xss +{- + x3309 = any (\ [x,y,z] -> or [ x <= 2630.6349999999998 + , y <= 8288.0 + , z <= 840.0]) + xss +-} + goto_40 = x3309 && + ( (underlyings(366,0) < 3758.05) || + (underlyings(366,2) < 1200.0 ) || + (underlyings(366,1) < 11840.0) ) + + price1 = trajInner 100.0 0 md_disc + + price2 = if goto_40 + then let m1 = min ((underlyings(366,2) / 1200.0 ) - 1.0) + ((underlyings(366,0) / 3758.05) - 1.0) + m2 = min ((underlyings(366,1) / 11840.0) - 1.0) m1 + amount = (1000.0 * (1.0 + m2 ) ) + in trajInner amount 1 md_disc + else trajInner 1000.0 1 md_disc + in price1 + price2 + + + +trajInner :: Double -> Int -> [Double] -> Double +trajInner amount i disc = amount * disc !! i + +-------------------------------------------- +-------------------------------------------- +-------------------------------------------- + + + +------------------------------------------- +--- Main Entry Point: price computation --- +------------------------------------------- + +--- Using only the (slightly inneficient) Sobol independent formula! --- +compute :: Int -> Int -> Int -> Int -> Int -> Int -> [[Int]] + -> [[[Double]]] -> [[[Double]]] -> [[[Double]]] + -> [[Double]] -> [[Double]] -> [[Double]] + -> [[Int]] -> [[Double]] + -> [Double] +compute contract num_mc_it num_dates num_under num_models num_bits + dir_vs md_cs md_vols md_drifts md_starts md_detvals + md_discts bb_inds bb_data = + + let sobol_mat = map (sobolIndR num_bits dir_vs) [1..num_mc_it] + gauss_mat = map ugaussian sobol_mat + bb_mat = map (brownianBridge num_under num_dates bb_inds bb_data) gauss_mat + + bs_mat = map (\bb_row -> zipWith4 (blackScholes num_under bb_row) md_cs md_vols md_drifts md_starts) bb_mat + payoffs = bs_mat `deepseq` map (\bs_row -> zipWith3 (payoff contract) md_discts md_detvals bs_row) bs_mat + + sum_prices= payoffs `deepseq` reduce (zipWith (+)) (replicate num_models 0.0) payoffs + prices = map (\sp -> sp / fromIntegral num_mc_it) sum_prices + in prices + + +--- Chunking the computation and using sobol-independent formula --- +--- for the first element and the more efficient sobol-recurrent --- +-- formula for the rest of elements --- +compute_chunk :: Int -> Int -> Int -> Int -> Int -> Int -> [[Int]] + -> [[[Double]]] -> [[[Double]]] -> [[[Double]]] + -> [[Double]] -> [[Double]] -> [[Double]] + -> [[Int ]] -> [[Double]] -> (Int,Int) + -> [Double] +compute_chunk contract num_mc_it num_dates num_under num_models num_bits + dir_vs md_cs md_vols md_drifts md_starts md_detvals + md_discts bb_inds bb_data (lb,ub) = + let sob_factor = 1.0 / (2.0 ** fromIntegral num_bits) + + sobol_mat = sobolRecMapPar sob_factor num_bits dir_vs (lb,ub) + gauss_mat = map ugaussian sobol_mat + bb_mat = map (brownianBridge num_under num_dates bb_inds bb_data) gauss_mat + bs_mat = map (\bb_row -> zipWith4 (blackScholes num_under bb_row) md_cs md_vols md_drifts md_starts) bb_mat + payoffs = bs_mat `deepseq` map (\bs_row -> zipWith3 (payoff contract) md_discts md_detvals bs_row) bs_mat + sum_prices= payoffs `deepseq` reduce (zipWith (+)) (replicate num_models 0.0) payoffs + prices = map (\sp -> sp / fromIntegral num_mc_it) sum_prices + in prices + +tiledSkeleton :: Int -> Int -> Int -> ((Int,Int) -> [Double]) -> [Double] +tiledSkeleton sob_dim num_mc_its chunk_sz fun = + let divides = num_mc_its `mod` chunk_sz == 0 + extra = if (divides) then [] else [num_mc_its] + iv = zip [1,chunk_sz+1..] ([chunk_sz, 2*chunk_sz .. num_mc_its] ++ extra ) + in (reduce (zipWith (+)) (replicate sob_dim 0.0) . map fun) iv +---------------------------------------------- +--- Formatting the Output of the Benchmark --- +---------------------------------------------- +validate :: [Double] -> [Double] -> (Int,Int,Int,Int) -> [String] +validate prices_ref prices info= + let errs = map abs $ zipWith (-) prices_ref prices + err = reduce max 0.0 errs + (contract,num_mc_it, num_dates, num_under) = info + in ["// Generic Pricing Haskell Benchmark (List-Homomorphism Style):", + "// Contract: " ++ show contract ++ ", MC Its#: " ++ show num_mc_it ++ + ", #Underlyings: " ++ show num_under ++ ", #Path Dates: " ++ + show num_dates, + ( if err <= 0.0005 + then "1\t\t// VALID Result," + else "0\t\t// INVALID Result," ), + "0\t\t// Runtime in microseconds,", + "1\t\t// CPU Threads,", + show prices ++ "\t// Generic Pricing Result."] + + +----------------------------------------- +--- Entry point for Generic Pricing --- +--- The only place where using Monads,--- +--- e.g., parsing Dataset from StdIn --- +----------------------------------------- +main :: IO () +main = do s <- getContents + case parse run "input" s of + Left e -> error $ show e + Right m -> do + (v, runtime) <- m + result <- getEnv "HIPERMARK_RESULT" + writeFile result $ show v + runtime_file <- getEnv "HIPERMARK_RUNTIME" + writeFile runtime_file $ show runtime + +-- either (error . show) print $ parse run "input" s + where run = do contract <- readInt + num_mc_it <- readInt + num_dates <- readInt + num_under <- readInt +{- + v <- compute contract num_mc_it num_dates num_under <$> + readInt <*> readInt <*> readInt2d <*> + readDouble3d <*> readDouble3d <*> readDouble3d <*> + readDouble2d <*> readDouble2d <*> readDouble2d <*> + readInt2d <*> readDouble2d +-} + + num_models<- readInt + num_bits <- readInt + sob_dirvs <- readInt2d + md_cs <- readDouble3d + md_vols <- readDouble3d + md_drifts <- readDouble3d + md_starts <- readDouble2d + md_detvals<- readDouble2d + md_discts <- readDouble2d + bb_inds <- readInt2d + bb_data <- readDouble2d + + let tiled_skel = tiledSkeleton (num_under*num_dates) num_mc_it 128 + let v = tiled_skel $ + compute_chunk + contract num_mc_it num_dates num_under num_models num_bits + sob_dirvs md_cs md_vols md_drifts md_starts md_detvals + md_discts bb_inds bb_data + + return $ do + start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + end <- v `deepseq` getCPUTime + return (v, (end - start) `div` 1000000000) + + + readInt2d = readArray $ readArray readInt + readDouble1d = readArray readDouble + readDouble2d = readArray $ readArray readDouble + readDouble3d = readArray $ readArray $ readArray readDouble + +-- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs +-- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/Makefile b/benchmarks/OptionPricing/implementations/haskell_lh/Makefile new file mode 100644 index 0000000..afdc764 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/haskell_lh/Makefile @@ -0,0 +1,26 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +include $(HIPERMARK_LIB_DIR)/setup.mk + +SOURCES = GenPricing.hs +EXECUTABLE = GenPricing +OBJECTS = GenPricing.hi GenPricing.o + +GHC_FLAGS = -Wall -O2 -msse2 -rtsopts -i$(HIPERMARK_IMPLEMENTATION) + +default: $(EXECUTABLE) + +$(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) + ghc $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) $(GHC_FLAGS) -o $(EXECUTABLE) + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs b/benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs new file mode 100644 index 0000000..136a27f --- /dev/null +++ b/benchmarks/OptionPricing/implementations/haskell_lh/Payoff3Cond.hs @@ -0,0 +1,1105 @@ +module Payoff3Cond where + +payoff3Cond :: [[Double]] -> Bool +payoff3Cond xss = + let underlyings (i,j) = (xss !! i) !! j + in (underlyings(0,0) <= 2630.6349999999998) || + (underlyings(0,2) <= 840.0) || + (underlyings(0,1) <= 8288.0) || + (underlyings(1,0) <= 2630.6349999999998) || + (underlyings(1,2) <= 840.0) || + (underlyings(1,1) <= 8288.0) || + (underlyings(2,0) <= 2630.6349999999998) || + (underlyings(2,2) <= 840.0) || + (underlyings(2,1) <= 8288.0) || + (underlyings(3,0) <= 2630.6349999999998) || + (underlyings(3,2) <= 840.0) || + (underlyings(3,1) <= 8288.0) || + (underlyings(4,0) <= 2630.6349999999998) || + (underlyings(4,2) <= 840.0) || + (underlyings(4,1) <= 8288.0) || + (underlyings(5,0) <= 2630.6349999999998) || + (underlyings(5,2) <= 840.0) || + (underlyings(5,1) <= 8288.0) || + (underlyings(6,0) <= 2630.6349999999998) || + (underlyings(6,2) <= 840.0) || + (underlyings(6,1) <= 8288.0) || + (underlyings(7,0) <= 2630.6349999999998) || + (underlyings(7,2) <= 840.0) || + (underlyings(7,1) <= 8288.0) || + (underlyings(8,0) <= 2630.6349999999998) || + (underlyings(8,2) <= 840.0) || + (underlyings(8,1) <= 8288.0) || + (underlyings(9,0) <= 2630.6349999999998) || + (underlyings(9,2) <= 840.0) || + (underlyings(9,1) <= 8288.0) || + (underlyings(10,0) <= 2630.6349999999998) || + (underlyings(10,2) <= 840.0) || + (underlyings(10,1) <= 8288.0) || + (underlyings(11,0) <= 2630.6349999999998) || + (underlyings(11,2) <= 840.0) || + (underlyings(11,1) <= 8288.0) || + (underlyings(12,0) <= 2630.6349999999998) || + (underlyings(12,2) <= 840.0) || + (underlyings(12,1) <= 8288.0) || + (underlyings(13,0) <= 2630.6349999999998) || + (underlyings(13,2) <= 840.0) || + (underlyings(13,1) <= 8288.0) || + (underlyings(14,0) <= 2630.6349999999998) || + (underlyings(14,2) <= 840.0) || + (underlyings(14,1) <= 8288.0) || + (underlyings(15,0) <= 2630.6349999999998) || + (underlyings(15,2) <= 840.0) || + (underlyings(15,1) <= 8288.0) || + (underlyings(16,0) <= 2630.6349999999998) || + (underlyings(16,2) <= 840.0) || + (underlyings(16,1) <= 8288.0) || + (underlyings(17,0) <= 2630.6349999999998) || + (underlyings(17,2) <= 840.0) || + (underlyings(17,1) <= 8288.0) || + (underlyings(18,0) <= 2630.6349999999998) || + (underlyings(18,2) <= 840.0) || + (underlyings(18,1) <= 8288.0) || + (underlyings(19,0) <= 2630.6349999999998) || + (underlyings(19,2) <= 840.0) || + (underlyings(19,1) <= 8288.0) || + (underlyings(20,0) <= 2630.6349999999998) || + (underlyings(20,2) <= 840.0) || + (underlyings(20,1) <= 8288.0) || + (underlyings(21,0) <= 2630.6349999999998) || + (underlyings(21,2) <= 840.0) || + (underlyings(21,1) <= 8288.0) || + (underlyings(22,0) <= 2630.6349999999998) || + (underlyings(22,2) <= 840.0) || + (underlyings(22,1) <= 8288.0) || + (underlyings(23,0) <= 2630.6349999999998) || + (underlyings(23,2) <= 840.0) || + (underlyings(23,1) <= 8288.0) || + (underlyings(24,0) <= 2630.6349999999998) || + (underlyings(24,2) <= 840.0) || + (underlyings(24,1) <= 8288.0) || + (underlyings(25,0) <= 2630.6349999999998) || + (underlyings(25,2) <= 840.0) || + (underlyings(25,1) <= 8288.0) || + (underlyings(26,0) <= 2630.6349999999998) || + (underlyings(26,2) <= 840.0) || + (underlyings(26,1) <= 8288.0) || + (underlyings(27,0) <= 2630.6349999999998) || + (underlyings(27,2) <= 840.0) || + (underlyings(27,1) <= 8288.0) || + (underlyings(28,0) <= 2630.6349999999998) || + (underlyings(28,2) <= 840.0) || + (underlyings(28,1) <= 8288.0) || + (underlyings(29,0) <= 2630.6349999999998) || + (underlyings(29,2) <= 840.0) || + (underlyings(29,1) <= 8288.0) || + (underlyings(30,0) <= 2630.6349999999998) || + (underlyings(30,2) <= 840.0) || + (underlyings(30,1) <= 8288.0) || + (underlyings(31,0) <= 2630.6349999999998) || + (underlyings(31,2) <= 840.0) || + (underlyings(31,1) <= 8288.0) || + (underlyings(32,0) <= 2630.6349999999998) || + (underlyings(32,2) <= 840.0) || + (underlyings(32,1) <= 8288.0) || + (underlyings(33,0) <= 2630.6349999999998) || + (underlyings(33,2) <= 840.0) || + (underlyings(33,1) <= 8288.0) || + (underlyings(34,0) <= 2630.6349999999998) || + (underlyings(34,2) <= 840.0) || + (underlyings(34,1) <= 8288.0) || + (underlyings(35,0) <= 2630.6349999999998) || + (underlyings(35,2) <= 840.0) || + (underlyings(35,1) <= 8288.0) || + (underlyings(36,0) <= 2630.6349999999998) || + (underlyings(36,2) <= 840.0) || + (underlyings(36,1) <= 8288.0) || + (underlyings(37,0) <= 2630.6349999999998) || + (underlyings(37,2) <= 840.0) || + (underlyings(37,1) <= 8288.0) || + (underlyings(38,0) <= 2630.6349999999998) || + (underlyings(38,2) <= 840.0) || + (underlyings(38,1) <= 8288.0) || + (underlyings(39,0) <= 2630.6349999999998) || + (underlyings(39,2) <= 840.0) || + (underlyings(39,1) <= 8288.0) || + (underlyings(40,0) <= 2630.6349999999998) || + (underlyings(40,2) <= 840.0) || + (underlyings(40,1) <= 8288.0) || + (underlyings(41,0) <= 2630.6349999999998) || + (underlyings(41,2) <= 840.0) || + (underlyings(41,1) <= 8288.0) || + (underlyings(42,0) <= 2630.6349999999998) || + (underlyings(42,2) <= 840.0) || + (underlyings(42,1) <= 8288.0) || + (underlyings(43,0) <= 2630.6349999999998) || + (underlyings(43,2) <= 840.0) || + (underlyings(43,1) <= 8288.0) || + (underlyings(44,0) <= 2630.6349999999998) || + (underlyings(44,2) <= 840.0) || + (underlyings(44,1) <= 8288.0) || + (underlyings(45,0) <= 2630.6349999999998) || + (underlyings(45,2) <= 840.0) || + (underlyings(45,1) <= 8288.0) || + (underlyings(46,0) <= 2630.6349999999998) || + (underlyings(46,2) <= 840.0) || + (underlyings(46,1) <= 8288.0) || + (underlyings(47,0) <= 2630.6349999999998) || + (underlyings(47,2) <= 840.0) || + (underlyings(47,1) <= 8288.0) || + (underlyings(48,0) <= 2630.6349999999998) || + (underlyings(48,2) <= 840.0) || + (underlyings(48,1) <= 8288.0) || + (underlyings(49,0) <= 2630.6349999999998) || + (underlyings(49,2) <= 840.0) || + (underlyings(49,1) <= 8288.0) || + (underlyings(50,0) <= 2630.6349999999998) || + (underlyings(50,2) <= 840.0) || + (underlyings(50,1) <= 8288.0) || + (underlyings(51,0) <= 2630.6349999999998) || + (underlyings(51,2) <= 840.0) || + (underlyings(51,1) <= 8288.0) || + (underlyings(52,0) <= 2630.6349999999998) || + (underlyings(52,2) <= 840.0) || + (underlyings(52,1) <= 8288.0) || + (underlyings(53,0) <= 2630.6349999999998) || + (underlyings(53,2) <= 840.0) || + (underlyings(53,1) <= 8288.0) || + (underlyings(54,0) <= 2630.6349999999998) || + (underlyings(54,2) <= 840.0) || + (underlyings(54,1) <= 8288.0) || + (underlyings(55,0) <= 2630.6349999999998) || + (underlyings(55,2) <= 840.0) || + (underlyings(55,1) <= 8288.0) || + (underlyings(56,0) <= 2630.6349999999998) || + (underlyings(56,2) <= 840.0) || + (underlyings(56,1) <= 8288.0) || + (underlyings(57,0) <= 2630.6349999999998) || + (underlyings(57,2) <= 840.0) || + (underlyings(57,1) <= 8288.0) || + (underlyings(58,0) <= 2630.6349999999998) || + (underlyings(58,2) <= 840.0) || + (underlyings(58,1) <= 8288.0) || + (underlyings(59,0) <= 2630.6349999999998) || + (underlyings(59,2) <= 840.0) || + (underlyings(59,1) <= 8288.0) || + (underlyings(60,0) <= 2630.6349999999998) || + (underlyings(60,2) <= 840.0) || + (underlyings(60,1) <= 8288.0) || + (underlyings(61,0) <= 2630.6349999999998) || + (underlyings(61,2) <= 840.0) || + (underlyings(61,1) <= 8288.0) || + (underlyings(62,0) <= 2630.6349999999998) || + (underlyings(62,2) <= 840.0) || + (underlyings(62,1) <= 8288.0) || + (underlyings(63,0) <= 2630.6349999999998) || + (underlyings(63,2) <= 840.0) || + (underlyings(63,1) <= 8288.0) || + (underlyings(64,0) <= 2630.6349999999998) || + (underlyings(64,2) <= 840.0) || + (underlyings(64,1) <= 8288.0) || + (underlyings(65,0) <= 2630.6349999999998) || + (underlyings(65,2) <= 840.0) || + (underlyings(65,1) <= 8288.0) || + (underlyings(66,0) <= 2630.6349999999998) || + (underlyings(66,2) <= 840.0) || + (underlyings(66,1) <= 8288.0) || + (underlyings(67,0) <= 2630.6349999999998) || + (underlyings(67,2) <= 840.0) || + (underlyings(67,1) <= 8288.0) || + (underlyings(68,0) <= 2630.6349999999998) || + (underlyings(68,2) <= 840.0) || + (underlyings(68,1) <= 8288.0) || + (underlyings(69,0) <= 2630.6349999999998) || + (underlyings(69,2) <= 840.0) || + (underlyings(69,1) <= 8288.0) || + (underlyings(70,0) <= 2630.6349999999998) || + (underlyings(70,2) <= 840.0) || + (underlyings(70,1) <= 8288.0) || + (underlyings(71,0) <= 2630.6349999999998) || + (underlyings(71,2) <= 840.0) || + (underlyings(71,1) <= 8288.0) || + (underlyings(72,0) <= 2630.6349999999998) || + (underlyings(72,2) <= 840.0) || + (underlyings(72,1) <= 8288.0) || + (underlyings(73,0) <= 2630.6349999999998) || + (underlyings(73,2) <= 840.0) || + (underlyings(73,1) <= 8288.0) || + (underlyings(74,0) <= 2630.6349999999998) || + (underlyings(74,2) <= 840.0) || + (underlyings(74,1) <= 8288.0) || + (underlyings(75,0) <= 2630.6349999999998) || + (underlyings(75,2) <= 840.0) || + (underlyings(75,1) <= 8288.0) || + (underlyings(76,0) <= 2630.6349999999998) || + (underlyings(76,2) <= 840.0) || + (underlyings(76,1) <= 8288.0) || + (underlyings(77,0) <= 2630.6349999999998) || + (underlyings(77,2) <= 840.0) || + (underlyings(77,1) <= 8288.0) || + (underlyings(78,0) <= 2630.6349999999998) || + (underlyings(78,2) <= 840.0) || + (underlyings(78,1) <= 8288.0) || + (underlyings(79,0) <= 2630.6349999999998) || + (underlyings(79,2) <= 840.0) || + (underlyings(79,1) <= 8288.0) || + (underlyings(80,0) <= 2630.6349999999998) || + (underlyings(80,2) <= 840.0) || + (underlyings(80,1) <= 8288.0) || + (underlyings(81,0) <= 2630.6349999999998) || + (underlyings(81,2) <= 840.0) || + (underlyings(81,1) <= 8288.0) || + (underlyings(82,0) <= 2630.6349999999998) || + (underlyings(82,2) <= 840.0) || + (underlyings(82,1) <= 8288.0) || + (underlyings(83,0) <= 2630.6349999999998) || + (underlyings(83,2) <= 840.0) || + (underlyings(83,1) <= 8288.0) || + (underlyings(84,0) <= 2630.6349999999998) || + (underlyings(84,2) <= 840.0) || + (underlyings(84,1) <= 8288.0) || + (underlyings(85,0) <= 2630.6349999999998) || + (underlyings(85,2) <= 840.0) || + (underlyings(85,1) <= 8288.0) || + (underlyings(86,0) <= 2630.6349999999998) || + (underlyings(86,2) <= 840.0) || + (underlyings(86,1) <= 8288.0) || + (underlyings(87,0) <= 2630.6349999999998) || + (underlyings(87,2) <= 840.0) || + (underlyings(87,1) <= 8288.0) || + (underlyings(88,0) <= 2630.6349999999998) || + (underlyings(88,2) <= 840.0) || + (underlyings(88,1) <= 8288.0) || + (underlyings(89,0) <= 2630.6349999999998) || + (underlyings(89,2) <= 840.0) || + (underlyings(89,1) <= 8288.0) || + (underlyings(90,0) <= 2630.6349999999998) || + (underlyings(90,2) <= 840.0) || + (underlyings(90,1) <= 8288.0) || + (underlyings(91,0) <= 2630.6349999999998) || + (underlyings(91,2) <= 840.0) || + (underlyings(91,1) <= 8288.0) || + (underlyings(92,0) <= 2630.6349999999998) || + (underlyings(92,2) <= 840.0) || + (underlyings(92,1) <= 8288.0) || + (underlyings(93,0) <= 2630.6349999999998) || + (underlyings(93,2) <= 840.0) || + (underlyings(93,1) <= 8288.0) || + (underlyings(94,0) <= 2630.6349999999998) || + (underlyings(94,2) <= 840.0) || + (underlyings(94,1) <= 8288.0) || + (underlyings(95,0) <= 2630.6349999999998) || + (underlyings(95,2) <= 840.0) || + (underlyings(95,1) <= 8288.0) || + (underlyings(96,0) <= 2630.6349999999998) || + (underlyings(96,2) <= 840.0) || + (underlyings(96,1) <= 8288.0) || + (underlyings(97,0) <= 2630.6349999999998) || + (underlyings(97,2) <= 840.0) || + (underlyings(97,1) <= 8288.0) || + (underlyings(98,0) <= 2630.6349999999998) || + (underlyings(98,2) <= 840.0) || + (underlyings(98,1) <= 8288.0) || + (underlyings(99,0) <= 2630.6349999999998) || + (underlyings(99,2) <= 840.0) || + (underlyings(99,1) <= 8288.0) || + (underlyings(100,0) <= 2630.6349999999998) || + (underlyings(100,2) <= 840.0) || + (underlyings(100,1) <= 8288.0) || + (underlyings(101,0) <= 2630.6349999999998) || + (underlyings(101,2) <= 840.0) || + (underlyings(101,1) <= 8288.0) || + (underlyings(102,0) <= 2630.6349999999998) || + (underlyings(102,2) <= 840.0) || + (underlyings(102,1) <= 8288.0) || + (underlyings(103,0) <= 2630.6349999999998) || + (underlyings(103,2) <= 840.0) || + (underlyings(103,1) <= 8288.0) || + (underlyings(104,0) <= 2630.6349999999998) || + (underlyings(104,2) <= 840.0) || + (underlyings(104,1) <= 8288.0) || + (underlyings(105,0) <= 2630.6349999999998) || + (underlyings(105,2) <= 840.0) || + (underlyings(105,1) <= 8288.0) || + (underlyings(106,0) <= 2630.6349999999998) || + (underlyings(106,2) <= 840.0) || + (underlyings(106,1) <= 8288.0) || + (underlyings(107,0) <= 2630.6349999999998) || + (underlyings(107,2) <= 840.0) || + (underlyings(107,1) <= 8288.0) || + (underlyings(108,0) <= 2630.6349999999998) || + (underlyings(108,2) <= 840.0) || + (underlyings(108,1) <= 8288.0) || + (underlyings(109,0) <= 2630.6349999999998) || + (underlyings(109,2) <= 840.0) || + (underlyings(109,1) <= 8288.0) || + (underlyings(110,0) <= 2630.6349999999998) || + (underlyings(110,2) <= 840.0) || + (underlyings(110,1) <= 8288.0) || + (underlyings(111,0) <= 2630.6349999999998) || + (underlyings(111,2) <= 840.0) || + (underlyings(111,1) <= 8288.0) || + (underlyings(112,0) <= 2630.6349999999998) || + (underlyings(112,2) <= 840.0) || + (underlyings(112,1) <= 8288.0) || + (underlyings(113,0) <= 2630.6349999999998) || + (underlyings(113,2) <= 840.0) || + (underlyings(113,1) <= 8288.0) || + (underlyings(114,0) <= 2630.6349999999998) || + (underlyings(114,2) <= 840.0) || + (underlyings(114,1) <= 8288.0) || + (underlyings(115,0) <= 2630.6349999999998) || + (underlyings(115,2) <= 840.0) || + (underlyings(115,1) <= 8288.0) || + (underlyings(116,0) <= 2630.6349999999998) || + (underlyings(116,2) <= 840.0) || + (underlyings(116,1) <= 8288.0) || + (underlyings(117,0) <= 2630.6349999999998) || + (underlyings(117,2) <= 840.0) || + (underlyings(117,1) <= 8288.0) || + (underlyings(118,0) <= 2630.6349999999998) || + (underlyings(118,2) <= 840.0) || + (underlyings(118,1) <= 8288.0) || + (underlyings(119,0) <= 2630.6349999999998) || + (underlyings(119,2) <= 840.0) || + (underlyings(119,1) <= 8288.0) || + (underlyings(120,0) <= 2630.6349999999998) || + (underlyings(120,2) <= 840.0) || + (underlyings(120,1) <= 8288.0) || + (underlyings(121,0) <= 2630.6349999999998) || + (underlyings(121,2) <= 840.0) || + (underlyings(121,1) <= 8288.0) || + (underlyings(122,0) <= 2630.6349999999998) || + (underlyings(122,2) <= 840.0) || + (underlyings(122,1) <= 8288.0) || + (underlyings(123,0) <= 2630.6349999999998) || + (underlyings(123,2) <= 840.0) || + (underlyings(123,1) <= 8288.0) || + (underlyings(124,0) <= 2630.6349999999998) || + (underlyings(124,2) <= 840.0) || + (underlyings(124,1) <= 8288.0) || + (underlyings(125,0) <= 2630.6349999999998) || + (underlyings(125,2) <= 840.0) || + (underlyings(125,1) <= 8288.0) || + (underlyings(126,0) <= 2630.6349999999998) || + (underlyings(126,2) <= 840.0) || + (underlyings(126,1) <= 8288.0) || + (underlyings(127,0) <= 2630.6349999999998) || + (underlyings(127,2) <= 840.0) || + (underlyings(127,1) <= 8288.0) || + (underlyings(128,0) <= 2630.6349999999998) || + (underlyings(128,2) <= 840.0) || + (underlyings(128,1) <= 8288.0) || + (underlyings(129,0) <= 2630.6349999999998) || + (underlyings(129,2) <= 840.0) || + (underlyings(129,1) <= 8288.0) || + (underlyings(130,0) <= 2630.6349999999998) || + (underlyings(130,2) <= 840.0) || + (underlyings(130,1) <= 8288.0) || + (underlyings(131,0) <= 2630.6349999999998) || + (underlyings(131,2) <= 840.0) || + (underlyings(131,1) <= 8288.0) || + (underlyings(132,0) <= 2630.6349999999998) || + (underlyings(132,2) <= 840.0) || + (underlyings(132,1) <= 8288.0) || + (underlyings(133,0) <= 2630.6349999999998) || + (underlyings(133,2) <= 840.0) || + (underlyings(133,1) <= 8288.0) || + (underlyings(134,0) <= 2630.6349999999998) || + (underlyings(134,2) <= 840.0) || + (underlyings(134,1) <= 8288.0) || + (underlyings(135,0) <= 2630.6349999999998) || + (underlyings(135,2) <= 840.0) || + (underlyings(135,1) <= 8288.0) || + (underlyings(136,0) <= 2630.6349999999998) || + (underlyings(136,2) <= 840.0) || + (underlyings(136,1) <= 8288.0) || + (underlyings(137,0) <= 2630.6349999999998) || + (underlyings(137,2) <= 840.0) || + (underlyings(137,1) <= 8288.0) || + (underlyings(138,0) <= 2630.6349999999998) || + (underlyings(138,2) <= 840.0) || + (underlyings(138,1) <= 8288.0) || + (underlyings(139,0) <= 2630.6349999999998) || + (underlyings(139,2) <= 840.0) || + (underlyings(139,1) <= 8288.0) || + (underlyings(140,0) <= 2630.6349999999998) || + (underlyings(140,2) <= 840.0) || + (underlyings(140,1) <= 8288.0) || + (underlyings(141,0) <= 2630.6349999999998) || + (underlyings(141,2) <= 840.0) || + (underlyings(141,1) <= 8288.0) || + (underlyings(142,0) <= 2630.6349999999998) || + (underlyings(142,2) <= 840.0) || + (underlyings(142,1) <= 8288.0) || + (underlyings(143,0) <= 2630.6349999999998) || + (underlyings(143,2) <= 840.0) || + (underlyings(143,1) <= 8288.0) || + (underlyings(144,0) <= 2630.6349999999998) || + (underlyings(144,2) <= 840.0) || + (underlyings(144,1) <= 8288.0) || + (underlyings(145,0) <= 2630.6349999999998) || + (underlyings(145,2) <= 840.0) || + (underlyings(145,1) <= 8288.0) || + (underlyings(146,0) <= 2630.6349999999998) || + (underlyings(146,2) <= 840.0) || + (underlyings(146,1) <= 8288.0) || + (underlyings(147,0) <= 2630.6349999999998) || + (underlyings(147,2) <= 840.0) || + (underlyings(147,1) <= 8288.0) || + (underlyings(148,0) <= 2630.6349999999998) || + (underlyings(148,2) <= 840.0) || + (underlyings(148,1) <= 8288.0) || + (underlyings(149,0) <= 2630.6349999999998) || + (underlyings(149,2) <= 840.0) || + (underlyings(149,1) <= 8288.0) || + (underlyings(150,0) <= 2630.6349999999998) || + (underlyings(150,2) <= 840.0) || + (underlyings(150,1) <= 8288.0) || + (underlyings(151,0) <= 2630.6349999999998) || + (underlyings(151,2) <= 840.0) || + (underlyings(151,1) <= 8288.0) || + (underlyings(152,0) <= 2630.6349999999998) || + (underlyings(152,2) <= 840.0) || + (underlyings(152,1) <= 8288.0) || + (underlyings(153,0) <= 2630.6349999999998) || + (underlyings(153,2) <= 840.0) || + (underlyings(153,1) <= 8288.0) || + (underlyings(154,0) <= 2630.6349999999998) || + (underlyings(154,2) <= 840.0) || + (underlyings(154,1) <= 8288.0) || + (underlyings(155,0) <= 2630.6349999999998) || + (underlyings(155,2) <= 840.0) || + (underlyings(155,1) <= 8288.0) || + (underlyings(156,0) <= 2630.6349999999998) || + (underlyings(156,2) <= 840.0) || + (underlyings(156,1) <= 8288.0) || + (underlyings(157,0) <= 2630.6349999999998) || + (underlyings(157,2) <= 840.0) || + (underlyings(157,1) <= 8288.0) || + (underlyings(158,0) <= 2630.6349999999998) || + (underlyings(158,2) <= 840.0) || + (underlyings(158,1) <= 8288.0) || + (underlyings(159,0) <= 2630.6349999999998) || + (underlyings(159,2) <= 840.0) || + (underlyings(159,1) <= 8288.0) || + (underlyings(160,0) <= 2630.6349999999998) || + (underlyings(160,2) <= 840.0) || + (underlyings(160,1) <= 8288.0) || + (underlyings(161,0) <= 2630.6349999999998) || + (underlyings(161,2) <= 840.0) || + (underlyings(161,1) <= 8288.0) || + (underlyings(162,0) <= 2630.6349999999998) || + (underlyings(162,2) <= 840.0) || + (underlyings(162,1) <= 8288.0) || + (underlyings(163,0) <= 2630.6349999999998) || + (underlyings(163,2) <= 840.0) || + (underlyings(163,1) <= 8288.0) || + (underlyings(164,0) <= 2630.6349999999998) || + (underlyings(164,2) <= 840.0) || + (underlyings(164,1) <= 8288.0) || + (underlyings(165,0) <= 2630.6349999999998) || + (underlyings(165,2) <= 840.0) || + (underlyings(165,1) <= 8288.0) || + (underlyings(166,0) <= 2630.6349999999998) || + (underlyings(166,2) <= 840.0) || + (underlyings(166,1) <= 8288.0) || + (underlyings(167,0) <= 2630.6349999999998) || + (underlyings(167,2) <= 840.0) || + (underlyings(167,1) <= 8288.0) || + (underlyings(168,0) <= 2630.6349999999998) || + (underlyings(168,2) <= 840.0) || + (underlyings(168,1) <= 8288.0) || + (underlyings(169,0) <= 2630.6349999999998) || + (underlyings(169,2) <= 840.0) || + (underlyings(169,1) <= 8288.0) || + (underlyings(170,0) <= 2630.6349999999998) || + (underlyings(170,2) <= 840.0) || + (underlyings(170,1) <= 8288.0) || + (underlyings(171,0) <= 2630.6349999999998) || + (underlyings(171,2) <= 840.0) || + (underlyings(171,1) <= 8288.0) || + (underlyings(172,0) <= 2630.6349999999998) || + (underlyings(172,2) <= 840.0) || + (underlyings(172,1) <= 8288.0) || + (underlyings(173,0) <= 2630.6349999999998) || + (underlyings(173,2) <= 840.0) || + (underlyings(173,1) <= 8288.0) || + (underlyings(174,0) <= 2630.6349999999998) || + (underlyings(174,2) <= 840.0) || + (underlyings(174,1) <= 8288.0) || + (underlyings(175,0) <= 2630.6349999999998) || + (underlyings(175,2) <= 840.0) || + (underlyings(175,1) <= 8288.0) || + (underlyings(176,0) <= 2630.6349999999998) || + (underlyings(176,2) <= 840.0) || + (underlyings(176,1) <= 8288.0) || + (underlyings(177,0) <= 2630.6349999999998) || + (underlyings(177,2) <= 840.0) || + (underlyings(177,1) <= 8288.0) || + (underlyings(178,0) <= 2630.6349999999998) || + (underlyings(178,2) <= 840.0) || + (underlyings(178,1) <= 8288.0) || + (underlyings(179,0) <= 2630.6349999999998) || + (underlyings(179,2) <= 840.0) || + (underlyings(179,1) <= 8288.0) || + (underlyings(180,0) <= 2630.6349999999998) || + (underlyings(180,2) <= 840.0) || + (underlyings(180,1) <= 8288.0) || + (underlyings(181,0) <= 2630.6349999999998) || + (underlyings(181,2) <= 840.0) || + (underlyings(181,1) <= 8288.0) || + (underlyings(182,0) <= 2630.6349999999998) || + (underlyings(182,2) <= 840.0) || + (underlyings(182,1) <= 8288.0) || + (underlyings(183,0) <= 2630.6349999999998) || + (underlyings(183,2) <= 840.0) || + (underlyings(183,1) <= 8288.0) || + (underlyings(184,0) <= 2630.6349999999998) || + (underlyings(184,2) <= 840.0) || + (underlyings(184,1) <= 8288.0) || + (underlyings(185,0) <= 2630.6349999999998) || + (underlyings(185,2) <= 840.0) || + (underlyings(185,1) <= 8288.0) || + (underlyings(186,0) <= 2630.6349999999998) || + (underlyings(186,2) <= 840.0) || + (underlyings(186,1) <= 8288.0) || + (underlyings(187,0) <= 2630.6349999999998) || + (underlyings(187,2) <= 840.0) || + (underlyings(187,1) <= 8288.0) || + (underlyings(188,0) <= 2630.6349999999998) || + (underlyings(188,2) <= 840.0) || + (underlyings(188,1) <= 8288.0) || + (underlyings(189,0) <= 2630.6349999999998) || + (underlyings(189,2) <= 840.0) || + (underlyings(189,1) <= 8288.0) || + (underlyings(190,0) <= 2630.6349999999998) || + (underlyings(190,2) <= 840.0) || + (underlyings(190,1) <= 8288.0) || + (underlyings(191,0) <= 2630.6349999999998) || + (underlyings(191,2) <= 840.0) || + (underlyings(191,1) <= 8288.0) || + (underlyings(192,0) <= 2630.6349999999998) || + (underlyings(192,2) <= 840.0) || + (underlyings(192,1) <= 8288.0) || + (underlyings(193,0) <= 2630.6349999999998) || + (underlyings(193,2) <= 840.0) || + (underlyings(193,1) <= 8288.0) || + (underlyings(194,0) <= 2630.6349999999998) || + (underlyings(194,2) <= 840.0) || + (underlyings(194,1) <= 8288.0) || + (underlyings(195,0) <= 2630.6349999999998) || + (underlyings(195,2) <= 840.0) || + (underlyings(195,1) <= 8288.0) || + (underlyings(196,0) <= 2630.6349999999998) || + (underlyings(196,2) <= 840.0) || + (underlyings(196,1) <= 8288.0) || + (underlyings(197,0) <= 2630.6349999999998) || + (underlyings(197,2) <= 840.0) || + (underlyings(197,1) <= 8288.0) || + (underlyings(198,0) <= 2630.6349999999998) || + (underlyings(198,2) <= 840.0) || + (underlyings(198,1) <= 8288.0) || + (underlyings(199,0) <= 2630.6349999999998) || + (underlyings(199,2) <= 840.0) || + (underlyings(199,1) <= 8288.0) || + (underlyings(200,0) <= 2630.6349999999998) || + (underlyings(200,2) <= 840.0) || + (underlyings(200,1) <= 8288.0) || + (underlyings(201,0) <= 2630.6349999999998) || + (underlyings(201,2) <= 840.0) || + (underlyings(201,1) <= 8288.0) || + (underlyings(202,0) <= 2630.6349999999998) || + (underlyings(202,2) <= 840.0) || + (underlyings(202,1) <= 8288.0) || + (underlyings(203,0) <= 2630.6349999999998) || + (underlyings(203,2) <= 840.0) || + (underlyings(203,1) <= 8288.0) || + (underlyings(204,0) <= 2630.6349999999998) || + (underlyings(204,2) <= 840.0) || + (underlyings(204,1) <= 8288.0) || + (underlyings(205,0) <= 2630.6349999999998) || + (underlyings(205,2) <= 840.0) || + (underlyings(205,1) <= 8288.0) || + (underlyings(206,0) <= 2630.6349999999998) || + (underlyings(206,2) <= 840.0) || + (underlyings(206,1) <= 8288.0) || + (underlyings(207,0) <= 2630.6349999999998) || + (underlyings(207,2) <= 840.0) || + (underlyings(207,1) <= 8288.0) || + (underlyings(208,0) <= 2630.6349999999998) || + (underlyings(208,2) <= 840.0) || + (underlyings(208,1) <= 8288.0) || + (underlyings(209,0) <= 2630.6349999999998) || + (underlyings(209,2) <= 840.0) || + (underlyings(209,1) <= 8288.0) || + (underlyings(210,0) <= 2630.6349999999998) || + (underlyings(210,2) <= 840.0) || + (underlyings(210,1) <= 8288.0) || + (underlyings(211,0) <= 2630.6349999999998) || + (underlyings(211,2) <= 840.0) || + (underlyings(211,1) <= 8288.0) || + (underlyings(212,0) <= 2630.6349999999998) || + (underlyings(212,2) <= 840.0) || + (underlyings(212,1) <= 8288.0) || + (underlyings(213,0) <= 2630.6349999999998) || + (underlyings(213,2) <= 840.0) || + (underlyings(213,1) <= 8288.0) || + (underlyings(214,0) <= 2630.6349999999998) || + (underlyings(214,2) <= 840.0) || + (underlyings(214,1) <= 8288.0) || + (underlyings(215,0) <= 2630.6349999999998) || + (underlyings(215,2) <= 840.0) || + (underlyings(215,1) <= 8288.0) || + (underlyings(216,0) <= 2630.6349999999998) || + (underlyings(216,2) <= 840.0) || + (underlyings(216,1) <= 8288.0) || + (underlyings(217,0) <= 2630.6349999999998) || + (underlyings(217,2) <= 840.0) || + (underlyings(217,1) <= 8288.0) || + (underlyings(218,0) <= 2630.6349999999998) || + (underlyings(218,2) <= 840.0) || + (underlyings(218,1) <= 8288.0) || + (underlyings(219,0) <= 2630.6349999999998) || + (underlyings(219,2) <= 840.0) || + (underlyings(219,1) <= 8288.0) || + (underlyings(220,0) <= 2630.6349999999998) || + (underlyings(220,2) <= 840.0) || + (underlyings(220,1) <= 8288.0) || + (underlyings(221,0) <= 2630.6349999999998) || + (underlyings(221,2) <= 840.0) || + (underlyings(221,1) <= 8288.0) || + (underlyings(222,0) <= 2630.6349999999998) || + (underlyings(222,2) <= 840.0) || + (underlyings(222,1) <= 8288.0) || + (underlyings(223,0) <= 2630.6349999999998) || + (underlyings(223,2) <= 840.0) || + (underlyings(223,1) <= 8288.0) || + (underlyings(224,0) <= 2630.6349999999998) || + (underlyings(224,2) <= 840.0) || + (underlyings(224,1) <= 8288.0) || + (underlyings(225,0) <= 2630.6349999999998) || + (underlyings(225,2) <= 840.0) || + (underlyings(225,1) <= 8288.0) || + (underlyings(226,0) <= 2630.6349999999998) || + (underlyings(226,2) <= 840.0) || + (underlyings(226,1) <= 8288.0) || + (underlyings(227,0) <= 2630.6349999999998) || + (underlyings(227,2) <= 840.0) || + (underlyings(227,1) <= 8288.0) || + (underlyings(228,0) <= 2630.6349999999998) || + (underlyings(228,2) <= 840.0) || + (underlyings(228,1) <= 8288.0) || + (underlyings(229,0) <= 2630.6349999999998) || + (underlyings(229,2) <= 840.0) || + (underlyings(229,1) <= 8288.0) || + (underlyings(230,0) <= 2630.6349999999998) || + (underlyings(230,2) <= 840.0) || + (underlyings(230,1) <= 8288.0) || + (underlyings(231,0) <= 2630.6349999999998) || + (underlyings(231,2) <= 840.0) || + (underlyings(231,1) <= 8288.0) || + (underlyings(232,0) <= 2630.6349999999998) || + (underlyings(232,2) <= 840.0) || + (underlyings(232,1) <= 8288.0) || + (underlyings(233,0) <= 2630.6349999999998) || + (underlyings(233,2) <= 840.0) || + (underlyings(233,1) <= 8288.0) || + (underlyings(234,0) <= 2630.6349999999998) || + (underlyings(234,2) <= 840.0) || + (underlyings(234,1) <= 8288.0) || + (underlyings(235,0) <= 2630.6349999999998) || + (underlyings(235,2) <= 840.0) || + (underlyings(235,1) <= 8288.0) || + (underlyings(236,0) <= 2630.6349999999998) || + (underlyings(236,2) <= 840.0) || + (underlyings(236,1) <= 8288.0) || + (underlyings(237,0) <= 2630.6349999999998) || + (underlyings(237,2) <= 840.0) || + (underlyings(237,1) <= 8288.0) || + (underlyings(238,0) <= 2630.6349999999998) || + (underlyings(238,2) <= 840.0) || + (underlyings(238,1) <= 8288.0) || + (underlyings(239,0) <= 2630.6349999999998) || + (underlyings(239,2) <= 840.0) || + (underlyings(239,1) <= 8288.0) || + (underlyings(240,0) <= 2630.6349999999998) || + (underlyings(240,2) <= 840.0) || + (underlyings(240,1) <= 8288.0) || + (underlyings(241,0) <= 2630.6349999999998) || + (underlyings(241,2) <= 840.0) || + (underlyings(241,1) <= 8288.0) || + (underlyings(242,0) <= 2630.6349999999998) || + (underlyings(242,2) <= 840.0) || + (underlyings(242,1) <= 8288.0) || + (underlyings(243,0) <= 2630.6349999999998) || + (underlyings(243,2) <= 840.0) || + (underlyings(243,1) <= 8288.0) || + (underlyings(244,0) <= 2630.6349999999998) || + (underlyings(244,2) <= 840.0) || + (underlyings(244,1) <= 8288.0) || + (underlyings(245,0) <= 2630.6349999999998) || + (underlyings(245,2) <= 840.0) || + (underlyings(245,1) <= 8288.0) || + (underlyings(246,0) <= 2630.6349999999998) || + (underlyings(246,2) <= 840.0) || + (underlyings(246,1) <= 8288.0) || + (underlyings(247,0) <= 2630.6349999999998) || + (underlyings(247,2) <= 840.0) || + (underlyings(247,1) <= 8288.0) || + (underlyings(248,0) <= 2630.6349999999998) || + (underlyings(248,2) <= 840.0) || + (underlyings(248,1) <= 8288.0) || + (underlyings(249,0) <= 2630.6349999999998) || + (underlyings(249,2) <= 840.0) || + (underlyings(249,1) <= 8288.0) || + (underlyings(250,0) <= 2630.6349999999998) || + (underlyings(250,2) <= 840.0) || + (underlyings(250,1) <= 8288.0) || + (underlyings(251,0) <= 2630.6349999999998) || + (underlyings(251,2) <= 840.0) || + (underlyings(251,1) <= 8288.0) || + (underlyings(252,0) <= 2630.6349999999998) || + (underlyings(252,2) <= 840.0) || + (underlyings(252,1) <= 8288.0) || + (underlyings(253,0) <= 2630.6349999999998) || + (underlyings(253,2) <= 840.0) || + (underlyings(253,1) <= 8288.0) || + (underlyings(254,0) <= 2630.6349999999998) || + (underlyings(254,2) <= 840.0) || + (underlyings(254,1) <= 8288.0) || + (underlyings(255,0) <= 2630.6349999999998) || + (underlyings(255,2) <= 840.0) || + (underlyings(255,1) <= 8288.0) || + (underlyings(256,0) <= 2630.6349999999998) || + (underlyings(256,2) <= 840.0) || + (underlyings(256,1) <= 8288.0) || + (underlyings(257,0) <= 2630.6349999999998) || + (underlyings(257,2) <= 840.0) || + (underlyings(257,1) <= 8288.0) || + (underlyings(258,0) <= 2630.6349999999998) || + (underlyings(258,2) <= 840.0) || + (underlyings(258,1) <= 8288.0) || + (underlyings(259,0) <= 2630.6349999999998) || + (underlyings(259,2) <= 840.0) || + (underlyings(259,1) <= 8288.0) || + (underlyings(260,0) <= 2630.6349999999998) || + (underlyings(260,2) <= 840.0) || + (underlyings(260,1) <= 8288.0) || + (underlyings(261,0) <= 2630.6349999999998) || + (underlyings(261,2) <= 840.0) || + (underlyings(261,1) <= 8288.0) || + (underlyings(262,0) <= 2630.6349999999998) || + (underlyings(262,2) <= 840.0) || + (underlyings(262,1) <= 8288.0) || + (underlyings(263,0) <= 2630.6349999999998) || + (underlyings(263,2) <= 840.0) || + (underlyings(263,1) <= 8288.0) || + (underlyings(264,0) <= 2630.6349999999998) || + (underlyings(264,2) <= 840.0) || + (underlyings(264,1) <= 8288.0) || + (underlyings(265,0) <= 2630.6349999999998) || + (underlyings(265,2) <= 840.0) || + (underlyings(265,1) <= 8288.0) || + (underlyings(266,0) <= 2630.6349999999998) || + (underlyings(266,2) <= 840.0) || + (underlyings(266,1) <= 8288.0) || + (underlyings(267,0) <= 2630.6349999999998) || + (underlyings(267,2) <= 840.0) || + (underlyings(267,1) <= 8288.0) || + (underlyings(268,0) <= 2630.6349999999998) || + (underlyings(268,2) <= 840.0) || + (underlyings(268,1) <= 8288.0) || + (underlyings(269,0) <= 2630.6349999999998) || + (underlyings(269,2) <= 840.0) || + (underlyings(269,1) <= 8288.0) || + (underlyings(270,0) <= 2630.6349999999998) || + (underlyings(270,2) <= 840.0) || + (underlyings(270,1) <= 8288.0) || + (underlyings(271,0) <= 2630.6349999999998) || + (underlyings(271,2) <= 840.0) || + (underlyings(271,1) <= 8288.0) || + (underlyings(272,0) <= 2630.6349999999998) || + (underlyings(272,2) <= 840.0) || + (underlyings(272,1) <= 8288.0) || + (underlyings(273,0) <= 2630.6349999999998) || + (underlyings(273,2) <= 840.0) || + (underlyings(273,1) <= 8288.0) || + (underlyings(274,0) <= 2630.6349999999998) || + (underlyings(274,2) <= 840.0) || + (underlyings(274,1) <= 8288.0) || + (underlyings(275,0) <= 2630.6349999999998) || + (underlyings(275,2) <= 840.0) || + (underlyings(275,1) <= 8288.0) || + (underlyings(276,0) <= 2630.6349999999998) || + (underlyings(276,2) <= 840.0) || + (underlyings(276,1) <= 8288.0) || + (underlyings(277,0) <= 2630.6349999999998) || + (underlyings(277,2) <= 840.0) || + (underlyings(277,1) <= 8288.0) || + (underlyings(278,0) <= 2630.6349999999998) || + (underlyings(278,2) <= 840.0) || + (underlyings(278,1) <= 8288.0) || + (underlyings(279,0) <= 2630.6349999999998) || + (underlyings(279,2) <= 840.0) || + (underlyings(279,1) <= 8288.0) || + (underlyings(280,0) <= 2630.6349999999998) || + (underlyings(280,2) <= 840.0) || + (underlyings(280,1) <= 8288.0) || + (underlyings(281,0) <= 2630.6349999999998) || + (underlyings(281,2) <= 840.0) || + (underlyings(281,1) <= 8288.0) || + (underlyings(282,0) <= 2630.6349999999998) || + (underlyings(282,2) <= 840.0) || + (underlyings(282,1) <= 8288.0) || + (underlyings(283,0) <= 2630.6349999999998) || + (underlyings(283,2) <= 840.0) || + (underlyings(283,1) <= 8288.0) || + (underlyings(284,0) <= 2630.6349999999998) || + (underlyings(284,2) <= 840.0) || + (underlyings(284,1) <= 8288.0) || + (underlyings(285,0) <= 2630.6349999999998) || + (underlyings(285,2) <= 840.0) || + (underlyings(285,1) <= 8288.0) || + (underlyings(286,0) <= 2630.6349999999998) || + (underlyings(286,2) <= 840.0) || + (underlyings(286,1) <= 8288.0) || + (underlyings(287,0) <= 2630.6349999999998) || + (underlyings(287,2) <= 840.0) || + (underlyings(287,1) <= 8288.0) || + (underlyings(288,0) <= 2630.6349999999998) || + (underlyings(288,2) <= 840.0) || + (underlyings(288,1) <= 8288.0) || + (underlyings(289,0) <= 2630.6349999999998) || + (underlyings(289,2) <= 840.0) || + (underlyings(289,1) <= 8288.0) || + (underlyings(290,0) <= 2630.6349999999998) || + (underlyings(290,2) <= 840.0) || + (underlyings(290,1) <= 8288.0) || + (underlyings(291,0) <= 2630.6349999999998) || + (underlyings(291,2) <= 840.0) || + (underlyings(291,1) <= 8288.0) || + (underlyings(292,0) <= 2630.6349999999998) || + (underlyings(292,2) <= 840.0) || + (underlyings(292,1) <= 8288.0) || + (underlyings(293,0) <= 2630.6349999999998) || + (underlyings(293,2) <= 840.0) || + (underlyings(293,1) <= 8288.0) || + (underlyings(294,0) <= 2630.6349999999998) || + (underlyings(294,2) <= 840.0) || + (underlyings(294,1) <= 8288.0) || + (underlyings(295,0) <= 2630.6349999999998) || + (underlyings(295,2) <= 840.0) || + (underlyings(295,1) <= 8288.0) || + (underlyings(296,0) <= 2630.6349999999998) || + (underlyings(296,2) <= 840.0) || + (underlyings(296,1) <= 8288.0) || + (underlyings(297,0) <= 2630.6349999999998) || + (underlyings(297,2) <= 840.0) || + (underlyings(297,1) <= 8288.0) || + (underlyings(298,0) <= 2630.6349999999998) || + (underlyings(298,2) <= 840.0) || + (underlyings(298,1) <= 8288.0) || + (underlyings(299,0) <= 2630.6349999999998) || + (underlyings(299,2) <= 840.0) || + (underlyings(299,1) <= 8288.0) || + (underlyings(300,0) <= 2630.6349999999998) || + (underlyings(300,2) <= 840.0) || + (underlyings(300,1) <= 8288.0) || + (underlyings(301,0) <= 2630.6349999999998) || + (underlyings(301,2) <= 840.0) || + (underlyings(301,1) <= 8288.0) || + (underlyings(302,0) <= 2630.6349999999998) || + (underlyings(302,2) <= 840.0) || + (underlyings(302,1) <= 8288.0) || + (underlyings(303,0) <= 2630.6349999999998) || + (underlyings(303,2) <= 840.0) || + (underlyings(303,1) <= 8288.0) || + (underlyings(304,0) <= 2630.6349999999998) || + (underlyings(304,2) <= 840.0) || + (underlyings(304,1) <= 8288.0) || + (underlyings(305,0) <= 2630.6349999999998) || + (underlyings(305,2) <= 840.0) || + (underlyings(305,1) <= 8288.0) || + (underlyings(306,0) <= 2630.6349999999998) || + (underlyings(306,2) <= 840.0) || + (underlyings(306,1) <= 8288.0) || + (underlyings(307,0) <= 2630.6349999999998) || + (underlyings(307,2) <= 840.0) || + (underlyings(307,1) <= 8288.0) || + (underlyings(308,0) <= 2630.6349999999998) || + (underlyings(308,2) <= 840.0) || + (underlyings(308,1) <= 8288.0) || + (underlyings(309,0) <= 2630.6349999999998) || + (underlyings(309,2) <= 840.0) || + (underlyings(309,1) <= 8288.0) || + (underlyings(310,0) <= 2630.6349999999998) || + (underlyings(310,2) <= 840.0) || + (underlyings(310,1) <= 8288.0) || + (underlyings(311,0) <= 2630.6349999999998) || + (underlyings(311,2) <= 840.0) || + (underlyings(311,1) <= 8288.0) || + (underlyings(312,0) <= 2630.6349999999998) || + (underlyings(312,2) <= 840.0) || + (underlyings(312,1) <= 8288.0) || + (underlyings(313,0) <= 2630.6349999999998) || + (underlyings(313,2) <= 840.0) || + (underlyings(313,1) <= 8288.0) || + (underlyings(314,0) <= 2630.6349999999998) || + (underlyings(314,2) <= 840.0) || + (underlyings(314,1) <= 8288.0) || + (underlyings(315,0) <= 2630.6349999999998) || + (underlyings(315,2) <= 840.0) || + (underlyings(315,1) <= 8288.0) || + (underlyings(316,0) <= 2630.6349999999998) || + (underlyings(316,2) <= 840.0) || + (underlyings(316,1) <= 8288.0) || + (underlyings(317,0) <= 2630.6349999999998) || + (underlyings(317,2) <= 840.0) || + (underlyings(317,1) <= 8288.0) || + (underlyings(318,0) <= 2630.6349999999998) || + (underlyings(318,2) <= 840.0) || + (underlyings(318,1) <= 8288.0) || + (underlyings(319,0) <= 2630.6349999999998) || + (underlyings(319,2) <= 840.0) || + (underlyings(319,1) <= 8288.0) || + (underlyings(320,0) <= 2630.6349999999998) || + (underlyings(320,2) <= 840.0) || + (underlyings(320,1) <= 8288.0) || + (underlyings(321,0) <= 2630.6349999999998) || + (underlyings(321,2) <= 840.0) || + (underlyings(321,1) <= 8288.0) || + (underlyings(322,0) <= 2630.6349999999998) || + (underlyings(322,2) <= 840.0) || + (underlyings(322,1) <= 8288.0) || + (underlyings(323,0) <= 2630.6349999999998) || + (underlyings(323,2) <= 840.0) || + (underlyings(323,1) <= 8288.0) || + (underlyings(324,0) <= 2630.6349999999998) || + (underlyings(324,2) <= 840.0) || + (underlyings(324,1) <= 8288.0) || + (underlyings(325,0) <= 2630.6349999999998) || + (underlyings(325,2) <= 840.0) || + (underlyings(325,1) <= 8288.0) || + (underlyings(326,0) <= 2630.6349999999998) || + (underlyings(326,2) <= 840.0) || + (underlyings(326,1) <= 8288.0) || + (underlyings(327,0) <= 2630.6349999999998) || + (underlyings(327,2) <= 840.0) || + (underlyings(327,1) <= 8288.0) || + (underlyings(328,0) <= 2630.6349999999998) || + (underlyings(328,2) <= 840.0) || + (underlyings(328,1) <= 8288.0) || + (underlyings(329,0) <= 2630.6349999999998) || + (underlyings(329,2) <= 840.0) || + (underlyings(329,1) <= 8288.0) || + (underlyings(330,0) <= 2630.6349999999998) || + (underlyings(330,2) <= 840.0) || + (underlyings(330,1) <= 8288.0) || + (underlyings(331,0) <= 2630.6349999999998) || + (underlyings(331,2) <= 840.0) || + (underlyings(331,1) <= 8288.0) || + (underlyings(332,0) <= 2630.6349999999998) || + (underlyings(332,2) <= 840.0) || + (underlyings(332,1) <= 8288.0) || + (underlyings(333,0) <= 2630.6349999999998) || + (underlyings(333,2) <= 840.0) || + (underlyings(333,1) <= 8288.0) || + (underlyings(334,0) <= 2630.6349999999998) || + (underlyings(334,2) <= 840.0) || + (underlyings(334,1) <= 8288.0) || + (underlyings(335,0) <= 2630.6349999999998) || + (underlyings(335,2) <= 840.0) || + (underlyings(335,1) <= 8288.0) || + (underlyings(336,0) <= 2630.6349999999998) || + (underlyings(336,2) <= 840.0) || + (underlyings(336,1) <= 8288.0) || + (underlyings(337,0) <= 2630.6349999999998) || + (underlyings(337,2) <= 840.0) || + (underlyings(337,1) <= 8288.0) || + (underlyings(338,0) <= 2630.6349999999998) || + (underlyings(338,2) <= 840.0) || + (underlyings(338,1) <= 8288.0) || + (underlyings(339,0) <= 2630.6349999999998) || + (underlyings(339,2) <= 840.0) || + (underlyings(339,1) <= 8288.0) || + (underlyings(340,0) <= 2630.6349999999998) || + (underlyings(340,2) <= 840.0) || + (underlyings(340,1) <= 8288.0) || + (underlyings(341,0) <= 2630.6349999999998) || + (underlyings(341,2) <= 840.0) || + (underlyings(341,1) <= 8288.0) || + (underlyings(342,0) <= 2630.6349999999998) || + (underlyings(342,2) <= 840.0) || + (underlyings(342,1) <= 8288.0) || + (underlyings(343,0) <= 2630.6349999999998) || + (underlyings(343,2) <= 840.0) || + (underlyings(343,1) <= 8288.0) || + (underlyings(344,0) <= 2630.6349999999998) || + (underlyings(344,2) <= 840.0) || + (underlyings(344,1) <= 8288.0) || + (underlyings(345,0) <= 2630.6349999999998) || + (underlyings(345,2) <= 840.0) || + (underlyings(345,1) <= 8288.0) || + (underlyings(346,0) <= 2630.6349999999998) || + (underlyings(346,2) <= 840.0) || + (underlyings(346,1) <= 8288.0) || + (underlyings(347,0) <= 2630.6349999999998) || + (underlyings(347,2) <= 840.0) || + (underlyings(347,1) <= 8288.0) || + (underlyings(348,0) <= 2630.6349999999998) || + (underlyings(348,2) <= 840.0) || + (underlyings(348,1) <= 8288.0) || + (underlyings(349,0) <= 2630.6349999999998) || + (underlyings(349,2) <= 840.0) || + (underlyings(349,1) <= 8288.0) || + (underlyings(350,0) <= 2630.6349999999998) || + (underlyings(350,2) <= 840.0) || + (underlyings(350,1) <= 8288.0) || + (underlyings(351,0) <= 2630.6349999999998) || + (underlyings(351,2) <= 840.0) || + (underlyings(351,1) <= 8288.0) || + (underlyings(352,0) <= 2630.6349999999998) || + (underlyings(352,2) <= 840.0) || + (underlyings(352,1) <= 8288.0) || + (underlyings(353,0) <= 2630.6349999999998) || + (underlyings(353,2) <= 840.0) || + (underlyings(353,1) <= 8288.0) || + (underlyings(354,0) <= 2630.6349999999998) || + (underlyings(354,2) <= 840.0) || + (underlyings(354,1) <= 8288.0) || + (underlyings(355,0) <= 2630.6349999999998) || + (underlyings(355,2) <= 840.0) || + (underlyings(355,1) <= 8288.0) || + (underlyings(356,0) <= 2630.6349999999998) || + (underlyings(356,2) <= 840.0) || + (underlyings(356,1) <= 8288.0) || + (underlyings(357,0) <= 2630.6349999999998) || + (underlyings(357,2) <= 840.0) || + (underlyings(357,1) <= 8288.0) || + (underlyings(358,0) <= 2630.6349999999998) || + (underlyings(358,2) <= 840.0) || + (underlyings(358,1) <= 8288.0) || + (underlyings(359,0) <= 2630.6349999999998) || + (underlyings(359,2) <= 840.0) || + (underlyings(359,1) <= 8288.0) || + (underlyings(360,0) <= 2630.6349999999998) || + (underlyings(360,2) <= 840.0) || + (underlyings(360,1) <= 8288.0) || + (underlyings(361,0) <= 2630.6349999999998) || + (underlyings(361,2) <= 840.0) || + (underlyings(361,1) <= 8288.0) || + (underlyings(362,0) <= 2630.6349999999998) || + (underlyings(362,2) <= 840.0) || + (underlyings(362,1) <= 8288.0) || + (underlyings(363,0) <= 2630.6349999999998) || + (underlyings(363,2) <= 840.0) || + (underlyings(363,1) <= 8288.0) || + (underlyings(364,0) <= 2630.6349999999998) || + (underlyings(364,2) <= 840.0) || + (underlyings(364,1) <= 8288.0) || + (underlyings(365,0) <= 2630.6349999999998) || + (underlyings(365,2) <= 840.0) || + (underlyings(365,1) <= 8288.0) || + (underlyings(366,0) <= 2630.6349999999998) || + (underlyings(366,2) <= 840.0) diff --git a/benchmarks/OptionPricing/lib/include/Constants.h b/benchmarks/OptionPricing/lib/include/Constants.h index b5e21ab..444a5bf 100644 --- a/benchmarks/OptionPricing/lib/include/Constants.h +++ b/benchmarks/OptionPricing/lib/include/Constants.h @@ -1,19 +1,12 @@ #ifndef CONSTANTS_H #define CONSTANTS_H +#include "real.h" #include "Optimizations.h" #define WARP (1< 1"); @@ -1226,7 +1226,7 @@ void trajectory_contract3( // BARRIER L40: //model->notify_cash_flow(model, 0, (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))), 1 /*2013-01-27, 2013-01-27, EUR*/); - const REAL amount = (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))); + const real_t amount = (1000. * (1. + fmin(((underlyings(366,1) / 11840.) - 1.), fmin(((underlyings(366,2) / 1200.) - 1.), ((underlyings(366,0) / 3758.05) - 1.))))); trajectory_inner( num_cash_flows, model_num, 1, amount, md_discts, vhat ); return; @@ -1241,9 +1241,9 @@ void aggregDiscountedPayoff( const UINT& num_under, // the number of underlyings const UINT& num_cash_flows, const UINT& num_pricers,// the number of deterministic procers - const REAL* md_discts, // [num_models][num_scash_flow] discounts - const REAL* md_detvals, // [num_models, num_det_pricers] pricers - const REAL* inst_traj, // [num_dates, num_under] current trajectory + const real_t* md_discts, // [num_models][num_scash_flow] discounts + const real_t* md_detvals, // [num_models, num_det_pricers] pricers + const real_t* inst_traj, // [num_dates, num_under] current trajectory double* vhat // [model_num] Accumulated per-model price ) { if (contr_num == 1) { diff --git a/benchmarks/OptionPricing/lib/include/ParseInput.h b/benchmarks/OptionPricing/lib/include/ParseInput.h index 546bf7f..f18f317 100644 --- a/benchmarks/OptionPricing/lib/include/ParseInput.h +++ b/benchmarks/OptionPricing/lib/include/ParseInput.h @@ -14,7 +14,7 @@ /*******************************/ #define EPS 0.0005 -#if _OPTIMIZATION_USE_FLOATS +#if REAL_IS_FLOAT #define read_real read_float #else #define read_real read_double @@ -37,7 +37,7 @@ typedef struct { typedef struct { int * bb_inds; // [3, num_dates], i.e., bi, li, ri - REAL* bb_data; // [3, num_dates], i.e., sd, lw, rw + real_t* bb_data; // [3, num_dates], i.e., sd, lw, rw void cleanup() { free(bb_inds); free(bb_data); @@ -46,12 +46,12 @@ typedef struct { typedef struct { - REAL* md_c; // [num_models, num_under, num_under] - REAL* md_vols; // [num_models, num_dates, num_under] - REAL* md_drifts; // [num_models, num_dates, num_under] - REAL* md_starts; // [num_models, num_under] - REAL* md_discts; // [num_models, num_cash_flows] - REAL* md_detvals; // [num_models, num_det_pricers] + real_t* md_c; // [num_models, num_under, num_under] + real_t* md_vols; // [num_models, num_dates, num_under] + real_t* md_drifts; // [num_models, num_dates, num_under] + real_t* md_starts; // [num_models, num_under] + real_t* md_discts; // [num_models, num_cash_flows] + real_t* md_detvals; // [num_models, num_det_pricers] void cleanup() { free(md_c); // all allocated together, hence free the first one @@ -142,7 +142,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, bool ok; // md_c - if (read_array(sizeof(REAL), read_real, (void**)&md_arrs.md_c, shape, 3) ) { + if (read_array(sizeof(real_t), read_real, (void**)&md_arrs.md_c, shape, 3) ) { fprintf(stderr, "Syntax error when reading md_c [%d,%d,%d].\n", scals.num_models, scals.num_under, scals.num_under); exit(1); @@ -153,7 +153,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, assert(ok && "Incorrect shape of md_c!"); // md_vols (volatility) - if (read_array(sizeof(REAL), read_real, (void**)&md_arrs.md_vols, shape, 3) ) { + if (read_array(sizeof(real_t), read_real, (void**)&md_arrs.md_vols, shape, 3) ) { fprintf(stderr, "Syntax error when reading md_vols [%d,%d,%d].\n", scals.num_models, scals.num_dates, scals.num_under); exit(1); @@ -164,7 +164,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, assert(ok && "Incorrect shape of md_vols!"); // md_drifts - if (read_array(sizeof(REAL), read_real, (void**)&md_arrs.md_drifts, shape, 3) ) { + if (read_array(sizeof(real_t), read_real, (void**)&md_arrs.md_drifts, shape, 3) ) { fprintf(stderr, "Syntax error when reading md_drifts [%d,%d,%d].\n", scals.num_models, scals.num_dates, scals.num_under); exit(1); @@ -175,7 +175,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, assert(ok && "Incorrect shape of md_drifts!"); // md_starts - if (read_array(sizeof(REAL), read_real, (void**)&md_arrs.md_starts, shape, 2) ) { + if (read_array(sizeof(real_t), read_real, (void**)&md_arrs.md_starts, shape, 2) ) { fprintf(stderr, "Syntax error when reading md_drifts [%d,%d].\n", scals.num_models, scals.num_under); exit(1); @@ -185,7 +185,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, assert(ok && "Incorrect shape of md_starts!"); // md_detvals (Model deterministic values) - if (read_array(sizeof(REAL), read_real, (void**)&md_arrs.md_detvals, shape, 2) ) { + if (read_array(sizeof(real_t), read_real, (void**)&md_arrs.md_detvals, shape, 2) ) { fprintf(stderr, "Syntax error when reading md_detvals [%d,..].\n", scals.num_models); exit(1); @@ -195,7 +195,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, scals.num_det_pricers = shape[1]; // md_discts (Model discounts) - if (read_array(sizeof(REAL), read_real, (void**)&md_arrs.md_discts, shape, 2) ) { + if (read_array(sizeof(real_t), read_real, (void**)&md_arrs.md_discts, shape, 2) ) { fprintf(stderr, "Syntax error when reading md_discts [%d,..].\n", scals.num_models); exit(1); @@ -206,13 +206,13 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, { // put all of them in a contiguous memory: int alloc_size, offset; - REAL* flat_arr; + real_t* flat_arr; alloc_size = scals.num_under * ( scals.num_under + 2*scals.num_dates + 1); alloc_size += scals.num_cash_flows + scals.num_det_pricers; alloc_size *= scals.num_models; alloc_size = do_padding( alloc_size ); - flat_arr = static_cast ( malloc( alloc_size * sizeof(REAL) ) ); + flat_arr = static_cast ( malloc( alloc_size * sizeof(real_t) ) ); // copy md_c offset = 0; @@ -268,7 +268,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, assert(ok && "Incorrect shape of bb_inds (brownian bridge indirect arrays)!"); // md_starts - if (read_array(sizeof(REAL), read_real, (void**)&bb_arrs.bb_data, shape, 2) ) { + if (read_array(sizeof(real_t), read_real, (void**)&bb_arrs.bb_data, shape, 2) ) { fprintf(stderr, "Syntax error when reading md_drifts [3,%d].\n", scals.num_dates ); exit(1); diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/SobolGaussBB.h b/benchmarks/OptionPricing/lib/include/SobolGaussBB.h similarity index 88% rename from benchmarks/OptionPricing/implementations/cpp_openmp/SobolGaussBB.h rename to benchmarks/OptionPricing/lib/include/SobolGaussBB.h index d6ae829..0b45daa 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/SobolGaussBB.h +++ b/benchmarks/OptionPricing/lib/include/SobolGaussBB.h @@ -85,8 +85,8 @@ sobolRecOpt( const int& sobol_dim, // size of the quasi-random vector (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) -inline static REAL small_case(const REAL& q) { - REAL x = 0.180625 - q * q; +inline static real_t small_case(const real_t& q) { + real_t x = 0.180625 - q * q; return q * rat_eval( 3.387132872796366608, 133.14166789178437745, @@ -107,8 +107,8 @@ inline static REAL small_case(const REAL& q) { 5226.495278852854561); } -inline static REAL intermediate(const REAL& r) { - REAL x = r - 1.6; +inline static real_t intermediate(const real_t& r) { + real_t x = r - 1.6; return rat_eval( 1.42343711074968357734, 4.6303378461565452959, @@ -129,8 +129,8 @@ inline static REAL intermediate(const REAL& r) { 1.05075007164441684324e-9); } -inline static REAL tail(const REAL& r) { - REAL x = r - 5.0; +inline static real_t tail(const real_t& r) { + real_t x = r - 5.0; return rat_eval( 6.6579046435011037772, 5.4637849111641143699, @@ -156,23 +156,23 @@ inline static REAL tail(const REAL& r) { * to a gaussian distribution, uniformely distributed in [-inf, +inf]. */ inline -void uGaussian( const REAL& fract, // 2 ^ sobol_bits +void uGaussian( const real_t& fract, // 2 ^ sobol_bits const UINT& dim, // size of the Sobol quasi-random vector const UINT* sob_vct, // [dim] Sobol quasi-random (int) vector - REAL* gauss_vct // result + real_t* gauss_vct // result ) { for ( int i = 0; i < dim; i ++ ) { // sobol int number -> sobol real number in [0,1) - REAL sob_real = static_cast(sob_vct[i]) * fract; + real_t sob_real = static_cast(sob_vct[i]) * fract; // sobol real number [0,1) -> gaussian number in (-inf, +inf) - REAL dp = sob_real - 0.5; + real_t dp = sob_real - 0.5; if ( fabs(dp) <= 0.425 ) { gauss_vct[i]= small_case(dp); } else { - REAL pp = (dp < 0.0) ? (0.5 + dp) : (0.5 - dp); - REAL r = sqrt (- log(pp)); - REAL x = (r <= 5.0) ? intermediate(r) : tail(r); + real_t pp = (dp < 0.0) ? (0.5 + dp) : (0.5 - dp); + real_t r = sqrt (- log(pp)); + real_t x = (r <= 5.0) ? intermediate(r) : tail(r); gauss_vct[i]= (dp < 0.0) ? (0.0 - x) : x; } } @@ -190,17 +190,17 @@ void brownianBridge( const UINT& num_under, const UINT& num_dates, const int* bb_inds, // [3, num_dates] Brownian Bridge's indirect indexing - const REAL* bb_data, // [3, num_dates] Brownian Bridge's data - REAL* md_zd, // [num_dates, num_under] the gaussian vector + const real_t* bb_data, // [3, num_dates] Brownian Bridge's data + real_t* md_zd, // [num_dates, num_under] the gaussian vector // also holds the result! - REAL* res // [num_dates, num_under] temporary array + real_t* res // [num_dates, num_under] temporary array ) { const int * bb_bi = bb_inds; const int * bb_li = bb_inds + num_dates; const int * bb_ri = bb_inds + 2*num_dates; - const REAL* bb_sd = bb_data; - const REAL* bb_lw = bb_data + num_dates; - const REAL* bb_rw = bb_data + 2*num_dates; + const real_t* bb_sd = bb_data; + const real_t* bb_lw = bb_data + num_dates; + const real_t* bb_rw = bb_data + 2*num_dates; for ( int m = 0; m < num_under; m ++ ) { res[ (bb_bi[0]-1) * num_under + m ] = bb_sd[0] * md_zd[m]; From da908605ed453e0f369b3afc28a69dcd44370d35 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 11:44:03 +0200 Subject: [PATCH 082/122] Fix some old REAL usage. --- .../implementations/cpp_openmp_naive/VolCalibOrig.cpp | 7 +------ .../implementations/cpp_sequential/VolCalibOrig.cpp | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp index 139a519..cf3381b 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp +++ b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp @@ -1,14 +1,9 @@ #include #include -#ifdef REAL_TYPE -typedef REAL_TYPE real_t; -#else -typedef double real_t; -#endif - #define WORKGROUP_SIZE 512 +#include "real.h" #include "Util.h" #include "ParseInput.h" diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp index fb8bd02..657f8bf 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp +++ b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp @@ -3,12 +3,7 @@ #define WORKGROUP_SIZE 512 -#ifdef REAL_TYPE -typedef REAL_TYPE real_t; -#else -typedef double real_t; -#endif - +#include "real.h" #include "Util.h" #include "ParseInput.h" From 15aed936e086b1d010492e3dbc9d7e373173ee75 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 13:48:11 +0200 Subject: [PATCH 083/122] OpenCL implementation of OptionPricing. --- .../cpp_opencl/ContractDefs/LargeContract.cl | 66 ++ .../cpp_opencl/ContractDefs/MediumContract.cl | 66 ++ .../cpp_opencl/ContractDefs/SmallContract.cl | 44 ++ .../implementations/cpp_opencl/GenPricing.cpp | 190 ++++++ .../cpp_opencl/GenericPricingPrivOpt.cl | 376 +++++++++++ .../cpp_opencl/GenericPricingVectOpt.cl | 588 ++++++++++++++++ .../GenericPricingVectUncoalesced.cl | 493 ++++++++++++++ .../implementations/cpp_opencl/Makefile | 46 ++ .../implementations/cpp_opencl/StructGPU.h | 631 ++++++++++++++++++ .../static_configuration_template.json | 3 + .../OptionPricing/lib/include/Optimizations.h | 1 - 11 files changed, 2503 insertions(+), 1 deletion(-) create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/MediumContract.cl create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/SmallContract.cl create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/Makefile create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h create mode 100644 benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl new file mode 100644 index 0000000..c491c9e --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/ContractDefs/LargeContract.cl @@ -0,0 +1,66 @@ +#include "Constants.h" + +#ifdef VECT_KERNEL + #define underlyings(i,j) \ + (inst_traj[(i*num_under + j)< ro_scal.num_mcits) { + ro_scal.num_gpuits = ro_scal.num_mcits - cur_iter; + globalWorkSize[0] = getWorkSize( ro_scal.num_gpuits,ro_scal.chunk,ro_scal.BLOCK); + } + if(cur_iter != 0) { + size_t cur_size = sizeof(LoopROScalars); + cl_int ciErr2; + ro_scal.sobol_count_ini = cur_iter + sob_ini_count; + clReleaseMemObject(ocl_arrs.ro_scals); + ocl_arrs.ro_scals = clCreateBuffer( + cxGPUContext, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 + ); + ciErr2 = clEnqueueWriteBuffer(cqCommandQueue[GPU_DEV_ID], ocl_arrs.ro_scals, CL_TRUE, 0, + cur_size, &ro_scal, 0, NULL, NULL); + oclCheckError(ciErr2, CL_SUCCESS); + } + + runGPU_VECT ( + ro_scal, glb_vhat, ocl_arrs, cqCommandQueue[GPU_DEV_ID], cpProgram, + globalWorkSize, localWorkSize + ); + + reduceVHAT_CPU( ro_scal, glb_vhat, vhat_fin ); + } + + ro_scal.sobol_count_ini = sob_ini_count; + } + + for(UINT ii = 0; ii Debug.txt diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl new file mode 100644 index 0000000..4473e8e --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingPrivOpt.cl @@ -0,0 +1,376 @@ +/***************************************************/ +/*** Contract Definitions Are Linked at Run time ***/ +/*** & The RO-Scalar Data-Structure is included, ***/ +/** for e.g., ContractDefs/SmallContract.cl ***/ +/***************************************************/ + +#define TYPE real_t +#define FLAG uchar +#include "Utilities.cl" + +/********************************************/ +/********** SOBOL NUMER GENERATOR ***********/ +/********************************************/ + +void mlfi_genmatrix_uniformGPUind ( + UINT seq_count, + __constant LoopROScalars* ro_scal, + __constant int* sobol_v_dir, + int* sobol_last_num_vec, + real_t* md_zd +) { + UINT j, k, gs, gv_k = 0; + + seq_count += 1; + gs = seq_count >> 1; + gs = seq_count ^ gs; + + UINT sob_dim = ro_scal->num_under * ro_scal->num_dates; + + for( j = 0; j < sob_dim; j++ ) + sobol_last_num_vec[j] = 0; + for( k = 0; k < ro_scal->sobol_bits; ++k ) { + if(gs & 1) { + __constant int* dir_vect + = sobol_v_dir + k*sob_dim; + for( j=0; j < sob_dim; j++ ) { + // xor term g_k * v_k to direction i + sobol_last_num_vec[j] ^= dir_vect[j]; + } + } + gs = gs >> 1; + } + for( j = 0; j < sob_dim; j++ ) { + md_zd[j] = sobol_last_num_vec[j] * ro_scal->sob_norm_fact; + } +} + +inline void mlfi_genmatrix_uniformGPUrecOpt( + UINT f_ind, + __constant LoopROScalars* ro_scal, + __constant int* sobol_v_dir, + int* sobol_last_num_vec, + real_t* md_zd +) { + UINT j; + UINT sob_dim = ro_scal->num_under * ro_scal->num_dates; + f_ind *= sob_dim; + for(j=0; j < sob_dim; j++) { + sobol_last_num_vec[j] ^= sobol_v_dir[ f_ind + j ]; //f_ind * sob_dim + md_zd[j] = sobol_last_num_vec[j] * ro_scal->sob_norm_fact; + } +} + + +inline void mlfi_genmatrix_uniformGPUrec( + UINT seq_count, + __constant LoopROScalars* ro_scal, + __constant int* sobol_v_dir, + int* sobol_last_num_vec, + real_t* md_zd +) { + UINT ell, j; + + UINT c = seq_count; + ell = 0; + while(c & 1) { + ell++; + c >>= 1; + } + UINT sob_dim = ro_scal->num_under * ro_scal->num_dates; + for(j=0; j < sob_dim; j++) { + + sobol_last_num_vec[j] ^= sobol_v_dir[ell*sob_dim + j]; + md_zd[j] = sobol_last_num_vec[j] * ro_scal->sob_norm_fact; //sobol_last_den_inv; + } +} + + +/********************************************/ +/********** GAUSSIAN DISTRIBUTION ***********/ +/********************************************/ + +#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ + (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ + (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) + +inline real_t small_case(real_t q) { + real_t x = 0.180625 - q * q; + return q * rat_eval( + 3.387132872796366608, + 133.14166789178437745, + 1971.5909503065514427, + 13731.693765509461125, + 45921.953931549871457, + 67265.770927008700853, + 33430.575583588128105, + 2509.0809287301226727, + + 1.0, + 42.313330701600911252, + 687.1870074920579083, + 5394.1960214247511077, + 21213.794301586595867, + 39307.89580009271061, + 28729.085735721942674, + 5226.495278852854561); +} + +inline real_t intermediate(real_t r) { + real_t x = r - 1.6; + return rat_eval( + 1.42343711074968357734, + 4.6303378461565452959, + 5.7694972214606914055, + 3.64784832476320460504, + 1.27045825245236838258, + 0.24178072517745061177, + 0.0227238449892691845833, + 7.7454501427834140764e-4, + + 1.0, + 2.05319162663775882187, + 1.6763848301838038494, + 0.68976733498510000455, + 0.14810397642748007459, + 0.0151986665636164571966, + 5.475938084995344946e-4, + 1.05075007164441684324e-9); +} + +inline real_t tail(real_t r) { + real_t x = r - 5.0; + return rat_eval( + 6.6579046435011037772, + 5.4637849111641143699, + 1.7848265399172913358, + 0.29656057182850489123, + 0.026532189526576123093, + 0.0012426609473880784386, + 2.71155556874348757815e-5, + 2.01033439929228813265e-7, + + 1.0, + 0.59983220655588793769, + 0.13692988092273580531, + 0.0148753612908506148525, + 7.868691311456132591e-4, + 1.8463183175100546818e-5, + 1.4215117583164458887e-7, + 2.04426310338993978564e-15); +} + +inline void mlfi_ugaussian_Pinv_vector(real_t* p, UINT N, UINT logBLOCK) { + UINT i, UB = N; + + for ( i=0; i < UB; i++ ) { + real_t dp = p[i] - 0.5; + if (fabs(dp) <= 0.425) { + p[i] = small_case(dp); + } else { + real_t pp = (dp < 0.0) ? dp + 0.5 : (0.5 - dp); + real_t r = sqrt (- log(pp)); + real_t x = (r <= 5.0) ? intermediate(r) : tail(r); + p[i] = (dp < 0.0) ? (0.0 - x) : x; + } + } +} + + +/********************************************/ +/************* BROWNIAN BRIDGE **************/ +/********************************************/ +inline void mlfi_brownianbridge_wiener_pathNoTransGPU( + __constant LoopROScalars* ro_scal, + __constant int* bb_inds, + __constant real_t* bb_data, + real_t* md_zd, + __local real_t* md_z, + UINT block_size +) { + + UINT n, m, md_dim = ro_scal->num_under * block_size, nb_path_dates = ro_scal->num_dates; + __constant int *bb_li, *bb_bi, *bb_ri; + __constant real_t *bb_rw, *bb_lw, *bb_sd; + + bb_bi = bb_inds; + bb_li = bb_inds + nb_path_dates; + bb_ri = bb_inds + (nb_path_dates<<1); + + bb_sd = bb_data; + bb_lw = bb_data + nb_path_dates; + bb_rw = bb_data + (nb_path_dates<<1); + + for (n=0, m=0; m < md_dim; n++, m+=block_size) { + UINT i; + + md_z [ (bb_bi[0]-1) * md_dim + m ] = bb_sd[0] * md_zd[n]; + + for(i=1; i < nb_path_dates; i++) { + int j = bb_li[i] - 1; + int k = bb_ri[i] - 1; + int l = bb_bi[i] - 1; + + real_t wk = md_z [k*md_dim+m]; + real_t zi = md_zd[i*ro_scal->num_under+n]; + + md_z[l*md_dim+m] = (j == -1) ? + bb_rw[i] * wk + bb_sd[i] * zi : + bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * md_z[j*md_dim+m]; + } + } +} + + + +__kernel void payoffGPU( + __constant LoopROScalars* ro_scal, // RO SCALARS + __constant int* sobol_v_dir, // RO SOBOL + __constant UCHAR* fix_index, + // RO Brownian Bridge + __constant int* bb_ia, + __constant real_t* bb_coefs, + // RO MODELS DATA + __constant real_t* model_coefs, + // WO (GLOBAL) VHAT + __global real_t* model_vhat, + // LOCAL ARRAYS + __local real_t* md_z, + //__local real_t* inst_trajWF, + __local real_t* vhat_local +) { + + UINT k, block_size = get_local_size(0); + const UINT ct_init = 0; //ro_scal->sobol_count_ini; + + int sobol_last_num_vec[15];//UINT[ro_scal->sobol_dim]; + real_t md_zd [15]; //[ro_scal->sobol_dim]; + + { // each local array is ajusted w.r.t. the local offset! + UINT localID = get_local_id(0); + md_z = md_z + localID; + //inst_trajWF = inst_trajWF + localID; + vhat_local = vhat_local + localID; + } + + // initialize vhat_local to 0 + for( k = 0; k < ro_scal->num_models*block_size; k+=block_size) { + vhat_local[k] = 0.0; + } + + // ready to go to the main loop + UINT lb = (get_global_id (0) << ro_scal->log_chunk); + UINT ub = min(lb + ro_scal->chunk, ro_scal->num_gpuits); + + + for( k = lb; k < ub; k++ ) { + + // 1. random number generation phase +#ifndef _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR + mlfi_genmatrix_uniformGPUind ( + ct_init+k, ro_scal, + sobol_v_dir, sobol_last_num_vec, md_zd + ); +#else + if( k > lb && k < ub-1) { + mlfi_genmatrix_uniformGPUrecOpt ( + fix_index[k-lb], ro_scal, sobol_v_dir, sobol_last_num_vec, md_zd + ); + } else if (k==lb) { + mlfi_genmatrix_uniformGPUind ( + ct_init+k, ro_scal, + sobol_v_dir, sobol_last_num_vec, md_zd + ); + } else { + mlfi_genmatrix_uniformGPUrec ( + ct_init+k, ro_scal, sobol_v_dir, sobol_last_num_vec, md_zd + ); + } +#endif + + + // 2. generate uniform distribution + mlfi_ugaussian_Pinv_vector(md_zd, ro_scal->num_under*ro_scal->num_dates, ro_scal->logBLOCK); + + // 3. brownian bridge refinement + mlfi_brownianbridge_wiener_pathNoTransGPU( + ro_scal, bb_ia, bb_coefs, md_zd, md_z, block_size + ); + + { // 4. expand md_zd + UINT i; + UINT LB = ro_scal->num_under * block_size; + UINT UB = (ro_scal->num_under * ro_scal->num_dates - 1) * block_size; + for ( i = UB; i >= LB; i -= block_size ) { + md_z[i] -= md_z[i - LB]; + } + } + + { // 5. compute trajectory + UINT m, i, j, q, l; + UINT num_under = ro_scal->num_under; + UINT num_dates = ro_scal->num_dates; + real_t* trajWF = md_zd; + + __constant real_t *md_c, *md_vols, *md_drifts, *md_starts, *md_discts, *md_detvals; + { + UINT num_mods = ro_scal->num_models; + UINT dim_paths = num_under*num_dates; + UINT offset = 0; + md_c = model_coefs + offset; offset += num_mods * num_under * num_under; + md_vols = model_coefs + offset; offset += num_mods * dim_paths; + md_drifts = model_coefs + offset; offset += num_mods * dim_paths; + md_starts = model_coefs + offset; offset += num_mods * num_under; + md_discts = model_coefs + offset; offset += num_mods * ro_scal->num_cash_flows; + md_detvals= model_coefs + offset; + } + + for (m = 0; m < ro_scal->num_models; m++) { + + for (j = 0; j < num_under; j++) { + real_t accum = md_starts[j]; + for( i = 0; i < num_dates; i ++) { + real_t temp = 0.0; + q = num_under*i + j; + + for (l = 0; l <= j; l++) + temp += md_c[num_under * j + l] * md_z[(q - j + l)*block_size]; //md_z[(q - j + l) << logBLOCK]; + + temp = exp(temp * md_vols[q] + md_drifts[q]); + accum *= temp; + trajWF[q] = accum; + } + } + + // 6. reduce each instance/model locally on the multiprocessor + payoffFunction( m, num_under, + ro_scal->num_cash_flows, + ro_scal->num_det_pricers, + md_discts, + md_detvals, + trajWF, + vhat_local + ); + + if ( m+1 < ro_scal->num_models ) { + UINT dim_paths = num_under*num_dates; + md_c += num_under * num_under; md_vols += dim_paths; + md_drifts += dim_paths; md_starts += num_under; + md_discts += ro_scal->num_cash_flows; md_detvals += ro_scal->num_det_pricers; + } + } + } // end 5. compute trajectory + + } // END for( k ) + + barrier(CLK_LOCAL_MEM_FENCE); + + segm_scan_reg_block ( vhat_local - get_local_id(0), block_size * ro_scal->num_models, block_size ); + if( get_local_id(0) == 0) { + UINT glob_size = get_global_size(0)/block_size; + for ( k = 0; k < ro_scal->num_models; k++ ) { + model_vhat[ k * glob_size + get_group_id(0) ] = + vhat_local[ (k + 1)*block_size - 1 ]; + } + } +} diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl new file mode 100644 index 0000000..39cf5d1 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl @@ -0,0 +1,588 @@ +/************************************/ +/************* MACROS ***************/ +/************************************/ + +#define TYPE real_T +#define FLAG uchar +#include "Utilities.cl" + +#define DUMMY 1 + +/********************************************/ +/********** SOBOL NUMER GENERATOR ***********/ +/********************************************/ + +#ifdef _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR + +__kernel void mlfi_genmatrix_uniform2 ( + __constant LoopROScalars* ro_scal, + __constant UCHAR* sobol_fix_ind, + __global int* sobol_v_dir, + __global real_t* md_zd +) { + UINT i, j, k; + UINT seq_count = ( get_global_id (0) << ro_scal->log_chunk ); + UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; + +#if(DUMMY==0) + uchar rmb_size = 0; + uchar rmb[32]; +#endif + + md_zd = md_zd + + ( ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) )*sobol_dim + + (get_global_id(0) & (WARP-1)) ); + __global real_t* md_zd_tmp = md_zd; + + UINT UB = (seq_count + (1 << ro_scal->log_chunk) < ro_scal->num_gpuits) ? + seq_count + (1 << ro_scal->log_chunk) : ro_scal->num_gpuits ; + UB = (UB > seq_count) ? UB - seq_count : 0; + + if( UB > 0 ) { + UINT gs; +#if(DUMMY==0) + // Compute gs == the Gray code rep of seq_count + gs = seq_count+1 + ro_scal->sobol_count_ini; + gs = gs ^ (gs>>1); + + // Compute the position of the 1 bits + for( k = 0; k < ro_scal->sobol_bits; ++k ) { + if(gs & 1) { + rmb[rmb_size] = (uchar)k; + rmb_size ++; + } + gs = gs >> 1; + } +#endif + // Compute the random number under the INDEPENDENT formulas + for( i = 0, j=0; j < sobol_dim; j++, i += WARP ) { + UINT accum = 0; + md_zd_tmp = md_zd; + + // FIRST ITER COMPUTED INDEPENDENTLY! +#if(DUMMY==0) + for(k=0; ksobol_bits + rmb[k] ]; + } +#else + gs = seq_count+1 + ro_scal->sobol_count_ini; + gs = gs ^ (gs>>1); + for(k=0; ksobol_bits; k++) { + if(gs & 1) { + accum ^= sobol_v_dir[ j*ro_scal->sobol_bits + k ]; + } + gs = gs >> 1; + } +#endif + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; +#if 1 + // THE REST OF CHUNK-1 ITERATIONS COMPUTED UNDER RECURRENT FORMULA + for( k = 1; k < UB-1; k++ ) { + accum = accum ^ sobol_v_dir[ j*ro_scal->sobol_bits + sobol_fix_ind[k] ]; + + md_zd_tmp += (sobol_dim << lgWARP); + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; + } + + gs = (seq_count + UB - 1 + ro_scal->sobol_count_ini) >> ro_scal->log_chunk; + UINT ell = ro_scal->log_chunk; + while(gs & 1) { + ell++; + gs >>= 1; + } + accum = accum ^ sobol_v_dir[j*ro_scal->sobol_bits + ell]; + md_zd_tmp += (sobol_dim << lgWARP); + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; +#else + for( k = seq_count+1 + ro_scal->sobol_count_ini; k < UB + ro_scal->sobol_count_ini; k++ ) { + gs = k; + UINT ell = 0; + while(gs & 1) { + ell++; + gs >>= 1; + } + + accum = accum ^ sobol_v_dir[j*ro_scal->sobol_bits + ell]; + + md_zd_tmp += (sobol_dim << lgWARP); + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; + } +#endif + } + } // end IF (seq_count < UB) + +} + +#else +/*********************************/ +/*** Independent formula Only ****/ +/*********************************/ + +__kernel void mlfi_genmatrix_uniform2 ( + __constant LoopROScalars* ro_scal, + __constant UCHAR* sobol_fix_ind, + __global int* sobol_v_dir, + __global real_t* md_zd +) { + UINT i, j, k, m; + UINT seq_count = ( get_global_id (0) << ro_scal->log_chunk ); + UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; + + uchar rmb_size = (uchar)0; + uchar rmb[32]; + + md_zd = md_zd + + ( ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) )*sobol_dim + + (get_global_id(0) & (WARP-1)) ); + __global real_t* md_zd_tmp = md_zd; + + UINT UB = (seq_count + (1 << ro_scal->log_chunk) < ro_scal->num_gpuits) ? + seq_count + (1 << ro_scal->log_chunk) : ro_scal->num_gpuits ; + UB = (UB > seq_count) ? UB - seq_count : 0; + + //if( UB > 0 ) + for(m=0; msobol_count_ini; + gs = gs ^ (gs>>1); + + // Compute the position of the 1 bits + for( k = 0; k < ro_scal->sobol_bits; ++k ) { + if(gs & 1) { + rmb[rmb_size] = (uchar)k; + rmb_size ++; + } + gs = gs >> 1; + } + + // Compute the random number under the INDEPENDENT formulas + for( i = 0, j=0; j < sobol_dim; j++, i += WARP ) { + UINT accum = 0; + + for(k=0; ksobol_bits + rmb[k] ]; + } + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; + } + + md_zd_tmp += (sobol_dim << lgWARP); + } // end IF (seq_count < UB) + +} + +#endif + + +/********************************************/ +/********** INV GAUSSIAN DISTRIB ************/ +/********************************************/ + + +#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ + (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ + (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) + +inline real_t small_case(real_t q) { + real_t x = 0.180625 - q * q; + return q * rat_eval( + 3.387132872796366608, + 133.14166789178437745, + 1971.5909503065514427, + 13731.693765509461125, + 45921.953931549871457, + 67265.770927008700853, + 33430.575583588128105, + 2509.0809287301226727, + + 1.0, + 42.313330701600911252, + 687.1870074920579083, + 5394.1960214247511077, + 21213.794301586595867, + 39307.89580009271061, + 28729.085735721942674, + 5226.495278852854561); +} + +inline real_t intermediate(real_t r) { + real_t x = r - 1.6; + return rat_eval( + 1.42343711074968357734, + 4.6303378461565452959, + 5.7694972214606914055, + 3.64784832476320460504, + 1.27045825245236838258, + 0.24178072517745061177, + 0.0227238449892691845833, + 7.7454501427834140764e-4, + + 1.0, + 2.05319162663775882187, + 1.6763848301838038494, + 0.68976733498510000455, + 0.14810397642748007459, + 0.0151986665636164571966, + 5.475938084995344946e-4, + 1.05075007164441684324e-9); +} + +inline real_t tail(real_t r) { + real_t x = r - 5.0; + return rat_eval( + 6.6579046435011037772, + 5.4637849111641143699, + 1.7848265399172913358, + 0.29656057182850489123, + 0.026532189526576123093, + 0.0012426609473880784386, + 2.71155556874348757815e-5, + 2.01033439929228813265e-7, + + 1.0, + 0.59983220655588793769, + 0.13692988092273580531, + 0.0148753612908506148525, + 7.868691311456132591e-4, + 1.8463183175100546818e-5, + 1.4215117583164458887e-7, + 2.04426310338993978564e-15); +} + +__kernel void mlfi_ugaussian_Pinv_vector1( + __constant LoopROScalars* ro_scal, __global real_t* p +) { + UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; + UINT id = get_global_id(0), i, UB; + p += ( (id >> lgWARP) << (ro_scal->log_chunk + lgWARP) )*sobol_dim + ( id & (WARP-1) ); + + id = get_global_id(0) << ro_scal->log_chunk; + + UB = min(id + (1<log_chunk), ro_scal->num_gpuits); + UB = (UB > id) ? UB - id : 0; + UB *= sobol_dim; + + for( id=0, i=0; id < UB; i+=WARP, id++) { + real_t dp = p[i] - 0.5; + if (fabs(dp) <= 0.425) { + p[i] = small_case(dp); + } else { + real_t pp = (dp < 0.0) ? dp + 0.5 : (0.5 - dp); + real_t r = sqrt (- log(pp)); + real_t x = (r <= 5.0) ? intermediate(r) : tail(r); + p[i] = (dp < 0.0) ? (0.0 - x) : x; + } + } +} + +/********************************************/ +/************* BROWNIAN BRIDGE **************/ +/********************************************/ + +__kernel void mlfi_brownianbridge_wiener_path1( + __constant LoopROScalars* ro_scal, + __constant int* bb_inds, + __constant real_t* bb_data, + __global real_t* md_zd, + __global real_t* md_z +) { + __constant int *bb_li, *bb_bi, *bb_ri; + __constant real_t *bb_rw, *bb_lw, *bb_sd; + + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + UINT m, i, md_dim = ro_scal->num_under << lgWARP, nb_path_dates = ro_scal->num_dates; + UINT sobol_dim = ro_scal->num_under * nb_path_dates; + + UINT UB = ( (cur_it + (1<log_chunk) ) < ro_scal->num_gpuits) ? + ( cur_it + (1<log_chunk) ) : ro_scal->num_gpuits; + + bb_bi = bb_inds; + bb_li = bb_inds + nb_path_dates; + bb_ri = bb_inds + (nb_path_dates<<1); + + bb_sd = bb_data; + bb_lw = bb_data + nb_path_dates; + bb_rw = bb_data + (nb_path_dates<<1); + + { + UINT tmp = ( (get_global_id(0) >> lgWARP) << (ro_scal->log_chunk + lgWARP) )*sobol_dim + ( get_global_id(0) & (WARP-1) ); + md_zd = md_zd + tmp; + md_z = md_z + tmp; + } + + for( ; cur_it < UB; cur_it++ ) { + for (m=0; m < md_dim; m+=WARP) { + md_z[ (bb_bi[0]-1) * md_dim + m ] = bb_sd[0] * md_zd[m]; + + for(i=1; i < nb_path_dates; i++) { + int j = bb_li[i] - 1; + int k = bb_ri[i] - 1; + int l = bb_bi[i] - 1; + + real_t wk = md_z [k*md_dim+m]; + real_t zi = md_zd[i*md_dim+m]; + + md_z[l*md_dim+m] = (j == -1) ? + bb_rw[i] * wk + bb_sd[i] * zi : + bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * md_z[j*md_dim+m]; + } + + } + md_z += (sobol_dim << lgWARP); + md_zd += (sobol_dim << lgWARP); + } +} + +/**************************************************/ +/************* TRAJECTORY COMPUTATION *************/ +/**************************************************/ + +void trajectory_contract( + UINT model_num, + __constant LoopROScalars* ro_scal, + __constant real_t* pc_coefs, + __global real_t* inst_traj, + __global real_t* vhat +); + +__kernel void mlfi_comp_traj1( + __constant LoopROScalars* ro_scal, // RO SCALARS + // RO MD INSTANCE DATA + __constant real_t* model_coefs, + // LOCAL SPACE 2 * ro_scal->num_under PER THREAD! + __local real_t* buff, + // RO (GLOBAL) MD_Z + __global real_t* md_z, + // WO (GLOBAL) traj + __global real_t* trajWF +) { + UINT offset; + UINT dim = ro_scal->num_under; + UINT dim_sq = dim*dim; + UINT dim_paths = dim*ro_scal->num_dates; + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + + UINT UB = ( cur_it+(1<log_chunk) < ro_scal->num_gpuits) ? + cur_it+(1<log_chunk) : ro_scal->num_gpuits ; + { + offset = ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) ); + md_z = md_z + offset*dim_paths + (get_global_id(0) & (WARP-1)); + trajWF = trajWF + offset*dim_paths*ro_scal->num_models + (get_global_id(0) & (WARP-1)); + + offset = get_local_id (0); + offset = (offset >> lgWARP)*(TILE << lgWARP) + (offset & (WARP-1)); // ro_scal->TILE_FACT + buff += offset; + + offset = dim_paths<= LB; i -= WARP ) { + md_z[i] -= md_z[i - LB]; + } + + } + + __constant real_t *md_c, *md_vols, *md_drifts, *md_starts, *md_discts, *md_detvals; + { + UINT num_mods = ro_scal->num_models; + UINT offset = 0; + md_c = model_coefs + offset; offset += num_mods * dim_sq; + md_vols = model_coefs + offset; offset += num_mods * dim_paths; + md_drifts = model_coefs + offset; offset += num_mods * dim_paths; + md_starts = model_coefs + offset; + } + for (m = 0; m < ro_scal->num_models; m++) { + // cache in local space md_starts + for (j = 0; j < dim; j++) { + buff[(dim+j) << lgWARP] = md_starts[ j ]; + } + + for (i = 0; i < ro_scal->num_dates; i++) { + ind = (dim*i) << lgWARP; + + // cache in local space md_z! + for ( j = 0; j<(dim<num_models ) { + md_c += dim_sq; md_vols += dim_paths; + md_drifts += dim_paths; md_starts += dim; + } + + trajWF += offset; + } // end for m + + md_z += offset; + + } // end for cur_it +} + + +__kernel void mlfi_comp_traj_unopt( + __constant LoopROScalars* ro_scal, // RO SCALARS + // RO MD INSTANCE DATA + __constant real_t* model_coefs, + // RO (GLOBAL) MD_Z + __global real_t* md_z, + // WO (GLOBAL) traj + __global real_t* trajWF +) { + UINT offset; + UINT dim = ro_scal->num_under; + UINT dim_sq = dim*dim; + UINT dim_paths = dim*ro_scal->num_dates; + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + + UINT UB = ( cur_it+(1<log_chunk) < ro_scal->num_gpuits ) ? + cur_it+(1<log_chunk) : ro_scal->num_gpuits ; + { + offset = ( (get_global_id (0) >> lgWARP) << (ro_scal->log_chunk+lgWARP) ); + md_z = md_z + offset*dim_paths + (get_global_id(0) & (WARP-1)); + trajWF = trajWF + offset*dim_paths*ro_scal->num_models + (get_global_id(0) & (WARP-1)); + + offset = dim_paths<= LB; i -= WARP ) { + md_z[i] -= md_z[i - LB]; + } + } + + __constant real_t *md_c, *md_vols, *md_drifts, *md_starts, *md_discts, *md_detvals; + { + UINT num_mods = ro_scal->num_models; + UINT offset = 0; + md_c = model_coefs + offset; offset += num_mods * dim_sq; + md_vols = model_coefs + offset; offset += num_mods * dim_paths; + md_drifts = model_coefs + offset; offset += num_mods * dim_paths; + md_starts = model_coefs + offset; + } + + for (m = 0; m < ro_scal->num_models; m++) { + for (i = 0; i < ro_scal->num_dates; i++) { + UINT ind = dim*i; + for (j = 0; j < dim; j++) { + real_t temp = 0.0; + + for (l = 0; l <= j; l++) { + temp += md_c[dim * j + l] * md_z[ (ind + l) << lgWARP ]; + } + temp = exp(temp * md_vols[ind + j] + md_drifts[ind + j]); + + trajWF[(ind+j) << lgWARP] = (i > 0) ? trajWF[(ind + j - dim) << lgWARP] * temp : + md_starts[ j ] * temp ; + } + } + + if ( m+1 < ro_scal->num_models ) { + md_c += dim_sq; md_vols += dim_paths; + md_drifts += dim_paths; md_starts += dim; + } + + trajWF += offset; + } // end for m + + md_z += offset; + + } // end for cur_it +} + +__kernel void mlfi_reduction_step1( + __constant LoopROScalars* ro_scal, // RO SCALARS + // RO MD INSTANCE DATA + __constant real_t* model_coefs, + // RO (GLOBAL) traj + __global real_t* inst_trajWF, + // WF (GLOBAL) traj + __global real_t* model_vhat, + __local real_t* vhat_local +) { + UINT j; + uint block_size = get_local_size(0); + int sobol_dim = ro_scal->num_under * ro_scal->num_dates; + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + + UINT UB = ( cur_it + (1<log_chunk) < ro_scal->num_gpuits) ? + cur_it + (1<log_chunk) : ro_scal->num_gpuits ; + + { // adjust the start index + UINT id = get_global_id (0); + inst_trajWF += (id & (WARP-1)) + ( (id >> lgWARP) << (ro_scal->log_chunk+lgWARP) ) * + sobol_dim * ro_scal->num_models; + vhat_local += get_local_id(0); + } + + // initialize vhat_local to 0 + for( j = 0; j < ro_scal->num_models*block_size; j += block_size ) { + vhat_local[j] = 0.0; + } + + __constant real_t *md_discts; + __constant real_t *md_detvals; + { // compute from model_coefs + int offset; + offset = ro_scal->num_under * ( ro_scal->num_under + 1) + 2 * sobol_dim; + offset *= ro_scal->num_models; + md_discts = model_coefs + offset; + md_detvals = md_discts + ro_scal->num_models * ro_scal->num_cash_flows; + } + + for( ; cur_it < UB; cur_it++ ) { + for (j = 0; j < ro_scal->num_models; j++) { + + payoffFunction( j, ro_scal->num_under, + ro_scal->num_cash_flows, + ro_scal->num_det_pricers, + md_discts + j*ro_scal->num_cash_flows, + md_detvals+ j*ro_scal->num_det_pricers, + inst_trajWF, + vhat_local + ); + + inst_trajWF += (sobol_dim << lgWARP); + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + segm_scan_reg_block ( vhat_local - get_local_id(0), block_size * ro_scal->num_models, block_size ); + if( get_local_id(0) == 0 ) { + UINT glob_size = get_global_size(0)/block_size; + for ( j = 0; j < ro_scal->num_models; j ++ ) { + model_vhat[ j * glob_size + get_group_id(0) ] = + vhat_local[ (j + 1) * block_size - 1 ]; + } + } + } +} + diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl new file mode 100644 index 0000000..e1f2867 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl @@ -0,0 +1,493 @@ +/************************************/ +/************* MACROS ***************/ +/************************************/ + +#define TYPE real_t +#define FLAG uchar +#include "Utilities.cl" + +#define DUMMY 1 + +/************************************/ +/************* MACROS ***************/ +/************************************/ +//#include "Constants.h" +// +//#define underlyings(i,j) \ +// (inst_traj[(i*ro_scal->md_dim + j)]) +// +//#define DUMMY 1 + +/********************************************/ +/********** SOBOL NUMER GENERATOR ***********/ +/********************************************/ + +// TO DO: if we want to overlap kernels, then, since we reuse md_zd for traj_wf multiply also with *ro_scal->num_models + + + +__kernel void mlfi_genmatrix_uniform2 ( + __constant LoopROScalars* ro_scal, + __constant UCHAR* sobol_fix_ind, + __global int* sobol_v_dir, + __global real_t* md_zd +) { + UINT i, j, k; + UINT seq_count = ( get_global_id (0) << ro_scal->log_chunk ); + UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; + + md_zd = md_zd + (get_global_id (0) << ro_scal->log_chunk)*sobol_dim; + __global real_t* md_zd_tmp = md_zd; + + //UINT UB = min(seq_count + (1 << ro_scal->log_chunk), ro_scal->num_gpuits); + UINT UB = (seq_count + (1 << ro_scal->log_chunk) < ro_scal->num_gpuits) ? + seq_count + (1 << ro_scal->log_chunk) : ro_scal->num_gpuits ; + UB = (UB > seq_count) ? UB - seq_count : 0; + + //seq_count += ro_scal->sobol_count_ini; + + if( UB > 0 ) { + UINT gs; + // Compute the random number under the INDEPENDENT formulas + for( i = 0, j=0; j < sobol_dim; j++, i ++ ) { + UINT accum = 0; + md_zd_tmp = md_zd; + + // FIRST ITER COMPUTED INDEPENDENTLY! + gs = seq_count+1 + ro_scal->sobol_count_ini; + gs = gs ^ (gs>>1); + for(k=0; ksobol_bits; k++) { + if(gs & 1) { + accum ^= sobol_v_dir[ j*ro_scal->sobol_bits + k ]; + } + gs = gs >> 1; + } + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; + + // THE REST OF CHUNK-1 ITERATIONS COMPUTED UNDER RECURRENT FORMULA + for( k = 1; k < UB-1; k++ ) { + accum = accum ^ sobol_v_dir[ j*ro_scal->sobol_bits + sobol_fix_ind[k] ]; + + md_zd_tmp += sobol_dim; + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; + } + + // last one + gs = (seq_count + UB - 1 + ro_scal->sobol_count_ini) >> ro_scal->log_chunk; + UINT ell = ro_scal->log_chunk; + while(gs & 1) { + ell++; + gs >>= 1; + } + accum = accum ^ sobol_v_dir[j*ro_scal->sobol_bits + ell]; + md_zd_tmp += sobol_dim; + md_zd_tmp[ i ] = ro_scal->sob_norm_fact*accum; + } + } // end IF (seq_count < UB) + +} + + + +/********************************************/ +/********** INV GAUSSIAN DISTRIB ************/ +/********************************************/ + + +#define rat_eval(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7) \ + (x*(x*(x*(x*(x*(x*(x*a7+a6)+a5)+a4)+a3)+a2)+a1)+a0)/ \ + (x*(x*(x*(x*(x*(x*(x*b7+b6)+b5)+b4)+b3)+b2)+b1)+b0) + +inline real_t small_case(real_t q) { + real_t x = 0.180625 - q * q; + return q * rat_eval( + 3.387132872796366608, + 133.14166789178437745, + 1971.5909503065514427, + 13731.693765509461125, + 45921.953931549871457, + 67265.770927008700853, + 33430.575583588128105, + 2509.0809287301226727, + + 1.0, + 42.313330701600911252, + 687.1870074920579083, + 5394.1960214247511077, + 21213.794301586595867, + 39307.89580009271061, + 28729.085735721942674, + 5226.495278852854561); +} + +inline real_t intermediate(real_t r) { + real_t x = r - 1.6; + return rat_eval( + 1.42343711074968357734, + 4.6303378461565452959, + 5.7694972214606914055, + 3.64784832476320460504, + 1.27045825245236838258, + 0.24178072517745061177, + 0.0227238449892691845833, + 7.7454501427834140764e-4, + + 1.0, + 2.05319162663775882187, + 1.6763848301838038494, + 0.68976733498510000455, + 0.14810397642748007459, + 0.0151986665636164571966, + 5.475938084995344946e-4, + 1.05075007164441684324e-9); +} + +inline real_t tail(real_t r) { + real_t x = r - 5.0; + return rat_eval( + 6.6579046435011037772, + 5.4637849111641143699, + 1.7848265399172913358, + 0.29656057182850489123, + 0.026532189526576123093, + 0.0012426609473880784386, + 2.71155556874348757815e-5, + 2.01033439929228813265e-7, + + 1.0, + 0.59983220655588793769, + 0.13692988092273580531, + 0.0148753612908506148525, + 7.868691311456132591e-4, + 1.8463183175100546818e-5, + 1.4215117583164458887e-7, + 2.04426310338993978564e-15); +} + + +__kernel void mlfi_ugaussian_Pinv_vector1( // UNTILED VERSION + __constant LoopROScalars* ro_scal, __global real_t* p + //__global real_t* p , __constant LoopROScalars* ro_scal, __local real_t* tmp_p +) { + UINT sobol_dim = ro_scal->num_under * ro_scal->num_dates; + UINT i, UB, id = get_global_id(0) << ro_scal->log_chunk; + p += id * sobol_dim; + + UB = min(id + (1<log_chunk), ro_scal->num_gpuits); + UB = (UB > id) ? UB - id : 0; + UB *= sobol_dim; + + for( i=0; i < UB; i++ ) { + real_t dp = p[i] - 0.5; + if (fabs(dp) <= 0.425) { + p[i] = small_case(dp); + } else { + real_t pp = (dp < 0.0) ? p[i] : (1.0 - p[i]); + real_t r = sqrt (- log(pp)); + real_t x = (r <= 5.0) ? intermediate(r) : tail(r); + p[i] = (dp < 0.0) ? (0.0 - x) : x; + } + } +} + +/********************************************/ +/************* BROWNIAN BRIDGE **************/ +/********************************************/ + +__kernel void mlfi_brownianbridge_wiener_path1( + __constant LoopROScalars* ro_scal, + __constant int* bb_inds, + __constant real_t* bb_data, + __global real_t* md_zd, + __global real_t* md_z +) { + __constant int *bb_li, *bb_bi, *bb_ri; + __constant real_t *bb_rw, *bb_lw, *bb_sd; + + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + UINT m, i, md_dim = ro_scal->num_under, nb_path_dates = ro_scal->num_dates; + UINT sobol_dim = ro_scal->num_under * nb_path_dates; + + UINT UB = ( (cur_it + (1<log_chunk) ) < ro_scal->num_gpuits) ? + ( cur_it + (1<log_chunk) ) : ro_scal->num_gpuits; + +// if ( ro_scal->bb_l != ro_scal->md_nb_path_dates || ro_scal->bb_l <= 0) return; + + bb_bi = bb_inds; + bb_li = bb_inds + nb_path_dates; + bb_ri = bb_inds + (nb_path_dates<<1); + + bb_sd = bb_data; + bb_lw = bb_data + nb_path_dates; + bb_rw = bb_data + (nb_path_dates<<1); + + { + UINT tmp = cur_it*sobol_dim; + md_zd = md_zd + tmp; + md_z = md_z + tmp; + } + + for( ; cur_it < UB; cur_it++ ) { + for (m=0; m < md_dim; m++) { + md_z[ (bb_bi[0]-1) * md_dim + m ] = bb_sd[0] * md_zd[m]; + + for(i=1; i < nb_path_dates; i++) { + int j = bb_li[i] - 1; + int k = bb_ri[i] - 1; + int l = bb_bi[i] - 1; + + real_t wk = md_z [k*md_dim+m]; + real_t zi = md_zd[i*md_dim+m]; + + md_z[l*md_dim+m] = (j == -1) ? + bb_rw[i] * wk + bb_sd[i] * zi : + bb_rw[i] * wk + bb_sd[i] * zi + bb_lw[i] * md_z[j*md_dim+m]; + } + + } + md_z += sobol_dim; + md_zd += sobol_dim; + } +} + +/**************************************************/ +/************* TRAJECTORY COMPUTATION *************/ +/**************************************************/ + +void trajectory_contract( + UINT model_num, + __constant LoopROScalars* ro_scal, + __constant real_t* pc_coefs, + __global real_t* inst_traj, + __global real_t* vhat +); + + +__kernel void mlfi_comp_traj1( + __constant LoopROScalars* ro_scal, // RO SCALARS + // RO MD INSTANCE DATA + __constant real_t* model_coefs, + // RO MODEL ATTRIBUTES +// __constant real_t* pc_coefs, +// __local real_t* buff, + // RO (GLOBAL) MD_Z + __global real_t* md_z, + // WO (GLOBAL) traj + __global real_t* trajWF +) { + UINT dim = ro_scal->num_under; + UINT dim_sq = dim*dim; + UINT dim_paths = dim*ro_scal->num_dates; + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + + UINT UB = (cur_it+(1<log_chunk) < ro_scal->num_gpuits) ? cur_it + (1<log_chunk) : ro_scal->num_gpuits; + + trajWF += cur_it*dim_paths*ro_scal->num_models; + md_z += cur_it*dim_paths; + + for( ; cur_it < UB; cur_it++ ) { // ... + UINT m, i, j, l; + + { // 4. expand md_zd -- does not affect execution time + UINT LB = dim; + for( i = (dim_paths - 1); i >= LB; i -- ) { + md_z[i] -= md_z[i - LB]; + } + } + + __constant real_t *c, *vols, *drift, *trajRO; + { + UINT num_mods = ro_scal->num_models; + UINT offset = 0; + c = model_coefs + offset; offset += num_mods * dim_sq; + vols = model_coefs + offset; offset += num_mods * dim_paths; + drift = model_coefs + offset; offset += num_mods * dim_paths; + trajRO = model_coefs + offset; + } + + + for (m = 0; m < ro_scal->num_models; m++) { + + + +// __constant real_t* c = inst_coefs + ( ro_scal->inst_c_beg + m*dim_sq ); +// __constant real_t* vols = inst_coefs + ( ro_scal->inst_vols_beg + m*dim_paths ); +// __constant real_t* drift = inst_coefs + ( ro_scal->inst_drifts_beg + m*dim_paths ); +// __constant real_t* trajRO= inst_coefs + ( ro_scal->inst_trajRO_beg + m*dim ); + + for (i = 0; i < ro_scal->num_dates; i++) { + UINT ind = dim*i; + for (j = 0; j < dim; j++) { + real_t temp = 0.0; + + for (l = 0; l <= j; l++) { + temp += c[dim * j + l] * md_z[ (ind + l) ]; + } + temp = exp(temp * vols[ind + j] + drift[ind + j]); + + trajWF[(ind+j)] = (i > 0) ? trajWF[(ind + j - dim)] * temp : trajRO[ j ] * temp ; + } + } + + if ( m+1 < ro_scal->num_models ) { + c += dim_sq; vols += dim_paths; + drift += dim_paths; trajRO += dim; + } + + trajWF += dim_paths; + } // end for m + + md_z += dim_paths; + + } // end for cur_it +} + + + + +__kernel void mlfi_reduction_step1( + __constant LoopROScalars* ro_scal, // RO SCALARS + // RO MD INSTANCE DATA + __constant real_t* inst_coefs, + // RO MODEL ATTRIBUTES +// __constant real_t* pc_coefs, + // RO (GLOBAL) traj + __global real_t* inst_trajWF, + // WF (GLOBAL) traj + __global real_t* model_vhat, + __local real_t* vhat_local +) { + UINT j; + uint block_size = get_local_size(0); + int sobol_dim = ro_scal->num_under * ro_scal->num_dates; + ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + + //UINT UB = min(cur_it + (1<log_chunk), ro_scal->num_gpuits); + UINT UB = ( cur_it + (1<log_chunk) < ro_scal->num_gpuits) ? + cur_it + (1<log_chunk) : ro_scal->num_gpuits ; + + { // adjust the start index + UINT id = get_global_id (0); +// vhat += ( (id >> lgWARP) << lgWARP )*ro_scal->num_contracts*ro_scal->num_models + (id & (WARP-1)); + inst_trajWF += cur_it*sobol_dim*ro_scal->num_models; + vhat_local += get_local_id(0); + } + + // initialize vhat_local to 0 + for( j = 0; j < ro_scal->num_models*block_size; j += block_size ) { + vhat_local[j] = 0.0; + } + +#if 0 + { // init vhat + UINT step_outer = ro_scal->num_contracts<num_models*step_outer; i+=step_outer) { + for( j = 0; j < step_outer; j+=WARP) { + vhat[j+i] = 0.0; + } + } + } +#endif + + __constant real_t *md_discts; + __constant real_t *md_detvals; + { // compute from model_coefs + int offset; + offset = ro_scal->num_under * ( ro_scal->num_under + 1) + 2 * sobol_dim; + offset *= ro_scal->num_models; + md_discts = inst_coefs + offset; + md_detvals = md_discts + ro_scal->num_models * ro_scal->num_cash_flows; + } + + for( ; cur_it < UB; cur_it++ ) { + //__global real_t* vhat_loc = vhat; + for (j = 0; j < ro_scal->num_models; j++) { + + payoffFunction( j, ro_scal->num_under, + ro_scal->num_cash_flows, + ro_scal->num_det_pricers, + md_discts + j*ro_scal->num_cash_flows, + md_detvals+ j*ro_scal->num_det_pricers, + inst_trajWF, + vhat_local + ); + + //inst_trajWF += (sobol_dim << lgWARP); + + inst_trajWF += sobol_dim; + //vhat_loc += (ro_scal->num_contracts << lgWARP); + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + segm_scan_reg_block ( vhat_local - get_local_id(0), block_size * ro_scal->num_models, block_size ); + if( get_local_id(0) == 0 ) { + UINT glob_size = get_global_size(0)/block_size; + for ( j = 0; j < ro_scal->num_models; j ++ ) { + model_vhat[ j * glob_size + get_group_id(0) ] = + vhat_local[ (j + 1) * block_size - 1 ]; + } + } + } + + +#if 0 + for( ; cur_it < UB; cur_it++ ) { + __global real_t* vhat_loc = vhat; + for (j = 0; j < ro_scal->num_models; j++) { + trajectory_contract( j, ro_scal, pc_coefs, inst_trajWF, vhat_loc ); + inst_trajWF += ro_scal->sobol_dim; + vhat_loc += (ro_scal->num_contracts << lgWARP); + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + if( get_local_id(0) == 0) { +#if 1 + UINT step_inner = ro_scal->num_contracts << lgWARP; + UINT step_outer = step_inner * ro_scal->num_models; + UINT BD = (step_outer >> lgWARP) * ro_scal->BLOCK; + UINT i, k; + for( i = 0; i < BD; i += step_outer ) { + for( j = 0; j < step_outer; j += step_inner ) { + for( k = j; k < j+step_inner; k += WARP ) { + for( cur_it = k+(i==0? 1 : 0); cur_it < k+WARP; cur_it++ ) { + vhat[k] += vhat[i+cur_it]; + } + } + } + } +#else + UINT step_j = ro_scal->num_contracts<num_models*step_j; + for (j = 0; j < BD_j; j+=step_j) { // for all instances + for(cur_it=0; cur_it < step_j; cur_it+=WARP) { // for all contracts + UINT i; + for(i=1; inum_cash_flows+date_index]; + //pc_coefs[ro_scal->pc_discounts_beg + model_num*ro_scal->num_cash_flows+date_index]; +} +*/ diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile new file mode 100644 index 0000000..9c7d431 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile @@ -0,0 +1,46 @@ +# Permit standalone compilation. +HIPERMARK_LIB_DIR ?= ../../../../lib/ + +# Default to double if nothing else defined. +HIPERMARK_CONFIG_REAL_TYPE ?= double + +include $(HIPERMARK_LIB_DIR)/setup.mk +include $(HIPERMARK_LIB_DIR)/setup_real_type.mk + +# FIXME - this should not even exist! +include $(HIPERMARK_LIB_DIR)/platform.mk + +INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include +INCLUDES += -I$(HIPERMARK_LIB_DIR)/include + +GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ + -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ + -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ + -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ + -D CURR_DIR_PATH='"$(MAKE_DIR)"' + +SOURCES_CPP =GenPricing.cpp +HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h +OBJECTS =GenPricing.o +EXECUTABLE =GenPricing + +default: $(EXECUTABLE) + +%.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -c -o $@ $< + +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(CXXFLAGS) $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) $(LIB) + +clean: + rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) + @# clean nVidia compiler cache + rm -rf $(HOME)/.nv/ComputeCache/* + +data: $(HIPERMARK_INPUT) + mkdir -p datasets/$(HIPERMARK_INPUT_NAME) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data + +run: + cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h b/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h new file mode 100644 index 0000000..eb62f2c --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h @@ -0,0 +1,631 @@ +#ifndef GPU_HELPERS +#define GPU_HELPERS + +#include "Optimizations.h" +#include "SDK_stub.h" + +#if REAL_IS_FLOAT + #define TILE GPU_TILE +#else + #define TILE GPU_TILE/2 +#endif + +/****************************/ +/*** GPU-Allocated Arrays ***/ +/****************************/ +struct oclLoopArrays { + + /* RO scalars */ + cl_mem ro_scals; + + /* sobol direction vector; RO */ + cl_mem sobol_dirvcts; // UINT[sobol_bit_count][num_under*num_dates]; + cl_mem sobol_fix_ind; // UCHAR[chunk-1] + + /* Brownian Bridge data RO */ + cl_mem bb_inds; // UINT[3][num_dates] + cl_mem bb_data; // real_t[3][num_dates] + + /* MD instance data; RO */ + cl_mem md_c; // Includes all arrays bellow: +// cl_mem md_c // RO; real_t[num_models][num_under^2] +// cl_mem md_vols; // RO; real_t[num_models][num_under*num_dates] +// cl_mem md_drifts; // RO; real_t[num_models][num_under*num_dates] +// cl_mem md_starts; // RO; real_t[num_models][num_under] +// cl_mem md_discts; // real_t[num_models][num_cash_flows ] +// cl_mem md_detvals; // real_t[num_models][num_det_pricers] + + /* FOR VECTORIZED VERSION */ + cl_mem md_zd; // RW: real_t[num_gpuits]x[num_under*num_dates] + cl_mem md_z; // RW: real_t[num_gpuits]x[num_models]x[num_under*num_dates] + + /* global array to be reduced on CPU; WO */ + cl_mem model_vhat; // WO; ~ [num_models]x[num_contracts]x[num_iter/(chunk*BLOCK)] + + /*** local tiled space ***/ + cl_mem local_space; + + void cleanupPRIV() { + clReleaseMemObject(ro_scals); + clReleaseMemObject(sobol_dirvcts); + clReleaseMemObject(sobol_fix_ind); + clReleaseMemObject(bb_inds); + clReleaseMemObject(bb_data); + clReleaseMemObject(md_c); + clReleaseMemObject(model_vhat); + } + void cleanupVECT() { + cleanupPRIV(); + clReleaseMemObject(md_z ); + clReleaseMemObject(md_zd); + } +}; + +/*********************************/ +/*** Math-Utility Functions ***/ +/*********************************/ + +UINT logNextPow2(UINT n) { + UINT ret = 1; + UINT logret = 0; + while(n>ret) { + ret = ret << 1; + logret += 1; + } + return logret; +} + +UINT prevMultipleOf(UINT n, UINT mul) { + if(n % mul == 0) return n; + UINT res = 0; + while(res <= n) res += mul; + return res - mul; +} + +/*********************************/ +/*** GPU-Glue Helper Functions ***/ +/*********************************/ + +enum GPU_KERNEL { PRIV, VECT }; + +GPU_KERNEL +priv_or_vect_kernel(const LoopROScalars& ro_scal) { +#if (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 1) + return VECT; +#elif (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 2) + return PRIV; +#else + UINT threshold = 16; + bool is_priv = (ro_scal.num_under*ro_scal.num_dates+ro_scal.num_models <= threshold); + fprintf(stderr, "\nCOST MODEL THRESHOLD: %u, PRIV_KERNEL: %d\n", threshold, (int)is_priv); + return (is_priv) ? PRIV : VECT; +#endif +} + +const char* +makeGPUprogPreamble( + const LoopROScalars& ro_scal, + const GPU_KERNEL & kernel_type +) { + const char* preamble = (ro_scal.contract == 1 && kernel_type == VECT) ? + "#define VECT_KERNEL\n#include \"ContractDefs/SmallContract.cl\"\n\n" : + (ro_scal.contract == 1 && kernel_type == PRIV) ? + "#include \"ContractDefs/SmallContract.cl\"\n\n" : + (ro_scal.contract == 2 && kernel_type == VECT) ? + "#define VECT_KERNEL\n#include \"ContractDefs/MediumContract.cl\"\n\n" : + (ro_scal.contract == 2 && kernel_type == PRIV) ? + "#include \"ContractDefs/MediumContract.cl\"\n\n" : + (ro_scal.contract == 3 && kernel_type == VECT) ? + "#define VECT_KERNEL\n#include \"ContractDefs/LargeContract.cl\"\n\n" : + (ro_scal.contract == 3 && kernel_type == PRIV) ? + "#include \"ContractDefs/LargeContract.cl\"\n\n" : NULL; + assert(preamble && "Invalid Contract Number (should be 1, 2 or 3) OR Invalid kernel type (PRIV or VECT)\n"); + return preamble; +} + + +UINT +getWorkSize(const UINT& num_iter, const UINT& chunk, const UINT& block) { + UINT tmp_rem = num_iter % chunk; + UINT res = (tmp_rem == 0) ? + (num_iter / chunk) : + ((num_iter / chunk) + 1) ; + + if(res % block == 0) return res; + + res = (res / block) * block + block; + return res; +} + +int +discriminate_cost_model( LoopROScalars& ro_scal, cl_device_id device, const GPU_KERNEL kernel) { + bool is_priv = (kernel == PRIV); + cl_uint tot_cuda_cores = 0; + + UINT size_vct = ro_scal.num_under * ro_scal.num_dates; + + ro_scal.logBLOCK = 7; + ro_scal.BLOCK = 1 << ro_scal.logBLOCK; + + // If not-enough GPU resources => sequentialize + // the loop into big chunks that execute on GPU. + if(!is_priv) { + // get device memory size info + cl_ulong glob_mem_size; + clGetDeviceInfo(device,CL_DEVICE_GLOBAL_MEM_SIZE,sizeof(glob_mem_size),&glob_mem_size,NULL); + { // check global mem matches the user-declared one + const size_t USER_MEM = ((size_t)GPU_GLB_MEM) << 30; + const size_t ub = static_cast( USER_MEM * 101.0 / 100.0 ); + const size_t lb = static_cast( USER_MEM * 99.0 / 100.0 ); + if ( !(glob_mem_size >= lb && glob_mem_size <= ub) ) { + fprintf(stderr, "WARNING! Querried GPU global memory %lu DIFFERS from what user declared: [%ld,%ld]!\n", + (unsigned long)glob_mem_size, lb, ub); + glob_mem_size = static_cast(USER_MEM); + fprintf(stderr, "Using user-declared size for global memory: %lu\n", (unsigned long)glob_mem_size); + } + } + + // check if there is enough memory + UINT perit_mem_size = size_vct*( ro_scal.num_models + 1 ) + ro_scal.num_models; + perit_mem_size *= sizeof(real_t); + + UINT max_mc_iter_num = ( (glob_mem_size * 3)/4 ) / perit_mem_size; + + UINT BLOCK = ro_scal.BLOCK; + if(max_mc_iter_num % BLOCK != 0) + max_mc_iter_num = (max_mc_iter_num / BLOCK)*BLOCK + BLOCK; + + max_mc_iter_num = prevMultipleOf(max_mc_iter_num, ro_scal.chunk); + + ro_scal.num_gpuits = MIN(max_mc_iter_num, ro_scal.num_mcits); + +// fprintf(stderr, "# of total iters: %u, # of gpu iters: %u, chunk: %u\n", +// ro_scal.num_mcits, ro_scal.num_gpuits, ro_scal.chunk ); + } else { + ro_scal.num_gpuits = ro_scal.num_mcits; + } + + { +#ifdef __APPLE__ + tot_cuda_cores = GPU_CORES; // MEMO: No correctness check... mael 2015-03-12 +#else + cl_uint compute_units; + clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, + sizeof(compute_units), &compute_units, NULL); + cl_uint comp_capabil_major, comp_capabil_minor; + clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, + sizeof(cl_uint), &comp_capabil_major, NULL); + clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, + sizeof(cl_uint), &comp_capabil_minor, NULL); + tot_cuda_cores = compute_units * + ConvertSMVer2CoresCopy(comp_capabil_major, comp_capabil_minor); + + if( tot_cuda_cores != GPU_CORES ) { + fprintf(stderr, "WARNING! Querried GPU number of cores %u DIFFERS from what user declared: %d!\n", + tot_cuda_cores, GPU_CORES ); + tot_cuda_cores = GPU_CORES; + fprintf(stderr, "Using user-declared GPU number of cores: %u\n", tot_cuda_cores); + } +#endif + UINT div = (1 << logNextPow2(tot_cuda_cores)) * 64; + ro_scal.log_chunk = logNextPow2(ro_scal.num_gpuits / div ); // was div*2 + ro_scal.log_chunk = MIN(ro_scal.log_chunk, logMAX_CHUNK); + if(ro_scal.log_chunk <= 3) ro_scal.log_chunk++; + } + + ro_scal.chunk = 1 << ro_scal.log_chunk; + +// fprintf(stderr, "\n\nCOST MODEL COMPUTED: MC_ITERS: %u, MC_TOT_ITERS: %u, CHUNK: %u, BLOCK: %u\n\n", +// ro_scal.num_gpuits, ro_scal.num_mcits, ro_scal.chunk, ro_scal.BLOCK); + + return tot_cuda_cores; +} + +/*********************************/ +/*** Allocating GPU Buffers & ***/ +/***running the Private Kernels***/ +/*********************************/ + +real_t* +oclAllocArrays_PrivKernel ( + oclLoopArrays& ocl_arrs, + cl_context cxGPUContext, + cl_command_queue& cqCommandQueue, + cl_int& ciErr, + const LoopROScalars& ro_scals, + const SobolArrays & sob_arrs, + const BrowBridgeArrays& bb_arrs, + const ModelArrays & md_arrs +) { + cl_int ciErr2; + size_t cur_size; + real_t* glb_vhat = NULL; + + { // 1. RO scalars + cur_size = sizeof(LoopROScalars); + ocl_arrs.ro_scals = clCreateBuffer( + cxGPUContext, CL_MEM_READ_ONLY, cur_size, NULL, &ciErr2 + ); + + ciErr = ciErr2; + ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, + cur_size, &ro_scals, 0, NULL, NULL); + } + + { // 2. Sobol RO Arrays + const SobolArrays& cpu_arrs = sob_arrs; + + cur_size = (UINT) ro_scals.num_under * ro_scals.num_dates * + ro_scals.sobol_bits * sizeof(UINT); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(sobol_dirvcts); + + cur_size+= ro_scals.chunk * sizeof(UCHAR); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(sobol_fix_ind); + } + + { // 3. BROWNIAN BRIDGE RO indirect arrays and data arrays + const BrowBridgeArrays& cpu_arrs = bb_arrs; + + cur_size = 3*ro_scals.num_dates*sizeof(UINT); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(bb_inds); + + cur_size = 3*ro_scals.num_dates*sizeof(real_t); + CREATE_AND_ENQUEUE_RO_CL_BUFFER(bb_data); + } + + { // 4. Various RO Model Data Arrays + const ModelArrays& cpu_arrs = md_arrs; + + cur_size = ro_scals.num_under * ( ro_scals.num_under + 2*ro_scals.num_dates + 1); + cur_size += ro_scals.num_cash_flows + ro_scals.num_det_pricers; + cur_size *= ro_scals.num_models * sizeof(real_t); + + CREATE_AND_ENQUEUE_RO_CL_BUFFER(md_c); + } + + { // 5. Finally, the WO Partial Result + //red_sz = getGlobalRedArrSize( ro_scal->mc_iter_num, ro_scal->CHUNK*ro_scal->BLOCK ); + cur_size = getWorkSize(ro_scals.num_gpuits, ro_scals.chunk, ro_scals.BLOCK) / ro_scals.BLOCK; + cur_size *= ro_scals.num_models * sizeof(real_t); + + glb_vhat = (real_t*)malloc(cur_size); + ocl_arrs.model_vhat = clCreateBuffer( + cxGPUContext, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + cur_size, glb_vhat, &ciErr2 + ); + ciErr |= ciErr2; + } + + // 2. the rest: priv_arr->sobol_last_num_vec/md_zd/inst_trajWF + // are implemented as __local (private) hence do not require + // global memory allocation. + + oclCheckError(ciErr, CL_SUCCESS); + + return glb_vhat; +} + + +void +runGPU_PRIV( + const LoopROScalars& ro_scals, + real_t* glb_vhat, + oclLoopArrays& dev_arr, + cl_command_queue& cqCommandQueue, + cl_program& cpProgram, + size_t* globalWorkSize, + size_t* localWorkSize +) { + cl_kernel ckGenPricing = NULL; // OpenCL kernel + cl_int ciErr1; + + size_t counter = 0, priv_sz = 0; // ro_scals + const int PRIV_MULT = sizeof(real_t)*ro_scals.BLOCK; + + ckGenPricing = clCreateKernel(cpProgram, "payoffGPU", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + // 1. RO SCALARS struct + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.ro_scals ); + + // 2. RO SOBOL ARR // + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.sobol_dirvcts); + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.sobol_fix_ind); + + // 3. RO BROWNIAN BRIDGE // + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.bb_inds); + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.bb_data); + + // 4. RO MD INSTANCE DATA // + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.md_c); + + // 5. GLOBAL WO Array // + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, sizeof(cl_mem), (void*)&dev_arr.model_vhat ); + + // 6. LOCAL (PRIVATE ARRAYS) MD_Z + priv_sz = PRIV_MULT*ro_scals.num_under*ro_scals.num_dates; + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, priv_sz, NULL); + + // 7. LOCAL (PRIVATE ARRAY) VHAT + priv_sz = PRIV_MULT * ro_scals.num_models; + ciErr1 |= clSetKernelArg(ckGenPricing, counter++, priv_sz, NULL); // model_vhat (the private one) + + oclCheckError(ciErr1, CL_SUCCESS); + + clFinish(cqCommandQueue); + struct timeval t_start, t_end, t_diff; unsigned long long elapsed; + gettimeofday(&t_start, NULL); + + // 8. ENQUEUE KERNEL!!! // + ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, ckGenPricing, 1, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL); + oclCheckError(ciErr1, CL_SUCCESS); + + clFinish(cqCommandQueue); + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + printf("KERNEL TIME IS: %llu\n\n", elapsed); + + gettimeofday(&t_start, NULL); + + // 9. FINALLY, WRITE BACK!!! // + priv_sz = (globalWorkSize[0]/ro_scals.BLOCK)*ro_scals.num_models*sizeof(real_t); + + ciErr1 |= clEnqueueReadBuffer(cqCommandQueue, dev_arr.model_vhat, CL_TRUE, 0, + priv_sz, glb_vhat, 0, NULL, NULL); + oclCheckError(ciErr1, CL_SUCCESS); + + clReleaseKernel(ckGenPricing); + + clFinish(cqCommandQueue); + gettimeofday(&t_end, NULL); + timeval_subtract(&t_diff, &t_end, &t_start); + elapsed = t_diff.tv_sec*1e6+t_diff.tv_usec; + printf("COPY-OUT and KERNEL RELEASE TIME IS: %llu\n\n", elapsed); +} + + +void reduceVHAT_CPU(const LoopROScalars& ro_scals, real_t* vhat, double* cpu_vhat ) { + // final reduction on CPU!!! + UINT SZ = getWorkSize(ro_scals.num_gpuits, ro_scals.chunk, ro_scals.BLOCK) / ro_scals.BLOCK; + + for( UINT ii = 0; ii 4" ); + UINT priv_sz = TILE * ro_scals.BLOCK * sizeof(real_t); + ciErr1 |= clSetKernelArg(ckGenPricing_traj, counter++, priv_sz, NULL); // local_space! + } +#endif + + ciErr1 |= clSetKernelArg(ckGenPricing_traj, counter++, sizeof(cl_mem), (void*)&dev_arr.md_z ); + ciErr1 |= clSetKernelArg(ckGenPricing_traj, counter++, sizeof(cl_mem), (void*)&dev_arr.md_zd); + + ciErr1 |= clEnqueueNDRangeKernel( cqCommandQueue, ckGenPricing_traj, 1, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + + + oclCheckError(ciErr1, CL_SUCCESS); + } + + { // final reduction! + //shrLog("Call Compute Reduction kernel on GPU...\n\n"); + counter = 0; + ckGenPricing_finred = clCreateKernel(cpProgram, "mlfi_reduction_step1", &ciErr1); + oclCheckError(ciErr1, CL_SUCCESS); + + ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.ro_scals ); + ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.md_c ); + + ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.md_zd ); + ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, sizeof(cl_mem), (void*)&dev_arr.model_vhat ); + + assert( (ro_scals.num_models <= TILE) && "Illegal dataset: num_models > 8" ); + UINT priv_sz = TILE * ro_scals.BLOCK * sizeof(real_t); + ciErr1 |= clSetKernelArg(ckGenPricing_finred, counter++, priv_sz, NULL); // local_space! + + ciErr1 |= clEnqueueNDRangeKernel( cqCommandQueue, ckGenPricing_finred, 1, NULL, + globalWorkSize, localWorkSize, 0, NULL, NULL ); + oclCheckError(ciErr1, CL_SUCCESS); + + ciErr1 |= clEnqueueReadBuffer( cqCommandQueue, dev_arr.model_vhat, CL_TRUE, 0, + globalWorkSize[0] * ro_scals.num_models * sizeof(real_t), + glb_vhat, 0, NULL, NULL); + oclCheckError(ciErr1, CL_SUCCESS); + } + + clReleaseKernel(ckGenPricing_sobol ); + clReleaseKernel(ckGenPricing_invg ); + clReleaseKernel(ckGenPricing_brown ); + clReleaseKernel(ckGenPricing_traj ); + clReleaseKernel(ckGenPricing_finred); +} + +#endif // GPU_HELPERS + diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json new file mode 100644 index 0000000..00bdffb --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json @@ -0,0 +1,3 @@ +{ + "REAL_TYPE" : ["float", "double"] +} diff --git a/benchmarks/OptionPricing/lib/include/Optimizations.h b/benchmarks/OptionPricing/lib/include/Optimizations.h index 76bd4fd..bf04f3a 100644 --- a/benchmarks/OptionPricing/lib/include/Optimizations.h +++ b/benchmarks/OptionPricing/lib/include/Optimizations.h @@ -1,7 +1,6 @@ #ifndef OPTIMISATIONS #define OPTIMISATIONS -#define _OPTIMIZATION_USE_FLOATS 1 #define _OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV 0 // cost model: 0, vectorized: 1, privatized: 2 #define _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR #define _OPTIMIZATION_MEM_COALES_ON From 997e33d9792b6b7887c7135f333df2ca34d8643b Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 13:48:18 +0200 Subject: [PATCH 084/122] Fix typo. --- lib/setup.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/setup.mk b/lib/setup.mk index c064870..e46bec8 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -24,6 +24,6 @@ else INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include endif -CXXFLAGS += -DIMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION_DIR)"' +CXXFLAGS += -DHIPERMARK_IMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION_DIR)"' CXXFLAGS += -DHIPERMARK_BENCHMARK_LIB_DIR='"$(HIPERMARK_BENCHMARK_LIB_DIR)"' CXXFLAGS += -DHIPERMARK_LIB_DIR='"$(HIPERMARK_LIB_DIR)"' From 8f1303aaac5f0384d361d83ec3876228a96d2d86 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 13:55:37 +0200 Subject: [PATCH 085/122] Fix typo. --- .../implementations/cpp_opencl/GenericPricingVectOpt.cl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl index 39cf5d1..cb58fa0 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl @@ -2,7 +2,7 @@ /************* MACROS ***************/ /************************************/ -#define TYPE real_T +#define TYPE real_t #define FLAG uchar #include "Utilities.cl" From 5d8e766812f7ee38beddf46d2b102fc1f8dc07a3 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 13:58:47 +0200 Subject: [PATCH 086/122] ULONG -> unsigned long. --- .../implementations/cpp_opencl/GenericPricingVectOpt.cl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl index cb58fa0..b716bab 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectOpt.cl @@ -291,7 +291,7 @@ __kernel void mlfi_brownianbridge_wiener_path1( __constant int *bb_li, *bb_bi, *bb_ri; __constant real_t *bb_rw, *bb_lw, *bb_sd; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; UINT m, i, md_dim = ro_scal->num_under << lgWARP, nb_path_dates = ro_scal->num_dates; UINT sobol_dim = ro_scal->num_under * nb_path_dates; @@ -362,7 +362,7 @@ __kernel void mlfi_comp_traj1( UINT dim = ro_scal->num_under; UINT dim_sq = dim*dim; UINT dim_paths = dim*ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; UINT UB = ( cur_it+(1<log_chunk) < ro_scal->num_gpuits) ? cur_it+(1<log_chunk) : ro_scal->num_gpuits ; @@ -455,7 +455,7 @@ __kernel void mlfi_comp_traj_unopt( UINT dim = ro_scal->num_under; UINT dim_sq = dim*dim; UINT dim_paths = dim*ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; UINT UB = ( cur_it+(1<log_chunk) < ro_scal->num_gpuits ) ? cur_it+(1<log_chunk) : ro_scal->num_gpuits ; @@ -529,7 +529,7 @@ __kernel void mlfi_reduction_step1( UINT j; uint block_size = get_local_size(0); int sobol_dim = ro_scal->num_under * ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; UINT UB = ( cur_it + (1<log_chunk) < ro_scal->num_gpuits) ? cur_it + (1<log_chunk) : ro_scal->num_gpuits ; From 0d82a27abe424158a5934d3ad17c0543351a8234 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 14:37:03 +0200 Subject: [PATCH 087/122] Dynamic thread count selection. --- .../cpp_openmp/dynamic_configuration_template.json | 2 +- .../cpp_openclmp_all/dynamic_configuration_template.json | 2 +- .../cpp_openclmp_outer/dynamic_configuration_template.json | 2 +- .../cpp_openmp_naive/dynamic_configuration_template.json | 2 +- .../cpp_openmp/dynamic_configuration_template.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json b/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json index 14298aa..713ae01 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/dynamic_configuration_template.json @@ -1 +1 @@ -{"NUM_THREADS": [1,2,3,4]} +{ "NUM_THREADS": "ncpus" } diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/dynamic_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/dynamic_configuration_template.json index 14298aa..713ae01 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/dynamic_configuration_template.json +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/dynamic_configuration_template.json @@ -1 +1 @@ -{"NUM_THREADS": [1,2,3,4]} +{ "NUM_THREADS": "ncpus" } diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/dynamic_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/dynamic_configuration_template.json index 14298aa..713ae01 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/dynamic_configuration_template.json +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/dynamic_configuration_template.json @@ -1 +1 @@ -{"NUM_THREADS": [1,2,3,4]} +{ "NUM_THREADS": "ncpus" } diff --git a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/dynamic_configuration_template.json b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/dynamic_configuration_template.json index 14298aa..713ae01 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/dynamic_configuration_template.json +++ b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/dynamic_configuration_template.json @@ -1 +1 @@ -{"NUM_THREADS": [1,2,3,4]} +{ "NUM_THREADS": "ncpus" } diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json index 14298aa..713ae01 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json @@ -1 +1 @@ -{"NUM_THREADS": [1,2,3,4]} +{ "NUM_THREADS": "ncpus" } From f8e0ae52320ef57a3e1bf40577da48f153025a08 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 15:29:33 +0200 Subject: [PATCH 088/122] Fix typo. --- benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h b/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h index 864bc1c..d877ce3 100644 --- a/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/UtilGPGPU.h @@ -189,7 +189,7 @@ void compileGPUprog( OclObjects& objs ) { sprintf( compile_option, "%s -D lgWARP=%d -D TODAY=%10f -D LWG_FB=%d -D INFTY=%f -D MAX_DATE=%f -D MIN_DATE=%f -D SOBOL_BITS_NUM=%d -D%s -I%s/include -I%s/include -I%s/SrcCL", flags, lgWARP, TODAY, LWG_FB, INFTY, MAX_DATE, MIN_DATE, NUM_SOBOL_BITS, REAL_FLAG, - HIPERMARK_BENCHMARK_LIB_DIR, HIPERMARK_LIB_DIR, IMPLEMENTATION_DIR); + HIPERMARK_BENCHMARK_LIB_DIR, HIPERMARK_LIB_DIR, HIPERMARK_IMPLEMENTATION_DIR); fprintf(stderr, "compiling like this: %s\n", compile_option); objs.dev_id = 0; From 92ff1d121a1d52848fb903ec5a2072485b0212b2 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Mon, 24 Aug 2015 15:39:45 +0200 Subject: [PATCH 089/122] Fix large dataset reference output. --- .../InterestCalib/datasets/large/output.json | 392 +++++++++--------- 1 file changed, 196 insertions(+), 196 deletions(-) diff --git a/benchmarks/InterestCalib/datasets/large/output.json b/benchmarks/InterestCalib/datasets/large/output.json index a82736c..19162b3 100644 --- a/benchmarks/InterestCalib/datasets/large/output.json +++ b/benchmarks/InterestCalib/datasets/large/output.json @@ -7,201 +7,201 @@ "lg_likelyhood": 504.367344, "swaption_calibration_result": [ - [ 74.172585 , 115.320470 , 35.681337 ], - [ 100.626570 , 162.945479 , 38.245252 ], - [ 118.719023 , 174.297729 , 31.887223 ], - [ 132.735321 , 171.631308 , 22.662524 ], - [ 143.164628 , 168.408756 , 14.989796 ], - [ 151.813418 , 168.310831 , 9.801754 ], - [ 158.832697 , 169.877089 , 6.501402 ], - [ 164.984854 , 172.511293 , 4.362868 ], - [ 169.170571 , 172.824865 , 2.114449 ], - [ 172.872471 , 172.561368 , 0.180286 ], - [ 181.530751 , 177.275607 , 2.400298 ], - [ 180.340962 , 161.933876 , 11.367038 ], - [ 172.565436 , 139.430038 , 23.764892 ], - [ 162.247156 , 120.029132 , 35.173148 ], - [ 74.172585 , 69.393222 , 6.887362 ], - [ 100.626570 , 116.015964 , 13.264894 ], - [ 118.719023 , 139.816103 , 15.089163 ], - [ 132.735321 , 149.054929 , 10.948721 ], - [ 143.164628 , 155.120122 , 7.707249 ], - [ 151.813418 , 159.302301 , 4.701052 ], - [ 158.832697 , 163.950093 , 3.121313 ], - [ 164.984854 , 167.731363 , 1.637445 ], - [ 169.170571 , 170.144777 , 0.572575 ], - [ 172.872471 , 170.402787 , 1.449321 ], - [ 181.530751 , 179.579039 , 1.086827 ], - [ 180.340962 , 161.791994 , 11.464700 ], - [ 172.565436 , 139.415641 , 23.777673 ], - [ 162.247156 , 119.885477 , 35.335121 ], - [ 74.172585 , 65.999080 , 12.384271 ], - [ 100.626570 , 105.242095 , 4.385626 ], - [ 118.719023 , 129.573722 , 8.377237 ], - [ 132.735321 , 142.022857 , 6.539466 ], - [ 143.164628 , 149.987013 , 4.548651 ], - [ 151.813418 , 156.932387 , 3.261895 ], - [ 158.832697 , 161.950891 , 1.925395 ], - [ 164.984854 , 166.244493 , 0.757703 ], - [ 169.170571 , 168.937454 , 0.137990 ], - [ 172.872471 , 170.174723 , 1.585282 ], - [ 181.530751 , 180.595670 , 0.517776 ], - [ 180.340962 , 161.777322 , 11.474810 ], - [ 172.565436 , 139.416628 , 23.776797 ], - [ 162.247156 , 119.914803 , 35.302024 ], - [ 74.172585 , 61.368583 , 20.864099 ], - [ 100.626570 , 99.252149 , 1.384777 ], - [ 118.719023 , 122.849829 , 3.362484 ], - [ 132.735321 , 137.637329 , 3.561540 ], - [ 143.164628 , 147.875713 , 3.185841 ], - [ 151.813418 , 154.781404 , 1.917534 ], - [ 158.832697 , 160.084818 , 0.782161 ], - [ 164.984854 , 165.269065 , 0.171969 ], - [ 169.170571 , 168.580130 , 0.350243 ], - [ 172.872471 , 170.856618 , 1.179851 ], - [ 181.530751 , 181.485729 , 0.024807 ], - [ 180.340962 , 161.795624 , 11.462200 ], - [ 172.565436 , 139.412376 , 23.780571 ], - [ 162.247156 , 119.914803 , 35.302024 ], - [ 74.172585 , 58.655078 , 26.455521 ], - [ 100.626570 , 95.973733 , 4.848031 ], - [ 118.719023 , 119.408556 , 0.577457 ], - [ 132.735321 , 134.902103 , 1.606189 ], - [ 143.164628 , 145.442875 , 1.566421 ], - [ 151.813418 , 153.303090 , 0.971717 ], - [ 158.832697 , 158.972444 , 0.087907 ], - [ 164.984854 , 165.290371 , 0.184837 ], - [ 169.170571 , 168.326957 , 0.501176 ], - [ 172.872471 , 172.681440 , 0.110626 ], - [ 181.530751 , 182.061213 , 0.291365 ], - [ 180.340962 , 161.805228 , 11.455584 ], - [ 172.565436 , 139.451166 , 23.746141 ], - [ 162.247156 , 119.902772 , 35.315600 ], - [ 74.172585 , 54.317928 , 36.552677 ], - [ 100.626570 , 90.924762 , 10.670150 ], - [ 118.719023 , 115.804615 , 2.516660 ], - [ 132.735321 , 131.667834 , 0.810742 ], - [ 143.164628 , 143.353504 , 0.131756 ], - [ 151.813418 , 151.871055 , 0.037951 ], - [ 158.832697 , 158.972444 , 0.087907 ], - [ 164.984854 , 165.332970 , 0.210555 ], - [ 169.170571 , 169.958627 , 0.463675 ], - [ 172.872471 , 174.591476 , 0.984587 ], - [ 181.530751 , 182.627862 , 0.600736 ], - [ 180.340962 , 161.791994 , 11.464700 ], - [ 172.565436 , 139.366537 , 23.821284 ], - [ 162.247156 , 119.882956 , 35.337967 ], - [ 74.172585 , 51.415081 , 44.262312 ], - [ 100.626570 , 88.139705 , 14.167127 ], - [ 118.719023 , 113.272969 , 4.807903 ], - [ 132.735321 , 129.285558 , 2.668328 ], - [ 143.164628 , 141.639008 , 1.077118 ], - [ 151.813418 , 151.139856 , 0.445654 ], - [ 158.832697 , 159.077811 , 0.154085 ], - [ 164.984854 , 166.349944 , 0.820614 ], - [ 169.170571 , 171.699296 , 1.472764 ], - [ 172.872471 , 176.724544 , 2.179704 ], - [ 181.530751 , 183.033936 , 0.821260 ], - [ 180.340962 , 161.805228 , 11.455584 ], - [ 172.565436 , 139.341880 , 23.843195 ], - [ 162.247156 , 119.866098 , 35.357001 ], - [ 74.172585 , 49.394757 , 50.162869 ], - [ 100.626570 , 85.483070 , 17.715203 ], - [ 118.719023 , 110.722034 , 7.222582 ], - [ 132.735321 , 128.407529 , 3.370356 ], - [ 143.164628 , 140.690570 , 1.758510 ], - [ 151.813418 , 151.038030 , 0.513372 ], - [ 158.832697 , 159.896627 , 0.665386 ], - [ 164.984854 , 168.125416 , 1.867988 ], - [ 169.170571 , 173.579086 , 2.539774 ], - [ 172.872471 , 178.889185 , 3.363375 ], - [ 181.530751 , 183.044146 , 0.826792 ], - [ 180.340962 , 161.778554 , 11.473961 ], - [ 172.565436 , 139.305384 , 23.875640 ], - [ 162.247156 , 119.868276 , 35.354542 ], - [ 74.172585 , 48.150355 , 54.043693 ], - [ 100.626570 , 83.680300 , 20.251205 ], - [ 118.719023 , 108.828031 , 9.088644 ], - [ 132.735321 , 126.982834 , 4.530130 ], - [ 143.164628 , 140.271822 , 2.062285 ], - [ 151.813418 , 151.871055 , 0.037951 ], - [ 158.832697 , 161.228617 , 1.486039 ], - [ 164.984854 , 169.848150 , 2.863320 ], - [ 169.170571 , 175.507928 , 3.610867 ], - [ 172.872471 , 180.935750 , 4.456432 ], - [ 181.530751 , 183.039043 , 0.824028 ], - [ 180.340962 , 161.705481 , 11.524334 ], - [ 172.565436 , 139.273208 , 23.904259 ], - [ 162.247156 , 119.959075 , 35.252090 ], - [ 74.172585 , 47.566884 , 55.933243 ], - [ 100.626570 , 82.699087 , 21.677969 ], - [ 118.719023 , 107.658511 , 10.273700 ], - [ 132.735321 , 126.233454 , 5.150669 ], - [ 143.164628 , 140.576453 , 1.841116 ], - [ 151.813418 , 152.719787 , 0.593485 ], - [ 158.832697 , 162.995553 , 2.553969 ], - [ 164.984854 , 171.857872 , 3.999246 ], - [ 169.170571 , 177.664858 , 4.781073 ], - [ 172.872471 , 182.786539 , 5.423850 ], - [ 181.530751 , 184.309522 , 1.507666 ], - [ 180.340962 , 161.643543 , 11.567068 ], - [ 172.565436 , 139.231253 , 23.941595 ], - [ 162.247156 , 119.965390 , 35.244969 ], - [ 74.172585 , 43.226030 , 71.592407 ], - [ 100.626570 , 77.234542 , 30.287003 ], - [ 118.719023 , 103.998937 , 14.154074 ], - [ 132.735321 , 124.711169 , 6.434189 ], - [ 143.164628 , 139.489096 , 2.634995 ], - [ 151.813418 , 152.376815 , 0.369740 ], - [ 158.832697 , 162.771016 , 2.419546 ], - [ 164.984854 , 171.399588 , 3.742561 ], - [ 169.170571 , 176.519214 , 4.163084 ], - [ 172.872471 , 180.536313 , 4.245041 ], - [ 181.530751 , 180.178093 , 0.750734 ], - [ 180.340962 , 160.074815 , 12.660422 ], - [ 172.565436 , 138.305476 , 24.771224 ], - [ 162.247156 , 119.353334 , 35.938520 ], - [ 74.172585 , 43.304897 , 71.279901 ], - [ 100.626570 , 78.454597 , 28.260897 ], - [ 118.719023 , 105.606244 , 12.416671 ], - [ 132.735321 , 125.994568 , 5.350034 ], - [ 143.164628 , 141.582230 , 1.117653 ], - [ 151.813418 , 153.343235 , 0.997643 ], - [ 158.832697 , 162.893544 , 2.492946 ], - [ 164.984854 , 170.999163 , 3.517157 ], - [ 169.170571 , 175.833917 , 3.789568 ], - [ 172.872471 , 179.068771 , 3.460291 ], - [ 181.530751 , 176.723990 , 2.719926 ], - [ 180.340962 , 157.752190 , 14.319149 ], - [ 172.565436 , 137.392795 , 25.600062 ], - [ 162.247156 , 118.903128 , 36.453228 ], - [ 74.172585 , 43.462616 , 70.658354 ], - [ 100.626570 , 78.912756 , 27.516228 ], - [ 118.719023 , 106.612590 , 11.355539 ], - [ 132.735321 , 126.403955 , 5.008836 ], - [ 143.164628 , 142.375639 , 0.554160 ], - [ 151.813418 , 153.724089 , 1.242923 ], - [ 158.832697 , 162.443649 , 2.222895 ], - [ 164.984854 , 169.949698 , 2.921361 ], - [ 169.170571 , 173.598830 , 2.550858 ], - [ 172.872471 , 176.799304 , 2.221068 ], - [ 181.530751 , 173.447298 , 4.660467 ], - [ 180.340962 , 156.392633 , 15.312952 ], - [ 172.565436 , 136.374905 , 26.537530 ], - [ 162.247156 , 118.714142 , 36.670453 ], - [ 1403.330455 , 876.885316 , 60.035803 ], - [ 1901.397958 , 1587.638861 , 19.762624 ], - [ 2232.562804 , 2124.580533 , 5.082522 ], - [ 2471.970560 , 2509.129235 , 1.480939 ], - [ 2650.891041 , 2819.187942 , 5.969694 ], - [ 2785.299006 , 3044.948789 , 8.527230 ], - [ 2886.144180 , 3196.018358 , 9.695632 ], - [ 2960.257561 , 3339.851753 , 11.365600 ], - [ 3012.875689 , 3435.052610 , 12.290261 ], - [ 3047.821242 , 3482.652710 , 12.485640 ], - [ 3044.984927 , 3448.098035 , 11.690883 ], - [ 2877.611282 , 3105.329082 , 7.333129 ], - [ 2641.365086 , 2736.951332 , 3.492435 ], - [ 2382.949281 , 2378.093534 , 0.204187 ] + [ 157.397565 , 115.320470 , 36.487100 ], + [ 158.760952 , 162.945479 , 2.568054 ], + [ 165.097976 , 174.297729 , 5.278183 ], + [ 175.510974 , 171.631308 , 2.260465 ], + [ 185.096581 , 168.408756 , 9.909120 ], + [ 193.322704 , 168.310831 , 14.860525 ], + [ 199.745999 , 169.877089 , 17.582659 ], + [ 204.980646 , 172.511293 , 18.821581 ], + [ 207.965455 , 172.824865 , 20.333063 ], + [ 210.211604 , 172.561368 , 21.818462 ], + [ 209.496752 , 177.275607 , 18.175735 ], + [ 198.058665 , 161.933876 , 22.308358 ], + [ 180.931070 , 139.430038 , 29.764772 ], + [ 162.740296 , 120.029132 , 35.583998 ], + [ 180.828953 , 136.735565 , 32.247198 ], + [ 197.570095 , 228.603138 , 13.575073 ], + [ 231.652896 , 275.866189 , 16.027079 ], + [ 267.035700 , 293.303444 , 8.955825 ], + [ 296.574053 , 305.655752 , 2.971218 ], + [ 320.041550 , 313.896508 , 1.957665 ], + [ 338.547315 , 323.484107 , 4.656553 ], + [ 352.372052 , 330.054072 , 6.761916 ], + [ 362.299599 , 335.261016 , 8.064935 ], + [ 369.752884 , 335.769411 , 10.121075 ], + [ 379.269057 , 354.321026 , 7.041081 ], + [ 362.343709 , 318.366856 , 13.813264 ], + [ 333.799298 , 274.710927 , 21.509290 ], + [ 301.589807 , 236.227803 , 27.669057 ], + [ 172.210684 , 192.203184 , 10.401753 ], + [ 227.955695 , 306.754568 , 25.687922 ], + [ 299.934061 , 377.675217 , 20.584129 ], + [ 362.136697 , 412.847194 , 12.283115 ], + [ 410.791383 , 436.793689 , 5.952995 ], + [ 448.676865 , 457.418930 , 1.911173 ], + [ 477.384722 , 472.046625 , 1.130841 ], + [ 499.183038 , 483.257228 , 3.295514 ], + [ 515.122617 , 491.981354 , 4.703687 ], + [ 527.462746 , 496.017051 , 6.339640 ], + [ 543.860701 , 526.391523 , 3.318666 ], + [ 520.875868 , 470.271579 , 10.760652 ], + [ 480.620983 , 406.010507 , 18.376489 ], + [ 434.912156 , 349.521869 , 24.430599 ], + [ 175.817605 , 234.956228 , 25.170060 ], + [ 281.983907 , 379.997542 , 25.793229 ], + [ 386.986699 , 470.343801 , 17.722590 ], + [ 470.710384 , 525.541048 , 10.433184 ], + [ 534.924952 , 566.158092 , 5.516682 ], + [ 583.629049 , 592.597274 , 1.513376 ], + [ 620.647894 , 612.901965 , 1.263812 ], + [ 648.638703 , 631.047390 , 2.787637 ], + [ 669.568744 , 645.427184 , 3.740400 ], + [ 684.736202 , 654.142965 , 4.676843 ], + [ 704.954513 , 694.837660 , 1.456002 ], + [ 674.726162 , 617.784741 , 9.217033 ], + [ 622.980296 , 533.755298 , 16.716461 ], + [ 563.277986 , 459.106740 , 22.689984 ], + [ 203.693343 , 276.585395 , 26.354266 ], + [ 354.131456 , 452.559843 , 21.749253 ], + [ 484.673742 , 563.065703 , 13.922347 ], + [ 585.697217 , 634.734726 , 7.725670 ], + [ 661.769994 , 685.829366 , 3.508070 ], + [ 719.413650 , 722.893858 , 0.481427 ], + [ 763.082942 , 749.627445 , 1.794958 ], + [ 796.409044 , 777.716103 , 2.403569 ], + [ 820.552620 , 793.738233 , 3.378241 ], + [ 838.266809 , 814.271603 , 2.946831 ], + [ 860.928096 , 858.501503 , 0.282654 ], + [ 824.031243 , 761.317980 , 8.237460 ], + [ 760.549282 , 657.575731 , 15.659573 ], + [ 687.849618 , 565.396155 , 21.657994 ], + [ 248.505950 , 302.881789 , 17.952826 ], + [ 434.064679 , 507.004879 , 14.386489 ], + [ 585.500618 , 646.006214 , 9.366101 ], + [ 700.296189 , 732.520960 , 4.399160 ], + [ 786.607031 , 799.352396 , 1.594461 ], + [ 851.884344 , 846.847045 , 0.594830 ], + [ 901.714482 , 886.814283 , 1.680194 ], + [ 939.036181 , 919.813612 , 2.089833 ], + [ 966.478792 , 947.705019 , 1.980972 ], + [ 986.566873 , 973.538216 , 1.338279 ], + [ 1012.284446 , 1018.774022 , 0.636999 ], + [ 968.529570 , 900.113746 , 7.600798 ], + [ 894.291386 , 777.120699 , 15.077540 ], + [ 809.047014 , 668.478449 , 21.028137 ], + [ 301.083452 , 329.637202 , 8.662175 ], + [ 515.826990 , 565.288233 , 8.749739 ], + [ 684.590231 , 726.481623 , 5.766339 ], + [ 811.675874 , 826.947428 , 1.846738 ], + [ 907.198294 , 908.089329 , 0.098122 ], + [ 979.880266 , 969.342726 , 1.087081 ], + [ 1034.847365 , 1020.253181 , 1.430447 ], + [ 1076.438202 , 1064.021851 , 1.166926 ], + [ 1107.169795 , 1100.814671 , 0.577311 ], + [ 1130.070001 , 1133.431347 , 0.296564 ], + [ 1158.486301 , 1173.896940 , 1.312776 ], + [ 1108.583472 , 1034.952546 , 7.114425 ], + [ 1023.739103 , 893.361764 , 14.594014 ], + [ 926.405670 , 768.766979 , 20.505393 ], + [ 356.263480 , 356.827677 , 0.158115 ], + [ 595.869060 , 617.529617 , 3.507614 ], + [ 780.304180 , 799.855865 , 2.444401 ], + [ 918.734772 , 925.119226 , 0.690122 ], + [ 1023.322212 , 1016.348538 , 0.686150 ], + [ 1102.541547 , 1091.098583 , 1.048756 ], + [ 1162.947248 , 1155.093079 , 0.679960 ], + [ 1208.815882 , 1211.268964 , 0.202522 ], + [ 1243.236271 , 1253.935152 , 0.853224 ], + [ 1268.212772 , 1292.295297 , 1.863547 ], + [ 1299.649410 , 1322.310735 , 1.713767 ], + [ 1243.247078 , 1165.542638 , 6.666804 ], + [ 1147.864983 , 1006.341959 , 14.063115 ], + [ 1037.737231 , 865.928307 , 19.841010 ], + [ 411.077411 , 385.708301 , 6.577279 ], + [ 673.052319 , 670.320845 , 0.407487 ], + [ 872.045789 , 871.766681 , 0.032016 ], + [ 1021.605672 , 1014.726741 , 0.677910 ], + [ 1134.443556 , 1123.647094 , 0.960841 ], + [ 1220.439476 , 1216.562717 , 0.318665 ], + [ 1286.238835 , 1291.521445 , 0.409022 ], + [ 1336.683060 , 1357.265823 , 1.516487 ], + [ 1373.994926 , 1405.905836 , 2.269776 ], + [ 1401.325508 , 1449.385390 , 3.315880 ], + [ 1434.917178 , 1466.233816 , 2.135856 ], + [ 1371.509883 , 1292.197312 , 6.137807 ], + [ 1264.493843 , 1115.647694 , 13.341680 ], + [ 1141.954794 , 960.931878 , 18.838267 ], + [ 464.369070 , 417.340024 , 11.268760 ], + [ 746.924235 , 725.581250 , 2.941502 ], + [ 960.029056 , 944.790788 , 1.612872 ], + [ 1119.892820 , 1104.819384 , 1.364335 ], + [ 1241.112296 , 1233.382877 , 0.626684 ], + [ 1333.761841 , 1339.925477 , 0.459998 ], + [ 1405.131840 , 1430.418237 , 1.767762 ], + [ 1459.286022 , 1504.133035 , 2.981586 ], + [ 1499.614145 , 1558.787332 , 3.796104 ], + [ 1529.026303 , 1603.723695 , 4.657747 ], + [ 1563.609130 , 1617.465612 , 3.329683 ], + [ 1491.509266 , 1414.735272 , 5.426739 ], + [ 1372.969721 , 1221.580427 , 12.392904 ], + [ 1238.265153 , 1052.546538 , 17.644694 ], + [ 697.607256 , 530.230908 , 31.566690 ], + [ 1069.199975 , 947.532306 , 12.840477 ], + [ 1345.044085 , 1275.884477 , 5.420523 ], + [ 1552.898160 , 1525.869310 , 1.771374 ], + [ 1711.010275 , 1711.039174 , 0.001689 ], + [ 1831.352455 , 1869.396149 , 2.035079 ], + [ 1922.088013 , 1996.914758 , 3.747118 ], + [ 1989.466621 , 2097.112670 , 5.133060 ], + [ 2037.854512 , 2165.268099 , 5.884425 ], + [ 2071.221986 , 2214.863774 , 6.485355 ], + [ 2085.093776 , 2210.469050 , 5.671886 ], + [ 1964.177356 , 1958.551506 , 0.287245 ], + [ 1790.799073 , 1696.520335 , 5.557183 ], + [ 1603.204230 , 1464.255987 , 9.489341 ], + [ 880.212905 , 661.437438 , 33.075761 ], + [ 1324.703181 , 1198.312686 , 10.547372 ], + [ 1650.853118 , 1613.025965 , 2.345105 ], + [ 1893.136248 , 1919.256956 , 1.360980 ], + [ 2073.770699 , 2162.521880 , 4.104059 ], + [ 2206.964010 , 2342.159055 , 5.772240 ], + [ 2304.126621 , 2488.030128 , 7.391531 ], + [ 2373.154766 , 2604.805409 , 8.893203 ], + [ 2420.005673 , 2685.680924 , 9.892286 ], + [ 2448.863167 , 2735.089966 , 10.464987 ], + [ 2422.889960 , 2699.275863 , 10.239261 ], + [ 2253.562833 , 2403.016190 , 6.219407 ], + [ 2034.519052 , 2098.532599 , 3.050396 ], + [ 1806.243306 , 1816.122090 , 0.543949 ], + [ 1023.193649 , 776.276975 , 31.807806 ], + [ 1525.146555 , 1409.444747 , 8.209035 ], + [ 1886.122306 , 1904.185866 , 0.948624 ], + [ 2148.130146 , 2251.764495 , 4.602362 ], + [ 2338.190044 , 2542.942445 , 8.051791 ], + [ 2474.348845 , 2745.634809 , 9.880628 ], + [ 2570.187192 , 2901.373100 , 11.414799 ], + [ 2635.146070 , 3027.489893 , 12.959377 ], + [ 2675.747420 , 3100.613536 , 13.702647 ], + [ 2697.190433 , 3157.776542 , 14.585773 ], + [ 2625.390139 , 3097.907042 , 15.252779 ], + [ 2405.414280 , 2785.983861 , 13.660150 ], + [ 2140.334096 , 2435.764543 , 12.128859 ], + [ 1918.911826 , 2120.329248 , 9.499346 ], + [ 1134.844622 , 876.885316 , 29.417679 ], + [ 1679.290415 , 1587.638861 , 5.772821 ], + [ 2062.069732 , 2124.580533 , 2.942266 ], + [ 2333.411719 , 2509.129235 , 7.003127 ], + [ 2525.701359 , 2819.187942 , 10.410323 ], + [ 2659.649760 , 3044.948789 , 12.653711 ], + [ 2750.616462 , 3196.018358 , 13.936150 ], + [ 2808.740074 , 3339.851753 , 15.902253 ], + [ 2841.435455 , 3435.052610 , 17.281166 ], + [ 2854.008165 , 3482.652710 , 18.050739 ], + [ 2726.384653 , 3448.098035 , 20.930767 ], + [ 2458.831616 , 3105.329082 , 20.818968 ], + [ 2239.608440 , 2736.951332 , 18.171419 ], + [ 1972.754114 , 2378.093534 , 17.044722 ] ] } From 8c8737d6b6ee668f1cc28f2bbcc2983ad83fbadb Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Wed, 26 Aug 2015 11:15:59 +0200 Subject: [PATCH 090/122] Fix large dataset. --- .../InterestCalib/datasets/large/input.json | 375 +++++++++--------- 1 file changed, 188 insertions(+), 187 deletions(-) diff --git a/benchmarks/InterestCalib/datasets/large/input.json b/benchmarks/InterestCalib/datasets/large/input.json index 7093357..6491f1b 100644 --- a/benchmarks/InterestCalib/datasets/large/input.json +++ b/benchmarks/InterestCalib/datasets/large/input.json @@ -19,185 +19,185 @@ [25.0,6.0, 1.0, 0.27155], [30.0,6.0, 1.0, 0.23465], - [1.0, 6.0, 1.0, 0.61445], - [2.0, 6.0, 1.0, 0.54805], - [3.0, 6.0, 1.0, 0.46795], - [4.0, 6.0, 1.0, 0.3919], - [5.0, 6.0, 1.0, 0.3434], - [6.0, 6.0, 1.0, 0.3083], - [7.0, 6.0, 1.0, 0.28655], - [8.0, 6.0, 1.0, 0.2697], - [9.0, 6.0, 1.0, 0.25775], - [10.0,6.0, 1.0, 0.2443], - [15.0,6.0, 1.0, 0.26495], - [20.0,6.0, 1.0, 0.28195], - [25.0,6.0, 1.0, 0.26845], - [30.0,6.0, 1.0, 0.20995], - - [1.0, 6.0, 1.0, 0.5835], - [2.0, 6.0, 1.0, 0.49255], - [3.0, 6.0, 1.0, 0.42825], - [4.0, 6.0, 1.0, 0.3695], - [5.0, 6.0, 1.0, 0.329], - [6.0, 6.0, 1.0, 0.3022], - [7.0, 6.0, 1.0, 0.28165], - [8.0, 6.0, 1.0, 0.26615], - [9.0, 6.0, 1.0, 0.25485], - [10.0,6.0, 1.0, 0.24375], - [15.0,6.0, 1.0, 0.2718], - [20.0,6.0, 1.0, 0.28135], - [25.0,6.0, 1.0, 0.26865], - [30.0,6.0, 1.0, 0.2131], - - [1.0, 6.0, 1.0, 0.5415], - [2.0, 6.0, 1.0, 0.46235], - [3.0, 6.0, 1.0, 0.403], - [4.0, 6.0, 1.0, 0.3559], - [5.0, 6.0, 1.0, 0.3232], - [6.0, 6.0, 1.0, 0.29675], - [7.0, 6.0, 1.0, 0.27715], - [8.0, 6.0, 1.0, 0.26385], - [9.0, 6.0, 1.0, 0.254], - [10.0,6.0, 1.0, 0.2454], - [15.0,6.0, 1.0, 0.27845], - [20.0,6.0, 1.0, 0.2821], - [25.0,6.0, 1.0, 0.2678], - [30.0,6.0, 1.0, 0.2131], - - [1.0, 6.0, 1.0, 0.517], - [2.0, 6.0, 1.0, 0.446], - [3.0, 6.0, 1.0, 0.3903], - [4.0, 6.0, 1.0, 0.34755], - [5.0, 6.0, 1.0, 0.3166], - [6.0, 6.0, 1.0, 0.29305], - [7.0, 6.0, 1.0, 0.2745], - [8.0, 6.0, 1.0, 0.2639], - [9.0, 6.0, 1.0, 0.2534], - [10.0, 6.0, 1.0, 0.2499], - [15.0, 6.0, 1.0, 0.28315], - [20.0, 6.0, 1.0, 0.2825], - [25.0, 6.0, 1.0, 0.277], - [30.0, 6.0, 1.0, 0.21175], - - [1.0, 6.0, 1.0, 0.478], - [2.0, 6.0, 1.0, 0.42105], - [3.0, 6.0, 1.0, 0.37715], - [4.0, 6.0, 1.0, 0.3378], - [5.0, 6.0, 1.0, 0.311], - [6.0, 6.0, 1.0, 0.2895], - [7.0, 6.0, 1.0, 0.2745], - [8.0, 6.0, 1.0, 0.264], - [9.0, 6.0, 1.0, 0.2573], - [10.0, 6.0, 1.0, 0.25475], - [15.0, 6.0, 1.0, 0.28815], - [20.0, 6.0, 1.0, 0.28195], - [25.0, 6.0, 1.0, 0.26015], - [30.0, 6.0, 1.0, 0.2097], - - [1.0, 6.0, 1.0, 0.452], - [2.0, 6.0, 1.0, 0.4074], - [3.0, 6.0, 1.0, 0.368], - [4.0, 6.0, 1.0, 0.3307], - [5.0, 6.0, 1.0, 0.30645], - [6.0, 6.0, 1.0, 0.2877], - [7.0, 6.0, 1.0, 0.27475], - [8.0, 6.0, 1.0, 0.2664], - [9.0, 6.0, 1.0, 0.26155], - [10.0, 6.0, 1.0, 0.26035], - [15.0, 6.0, 1.0, 0.292], - [20.0, 6.0, 1.0, 0.2825], - [25.0, 6.0, 1.0, 0.25685], - [30.0, 6.0, 1.0, 0.2081], - - [1.0, 6.0, 1.0, 0.43395], - [2.0, 6.0, 1.0, 0.39445], - [3.0, 6.0, 1.0, 0.35885], - [4.0, 6.0, 1.0, 0.3281], - [5.0, 6.0, 1.0, 0.30395], - [6.0, 6.0, 1.0, 0.28745], - [7.0, 6.0, 1.0, 0.2767], - [8.0, 6.0, 1.0, 0.27065], - [9.0, 6.0, 1.0, 0.26625], - [10.0, 6.0, 1.0, 0.26625], - [15.0, 6.0, 1.0, 0.2921], - [20.0, 6.0, 1.0, 0.2814], - [25.0, 6.0, 1.0, 0.25265], - [30.0, 6.0, 1.0, 0.2083], - - [1.0, 6.0, 1.0, 0.42285], - [2.0, 6.0, 1.0, 0.3857], - [3.0, 6.0, 1.0, 0.3521], - [4.0, 6.0, 1.0, 0.3239], - [5.0, 6.0, 1.0, 0.30285], - [6.0, 6.0, 1.0, 0.2895], - [7.0, 6.0, 1.0, 0.2799], - [8.0, 6.0, 1.0, 0.27485], - [9.0, 6.0, 1.0, 0.2712], - [10.0, 6.0, 1.0, 0.27205], - [15.0, 6.0, 1.0, 0.29205], - [20.0, 6.0, 1.0, 0.27855], - [25.0, 6.0, 1.0, 0.24945], - [30.0, 6.0, 1.0, 0.219], - - [1.0, 6.0, 1.0, 0.41765], - [2.0, 6.0, 1.0, 0.38095], - [3.0, 6.0, 1.0, 0.34795], - [4.0, 6.0, 1.0, 0.3217], - [5.0, 6.0, 1.0, 0.30365], - [6.0, 6.0, 1.0, 0.2916], - [7.0, 6.0, 1.0, 0.2842], - [8.0, 6.0, 1.0, 0.27985], - [9.0, 6.0, 1.0, 0.2769], - [10.0, 6.0, 1.0, 0.2775], - [15.0, 6.0, 1.0, 0.306], - [20.0, 6.0, 1.0, 0.2763], - [25.0, 6.0, 1.0, 0.2458], - [30.0, 6.0, 1.0, 0.22], - - [1.0, 6.0, 1.0, 0.37905], - [2.0, 6.0, 1.0, 0.35465], - [3.0, 6.0, 1.0, 0.33505], - [4.0, 6.0, 1.0, 0.31725], - [5.0, 6.0, 1.0, 0.3008], - [6.0, 6.0, 1.0, 0.29075], - [7.0, 6.0, 1.0, 0.28365], - [8.0, 6.0, 1.0, 0.2787], - [9.0, 6.0, 1.0, 0.27385], - [10.0, 6.0, 1.0, 0.2709], - [15.0, 6.0, 1.0, 0.2689], - [20.0, 6.0, 1.0, 0.24225], - [25.0, 6.0, 1.0, 0.2096], - [30.0, 6.0, 1.0, 0.18285], - - [1.0, 6.0, 1.0, 0.37975], - [2.0, 6.0, 1.0, 0.3605], - [3.0, 6.0, 1.0, 0.3407], - [4.0, 6.0, 1.0, 0.321], - [5.0, 6.0, 1.0, 0.3063], - [6.0, 6.0, 1.0, 0.29315], - [7.0, 6.0, 1.0, 0.28395], - [8.0, 6.0, 1.0, 0.2777], - [9.0, 6.0, 1.0, 0.27205], - [10.0, 6.0, 1.0, 0.26675], - [15.0, 6.0, 1.0, 0.24875], - [20.0, 6.0, 1.0, 0.21735], - [25.0, 6.0, 1.0, 0.1939], - [30.0, 6.0, 1.0, 0.17205], - - [1.0, 6.0, 1.0, 0.38115], - [2.0, 6.0, 1.0, 0.3627], - [3.0, 6.0, 1.0, 0.34425], - [4.0, 6.0, 1.0, 0.3222], - [5.0, 6.0, 1.0, 0.3084], - [6.0, 6.0, 1.0, 0.2941], - [7.0, 6.0, 1.0, 0.28285], - [8.0, 6.0, 1.0, 0.2751], - [9.0, 6.0, 1.0, 0.2663], - [10.0, 6.0, 1.0, 0.26055], - [15.0, 6.0, 1.0, 0.2338], - [20.0, 6.0, 1.0, 0.20735], - [25.0, 6.0, 1.0, 0.1823], - [30.0, 6.0, 1.0, 0.1686], + [1.0, 6.0, 2.0, 0.61445], + [2.0, 6.0, 2.0, 0.54805], + [3.0, 6.0, 2.0, 0.46795], + [4.0, 6.0, 2.0, 0.3919], + [5.0, 6.0, 2.0, 0.3434], + [6.0, 6.0, 2.0, 0.3083], + [7.0, 6.0, 2.0, 0.28655], + [8.0, 6.0, 2.0, 0.2697], + [9.0, 6.0, 2.0, 0.25775], + [10.0,6.0, 2.0, 0.2443], + [15.0,6.0, 2.0, 0.26495], + [20.0,6.0, 2.0, 0.28195], + [25.0,6.0, 2.0, 0.26845], + [30.0,6.0, 2.0, 0.20995], + + [1.0, 6.0, 3.0, 0.5835], + [2.0, 6.0, 3.0, 0.49255], + [3.0, 6.0, 3.0, 0.42825], + [4.0, 6.0, 3.0, 0.3695], + [5.0, 6.0, 3.0, 0.329], + [6.0, 6.0, 3.0, 0.3022], + [7.0, 6.0, 3.0, 0.28165], + [8.0, 6.0, 3.0, 0.26615], + [9.0, 6.0, 3.0, 0.25485], + [10.0,6.0, 3.0, 0.24375], + [15.0,6.0, 3.0, 0.2718], + [20.0,6.0, 3.0, 0.28135], + [25.0,6.0, 3.0, 0.26865], + [30.0,6.0, 3.0, 0.2131], + + [1.0, 6.0, 4.0, 0.5415], + [2.0, 6.0, 4.0, 0.46235], + [3.0, 6.0, 4.0, 0.403], + [4.0, 6.0, 4.0, 0.3559], + [5.0, 6.0, 4.0, 0.3232], + [6.0, 6.0, 4.0, 0.29675], + [7.0, 6.0, 4.0, 0.27715], + [8.0, 6.0, 4.0, 0.26385], + [9.0, 6.0, 4.0, 0.254], + [10.0,6.0, 4.0, 0.2454], + [15.0,6.0, 4.0, 0.27845], + [20.0,6.0, 4.0, 0.2821], + [25.0,6.0, 4.0, 0.2678], + [30.0,6.0, 4.0, 0.2131], + + [1.0, 6.0, 5.0, 0.517], + [2.0, 6.0, 5.0, 0.446], + [3.0, 6.0, 5.0, 0.3903], + [4.0, 6.0, 5.0, 0.34755], + [5.0, 6.0, 5.0, 0.3166], + [6.0, 6.0, 5.0, 0.29305], + [7.0, 6.0, 5.0, 0.2745], + [8.0, 6.0, 5.0, 0.2639], + [9.0, 6.0, 5.0, 0.2534], + [10.0, 6.0, 5.0, 0.2499], + [15.0, 6.0, 5.0, 0.28315], + [20.0, 6.0, 5.0, 0.2825], + [25.0, 6.0, 5.0, 0.277], + [30.0, 6.0, 5.0, 0.21175], + + [1.0, 6.0, 6.0, 0.478], + [2.0, 6.0, 6.0, 0.42105], + [3.0, 6.0, 6.0, 0.37715], + [4.0, 6.0, 6.0, 0.3378], + [5.0, 6.0, 6.0, 0.311], + [6.0, 6.0, 6.0, 0.2895], + [7.0, 6.0, 6.0, 0.2745], + [8.0, 6.0, 6.0, 0.264], + [9.0, 6.0, 6.0, 0.2573], + [10.0, 6.0, 6.0, 0.25475], + [15.0, 6.0, 6.0, 0.28815], + [20.0, 6.0, 6.0, 0.28195], + [25.0, 6.0, 6.0, 0.26015], + [30.0, 6.0, 6.0, 0.2097], + + [1.0, 6.0, 7.0, 0.452], + [2.0, 6.0, 7.0, 0.4074], + [3.0, 6.0, 7.0, 0.368], + [4.0, 6.0, 7.0, 0.3307], + [5.0, 6.0, 7.0, 0.30645], + [6.0, 6.0, 7.0, 0.2877], + [7.0, 6.0, 7.0, 0.27475], + [8.0, 6.0, 7.0, 0.2664], + [9.0, 6.0, 7.0, 0.26155], + [10.0, 6.0, 7.0, 0.26035], + [15.0, 6.0, 7.0, 0.292], + [20.0, 6.0, 7.0, 0.2825], + [25.0, 6.0, 7.0, 0.25685], + [30.0, 6.0, 7.0, 0.2081], + + [1.0, 6.0, 8.0, 0.43395], + [2.0, 6.0, 8.0, 0.39445], + [3.0, 6.0, 8.0, 0.35885], + [4.0, 6.0, 8.0, 0.3281], + [5.0, 6.0, 8.0, 0.30395], + [6.0, 6.0, 8.0, 0.28745], + [7.0, 6.0, 8.0, 0.2767], + [8.0, 6.0, 8.0, 0.27065], + [9.0, 6.0, 8.0, 0.26625], + [10.0, 6.0, 8.0, 0.26625], + [15.0, 6.0, 8.0, 0.2921], + [20.0, 6.0, 8.0, 0.2814], + [25.0, 6.0, 8.0, 0.25265], + [30.0, 6.0, 8.0, 0.2083], + + [1.0, 6.0, 9.0, 0.42285], + [2.0, 6.0, 9.0, 0.3857], + [3.0, 6.0, 9.0, 0.3521], + [4.0, 6.0, 9.0, 0.3239], + [5.0, 6.0, 9.0, 0.30285], + [6.0, 6.0, 9.0, 0.2895], + [7.0, 6.0, 9.0, 0.2799], + [8.0, 6.0, 9.0, 0.27485], + [9.0, 6.0, 9.0, 0.2712], + [10.0, 6.0, 9.0, 0.27205], + [15.0, 6.0, 9.0, 0.29205], + [20.0, 6.0, 9.0, 0.27855], + [25.0, 6.0, 9.0, 0.24945], + [30.0, 6.0, 9.0, 0.219], + + [1.0, 6.0, 10.0, 0.41765], + [2.0, 6.0, 10.0, 0.38095], + [3.0, 6.0, 10.0, 0.34795], + [4.0, 6.0, 10.0, 0.3217], + [5.0, 6.0, 10.0, 0.30365], + [6.0, 6.0, 10.0, 0.2916], + [7.0, 6.0, 10.0, 0.2842], + [8.0, 6.0, 10.0, 0.27985], + [9.0, 6.0, 10.0, 0.2769], + [10.0, 6.0, 10.0, 0.2775], + [15.0, 6.0, 10.0, 0.306], + [20.0, 6.0, 10.0, 0.2763], + [25.0, 6.0, 10.0, 0.2458], + [30.0, 6.0, 10.0, 0.22], + + [1.0, 6.0, 15.0, 0.37905], + [2.0, 6.0, 15.0, 0.35465], + [3.0, 6.0, 15.0, 0.33505], + [4.0, 6.0, 15.0, 0.31725], + [5.0, 6.0, 15.0, 0.3008], + [6.0, 6.0, 15.0, 0.29075], + [7.0, 6.0, 15.0, 0.28365], + [8.0, 6.0, 15.0, 0.2787], + [9.0, 6.0, 15.0, 0.27385], + [10.0, 6.0, 15.0, 0.2709], + [15.0, 6.0, 15.0, 0.2689], + [20.0, 6.0, 15.0, 0.24225], + [25.0, 6.0, 15.0, 0.2096], + [30.0, 6.0, 15.0, 0.18285], + + [1.0, 6.0, 20.0, 0.37975], + [2.0, 6.0, 20.0, 0.3605], + [3.0, 6.0, 20.0, 0.3407], + [4.0, 6.0, 20.0, 0.321], + [5.0, 6.0, 20.0, 0.3063], + [6.0, 6.0, 20.0, 0.29315], + [7.0, 6.0, 20.0, 0.28395], + [8.0, 6.0, 20.0, 0.2777], + [9.0, 6.0, 20.0, 0.27205], + [10.0, 6.0, 20.0, 0.26675], + [15.0, 6.0, 20.0, 0.24875], + [20.0, 6.0, 20.0, 0.21735], + [25.0, 6.0, 20.0, 0.1939], + [30.0, 6.0, 20.0, 0.17205], + + [1.0, 6.0, 25.0, 0.38115], + [2.0, 6.0, 25.0, 0.3627], + [3.0, 6.0, 25.0, 0.34425], + [4.0, 6.0, 25.0, 0.3222], + [5.0, 6.0, 25.0, 0.3084], + [6.0, 6.0, 25.0, 0.2941], + [7.0, 6.0, 25.0, 0.28285], + [8.0, 6.0, 25.0, 0.2751], + [9.0, 6.0, 25.0, 0.2663], + [10.0, 6.0, 25.0, 0.26055], + [15.0, 6.0, 25.0, 0.2338], + [20.0, 6.0, 25.0, 0.20735], + [25.0, 6.0, 25.0, 0.1823], + [30.0, 6.0, 25.0, 0.1686], [1.0, 6.0, 30.0, 0.38285], [2.0, 6.0, 30.0, 0.3633], @@ -217,18 +217,19 @@ "num_hermite_coefficients": 11, "hermite_coefficients": - [ 0.0, 0.6568095668820999044613, -0.6568095668820997934390, - -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, - -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, - 3.6684708465595856630159, -3.6684708465595838866591 + [ + 0.0, 0.6568095668820999044613, -0.6568095668820997934390, + -1.3265570844949334805563, 1.3265570844949330364670, 2.0259480158257567872226, + -2.0259480158257558990442, -2.7832900997816496513337, 2.7832900997816474308877, + 3.6684708465595856630159, -3.6684708465595838866591 ], "hermite_coefficient_weights": [ - 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, - 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, - 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, - 1.0065267861723647957461, 1.0065267861723774522886 + 0.6547592869145917315876, 0.6609604194409607336169, 0.6609604194409606225946, + 0.6812118810666693002887, 0.6812118810666689672217, 0.7219536247283847574252, + 0.7219536247283852015144, 0.8025168688510405656800, 0.8025168688510396775015, + 1.0065267861723647957461, 1.0065267861723774522886 ], "sobol_num_bits": 30, From 9c329ec253bc06e5c0e564a4fca03cd0ad000f84 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Wed, 26 Aug 2015 12:43:16 +0200 Subject: [PATCH 091/122] Improve readDouble. --- .../OptionPricing/implementations/haskell_lh/GenPricing.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs index e348336..1d76f64 100644 --- a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs +++ b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs @@ -33,6 +33,9 @@ import qualified Data.Vector.Unboxed as V signed :: Parser String -> Parser String signed p = (char '-' >> (('-':) <$> p)) <|> p +exponented :: Parser String -> Parser String +exponented p = (++) <$> p <*> (((:) <$> oneOf "eE" <*> signed (many1 digit)) <|> pure "") + whitespace :: Parser () whitespace = spaces <* optional (string "//" >> manyTill anyChar (char '\n') >> whitespace) @@ -46,7 +49,7 @@ readInt :: Parser Int readInt = lexeme $ read <$> signed (many1 digit) readDouble :: Parser Double -readDouble = lexeme $ read <$> signed (s2 <|> s1) +readDouble = lexeme $ read <$> exponented (signed $ s2 <|> s1) where s1 = do bef <- many1 digit aft <- fromMaybe "" <$> optional ((:) <$> char '.' <*> many1 digit) return $ bef ++ aft From a8596fe33154a74762a912d80141220eb9240634 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Wed, 26 Aug 2015 14:19:45 +0200 Subject: [PATCH 092/122] Remove the data targets. --- .../implementations/cpp_opencl/Makefile | 6 +---- .../implementations/cpp_openmp/Makefile | 6 +---- .../cpp_openmp/instantiate_data | 7 ----- .../implementations/cpp_openmp/run | 3 --- .../implementations/cpp_sequential/Makefile | 6 +---- .../implementations/haskell_lh/Makefile | 6 +---- .../implementations/cpp_openclmp_all/Makefile | 6 +---- .../cpp_openclmp_outer/Makefile | 6 +---- .../implementations/cpp_openmp_naive/Makefile | 6 +---- .../implementations/cpp_sequential/Makefile | 7 ++--- .../implementations/haskell_lh/Makefile | 6 +---- .../implementations/cpp_opencl/Makefile | 6 +---- .../implementations/cpp_openmp/Makefile | 6 +---- .../implementations/cpp_openmp/instantiate | 26 ------------------- .../cpp_openmp/instantiate_data | 7 ----- .../implementations/cpp_openmp/run | 3 --- .../implementations/cpp_sequential/Makefile | 6 +---- .../implementations/haskell_lh/Makefile | 6 +---- 18 files changed, 14 insertions(+), 111 deletions(-) delete mode 100755 benchmarks/InterestCalib/implementations/cpp_openmp/instantiate_data delete mode 100755 benchmarks/InterestCalib/implementations/cpp_openmp/run delete mode 100755 benchmarks/OptionPricing/implementations/cpp_openmp/instantiate delete mode 100755 benchmarks/OptionPricing/implementations/cpp_openmp/instantiate_data delete mode 100755 benchmarks/OptionPricing/implementations/cpp_openmp/run diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile index 3698123..2d4f7e1 100644 --- a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile @@ -37,10 +37,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ ./$(EXECUTABLE) diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile index a97de36..20acfd5 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile @@ -29,10 +29,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate_data b/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate_data deleted file mode 100755 index b8ccb2b..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/instantiate_data +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e - -mkdir -p datasets/$HIPERMARK_INPUT_NAME - -$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/run b/benchmarks/InterestCalib/implementations/cpp_openmp/run deleted file mode 100755 index ff0deb0..0000000 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -#export OMP_NUM_THREADS=$NCORES -cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./SwapCalib diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile index 1b4da85..b92c38a 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile @@ -25,10 +25,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ ./$(EXECUTABLE) diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile index 5a66b3c..cb64a37 100644 --- a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile @@ -17,10 +17,6 @@ $(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ ./$(EXECUTABLE) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile index ddba0b5..46fb61e 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile @@ -46,10 +46,6 @@ clean: @# clean nVidia compiler cache rm -rf $(HOME)/.nv/ComputeCache/* -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile index fec72d5..b107ef7 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile @@ -46,10 +46,6 @@ clean: @# clean nVidia compiler cache rm -rf $(HOME)/.nv/ComputeCache/* -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile index 119dd37..8e66db2 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile @@ -25,10 +25,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile index 9f825b4..3117932 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile @@ -34,9 +34,6 @@ run_large: $(EXECUTABLE) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ + ./$(EXECUTABLE) diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile index 6f5e944..01e013a 100644 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile +++ b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile @@ -15,9 +15,5 @@ $(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) clean: rm $(EXECUTABLE) *o *hi -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) outer num_x num_y num_t > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | ./$(EXECUTABLE) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile index 9c7d431..b52b3fd 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile @@ -37,10 +37,6 @@ clean: @# clean nVidia compiler cache rm -rf $(HOME)/.nv/ComputeCache/* -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile b/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile index 7447ebf..0b6e2ab 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile @@ -26,10 +26,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate b/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate deleted file mode 100755 index 009dae1..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/instantiate +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -set -e - -cp $HIPERMARK_LIB_DIR/setup.mk . -cp $HIPERMARK_LIB_DIR/include/ParserC.h . -cp $HIPERMARK_LIB_DIR/include/Util.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Constants.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/Optimizations.h . -cp $HIPERMARK_BENCHMARK_LIB_DIR/include/ParseInput.h . -cp $HIPERMARK_IMPLEMENTATION_DIR/*cpp $HIPERMARK_IMPLEMENTATION/*h $HIPERMARK_IMPLEMENTATION/Makefile . -cp $HIPERMARK_IMPLEMENTATION_DIR/run . - -#$HIPERMARK_LIB_DIR/linearise_data.py $HIPERMARK_INPUT contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > input.data -$HIPERMARK_LIB_DIR/generate_platform_mk.py $HIPERMARK_PLATFORM > platform.mk -#NCORES=$($HIPERMARK_LIB_DIR/json_get.py $HIPERMARK_PLATFORM num_cores) - -# cat > run < datasets/$HIPERMARK_INPUT_NAME/input.data diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/run b/benchmarks/OptionPricing/implementations/cpp_openmp/run deleted file mode 100755 index 22d7e81..0000000 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -#export OMP_NUM_THREADS=$NCORES -cat datasets/$HIPERMARK_INPUT_NAME/input.data | ./GenPricing \ No newline at end of file diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile index 7808673..4a6677d 100644 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile @@ -26,10 +26,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ ./$(EXECUTABLE) diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/Makefile b/benchmarks/OptionPricing/implementations/haskell_lh/Makefile index afdc764..4e30a00 100644 --- a/benchmarks/OptionPricing/implementations/haskell_lh/Makefile +++ b/benchmarks/OptionPricing/implementations/haskell_lh/Makefile @@ -17,10 +17,6 @@ $(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -data: $(HIPERMARK_INPUT) - mkdir -p datasets/$(HIPERMARK_INPUT_NAME) - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data > datasets/$(HIPERMARK_INPUT_NAME)/input.data - run: - cat datasets/$(HIPERMARK_INPUT_NAME)/input.data | \ + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ ./$(EXECUTABLE) From 796556c611e2adc9fa58f9d2e225a7db4e4371b5 Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 26 Aug 2015 21:32:06 +0200 Subject: [PATCH 093/122] Fixed run script for InterestCalib --- run_hipermark_InterestCalib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run_hipermark_InterestCalib b/run_hipermark_InterestCalib index 3a55487..74ef13a 100755 --- a/run_hipermark_InterestCalib +++ b/run_hipermark_InterestCalib @@ -2,8 +2,8 @@ clear echo Deleting all files in instantiations/InterestCalib -echo Running hipermark InterestCalib CppOpenMP small dataset, 2 times. +echo Running hipermark InterestCalib cpp_openmp small dataset, 2 times. echo Storing all results in instantiations/ rm -rf instantiations/InterestCalib -../hipermark/hipermark instantiations/ 2 benchmarks/InterestCalib CppOpenMP small \ No newline at end of file +../hipermark/hipermark instantiations/ 2 benchmarks/InterestCalib cpp_openmp small From bd320d7ba98c4eece9829b6b4897af5a5ebb7056 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Fri, 28 Aug 2015 15:23:21 +0200 Subject: [PATCH 094/122] Make hipermark a submodule. --- .gitmodules | 3 +++ hipermark | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 hipermark diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f7271f0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "hipermark"] + path = hipermark + url = https://github.com/HIPERFIT/hipermark.git diff --git a/hipermark b/hipermark new file mode 160000 index 0000000..bee8804 --- /dev/null +++ b/hipermark @@ -0,0 +1 @@ +Subproject commit bee88042ae09c79bf534d1c44eea2492a3aadf39 From 6ed9d2a5241079f912fba8e85e9913906eb5d42d Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 1 Sep 2015 16:15:40 +0200 Subject: [PATCH 095/122] Add ad-hoc run_%s targets. --- .gitignore | 4 ++++ .../implementations/cpp_opencl/Makefile | 6 +++--- .../implementations/cpp_openmp/.gitignore | 1 + .../implementations/cpp_openmp/Makefile | 8 +++++--- .../implementations/cpp_openmp/SwapCalib | Bin 85584 -> 75880 bytes .../implementations/cpp_sequential/Makefile | 6 +++--- .../implementations/haskell_lh/Makefile | 6 +++--- .../implementations/cpp_openclmp_all/Makefile | 17 +++++------------ .../cpp_openclmp_outer/Makefile | 17 +++++------------ .../implementations/cpp_openmp_naive/Makefile | 8 +++++--- .../implementations/cpp_sequential/Makefile | 15 +++------------ .../implementations/haskell_lh/Makefile | 5 +++-- .../implementations/cpp_opencl/Makefile | 6 +++--- .../implementations/cpp_openmp/.gitignore | 1 + .../implementations/cpp_openmp/Makefile | 8 +++++--- .../implementations/cpp_sequential/.gitignore | 1 + .../implementations/cpp_sequential/Makefile | 10 +++++----- .../implementations/haskell_lh/.gitignore | 1 + .../implementations/haskell_lh/Makefile | 6 +++--- lib/flat_data_helper.mk | 16 ++++++++++++++++ lib/setup.mk | 4 ++-- 21 files changed, 77 insertions(+), 69 deletions(-) create mode 100644 benchmarks/InterestCalib/implementations/cpp_openmp/.gitignore create mode 100644 benchmarks/OptionPricing/implementations/cpp_openmp/.gitignore create mode 100644 benchmarks/OptionPricing/implementations/cpp_sequential/.gitignore create mode 100644 benchmarks/OptionPricing/implementations/haskell_lh/.gitignore create mode 100644 lib/flat_data_helper.mk diff --git a/.gitignore b/.gitignore index 7c68cb7..ace4b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,10 @@ GenericPricing/HaskellLH/GenPricing GenericPricing/Orig_COpenMp/GenPricing CalibVolDiff/Original/CalibVol +# Ad-hoc run artifacts +benchmarks/*/implementations/*/result.json +benchmarks/*/implementations/*/runtime.txt + # all instantiations instantiations/* diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile index 2d4f7e1..5c0f9a4 100644 --- a/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/Makefile @@ -37,6 +37,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/.gitignore b/benchmarks/InterestCalib/implementations/cpp_openmp/.gitignore new file mode 100644 index 0000000..cd95011 --- /dev/null +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/.gitignore @@ -0,0 +1 @@ +GenPricing diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile index 20acfd5..da969e5 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/Makefile @@ -29,6 +29,8 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ - OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs +ifdef HIPERMARK_CONFIG_NUM_THREADS + HIPERMARK_RUN_ENVIRONMENT=OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) +endif +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib index b8aafbb55bf017f712e1f7c2f0946e2efacb952b..e3164b771260a352a713f589cb1a5025b07f8a58 100755 GIT binary patch literal 75880 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⪚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ⅆ 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 diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile index b92c38a..a177855 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/Makefile @@ -25,6 +25,6 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile index cb64a37..3bc2035 100644 --- a/benchmarks/InterestCalib/implementations/haskell_lh/Makefile +++ b/benchmarks/InterestCalib/implementations/haskell_lh/Makefile @@ -17,6 +17,6 @@ $(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=population_size convergence_iterations num_swaption_quotes swaption_quotes num_hermite_coefficients hermite_coefficients hermite_coefficient_weights sobol_num_bits sobol_dir_vs +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile index 46fb61e..cd0ad0e 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/Makefile @@ -32,20 +32,13 @@ $(EXECUTABLE): $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) -run_small: - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt @# clean nVidia compiler cache rm -rf $(HOME)/.nv/ComputeCache/* -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ - OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=outer num_x num_y num_t +ifdef HIPERMARK_CONFIG_NUM_THREADS + HIPERMARK_RUN_ENVIRONMENT=OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) +endif +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile index b107ef7..65c467d 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/Makefile @@ -32,20 +32,13 @@ $(EXECUTABLE): $(CXX) $(CXXFLAGS) -D IS_GPU=1 $(GPU_OPTS) $(INCLUDES) -o $(EXECUTABLE) $(SOURCES_CPP) $(LIB) -run_small: - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: rm -f $(EXECUTABLE) $(OBJECTS) ./*.ptx ./Debug.txt @# clean nVidia compiler cache rm -rf $(HOME)/.nv/ComputeCache/* -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ - OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=outer num_x num_y num_t +ifdef HIPERMARK_CONFIG_NUM_THREADS + HIPERMARK_RUN_ENVIRONMENT=OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) +endif +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile index 8e66db2..d1fe958 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/Makefile @@ -25,6 +25,8 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ - OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=outer num_x num_y num_t +ifdef HIPERMARK_CONFIG_NUM_THREADS + HIPERMARK_RUN_ENVIRONMENT=OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) +endif +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile index 3117932..98a8a4f 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile +++ b/benchmarks/LocVolCalib/implementations/cpp_sequential/Makefile @@ -22,18 +22,9 @@ default: $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) -run_small: $(EXECUTABLE) - cat ../Data/Small/input.data ../Data/Small/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_medium: $(EXECUTABLE) - cat ../Data/Medium/input.data ../Data/Medium/output.data | ./$(EXECUTABLE) 2> Debug.txt - -run_large: $(EXECUTABLE) - cat ../Data/Large/input.data ../Data/Large/output.data | ./$(EXECUTABLE) 2> Debug.txt - clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=outer num_x num_y num_t +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile index 01e013a..4d1215c 100644 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile +++ b/benchmarks/LocVolCalib/implementations/haskell_lh/Makefile @@ -15,5 +15,6 @@ $(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) clean: rm $(EXECUTABLE) *o *hi -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) outer num_x num_y num_t | ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=outer num_x num_y num_t +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile index b52b3fd..0e574b2 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile @@ -37,6 +37,6 @@ clean: @# clean nVidia compiler cache rm -rf $(HOME)/.nv/ComputeCache/* -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/.gitignore b/benchmarks/OptionPricing/implementations/cpp_openmp/.gitignore new file mode 100644 index 0000000..cf8c610 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/.gitignore @@ -0,0 +1 @@ +GenPricing \ No newline at end of file diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile b/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile index 0b6e2ab..b0e249b 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/Makefile @@ -26,6 +26,8 @@ $(EXECUTABLE): $(OBJECTS) clean: rm -f $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ - OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data +ifdef HIPERMARK_CONFIG_NUM_THREADS + HIPERMARK_RUN_ENVIRONMENT=OMP_NUM_THREADS=$(HIPERMARK_CONFIG_NUM_THREADS) +endif +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/.gitignore b/benchmarks/OptionPricing/implementations/cpp_sequential/.gitignore new file mode 100644 index 0000000..cf8c610 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/.gitignore @@ -0,0 +1 @@ +GenPricing \ No newline at end of file diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile index 4a6677d..bfe027c 100644 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/Makefile @@ -18,14 +18,14 @@ EXECUTABLE =GenPricing default: $(EXECUTABLE) %.o: $(HIPERMARK_IMPLEMENTATION_DIR)/%.cpp $(HELPERS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< + $(CXX) $(CXXFLAGS) -g $(INCLUDES) -c -o $@ $< $(EXECUTABLE): $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) + $(CXX) $(CXXFLAGS) -g $(INCLUDES) -o $(EXECUTABLE) $(OBJECTS) clean: rm -f $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/.gitignore b/benchmarks/OptionPricing/implementations/haskell_lh/.gitignore new file mode 100644 index 0000000..cf8c610 --- /dev/null +++ b/benchmarks/OptionPricing/implementations/haskell_lh/.gitignore @@ -0,0 +1 @@ +GenPricing \ No newline at end of file diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/Makefile b/benchmarks/OptionPricing/implementations/haskell_lh/Makefile index 4e30a00..9f88571 100644 --- a/benchmarks/OptionPricing/implementations/haskell_lh/Makefile +++ b/benchmarks/OptionPricing/implementations/haskell_lh/Makefile @@ -17,6 +17,6 @@ $(EXECUTABLE): $(HIPERMARK_IMPLEMENTATION_DIR)/$(SOURCES) clean: rm -f Debug.txt $(EXECUTABLE) $(OBJECTS) -run: - $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data | \ - ./$(EXECUTABLE) +HIPERMARK_DATA_FIELDS=contract_number monte_carlo_iterations num_path_dates num_underlyings num_models num_bits dir_vs md_c md_vols md_drifts md_starts md_deterministic_values md_discounts bb_inds bb_data +HIPERMARK_RUN_ENVIRONMENT= +include $(HIPERMARK_LIB_DIR)/flat_data_helper.mk diff --git a/lib/flat_data_helper.mk b/lib/flat_data_helper.mk new file mode 100644 index 0000000..e2d461e --- /dev/null +++ b/lib/flat_data_helper.mk @@ -0,0 +1,16 @@ +# Utility makefile definitions for conveniently defining run targets +# (with some assumptions). + +AD_HOC_RUNTIME_FILE=runtime.txt +AD_HOC_RESULT_FILE=result.json + +AD_HOC_RUN_FLAGS=HIPERMARK_RUNTIME=$(AD_HOC_RUNTIME_FILE) HIPERMARK_RESULT=$(AD_HOC_RESULT_FILE) + +run_%: $(EXECUTABLE) + $(HIPERMARK_LIB_DIR)/linearise_data.py ../../datasets/$(subst run_,,$@)/input.json $(HIPERMARK_DATA_FIELDS) | $(AD_HOC_RUN_FLAGS) ./$(EXECUTABLE) + @echo "Result: `cat result.json`" + @echo "Runtime: `cat runtime.txt`ms" + +run: $(EXECUTABLE) + $(HIPERMARK_LIB_DIR)/linearise_data.py $(HIPERMARK_INPUT_FILE) $(HIPERMARK_DATA_FIELDS) | \ + $(HIPERMARK_RUN_ENVIRONMENT) ./$(EXECUTABLE) diff --git a/lib/setup.mk b/lib/setup.mk index e46bec8..2e16dcb 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -1,8 +1,8 @@ # If we are run from outside Hipermark itself, a number of environment # variables will be missing. Set these to hopefully-working values to # support standalone compilation. -HIPERMARK_BENCHMARK_LIB_DIR ?= ../../lib/ -HIPERMARK_IMPLEMENTATION_DIR ?= . +HIPERMARK_BENCHMARK_LIB_DIR ?= ../../lib/ +HIPERMARK_IMPLEMENTATION_DIR ?= . OS=$(shell uname -s) From 2ee9833b181f1479096d4119e4b4d81302aa1ccd Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 1 Sep 2015 16:21:50 +0200 Subject: [PATCH 096/122] Newer hipermark. --- hipermark | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hipermark b/hipermark index bee8804..50d031a 160000 --- a/hipermark +++ b/hipermark @@ -1 +1 @@ -Subproject commit bee88042ae09c79bf534d1c44eea2492a3aadf39 +Subproject commit 50d031afd3c7de09ee377a7ea78755c2e0022acc From 75bc73e331ab665b90d02d55c5757fd6bc02de1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sat, 5 Sep 2015 23:36:06 +0200 Subject: [PATCH 097/122] Added configuration file for producing graphs with hiperpret --- .gitignore | 3 ++ hipermark | 1 - hiperpret_figure_configuration.json | 74 +++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) delete mode 160000 hipermark create mode 100644 hiperpret_figure_configuration.json diff --git a/.gitignore b/.gitignore index ace4b3b..a222daf 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ benchmarks/*/implementations/*/runtime.txt # all instantiations instantiations/* +#all hiperpret-created data +hiperpret/* + # emacs backups *~ diff --git a/hipermark b/hipermark deleted file mode 160000 index 50d031a..0000000 --- a/hipermark +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 50d031afd3c7de09ee377a7ea78755c2e0022acc diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json new file mode 100644 index 0000000..251a027 --- /dev/null +++ b/hiperpret_figure_configuration.json @@ -0,0 +1,74 @@ +{ + "InterestCalib, cpp_openmp, small ds, real type double": { + "benchmark_name": "InterestCalib", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "double"}, + "sticky": "False" + }, + "InterestCalib, cpp_openmp, small ds, real type float": { + "benchmark_name": "InterestCalib", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "float"}, + "sticky": "True" + }, + "OptionPricing, cpp_openmp, small ds, real type double": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "double"}, + "sticky": "False" + }, + "OptionPricing, cpp_openmp, small ds, real type float": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "float"}, + "sticky": "True" + }, + "LocVolCalib, cpp_openmp_naive, small ds, real type double": { + "benchmark_name": "LocVolCalib", + "implementation_name": "cpp_openmp_naive", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "double"}, + "sticky": "False" + }, + "LocVolCalib, cpp_openmp, small ds, real type float": { + "benchmark_name": "LocVolCalib", + "implementation_name": "cpp_openmp_naive", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "float"}, + "sticky": "True" + } +} From 17827b7cdf44545522d987e7d74f717552594e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sat, 5 Sep 2015 23:56:10 +0200 Subject: [PATCH 098/122] One more figure is now produced by hiperpret --- hiperpret_figure_configuration.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json index 251a027..2d2762d 100644 --- a/hiperpret_figure_configuration.json +++ b/hiperpret_figure_configuration.json @@ -70,5 +70,27 @@ "dataset_name": "medium", "REAL_TYPE": "float"}, "sticky": "True" + }, + "LocVolCalib, cpp_sequential, small ds, real type double": { + "benchmark_name": "LocVolCalib", + "implementation_name": "cpp_sequential", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "REAL_TYPE", + "locked_vars": { + "dataset_name": "medium"}, + "sticky": "False" + }, + "LocVolCalib, cpp_sequential, small ds, real type float": { + "benchmark_name": "LocVolCalib", + "implementation_name": "cpp_sequential", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "REAL_TYPE", + "locked_vars": { + "dataset_name": "medium"}, + "sticky": "True" } } From 6ee7fb730c0ad3706715a173f03955c6e04c81cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 6 Sep 2015 00:24:21 +0200 Subject: [PATCH 099/122] Many graphs are now produced. --- hiperpret_figure_configuration.json | 71 ++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json index 2d2762d..f431402 100644 --- a/hiperpret_figure_configuration.json +++ b/hiperpret_figure_configuration.json @@ -22,7 +22,7 @@ "dataset_name": "small", "REAL_TYPE": "float"}, "sticky": "True" - }, + }, "OptionPricing, cpp_openmp, small ds, real type double": { "benchmark_name": "OptionPricing", "implementation_name": "cpp_openmp", @@ -47,7 +47,31 @@ "REAL_TYPE": "float"}, "sticky": "True" }, - "LocVolCalib, cpp_openmp_naive, small ds, real type double": { + "OptionPricing, cpp_openmp, medium ds, real type double": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "double"}, + "sticky": "False" + }, + "OptionPricing, cpp_openmp, medium ds, real type float": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "float"}, + "sticky": "True" + }, + "LocVolCalib, cpp_openmp_naive, medium ds, real type double": { "benchmark_name": "LocVolCalib", "implementation_name": "cpp_openmp_naive", "type": "graph", @@ -59,7 +83,7 @@ "REAL_TYPE": "double"}, "sticky": "False" }, - "LocVolCalib, cpp_openmp, small ds, real type float": { + "LocVolCalib, cpp_openmp_naive, medium ds, real type float": { "benchmark_name": "LocVolCalib", "implementation_name": "cpp_openmp_naive", "type": "graph", @@ -71,26 +95,61 @@ "REAL_TYPE": "float"}, "sticky": "True" }, - "LocVolCalib, cpp_sequential, small ds, real type double": { + "LocVolCalib, cpp_sequential, medium ds": { "benchmark_name": "LocVolCalib", "implementation_name": "cpp_sequential", "type": "graph", "dependent_var": "average runtime", "get normalized performance": "True", "free_var": "REAL_TYPE", + "locked_vars": { + "dataset_name": "medium"}, + "sticky": "True" + }, + "Bar chart, LocVolCalib, cpp_sequential, medium ds, real type double": { + "benchmark_name": "LocVolCalib", + "implementation_name": "cpp_sequential", + "type": "bar", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "REAL_TYPE", "locked_vars": { "dataset_name": "medium"}, "sticky": "False" }, - "LocVolCalib, cpp_sequential, small ds, real type float": { + "Bar chart, LocVolCalib, cpp_sequential, medium ds, real type float": { "benchmark_name": "LocVolCalib", "implementation_name": "cpp_sequential", - "type": "graph", + "type": "bar", "dependent_var": "average runtime", "get normalized performance": "True", "free_var": "REAL_TYPE", "locked_vars": { "dataset_name": "medium"}, "sticky": "True" + }, + "Runtime, OptionPricing, cpp_openmp, small ds, real type float": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "float"}, + "sticky": "True" + }, + "Runtime, OptionPricing, cpp_openmp, medium ds, real type double": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "double"}, + "sticky": "False" } } From db5a99ad7a1368abe5aa69b6ddf7a30e9eeb27a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 6 Sep 2015 00:40:29 +0200 Subject: [PATCH 100/122] Two graphs with dataset as indep. var. is now defined in JSON and produced by hiperpret. --- hiperpret_figure_configuration.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json index f431402..cebbf50 100644 --- a/hiperpret_figure_configuration.json +++ b/hiperpret_figure_configuration.json @@ -151,5 +151,29 @@ "dataset_name": "medium", "REAL_TYPE": "double"}, "sticky": "False" + }, + "OptionPricing, cpp_openmp, 1 thread, real type double": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "locked_vars": { + "NUM_THREADS": "1", + "REAL_TYPE": "double"}, + "sticky": "False" + }, + "OptionPricing, cpp_openmp, 4 threads, real type double": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "locked_vars": { + "NUM_THREADS": "4", + "REAL_TYPE": "double"}, + "sticky": "False" } } From d4bdc33902ced901dd5934a206360103480f5582 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Sun, 6 Sep 2015 09:18:53 +0200 Subject: [PATCH 101/122] Fix hipermark submodule. --- hipermark | 1 + 1 file changed, 1 insertion(+) create mode 160000 hipermark diff --git a/hipermark b/hipermark new file mode 160000 index 0000000..a5ffd5f --- /dev/null +++ b/hipermark @@ -0,0 +1 @@ +Subproject commit a5ffd5fde3ad5ee43556f36ac0749c8c75cb2d00 From b096c1ba0ccf78d18ac30d9b167aa285bfc5b21a Mon Sep 17 00:00:00 2001 From: Thor Date: Tue, 8 Sep 2015 12:38:22 +0200 Subject: [PATCH 102/122] hiperpret figure configuration file format changed to list of dicts. --- hiperpret_figure_configuration.json | 240 +++++++--------------------- 1 file changed, 61 insertions(+), 179 deletions(-) diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json index cebbf50..fa46154 100644 --- a/hiperpret_figure_configuration.json +++ b/hiperpret_figure_configuration.json @@ -1,179 +1,61 @@ -{ - "InterestCalib, cpp_openmp, small ds, real type double": { - "benchmark_name": "InterestCalib", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "double"}, - "sticky": "False" - }, - "InterestCalib, cpp_openmp, small ds, real type float": { - "benchmark_name": "InterestCalib", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "float"}, - "sticky": "True" - }, - "OptionPricing, cpp_openmp, small ds, real type double": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "double"}, - "sticky": "False" - }, - "OptionPricing, cpp_openmp, small ds, real type float": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "float"}, - "sticky": "True" - }, - "OptionPricing, cpp_openmp, medium ds, real type double": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "double"}, - "sticky": "False" - }, - "OptionPricing, cpp_openmp, medium ds, real type float": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "float"}, - "sticky": "True" - }, - "LocVolCalib, cpp_openmp_naive, medium ds, real type double": { - "benchmark_name": "LocVolCalib", - "implementation_name": "cpp_openmp_naive", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "double"}, - "sticky": "False" - }, - "LocVolCalib, cpp_openmp_naive, medium ds, real type float": { - "benchmark_name": "LocVolCalib", - "implementation_name": "cpp_openmp_naive", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "float"}, - "sticky": "True" - }, - "LocVolCalib, cpp_sequential, medium ds": { - "benchmark_name": "LocVolCalib", - "implementation_name": "cpp_sequential", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "REAL_TYPE", - "locked_vars": { - "dataset_name": "medium"}, - "sticky": "True" - }, - "Bar chart, LocVolCalib, cpp_sequential, medium ds, real type double": { - "benchmark_name": "LocVolCalib", - "implementation_name": "cpp_sequential", - "type": "bar", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "REAL_TYPE", - "locked_vars": { - "dataset_name": "medium"}, - "sticky": "False" - }, - "Bar chart, LocVolCalib, cpp_sequential, medium ds, real type float": { - "benchmark_name": "LocVolCalib", - "implementation_name": "cpp_sequential", - "type": "bar", - "dependent_var": "average runtime", - "get normalized performance": "True", - "free_var": "REAL_TYPE", - "locked_vars": { - "dataset_name": "medium"}, - "sticky": "True" - }, - "Runtime, OptionPricing, cpp_openmp, small ds, real type float": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "False", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "float"}, - "sticky": "True" - }, - "Runtime, OptionPricing, cpp_openmp, medium ds, real type double": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "False", - "free_var": "NUM_THREADS", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "double"}, - "sticky": "False" - }, - "OptionPricing, cpp_openmp, 1 thread, real type double": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "locked_vars": { - "NUM_THREADS": "1", - "REAL_TYPE": "double"}, - "sticky": "False" - }, - "OptionPricing, cpp_openmp, 4 threads, real type double": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "average runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "locked_vars": { - "NUM_THREADS": "4", - "REAL_TYPE": "double"}, - "sticky": "False" - } -} +[{"OptionPricing, cpp_openmp": + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Double, small", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "double"}, + "sticky": "True" + } + }, + {"OptionPricing, cpp_openmp": + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Float, small", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "float"}, + "sticky": "True" + } + }, + {"OptionPricing, cpp_openmp": + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Double, medium", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "double"}, + "sticky": "True" + } + }, + {"OptionPricing, cpp_openmp": + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "average runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Float, medium", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "float"}, + "sticky": "True" + } + } +] From a45b1bfa761fa53e0be7aea337249df0b16f4a25 Mon Sep 17 00:00:00 2001 From: Thor Date: Tue, 29 Sep 2015 19:51:36 +0200 Subject: [PATCH 103/122] figure configuration file updated to fit new hiperpret program. --- hiperpret_figure_configuration.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json index fa46154..9dccb8c 100644 --- a/hiperpret_figure_configuration.json +++ b/hiperpret_figure_configuration.json @@ -3,7 +3,7 @@ "benchmark_name": "OptionPricing", "implementation_name": "cpp_openmp", "type": "graph", - "dependent_var": "average runtime", + "dependent_var": "mean runtime", "get normalized performance": "True", "free_var": "NUM_THREADS", "legend": "Double, small", @@ -18,7 +18,7 @@ "benchmark_name": "OptionPricing", "implementation_name": "cpp_openmp", "type": "graph", - "dependent_var": "average runtime", + "dependent_var": "mean runtime", "get normalized performance": "True", "free_var": "NUM_THREADS", "legend": "Float, small", @@ -33,7 +33,7 @@ "benchmark_name": "OptionPricing", "implementation_name": "cpp_openmp", "type": "graph", - "dependent_var": "average runtime", + "dependent_var": "mean runtime", "get normalized performance": "True", "free_var": "NUM_THREADS", "legend": "Double, medium", @@ -48,7 +48,7 @@ "benchmark_name": "OptionPricing", "implementation_name": "cpp_openmp", "type": "graph", - "dependent_var": "average runtime", + "dependent_var": "mean runtime", "get normalized performance": "True", "free_var": "NUM_THREADS", "legend": "Float, medium", From f0438cd9cfcd2e823f9e12cdd1f9cb2fe94caa51 Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 30 Sep 2015 18:21:14 +0200 Subject: [PATCH 104/122] Removed sticky keyword from JSON parsing for graph generation. Each JSON now produces one figure --- hiperpret_figure_configuration_new.json | 50 ++++++++++++++++ hiperpret_figure_configuration_new2.json | 74 ++++++++++++++++++++++++ hiperpret_figure_configuration_new3.json | 26 +++++++++ hiperpret_figure_configuration_new4.json | 14 +++++ hiperpret_figure_configuration_new5.json | 26 +++++++++ run_hiperpret_OptionPricing | 10 ++++ 6 files changed, 200 insertions(+) create mode 100644 hiperpret_figure_configuration_new.json create mode 100644 hiperpret_figure_configuration_new2.json create mode 100644 hiperpret_figure_configuration_new3.json create mode 100644 hiperpret_figure_configuration_new4.json create mode 100644 hiperpret_figure_configuration_new5.json create mode 100755 run_hiperpret_OptionPricing diff --git a/hiperpret_figure_configuration_new.json b/hiperpret_figure_configuration_new.json new file mode 100644 index 0000000..c28aa35 --- /dev/null +++ b/hiperpret_figure_configuration_new.json @@ -0,0 +1,50 @@ +[ + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Double, small", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Float, small", + "locked_vars": { + "dataset_name": "small", + "REAL_TYPE": "float"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Double, medium", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Float, medium", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "float"} + } +] diff --git a/hiperpret_figure_configuration_new2.json b/hiperpret_figure_configuration_new2.json new file mode 100644 index 0000000..eb3c313 --- /dev/null +++ b/hiperpret_figure_configuration_new2.json @@ -0,0 +1,74 @@ +[ + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "legend": "Double, 32 threads", + "locked_vars": { + "NUM_THREADS": "32", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "legend": "Double, 16 threads", + "locked_vars": { + "NUM_THREADS": "16", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "legend": "Double, 8 threads", + "locked_vars": { + "NUM_THREADS": "8", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "legend": "Double, 4 threads", + "locked_vars": { + "NUM_THREADS": "4", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "legend": "Double, 2 threads", + "locked_vars": { + "NUM_THREADS": "2", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "dataset_name", + "legend": "Double, 1 threads", + "locked_vars": { + "NUM_THREADS": "1", + "REAL_TYPE": "double"} + } +] diff --git a/hiperpret_figure_configuration_new3.json b/hiperpret_figure_configuration_new3.json new file mode 100644 index 0000000..f3f832f --- /dev/null +++ b/hiperpret_figure_configuration_new3.json @@ -0,0 +1,26 @@ +[ + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "REAL_TYPE", + "legend": "32 threads, small", + "locked_vars": { + "NUM_THREADS": "32", + "dataset_name": "small"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "bar", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "REAL_TYPE", + "legend": "32 threads, medium", + "locked_vars": { + "NUM_THREADS": "32", + "dataset_name": "medium"} + } +] diff --git a/hiperpret_figure_configuration_new4.json b/hiperpret_figure_configuration_new4.json new file mode 100644 index 0000000..31b8512 --- /dev/null +++ b/hiperpret_figure_configuration_new4.json @@ -0,0 +1,14 @@ +[ + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "Real type: double, small dataset", + "locked_vars": { + "REAL_TYPE": "double", + "dataset_name": "small"} + } +] diff --git a/hiperpret_figure_configuration_new5.json b/hiperpret_figure_configuration_new5.json new file mode 100644 index 0000000..0ddfb7e --- /dev/null +++ b/hiperpret_figure_configuration_new5.json @@ -0,0 +1,26 @@ +[ + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "Double, medium", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "double"} + }, + { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "type": "graph", + "dependent_var": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "Float, medium", + "locked_vars": { + "dataset_name": "medium", + "REAL_TYPE": "float"} + } +] diff --git a/run_hiperpret_OptionPricing b/run_hiperpret_OptionPricing new file mode 100755 index 0000000..f2dff7d --- /dev/null +++ b/run_hiperpret_OptionPricing @@ -0,0 +1,10 @@ +#!/bin/bash + +clear +echo Deleting all files in ./hiperpret +echo Running Hiperpret analysis, assuming that the option pricing dataset from Napoleon is present in ./instantiations. +echo Storing analysis results in ./hiperpret +echo Expecting five config JSONs in this folder. + +rm -rf hiperpret/ +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_new.json -f hiperpret_figure_configuration_new2.json -f hiperpret_figure_configuration_new3.json -f hiperpret_figure_configuration_new4.json -f hiperpret_figure_configuration_new5.json -o ./hiperpret From 3fe06acda0ff54bc22638f9b799efd8d6e55ec86 Mon Sep 17 00:00:00 2001 From: Thor Date: Tue, 20 Oct 2015 19:50:53 +0200 Subject: [PATCH 105/122] finpar configuration files for working with underspecified hiperpret figures have been added --- hiperpret_figure_configuration.json | 73 ++++-------------- hiperpret_figure_configuration_new.json | 16 ++-- hiperpret_figure_configuration_new2.json | 74 ------------------- hiperpret_figure_configuration_new3.json | 26 ------- hiperpret_figure_configuration_new4.json | 14 ---- hiperpret_figure_configuration_new5.json | 26 ------- ...t_figure_configuration_underspecified.json | 11 +++ run_hiperpret_OptionPricing | 4 +- 8 files changed, 34 insertions(+), 210 deletions(-) delete mode 100644 hiperpret_figure_configuration_new2.json delete mode 100644 hiperpret_figure_configuration_new3.json delete mode 100644 hiperpret_figure_configuration_new4.json delete mode 100644 hiperpret_figure_configuration_new5.json create mode 100644 hiperpret_figure_configuration_underspecified.json diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json index 9dccb8c..9a79879 100644 --- a/hiperpret_figure_configuration.json +++ b/hiperpret_figure_configuration.json @@ -1,61 +1,14 @@ -[{"OptionPricing, cpp_openmp": - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Double, small", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "double"}, - "sticky": "True" - } - }, - {"OptionPricing, cpp_openmp": - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Float, small", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "float"}, - "sticky": "True" - } - }, - {"OptionPricing, cpp_openmp": - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Double, medium", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "double"}, - "sticky": "True" - } - }, - {"OptionPricing, cpp_openmp": - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Float, medium", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "float"}, - "sticky": "True" - } - } +[ + { + "type": "bar", + "dependent variable": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, medium dataset, double precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "medium", + "REAL_TYPE": "double"} + } ] diff --git a/hiperpret_figure_configuration_new.json b/hiperpret_figure_configuration_new.json index c28aa35..7a4f3eb 100644 --- a/hiperpret_figure_configuration_new.json +++ b/hiperpret_figure_configuration_new.json @@ -1,7 +1,7 @@ [ { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", + "benchmark": "OptionPricing", + "implementation": "cpp_openmp", "type": "graph", "dependent_var": "mean runtime", "get normalized performance": "True", @@ -12,8 +12,8 @@ "REAL_TYPE": "double"} }, { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", + "benchmark": "OptionPricing", + "implementation": "cpp_openmp", "type": "graph", "dependent_var": "mean runtime", "get normalized performance": "True", @@ -24,8 +24,8 @@ "REAL_TYPE": "float"} }, { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", + "benchmark": "OptionPricing", + "implementation": "cpp_openmp", "type": "graph", "dependent_var": "mean runtime", "get normalized performance": "True", @@ -36,8 +36,8 @@ "REAL_TYPE": "double"} }, { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", + "benchmark": "OptionPricing", + "implementation": "cpp_openmp", "type": "graph", "dependent_var": "mean runtime", "get normalized performance": "True", diff --git a/hiperpret_figure_configuration_new2.json b/hiperpret_figure_configuration_new2.json deleted file mode 100644 index eb3c313..0000000 --- a/hiperpret_figure_configuration_new2.json +++ /dev/null @@ -1,74 +0,0 @@ -[ - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "legend": "Double, 32 threads", - "locked_vars": { - "NUM_THREADS": "32", - "REAL_TYPE": "double"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "legend": "Double, 16 threads", - "locked_vars": { - "NUM_THREADS": "16", - "REAL_TYPE": "double"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "legend": "Double, 8 threads", - "locked_vars": { - "NUM_THREADS": "8", - "REAL_TYPE": "double"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "legend": "Double, 4 threads", - "locked_vars": { - "NUM_THREADS": "4", - "REAL_TYPE": "double"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "legend": "Double, 2 threads", - "locked_vars": { - "NUM_THREADS": "2", - "REAL_TYPE": "double"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "dataset_name", - "legend": "Double, 1 threads", - "locked_vars": { - "NUM_THREADS": "1", - "REAL_TYPE": "double"} - } -] diff --git a/hiperpret_figure_configuration_new3.json b/hiperpret_figure_configuration_new3.json deleted file mode 100644 index f3f832f..0000000 --- a/hiperpret_figure_configuration_new3.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "REAL_TYPE", - "legend": "32 threads, small", - "locked_vars": { - "NUM_THREADS": "32", - "dataset_name": "small"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "bar", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "REAL_TYPE", - "legend": "32 threads, medium", - "locked_vars": { - "NUM_THREADS": "32", - "dataset_name": "medium"} - } -] diff --git a/hiperpret_figure_configuration_new4.json b/hiperpret_figure_configuration_new4.json deleted file mode 100644 index 31b8512..0000000 --- a/hiperpret_figure_configuration_new4.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Real type: double, small dataset", - "locked_vars": { - "REAL_TYPE": "double", - "dataset_name": "small"} - } -] diff --git a/hiperpret_figure_configuration_new5.json b/hiperpret_figure_configuration_new5.json deleted file mode 100644 index 0ddfb7e..0000000 --- a/hiperpret_figure_configuration_new5.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "NUM_THREADS", - "legend": "Double, medium", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "double"} - }, - { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "False", - "free_var": "NUM_THREADS", - "legend": "Float, medium", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "float"} - } -] diff --git a/hiperpret_figure_configuration_underspecified.json b/hiperpret_figure_configuration_underspecified.json new file mode 100644 index 0000000..8eb9dae --- /dev/null +++ b/hiperpret_figure_configuration_underspecified.json @@ -0,0 +1,11 @@ +[ + { + "type": "underspecified", + "dependent variable": "mean runtime", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "medium" + } + } +] diff --git a/run_hiperpret_OptionPricing b/run_hiperpret_OptionPricing index f2dff7d..dc11773 100755 --- a/run_hiperpret_OptionPricing +++ b/run_hiperpret_OptionPricing @@ -4,7 +4,7 @@ clear echo Deleting all files in ./hiperpret echo Running Hiperpret analysis, assuming that the option pricing dataset from Napoleon is present in ./instantiations. echo Storing analysis results in ./hiperpret -echo Expecting five config JSONs in this folder. +echo Expecting one figure config JSONs in this folder. rm -rf hiperpret/ -../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_new.json -f hiperpret_figure_configuration_new2.json -f hiperpret_figure_configuration_new3.json -f hiperpret_figure_configuration_new4.json -f hiperpret_figure_configuration_new5.json -o ./hiperpret +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration.json -f hiperpret_figure_configuration_underspecified.json -o ./hiperpret From ff9b927da941d8306579f7e7d6a8e166d1ace2d8 Mon Sep 17 00:00:00 2001 From: Thor Date: Wed, 21 Oct 2015 18:36:23 +0200 Subject: [PATCH 106/122] Script for printing runtimes bar chart now handles two implementations of OptionPricing benchmark. --- ....json => hiperpret_figure_configuration_runtimes.json | 6 +++--- run_hipermark_OptionPricing_cpp_openmp_cpp_sequential | 9 +++++++++ run_hiperpret_OptionPricing | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) rename hiperpret_figure_configuration_underspecified.json => hiperpret_figure_configuration_runtimes.json (55%) create mode 100755 run_hipermark_OptionPricing_cpp_openmp_cpp_sequential diff --git a/hiperpret_figure_configuration_underspecified.json b/hiperpret_figure_configuration_runtimes.json similarity index 55% rename from hiperpret_figure_configuration_underspecified.json rename to hiperpret_figure_configuration_runtimes.json index 8eb9dae..b999af1 100644 --- a/hiperpret_figure_configuration_underspecified.json +++ b/hiperpret_figure_configuration_runtimes.json @@ -1,11 +1,11 @@ [ { - "type": "underspecified", + "type": "runtimes", "dependent variable": "mean runtime", "locked variables": { "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "dataset_name": "medium" + "dataset_name": "medium", + "NUM_THREADS": "4" } } ] diff --git a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential new file mode 100755 index 0000000..f055d26 --- /dev/null +++ b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/OptionPricing/ +echo Running hipermark OptionPricing cpp_openmp small + medium dataset, 10 times. +echo Storing all results in instantiations/ + +rm -rf instantiations/OptionPricing/ +../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_openmp,cpp_sequential small,medium diff --git a/run_hiperpret_OptionPricing b/run_hiperpret_OptionPricing index dc11773..9a32437 100755 --- a/run_hiperpret_OptionPricing +++ b/run_hiperpret_OptionPricing @@ -7,4 +7,4 @@ echo Storing analysis results in ./hiperpret echo Expecting one figure config JSONs in this folder. rm -rf hiperpret/ -../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration.json -f hiperpret_figure_configuration_underspecified.json -o ./hiperpret +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration.json -f hiperpret_figure_configuration_runtimes.json -o ./hiperpret From 8e2e50acd57c9a850955ed90640bdb704070ac6a Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 6 Nov 2015 17:24:38 +0100 Subject: [PATCH 107/122] Added dynamic compile time options for OptionPricing/cpp_opencl --- .../implementations/cpp_opencl/GenPricing.cpp | 2 +- .../implementations/cpp_opencl/Makefile | 14 ++++++++++++++ .../cpp_opencl/static_configuration_template.json | 4 +++- .../OptionPricing/lib/include/Optimizations.h | 2 -- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp index 2214ca5..5661ba4 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp @@ -179,7 +179,7 @@ int main() { { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%ld\n", elapsed_usec); fclose(runtime); write_1Darr(result, prices, scals.num_models); fclose(result); diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile index 0e574b2..ff0439a 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile @@ -10,6 +10,20 @@ include $(HIPERMARK_LIB_DIR)/setup_real_type.mk # FIXME - this should not even exist! include $(HIPERMARK_LIB_DIR)/platform.mk +# Handle Strength reduction and vectorization +ifeq ($(HIPERMARK_CONFIG_STRENGTH_REDUCTION),on) + CXXFLAGS += -D_OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR +endif +ifeq ($(HIPERMARK_CONFIG_VECTORIZATION),auto) + CXXFLAGS += -D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=0 +else ifeq ($(HIPERMARK_CONFIG_VECTORIZATION),off) + CXXFLAGS += -D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=2 +else ifeq ($(HIPERMARK_CONFIG_VECTORIZATION),on) + CXXFLAGS += -D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=1 +endif + + + INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include INCLUDES += -I$(HIPERMARK_LIB_DIR)/include diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json index 00bdffb..8433596 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json @@ -1,3 +1,5 @@ { - "REAL_TYPE" : ["float", "double"] + "REAL_TYPE" : ["float", "double"], + "STRENGTH_REDUCTION" : ["on", "off"], + "VECTORIZATION" : ["on", "off", "auto"] } diff --git a/benchmarks/OptionPricing/lib/include/Optimizations.h b/benchmarks/OptionPricing/lib/include/Optimizations.h index bf04f3a..944a03a 100644 --- a/benchmarks/OptionPricing/lib/include/Optimizations.h +++ b/benchmarks/OptionPricing/lib/include/Optimizations.h @@ -1,8 +1,6 @@ #ifndef OPTIMISATIONS #define OPTIMISATIONS -#define _OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV 0 // cost model: 0, vectorized: 1, privatized: 2 -#define _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR #define _OPTIMIZATION_MEM_COALES_ON #endif // OPTIMISATIONS From ea0eb0e7e1a5b238e230e673c21a78fea1717f93 Mon Sep 17 00:00:00 2001 From: Thor Date: Fri, 6 Nov 2015 18:12:41 +0100 Subject: [PATCH 108/122] Editing source code cpp_opencl for vectorization stuff --- .../implementations/cpp_opencl/GenPricing.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp index 5661ba4..84a8e7f 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp @@ -49,9 +49,23 @@ run_GPUkernel ( { // build the OpenCL program const char* preamble = makeGPUprogPreamble( ro_scal, kernel_type ); char compile_opts[1024]; - sprintf( compile_opts, "-D lgWARP=%d -D TILE=%d -D%s -I%s/include -I%s/include -I%s", +#ifdef _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR +#define STRENGTH_RED_FLAG "-D_OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR" +#else +#define STRENGTH_RED_FLAG "" +#endif +#if (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 0) +#define VECT_FLAG "-D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=0" +#elif (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 1) +#define VECT_FLAG "-D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=1" +#elif (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 2) +#define VECT_FLAG "-D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=2" +#endif + + sprintf( compile_opts, "-D lgWARP=%d -D TILE=%d -D%s %s -I%s/include -I%s/include -I%s", lgWARP, TILE, REAL_FLAG, + STRENGTH_RED_FLAG, HIPERMARK_BENCHMARK_LIB_DIR, HIPERMARK_LIB_DIR, HIPERMARK_IMPLEMENTATION_DIR); From b91d7deedcba7d374f63b214b8c73064f2bd1e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 8 Nov 2015 02:14:19 +0100 Subject: [PATCH 109/122] Better scripts and better graph definition files --- .../implementations/cpp_opencl/Makefile | 2 +- hiperpret_figure_configuration.json | 14 ----- ...guration_graph_OptionPricing_runtimes.json | 50 ++++++++++++++++++ ...iguration_graph_OptionPricing_speedup.json | 51 +++++++++++++++++++ hiperpret_figure_configuration_new.json | 50 ------------------ ...iguration_runtimes_OptionPricing_both.json | 9 ++++ ...guration_runtimes_OptionPricing_small.json | 3 +- run_hipermark_OptionPricing_cpp_opencl | 9 ++++ ... => run_hipermark_OptionPricing_cpp_openmp | 4 +- ...rk_OptionPricing_cpp_openmp_cpp_sequential | 4 +- run_hiperpret_OptionPricing | 6 +-- 11 files changed, 128 insertions(+), 74 deletions(-) delete mode 100644 hiperpret_figure_configuration.json create mode 100644 hiperpret_figure_configuration_graph_OptionPricing_runtimes.json create mode 100644 hiperpret_figure_configuration_graph_OptionPricing_speedup.json delete mode 100644 hiperpret_figure_configuration_new.json create mode 100644 hiperpret_figure_configuration_runtimes_OptionPricing_both.json rename hiperpret_figure_configuration_runtimes.json => hiperpret_figure_configuration_runtimes_OptionPricing_small.json (71%) create mode 100755 run_hipermark_OptionPricing_cpp_opencl rename run_hipermark_OptionPricing => run_hipermark_OptionPricing_cpp_openmp (63%) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile index ff0439a..966bbaa 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile @@ -31,7 +31,7 @@ GPU_OPTS = -D lgWARP=$(GPU_LG_WARP) -D GPU_DEV_ID=$(GPU_DEVICE_ID) \ -D GPU_LOC_MEM=$(GPU_LOCAL_MEM) -D GPU_CONST_MEM=$(GPU_CONST_MEM) \ -D GPU_REG_MEM=$(GPU_REG_MEM) -D GPU_GLB_MEM=$(GPU_DEVICE_MEM) \ -D GPU_TILE=$(GPU_LOCAL_MEM_PER_TH) -D GPU_CORES=$(GPU_NUM_CORES) \ - -D CURR_DIR_PATH='"$(MAKE_DIR)"' + -D CURR_DIR_PATH='"$(MAKE_DIR)"' SOURCES_CPP =GenPricing.cpp HELPERS =$(HIPERMARK_BENCHMARK_LIB_DIR)/include/ParseInput.h diff --git a/hiperpret_figure_configuration.json b/hiperpret_figure_configuration.json deleted file mode 100644 index 9a79879..0000000 --- a/hiperpret_figure_configuration.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "type": "bar", - "dependent variable": "mean runtime", - "get normalized performance": "False", - "free_var": "NUM_THREADS", - "legend": "OptionPricing, cpp_openmp, medium dataset, double precision", - "locked variables": { - "benchmark_name": "OptionPricing", - "implementation_name": "cpp_openmp", - "dataset_name": "medium", - "REAL_TYPE": "double"} - } -] diff --git a/hiperpret_figure_configuration_graph_OptionPricing_runtimes.json b/hiperpret_figure_configuration_graph_OptionPricing_runtimes.json new file mode 100644 index 0000000..e3c4e95 --- /dev/null +++ b/hiperpret_figure_configuration_graph_OptionPricing_runtimes.json @@ -0,0 +1,50 @@ +[ + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, small dataset, double precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "small", + "REAL_TYPE": "double"} + }, + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, small dataset, float precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "small", + "REAL_TYPE": "float"} + }, + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, medium dataset, double precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "medium", + "REAL_TYPE": "double"} + }, + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "False", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, medium dataset, float precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "medium", + "REAL_TYPE": "float"} + } +] diff --git a/hiperpret_figure_configuration_graph_OptionPricing_speedup.json b/hiperpret_figure_configuration_graph_OptionPricing_speedup.json new file mode 100644 index 0000000..c22070e --- /dev/null +++ b/hiperpret_figure_configuration_graph_OptionPricing_speedup.json @@ -0,0 +1,51 @@ +[ + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, small dataset, double precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "small", + "REAL_TYPE": "double"} + }, + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, small dataset, float precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "small", + "REAL_TYPE": "float"} + }, + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, medium dataset, double precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "medium", + "REAL_TYPE": "double"} + }, + { + "type": "graph", + "dependent variable": "mean runtime", + "get normalized performance": "True", + "free_var": "NUM_THREADS", + "legend": "OptionPricing, cpp_openmp, medium dataset, float precision", + "locked variables": { + "benchmark_name": "OptionPricing", + "implementation_name": "cpp_openmp", + "dataset_name": "medium", + "REAL_TYPE": "float"} + } + +] diff --git a/hiperpret_figure_configuration_new.json b/hiperpret_figure_configuration_new.json deleted file mode 100644 index 7a4f3eb..0000000 --- a/hiperpret_figure_configuration_new.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "benchmark": "OptionPricing", - "implementation": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Double, small", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "double"} - }, - { - "benchmark": "OptionPricing", - "implementation": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Float, small", - "locked_vars": { - "dataset_name": "small", - "REAL_TYPE": "float"} - }, - { - "benchmark": "OptionPricing", - "implementation": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Double, medium", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "double"} - }, - { - "benchmark": "OptionPricing", - "implementation": "cpp_openmp", - "type": "graph", - "dependent_var": "mean runtime", - "get normalized performance": "True", - "free_var": "NUM_THREADS", - "legend": "Float, medium", - "locked_vars": { - "dataset_name": "medium", - "REAL_TYPE": "float"} - } -] diff --git a/hiperpret_figure_configuration_runtimes_OptionPricing_both.json b/hiperpret_figure_configuration_runtimes_OptionPricing_both.json new file mode 100644 index 0000000..c152338 --- /dev/null +++ b/hiperpret_figure_configuration_runtimes_OptionPricing_both.json @@ -0,0 +1,9 @@ +[ + { + "type": "runtimes", + "dependent variable": "mean runtime", + "locked variables": { + "benchmark_name": "OptionPricing" + } + } +] diff --git a/hiperpret_figure_configuration_runtimes.json b/hiperpret_figure_configuration_runtimes_OptionPricing_small.json similarity index 71% rename from hiperpret_figure_configuration_runtimes.json rename to hiperpret_figure_configuration_runtimes_OptionPricing_small.json index b999af1..0d94aa9 100644 --- a/hiperpret_figure_configuration_runtimes.json +++ b/hiperpret_figure_configuration_runtimes_OptionPricing_small.json @@ -4,8 +4,7 @@ "dependent variable": "mean runtime", "locked variables": { "benchmark_name": "OptionPricing", - "dataset_name": "medium", - "NUM_THREADS": "4" + "dataset_name": "small" } } ] diff --git a/run_hipermark_OptionPricing_cpp_opencl b/run_hipermark_OptionPricing_cpp_opencl new file mode 100755 index 0000000..02602ab --- /dev/null +++ b/run_hipermark_OptionPricing_cpp_opencl @@ -0,0 +1,9 @@ +#!/bin/bash + +clear +echo Deleting all files in instantiations/OptionPricing/ +echo Running hipermark OptionPricing cpp_sequential and cpp_opencl small dataset, 4 times. +echo Storing all results in instantiations/ + +rm -rf instantiations/OptionPricing/ +../hipermark/hipermark instantiations/ 4 benchmarks/OptionPricing cpp_sequential,cpp_opencl small diff --git a/run_hipermark_OptionPricing b/run_hipermark_OptionPricing_cpp_openmp similarity index 63% rename from run_hipermark_OptionPricing rename to run_hipermark_OptionPricing_cpp_openmp index e613272..74ba4c2 100755 --- a/run_hipermark_OptionPricing +++ b/run_hipermark_OptionPricing_cpp_openmp @@ -2,8 +2,8 @@ clear echo Deleting all files in instantiations/OptionPricing/ -echo Running hipermark OptionPricing cpp_openmp small + medium dataset, 10 times. +echo Running hipermark OptionPricing cpp_sequential and cpp_openmp small dataset, 10 times. echo Storing all results in instantiations/ rm -rf instantiations/OptionPricing/ -../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_openmp small,medium +../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_sequential,cpp_openmp small diff --git a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential index f055d26..7e0ef4f 100755 --- a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential +++ b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential @@ -2,8 +2,8 @@ clear echo Deleting all files in instantiations/OptionPricing/ -echo Running hipermark OptionPricing cpp_openmp small + medium dataset, 10 times. +echo Running hipermark OptionPricing cpp_sequential and cpp_openmp small and medium dataset, 10 times. echo Storing all results in instantiations/ rm -rf instantiations/OptionPricing/ -../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_openmp,cpp_sequential small,medium +../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_sequential,cpp_openmp small,medium diff --git a/run_hiperpret_OptionPricing b/run_hiperpret_OptionPricing index 9a32437..944e760 100755 --- a/run_hiperpret_OptionPricing +++ b/run_hiperpret_OptionPricing @@ -2,9 +2,9 @@ clear echo Deleting all files in ./hiperpret -echo Running Hiperpret analysis, assuming that the option pricing dataset from Napoleon is present in ./instantiations. +echo Running Hiperpret analysis, assuming that hiperMARK output data is present in ./instantiations. echo Storing analysis results in ./hiperpret -echo Expecting one figure config JSONs in this folder. +echo Expecting one figure configs JSONs in this folder. rm -rf hiperpret/ -../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration.json -f hiperpret_figure_configuration_runtimes.json -o ./hiperpret +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_runtimes_OptionPricing_small.json -f hiperpret_figure_configuration_runtimes_OptionPricing_both.json -f hiperpret_figure_configuration_graph_OptionPricing_speedup.json -f hiperpret_figure_configuration_graph_OptionPricing_runtimes.json -o ./hiperpret From 107ed047b9dc8b6970b8526a9561334d81327514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 8 Nov 2015 02:52:47 +0100 Subject: [PATCH 110/122] Added script for running HIPERpret on OpenCL output --- run_hiperpret_OptionPricing_cpp_opencl | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 run_hiperpret_OptionPricing_cpp_opencl diff --git a/run_hiperpret_OptionPricing_cpp_opencl b/run_hiperpret_OptionPricing_cpp_opencl new file mode 100755 index 0000000..db57b75 --- /dev/null +++ b/run_hiperpret_OptionPricing_cpp_opencl @@ -0,0 +1,10 @@ +#!/bin/bash + +clear +echo Deleting all files in ./hiperpret +echo Running Hiperpret analysis, assuming that hiperMARK output data is present in ./instantiations. +echo Storing analysis results in ./hiperpret +echo Expecting one figure configs JSONs in this folder. + +rm -rf hiperpret/ +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_runtimes_OptionPricing_both.json -o ./hiperpret From 0acd9274ae9f5b8ad2fc032ac4ec32e4607868b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 8 Nov 2015 02:58:28 +0100 Subject: [PATCH 111/122] Better runtime bar diagrams for OpenCL runs --- ...ure_configuration_runtimes_OptionPricing_large.json | 10 ++++++++++ ...re_configuration_runtimes_OptionPricing_medium.json | 10 ++++++++++ run_hiperpret_OptionPricing_cpp_opencl | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 hiperpret_figure_configuration_runtimes_OptionPricing_large.json create mode 100644 hiperpret_figure_configuration_runtimes_OptionPricing_medium.json diff --git a/hiperpret_figure_configuration_runtimes_OptionPricing_large.json b/hiperpret_figure_configuration_runtimes_OptionPricing_large.json new file mode 100644 index 0000000..e5bc955 --- /dev/null +++ b/hiperpret_figure_configuration_runtimes_OptionPricing_large.json @@ -0,0 +1,10 @@ +[ + { + "type": "runtimes", + "dependent variable": "mean runtime", + "locked variables": { + "benchmark_name": "OptionPricing", + "dataset_name": "large" + } + } +] diff --git a/hiperpret_figure_configuration_runtimes_OptionPricing_medium.json b/hiperpret_figure_configuration_runtimes_OptionPricing_medium.json new file mode 100644 index 0000000..1492ae5 --- /dev/null +++ b/hiperpret_figure_configuration_runtimes_OptionPricing_medium.json @@ -0,0 +1,10 @@ +[ + { + "type": "runtimes", + "dependent variable": "mean runtime", + "locked variables": { + "benchmark_name": "OptionPricing", + "dataset_name": "medium" + } + } +] diff --git a/run_hiperpret_OptionPricing_cpp_opencl b/run_hiperpret_OptionPricing_cpp_opencl index db57b75..0b556d1 100755 --- a/run_hiperpret_OptionPricing_cpp_opencl +++ b/run_hiperpret_OptionPricing_cpp_opencl @@ -7,4 +7,4 @@ echo Storing analysis results in ./hiperpret echo Expecting one figure configs JSONs in this folder. rm -rf hiperpret/ -../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_runtimes_OptionPricing_both.json -o ./hiperpret +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_runtimes_OptionPricing_small.json -f hiperpret_figure_configuration_runtimes_OptionPricing_medium.json -f hiperpret_figure_configuration_runtimes_OptionPricing_large.json -o ./hiperpret From 5d8f0ce321e2f9217579d3c917c141643cab1987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 8 Nov 2015 05:09:32 +0100 Subject: [PATCH 112/122] Changed scripts to handle new input format for HIPERmark --- ...et_figure_configuration_runtimes_InterestCalib.json | 10 ++++++++++ run_hipermark_InterestCalib | 2 +- run_hipermark_LocVolCalib | 2 +- run_hipermark_OptionPricing_cpp_opencl | 2 +- run_hipermark_OptionPricing_cpp_openmp | 9 --------- run_hipermark_OptionPricing_cpp_openmp_cpp_sequential | 5 +++-- run_hiperpret_InterestCalib_cpp_openmp | 10 ++++++++++ 7 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 hiperpret_figure_configuration_runtimes_InterestCalib.json delete mode 100755 run_hipermark_OptionPricing_cpp_openmp create mode 100755 run_hiperpret_InterestCalib_cpp_openmp diff --git a/hiperpret_figure_configuration_runtimes_InterestCalib.json b/hiperpret_figure_configuration_runtimes_InterestCalib.json new file mode 100644 index 0000000..11dfca9 --- /dev/null +++ b/hiperpret_figure_configuration_runtimes_InterestCalib.json @@ -0,0 +1,10 @@ +[ + { + "type": "runtimes", + "dependent variable": "mean runtime", + "locked variables": { + "benchmark_name": "InterestCalib", + "dataset_name": "small" + } + } +] diff --git a/run_hipermark_InterestCalib b/run_hipermark_InterestCalib index 74ef13a..37aea67 100755 --- a/run_hipermark_InterestCalib +++ b/run_hipermark_InterestCalib @@ -6,4 +6,4 @@ echo Running hipermark InterestCalib cpp_openmp small dataset, 2 times. echo Storing all results in instantiations/ rm -rf instantiations/InterestCalib -../hipermark/hipermark instantiations/ 2 benchmarks/InterestCalib cpp_openmp small +../hipermark/hipermark -o instantiations/ -n 2 -b benchmarks/InterestCalib -m cpp_openmp -d small diff --git a/run_hipermark_LocVolCalib b/run_hipermark_LocVolCalib index b79e650..e23fef6 100755 --- a/run_hipermark_LocVolCalib +++ b/run_hipermark_LocVolCalib @@ -6,4 +6,4 @@ echo Running hipermark LocVolCalib cpp_openmp_naive + cpp_sequential medium data echo Storing all results in instantiations/ rm -rf instantiations/LocVolCalib -../hipermark/hipermark instantiations/ 2 benchmarks/LocVolCalib cpp_openmp_naive,cpp_sequential medium +../hipermark/hipermark -o instantiations/ -n 2 -b benchmarks/LocVolCalib -m cpp_openmp_naive -m cpp_sequential -d medium diff --git a/run_hipermark_OptionPricing_cpp_opencl b/run_hipermark_OptionPricing_cpp_opencl index 02602ab..a87e3d9 100755 --- a/run_hipermark_OptionPricing_cpp_opencl +++ b/run_hipermark_OptionPricing_cpp_opencl @@ -6,4 +6,4 @@ echo Running hipermark OptionPricing cpp_sequential and cpp_opencl small dataset echo Storing all results in instantiations/ rm -rf instantiations/OptionPricing/ -../hipermark/hipermark instantiations/ 4 benchmarks/OptionPricing cpp_sequential,cpp_opencl small +../hipermark/hipermark -o instantiations/ -n 4 -b benchmarks/OptionPricing -m cpp_sequential -m cpp_opencl -d small diff --git a/run_hipermark_OptionPricing_cpp_openmp b/run_hipermark_OptionPricing_cpp_openmp deleted file mode 100755 index 74ba4c2..0000000 --- a/run_hipermark_OptionPricing_cpp_openmp +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -clear -echo Deleting all files in instantiations/OptionPricing/ -echo Running hipermark OptionPricing cpp_sequential and cpp_openmp small dataset, 10 times. -echo Storing all results in instantiations/ - -rm -rf instantiations/OptionPricing/ -../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_sequential,cpp_openmp small diff --git a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential index 7e0ef4f..08b1783 100755 --- a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential +++ b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential @@ -2,8 +2,9 @@ clear echo Deleting all files in instantiations/OptionPricing/ -echo Running hipermark OptionPricing cpp_sequential and cpp_openmp small and medium dataset, 10 times. +echo Running hipermark OptionPricing cpp_sequential and cpp_openmp small dataset, 10 times. echo Storing all results in instantiations/ rm -rf instantiations/OptionPricing/ -../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_sequential,cpp_openmp small,medium +#../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_sequential,cpp_openmp small +../hipermark/hipermark -o instantiations/ -n 10 -b benchmarks/OptionPricing -m cpp_sequential -m cpp_openmp -d small -d medium diff --git a/run_hiperpret_InterestCalib_cpp_openmp b/run_hiperpret_InterestCalib_cpp_openmp new file mode 100755 index 0000000..6d0b50d --- /dev/null +++ b/run_hiperpret_InterestCalib_cpp_openmp @@ -0,0 +1,10 @@ +#!/bin/bash + +clear +echo Deleting all files in ./hiperpret +echo Running Hiperpret analysis, assuming that hiperMARK output data is present in ./instantiations. +echo Storing analysis results in ./hiperpret +echo Expecting one figure configs JSONs in this folder. + +rm -rf hiperpret/ +../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_runtimes_InterestCalib.json -o ./hiperpret From a0f7d9800158d52f106bf4fce02c8d8fa8ebcbf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorkil=20V=C3=A6rge?= Date: Sun, 8 Nov 2015 05:20:12 +0100 Subject: [PATCH 113/122] script --- run_hipermark_OptionPricing_cpp_openmp_cpp_sequential | 1 - 1 file changed, 1 deletion(-) diff --git a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential index 08b1783..0684ef1 100755 --- a/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential +++ b/run_hipermark_OptionPricing_cpp_openmp_cpp_sequential @@ -6,5 +6,4 @@ echo Running hipermark OptionPricing cpp_sequential and cpp_openmp small dataset echo Storing all results in instantiations/ rm -rf instantiations/OptionPricing/ -#../hipermark/hipermark instantiations/ 10 benchmarks/OptionPricing cpp_sequential,cpp_openmp small ../hipermark/hipermark -o instantiations/ -n 10 -b benchmarks/OptionPricing -m cpp_sequential -m cpp_openmp -d small -d medium From 34a62b7d9dc9a156a64a065894fec6d083972657 Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 10 Nov 2015 12:44:27 +0100 Subject: [PATCH 114/122] We measure microseconds now. --- .../OptionPricing/implementations/cpp_openmp/GenPricing.cpp | 2 +- .../implementations/cpp_sequential/GenPricing.cpp | 2 +- .../OptionPricing/implementations/haskell_lh/GenPricing.hs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp index 7d6695f..4f8fcc4 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp @@ -171,7 +171,7 @@ int main() { { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); write_1Darr(result, prices, scals.num_models); fclose(result); diff --git a/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp index e52d301..d3bca2e 100644 --- a/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_sequential/GenPricing.cpp @@ -140,7 +140,7 @@ int main() { { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); write_1Darr(result, prices, scals.num_models); fclose(result); diff --git a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs index 1d76f64..3d52d4c 100644 --- a/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs +++ b/benchmarks/OptionPricing/implementations/haskell_lh/GenPricing.hs @@ -483,9 +483,9 @@ main = do s <- getContents md_discts bb_inds bb_data return $ do - start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + start <- getCPUTime -- In picoseconds; 1 microsecond == 10^6 picoseconds. end <- v `deepseq` getCPUTime - return (v, (end - start) `div` 1000000000) + return (v, (end - start) `div` 1000000) readInt2d = readArray $ readArray readInt From 8c62fc84366b0250ac7c1b4423c4e9e0a2056bec Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 10 Nov 2015 12:44:45 +0100 Subject: [PATCH 115/122] Do not touch! --- lib/setup.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/setup.mk b/lib/setup.mk index 2e16dcb..18b3012 100644 --- a/lib/setup.mk +++ b/lib/setup.mk @@ -1,6 +1,6 @@ # If we are run from outside Hipermark itself, a number of environment # variables will be missing. Set these to hopefully-working values to -# support standalone compilation. +# support standalone compilation. Users should not need to modify this. HIPERMARK_BENCHMARK_LIB_DIR ?= ../../lib/ HIPERMARK_IMPLEMENTATION_DIR ?= . @@ -24,6 +24,7 @@ else INCLUDES = -I$(OPENCL_INCDIR) -I. -I../../include endif +# Users should not modify this. CXXFLAGS += -DHIPERMARK_IMPLEMENTATION_DIR='"$(HIPERMARK_IMPLEMENTATION_DIR)"' CXXFLAGS += -DHIPERMARK_BENCHMARK_LIB_DIR='"$(HIPERMARK_BENCHMARK_LIB_DIR)"' CXXFLAGS += -DHIPERMARK_LIB_DIR='"$(HIPERMARK_LIB_DIR)"' From 281e5cf22893f982aaf0ad6e216a0b52b98a75ff Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 10 Nov 2015 12:45:55 +0100 Subject: [PATCH 116/122] Measure InterestCalib runtimes in microseconds. --- .../InterestCalib/implementations/cpp_opencl/SwapCalib.cpp | 2 +- .../InterestCalib/implementations/cpp_openmp/SwapCalib.cpp | 2 +- .../implementations/cpp_sequential/SwapCalib.cpp | 2 +- .../InterestCalib/implementations/haskell_lh/SwapCalib.hs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp index 7bdd251..652de3a 100644 --- a/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp +++ b/benchmarks/InterestCalib/implementations/cpp_opencl/SwapCalib.cpp @@ -45,7 +45,7 @@ int main() FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); const int Ps = get_CPU_num_threads(); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); writeResult(result, diff --git a/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp index 192c7e2..34487f9 100644 --- a/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp +++ b/benchmarks/InterestCalib/implementations/cpp_openmp/SwapCalib.cpp @@ -44,7 +44,7 @@ int main() FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); const int Ps = get_CPU_num_threads(); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); writeResult(result, diff --git a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp index b29ba4e..3d73a87 100644 --- a/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp +++ b/benchmarks/InterestCalib/implementations/cpp_sequential/SwapCalib.cpp @@ -42,7 +42,7 @@ int main() FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); const int Ps = get_CPU_num_threads(); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); writeResult(result, diff --git a/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs b/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs index 3cc1f53..9121592 100644 --- a/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs +++ b/benchmarks/InterestCalib/implementations/haskell_lh/SwapCalib.hs @@ -247,10 +247,10 @@ main = do s <- getContents hermite_coeffs hermite_weights (V.fromList sobol_dir_vct) return $ do - start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + start <- getCPUTime -- In picoseconds; 1 microsecond == 10^6 picoseconds. let v = (win_genome, win_logLik, win_swap_arr) end <- v `deepseq` getCPUTime - return (v, (end - start) `div` 1000000000) + return (v, (end - start) `div` 1000000) readInt1d = readArray readInt readDouble1d = readArray readDouble From 26e2a511158f15ecba7c57dd502eb616879dc56a Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 10 Nov 2015 12:47:01 +0100 Subject: [PATCH 117/122] Measure LocVolCalib runtimes in microseconds. --- .../implementations/cpp_openclmp_all/VolCalibAll.cpp | 2 +- .../implementations/cpp_openclmp_outer/VolCalibOuter.cpp | 2 +- .../implementations/cpp_openmp_naive/VolCalibOrig.cpp | 2 +- .../implementations/cpp_sequential/VolCalibOrig.cpp | 2 +- benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp index 93c2320..e5a5ac5 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_all/VolCalibAll.cpp @@ -152,7 +152,7 @@ int main() { { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); write_1Darr(result, res, OUTER_LOOP_COUNT); fclose(result); diff --git a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp index 436e5ec..8c8021a 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp +++ b/benchmarks/LocVolCalib/implementations/cpp_openclmp_outer/VolCalibOuter.cpp @@ -154,7 +154,7 @@ int main() { { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); write_1Darr(result, res, OUTER_LOOP_COUNT); fclose(result); diff --git a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp index cf3381b..85b68b6 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp +++ b/benchmarks/LocVolCalib/implementations/cpp_openmp_naive/VolCalibOrig.cpp @@ -339,7 +339,7 @@ int main() { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); write_1Darr(result, res.data(), OUTER_LOOP_COUNT); fclose(result); diff --git a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp index 657f8bf..dadbebc 100644 --- a/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp +++ b/benchmarks/LocVolCalib/implementations/cpp_sequential/VolCalibOrig.cpp @@ -307,7 +307,7 @@ int main() { FILE* runtime = fopen(getenv("HIPERMARK_RUNTIME"), "w"); FILE* result = fopen(getenv("HIPERMARK_RESULT"), "w"); - fprintf(runtime, "%d\n", elapsed_usec / 1000); + fprintf(runtime, "%d\n", elapsed_usec); fclose(runtime); write_1Darr(result, res.data(), OUTER_LOOP_COUNT); fclose(result); diff --git a/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs b/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs index 8068470..f59dd8b 100644 --- a/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs +++ b/benchmarks/LocVolCalib/implementations/haskell_lh/VolCalib.hs @@ -435,10 +435,10 @@ main = do s <- getContents let params = (0.03, 5.0, 0.2, 0.6, 0.5) --(s0, t, alpha, nu, beta) return $ do - start <- getCPUTime -- In picoseconds; 1 millisecond == 10^9 picoseconds. + start <- getCPUTime -- In picoseconds; 1 microsecond == 10^6 picoseconds. let v = compute (outer, num_x, num_y, num_t) params end <- v `deepseq` getCPUTime - return (v, (end - start) `div` 1000000000) + return (v, (end - start) `div` 1000000) -- ghc -O2 -msse2 -rtsopts PricingLexiFi.hs -- ./PricingLexiFi +RTS -K128m -RTS < ../Data/Medium/input.data From 693e02bd7084002327b41fc438c1798bf2c4ee2c Mon Sep 17 00:00:00 2001 From: Troels Henriksen Date: Tue, 10 Nov 2015 14:28:43 +0100 Subject: [PATCH 118/122] Add missing initialisation. --- benchmarks/OptionPricing/lib/include/ParseInput.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/OptionPricing/lib/include/ParseInput.h b/benchmarks/OptionPricing/lib/include/ParseInput.h index f18f317..f7ec5f6 100644 --- a/benchmarks/OptionPricing/lib/include/ParseInput.h +++ b/benchmarks/OptionPricing/lib/include/ParseInput.h @@ -135,7 +135,7 @@ void readDataSet( LoopROScalars& scals, SobolArrays& sob_arrs, } sob_arrs.sobol_fix_ind = (UCHAR*) (sob_arrs.sobol_dirvcts + sob_dim * scals.sobol_bits); - for ( int j; j < (1< Date: Tue, 10 Nov 2015 14:55:12 +0100 Subject: [PATCH 119/122] ULONG does not exist anymore. --- .../implementations/cpp_opencl/GenericPricingVectUncoalesced.cl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl index e1f2867..eb57c90 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenericPricingVectUncoalesced.cl @@ -204,7 +204,7 @@ __kernel void mlfi_brownianbridge_wiener_path1( __constant int *bb_li, *bb_bi, *bb_ri; __constant real_t *bb_rw, *bb_lw, *bb_sd; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; UINT m, i, md_dim = ro_scal->num_under, nb_path_dates = ro_scal->num_dates; UINT sobol_dim = ro_scal->num_under * nb_path_dates; From a3e2728c56adb10ea9e5a93efa8ac37c31357658 Mon Sep 17 00:00:00 2001 From: Cosmin Oancea Date: Tue, 10 Nov 2015 18:41:10 +0100 Subject: [PATCH 120/122] small changes, adding option for memory coalesced or not --- benchmarks/OptionPricing/implementations/cpp_opencl/Makefile | 4 +++- .../cpp_opencl/static_configuration_template.json | 5 +++-- .../cpp_openmp/dynamic_configuration_template.json | 2 +- benchmarks/OptionPricing/lib/include/Optimizations.h | 2 +- run_hipermark_OptionPricing_cpp_opencl | 2 +- run_hiperpret_OptionPricing_cpp_opencl | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile index 966bbaa..20c916a 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/Makefile @@ -22,7 +22,9 @@ else ifeq ($(HIPERMARK_CONFIG_VECTORIZATION),on) CXXFLAGS += -D_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV=1 endif - +ifeq ($(HIPERMARK_CONFIG_MEM_COALESCING),on) + CXXFLAGS += -D_OPTIMIZATION_MEM_COALES_ON +endif INCLUDES += -I$(HIPERMARK_BENCHMARK_LIB_DIR)/include INCLUDES += -I$(HIPERMARK_LIB_DIR)/include diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json index 8433596..13d98fe 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/static_configuration_template.json @@ -1,5 +1,6 @@ { - "REAL_TYPE" : ["float", "double"], + "REAL_TYPE" : ["float"], "STRENGTH_REDUCTION" : ["on", "off"], - "VECTORIZATION" : ["on", "off", "auto"] + "VECTORIZATION" : ["on", "off"], + "MEM_COALESCING" : ["on", "off"] } diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json b/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json index 713ae01..8276926 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/dynamic_configuration_template.json @@ -1 +1 @@ -{ "NUM_THREADS": "ncpus" } +{ "NUM_THREADS": ["4", "8", "12", "16", "32"] } diff --git a/benchmarks/OptionPricing/lib/include/Optimizations.h b/benchmarks/OptionPricing/lib/include/Optimizations.h index 944a03a..db6369f 100644 --- a/benchmarks/OptionPricing/lib/include/Optimizations.h +++ b/benchmarks/OptionPricing/lib/include/Optimizations.h @@ -1,7 +1,7 @@ #ifndef OPTIMISATIONS #define OPTIMISATIONS -#define _OPTIMIZATION_MEM_COALES_ON +//#define _OPTIMIZATION_MEM_COALES_ON #endif // OPTIMISATIONS diff --git a/run_hipermark_OptionPricing_cpp_opencl b/run_hipermark_OptionPricing_cpp_opencl index a87e3d9..4dd7d65 100755 --- a/run_hipermark_OptionPricing_cpp_opencl +++ b/run_hipermark_OptionPricing_cpp_opencl @@ -6,4 +6,4 @@ echo Running hipermark OptionPricing cpp_sequential and cpp_opencl small dataset echo Storing all results in instantiations/ rm -rf instantiations/OptionPricing/ -../hipermark/hipermark -o instantiations/ -n 4 -b benchmarks/OptionPricing -m cpp_sequential -m cpp_opencl -d small +../hipermark/hipermark -o instantiations/ -n 30 -b benchmarks/OptionPricing -m cpp_opencl -m cpp_sequential -m cpp_openmp -d small -d medium -d large diff --git a/run_hiperpret_OptionPricing_cpp_opencl b/run_hiperpret_OptionPricing_cpp_opencl index 0b556d1..c972bea 100755 --- a/run_hiperpret_OptionPricing_cpp_opencl +++ b/run_hiperpret_OptionPricing_cpp_opencl @@ -7,4 +7,4 @@ echo Storing analysis results in ./hiperpret echo Expecting one figure configs JSONs in this folder. rm -rf hiperpret/ -../hipermark/hiperpret -i ./instantiations/ -f hiperpret_figure_configuration_runtimes_OptionPricing_small.json -f hiperpret_figure_configuration_runtimes_OptionPricing_medium.json -f hiperpret_figure_configuration_runtimes_OptionPricing_large.json -o ./hiperpret +../hipermark/hiperpret -i ./instantiations/ -o ./hiperpret From a0a04ef4595b6795037863d6e1744254cfc634a1 Mon Sep 17 00:00:00 2001 From: Cosmin Oancea Date: Tue, 10 Nov 2015 20:56:21 +0100 Subject: [PATCH 121/122] various fixes --- .../implementations/cpp_opencl/GenPricing.cpp | 26 ++++++++++++++----- .../GenericPricingVectUncoalesced.cl | 4 +-- .../implementations/cpp_opencl/StructGPU.h | 13 ++++++++-- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp index 84a8e7f..51fe52f 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/GenPricing.cpp @@ -73,9 +73,6 @@ run_GPUkernel ( cdDevices, cpProgram, GPU_DEV_ID, compile_opts, preamble, kernel_filename ); } - // we do not measure the just-in-time compilation time! - struct timeval t_start, t_end, t_diff; - gettimeofday(&t_start, NULL); { num_cores = discriminate_cost_model(ro_scal, cdDevices[GPU_DEV_ID], kernel_type); @@ -86,6 +83,21 @@ run_GPUkernel ( } oclLoopArrays ocl_arrs; + { // allocate RO scalars + cl_int ciErr2; + ocl_arrs.ro_scals = clCreateBuffer( + cxGPUContext, CL_MEM_READ_ONLY, sizeof(LoopROScalars), NULL, &ciErr2 + ); + ciErr2 |= clEnqueueWriteBuffer(cqCommandQueue[GPU_DEV_ID], ocl_arrs.ro_scals, CL_TRUE, 0, + sizeof(LoopROScalars), &ro_scal, 0, NULL, NULL); + oclCheckError(ciErr2, CL_SUCCESS); + clFinish(cqCommandQueue[GPU_DEV_ID]); + } + + // we do not measure the just-in-time compilation time! + struct timeval t_start, t_end, t_diff; + gettimeofday(&t_start, NULL); + if(kernel_type == PRIV) { // CALL THE PRIVATE KERNEL glb_vhat = oclAllocArrays_PrivKernel( ocl_arrs, cxGPUContext, cqCommandQueue[GPU_DEV_ID], @@ -137,14 +149,14 @@ run_GPUkernel ( ro_scal.sobol_count_ini = sob_ini_count; } - for(UINT ii = 0; iinum_under; UINT dim_sq = dim*dim; UINT dim_paths = dim*ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; UINT UB = (cur_it+(1<log_chunk) < ro_scal->num_gpuits) ? cur_it + (1<log_chunk) : ro_scal->num_gpuits; @@ -360,7 +360,7 @@ __kernel void mlfi_reduction_step1( UINT j; uint block_size = get_local_size(0); int sobol_dim = ro_scal->num_under * ro_scal->num_dates; - ULONG cur_it = get_global_id (0) << ro_scal->log_chunk; + unsigned long cur_it = get_global_id (0) << ro_scal->log_chunk; //UINT UB = min(cur_it + (1<log_chunk), ro_scal->num_gpuits); UINT UB = ( cur_it + (1<log_chunk) < ro_scal->num_gpuits) ? diff --git a/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h b/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h index eb62f2c..b7624d5 100644 --- a/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h +++ b/benchmarks/OptionPricing/implementations/cpp_opencl/StructGPU.h @@ -90,6 +90,10 @@ enum GPU_KERNEL { PRIV, VECT }; GPU_KERNEL priv_or_vect_kernel(const LoopROScalars& ro_scal) { +#ifndef _OPTIMIZATION_MEM_COALES_ON + return VECT; +#endif + #if (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 1) return VECT; #elif (_OPTIMIZATION_COST_MODEL_OR_FORCE_VECT_OR_FORCE_PRIV == 2) @@ -240,7 +244,9 @@ oclAllocArrays_PrivKernel ( cl_int ciErr2; size_t cur_size; real_t* glb_vhat = NULL; + ciErr = 0; +#if 0 { // 1. RO scalars cur_size = sizeof(LoopROScalars); ocl_arrs.ro_scals = clCreateBuffer( @@ -251,6 +257,7 @@ oclAllocArrays_PrivKernel ( ciErr |= clEnqueueWriteBuffer(cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, cur_size, &ro_scals, 0, NULL, NULL); } +#endif { // 2. Sobol RO Arrays const SobolArrays& cpu_arrs = sob_arrs; @@ -352,7 +359,7 @@ runGPU_PRIV( oclCheckError(ciErr1, CL_SUCCESS); - clFinish(cqCommandQueue); + //clFinish(cqCommandQueue); struct timeval t_start, t_end, t_diff; unsigned long long elapsed; gettimeofday(&t_start, NULL); @@ -422,7 +429,8 @@ oclAllocArrays_VectKernel ( cl_int ciErr2; size_t cur_size; real_t* glb_vhat; - + ciErr = 0; +#if 0 { // 1. RO scalars cur_size = sizeof(LoopROScalars); ocl_arrs.ro_scals = clCreateBuffer( @@ -432,6 +440,7 @@ oclAllocArrays_VectKernel ( ciErr |= clEnqueueWriteBuffer( cqCommandQueue, ocl_arrs.ro_scals, CL_TRUE, 0, cur_size, &ro_scals, 0, NULL, NULL); } +#endif { // 2. SOBOL DIR VECTOR const SobolArrays& cpu_arrs = sob_arrs; From 7e00cdcf06c1cdff1e42f6670c9f6b466460fef7 Mon Sep 17 00:00:00 2001 From: Cosmin Oancea Date: Tue, 8 Dec 2015 20:21:59 +0100 Subject: [PATCH 122/122] enabled strength reduction --- .../OptionPricing/implementations/cpp_openmp/GenPricing.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp b/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp index 4f8fcc4..cd155a0 100644 --- a/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp +++ b/benchmarks/OptionPricing/implementations/cpp_openmp/GenPricing.cpp @@ -1,5 +1,7 @@ #define FAST_BB +#define _OPTIMIZATION_SOBOL_STRENGTH_RED_RECURR + #include #include