diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sc/source/core/opencl | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/source/core/opencl')
23 files changed, 15871 insertions, 0 deletions
diff --git a/sc/source/core/opencl/cl-test.ods b/sc/source/core/opencl/cl-test.ods Binary files differnew file mode 100644 index 0000000000..7e2bae4cb3 --- /dev/null +++ b/sc/source/core/opencl/cl-test.ods diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx new file mode 100644 index 0000000000..4d61b00ed3 --- /dev/null +++ b/sc/source/core/opencl/formulagroupcl.cxx @@ -0,0 +1,3047 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <formulagroup.hxx> +#include <formulagroupcl.hxx> +#include <document.hxx> +#include <formulacell.hxx> +#include <tokenarray.hxx> +#include <compiler.hxx> +#include <comphelper/random.hxx> +#include <scmatrix.hxx> +#include <sal/log.hxx> + +#include <opencl/openclwrapper.hxx> +#include <opencl/OpenCLZone.hxx> + +#include "op_financial.hxx" +#include "op_math.hxx" +#include "op_logical.hxx" +#include "op_statistical.hxx" +#include "op_array.hxx" +#include "op_spreadsheet.hxx" +#include "op_addin.hxx" + +#include <limits> + +#include <com/sun/star/sheet/FormulaLanguage.hpp> + +const char* const publicFunc = + "\n" + "#define IllegalArgument 502\n" + "#define IllegalFPOperation 503 // #NUM!\n" + "#define NoValue 519 // #VALUE!\n" + "#define NoConvergence 523\n" + "#define DivisionByZero 532 // #DIV/0!\n" + "#define NOTAVAILABLE 0x7fff // #N/A\n" + "\n" + "double CreateDoubleError(ulong nErr)\n" + "{\n" + // At least nVidia on Linux and Intel on Windows seem to ignore the argument to nan(), + // so using that would not propagate the type of error, work that around + // by directly constructing the proper IEEE double NaN value + // TODO: maybe use a better way to detect such systems? + " return as_double(0x7FF8000000000000+nErr);\n" +// " return nan(nErr);\n" + "}\n" + "\n" + "double fsum(double a, double b) { return isnan(a)?b:a+b; }\n" + "double legalize(double a, double b) { return isnan(a)?b:a;}\n" + ; + +#include <utility> +#include <vector> +#include <map> +#include <iostream> +#include <algorithm> + +#include <rtl/digest.h> + +#include <memory> + +using namespace formula; + +namespace sc::opencl { + +namespace { + +std::string linenumberify(const std::string& s) +{ + outputstream ss; + int linenumber = 1; + size_t start = 0; + size_t newline; + while ((newline = s.find('\n', start)) != std::string::npos) + { + ss << "/*" << std::setw(4) << linenumber++ << "*/ " << s.substr(start, newline-start+1); + start = newline + 1; + } + if (start < s.size()) + ss << "/*" << std::setw(4) << linenumber++ << "*/ " << s.substr(start, std::string::npos); + return ss.str(); +} + +bool AllStringsAreNull(const rtl_uString* const* pStringArray, size_t nLength) +{ + if (pStringArray == nullptr) + return true; + + for (size_t i = 0; i < nLength; i++) + if (pStringArray[i] != nullptr) + return false; + + return true; +} + +OUString LimitedString( std::u16string_view str ) +{ + if( str.size() < 20 ) + return OUString::Concat("\"") + str + "\""; + else + return OUString::Concat("\"") + str.substr( 0, 20 ) + "\"..."; +} + +const int MAX_PEEK_ELEMENTS = 5; +// Returns formatted contents of the data (possibly shortened), to be used in debug output. +std::string DebugPeekData(const FormulaToken* ref, int doubleRefIndex = 0) +{ + if (ref->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*>(ref); + outputstream buf; + buf << "SingleRef {"; + for( size_t i = 0; i < std::min< size_t >( MAX_PEEK_ELEMENTS, pSVR->GetArrayLength()); ++i ) + { + if( i != 0 ) + buf << ","; + if( pSVR->GetArray().mpStringArray != nullptr + && pSVR->GetArray().mpStringArray[ i ] != nullptr ) + { + buf << LimitedString( OUString( pSVR->GetArray().mpStringArray[ i ] )); + } + else if( pSVR->GetArray().mpNumericArray != nullptr ) + buf << pSVR->GetArray().mpNumericArray[ i ]; + } + if( pSVR->GetArrayLength() > MAX_PEEK_ELEMENTS ) + buf << ",..."; + buf << "}"; + return buf.str(); + } + else if (ref->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken*>(ref); + outputstream buf; + buf << "DoubleRef {"; + for( size_t i = 0; i < std::min< size_t >( MAX_PEEK_ELEMENTS, pDVR->GetArrayLength()); ++i ) + { + if( i != 0 ) + buf << ","; + if( pDVR->GetArrays()[doubleRefIndex].mpStringArray != nullptr + && pDVR->GetArrays()[doubleRefIndex].mpStringArray[ i ] != nullptr ) + { + buf << LimitedString( OUString( pDVR->GetArrays()[doubleRefIndex].mpStringArray[ i ] )); + } + else if( pDVR->GetArrays()[doubleRefIndex].mpNumericArray != nullptr ) + buf << pDVR->GetArrays()[doubleRefIndex].mpNumericArray[ i ]; + } + if( pDVR->GetArrayLength() > MAX_PEEK_ELEMENTS ) + buf << ",..."; + buf << "}"; + return buf.str(); + } + else if (ref->GetType() == formula::svString) + { + outputstream buf; + buf << "String " << LimitedString( ref->GetString().getString()); + return buf.str(); + } + else if (ref->GetType() == formula::svDouble) + { + return preciseFloat(ref->GetDouble()); + } + else + { + return "?"; + } +} + +// Returns formatted contents of a doubles buffer, to be used in debug output. +std::string DebugPeekDoubles(const double* data, int size) +{ + outputstream buf; + buf << "{"; + for( int i = 0; i < std::min( MAX_PEEK_ELEMENTS, size ); ++i ) + { + if( i != 0 ) + buf << ","; + buf << data[ i ]; + } + if( size > MAX_PEEK_ELEMENTS ) + buf << ",..."; + buf << "}"; + return buf.str(); +} + +} // anonymous namespace + +/// Map the buffer used by an argument and do necessary argument setting +size_t VectorRef::Marshal( cl_kernel k, int argno, int, cl_program ) +{ + OpenCLZone zone; + FormulaToken* ref = mFormulaTree->GetFormulaToken(); + double* pHostBuffer = nullptr; + size_t szHostBuffer = 0; + if (ref->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*>(ref); + + SAL_INFO("sc.opencl", "SingleVectorRef len=" << pSVR->GetArrayLength() << " mpNumericArray=" << pSVR->GetArray().mpNumericArray << " (mpStringArray=" << pSVR->GetArray().mpStringArray << ")"); + + if( forceStringsToZero && pSVR->GetArray().mpStringArray != nullptr ) + { + dataBuffer.resize( pSVR->GetArrayLength()); + for( size_t i = 0; i < pSVR->GetArrayLength(); ++i ) + if( pSVR->GetArray().mpStringArray[ i ] != nullptr ) + dataBuffer[ i ] = 0; + else + dataBuffer[ i ] = pSVR->GetArray().mpNumericArray[ i ]; + pHostBuffer = dataBuffer.data(); + SAL_INFO("sc.opencl", "Forced strings to zero : " << DebugPeekDoubles( pHostBuffer, pSVR->GetArrayLength())); + } + else + { + pHostBuffer = const_cast<double*>(pSVR->GetArray().mpNumericArray); + } + szHostBuffer = pSVR->GetArrayLength() * sizeof(double); + } + else if (ref->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken*>(ref); + + SAL_INFO("sc.opencl", "DoubleVectorRef index=" << mnIndex << " len=" << pDVR->GetArrayLength() << " mpNumericArray=" << pDVR->GetArrays()[mnIndex].mpNumericArray << " (mpStringArray=" << pDVR->GetArrays()[mnIndex].mpStringArray << ")"); + + if( forceStringsToZero && pDVR->GetArrays()[mnIndex].mpStringArray != nullptr ) + { + dataBuffer.resize( pDVR->GetArrayLength()); + for( size_t i = 0; i < pDVR->GetArrayLength(); ++i ) + if( pDVR->GetArrays()[mnIndex].mpStringArray[ i ] != nullptr ) + dataBuffer[ i ] = 0; + else + dataBuffer[ i ] = pDVR->GetArrays()[mnIndex].mpNumericArray[ i ]; + pHostBuffer = dataBuffer.data(); + SAL_INFO("sc.opencl", "Forced strings to zero : " << DebugPeekDoubles( pHostBuffer, pDVR->GetArrayLength())); + } + else + { + pHostBuffer = const_cast<double*>(pDVR->GetArrays()[mnIndex].mpNumericArray); + } + szHostBuffer = pDVR->GetArrayLength() * sizeof(double); + } + else + { + throw Unhandled(__FILE__, __LINE__); + } + + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + cl_int err; + if (pHostBuffer) + { + mpClmem = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_ONLY) | CL_MEM_USE_HOST_PTR, + szHostBuffer, + pHostBuffer, &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem << " size " << szHostBuffer << " using host buffer " << pHostBuffer); + } + else + { + if (szHostBuffer == 0) + szHostBuffer = sizeof(double); // a dummy small value + // Marshal as a buffer of NANs + mpClmem = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_ONLY) | CL_MEM_ALLOC_HOST_PTR, + szHostBuffer, nullptr, &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem << " size " << szHostBuffer); + + double* pNanBuffer = static_cast<double*>(clEnqueueMapBuffer( + kEnv.mpkCmdQueue, mpClmem, CL_TRUE, CL_MAP_WRITE, 0, + szHostBuffer, 0, nullptr, nullptr, &err)); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__); + + for (size_t i = 0; i < szHostBuffer / sizeof(double); i++) + pNanBuffer[i] = std::numeric_limits<double>::quiet_NaN(); + err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpClmem, + pNanBuffer, 0, nullptr, nullptr); + // FIXME: Is it intentional to not throw an OpenCLError even if the clEnqueueUnmapMemObject() fails? + if (CL_SUCCESS != err) + SAL_WARN("sc.opencl", "clEnqueueUnmapMemObject failed: " << openclwrapper::errorString(err)); + } + + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": cl_mem: " << mpClmem << " (" << DebugPeekData(ref, mnIndex) << ")"); + err = clSetKernelArg(k, argno, sizeof(cl_mem), static_cast<void*>(&mpClmem)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; +} + +namespace { + +class DynamicKernelPiArgument : public DynamicKernelArgument +{ +public: + DynamicKernelPiArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft ) : + DynamicKernelArgument(config, s, ft) { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + ss << "double " << mSymName; + } + virtual void GenDeclRef( outputstream& ss ) const override + { + ss << "M_PI"; + } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + GenDecl(ss); + } + virtual std::string GenSlidingWindowDeclRef( bool = false ) const override + { + return mSymName; + } + virtual size_t GetWindowSize() const override + { + return 1; + } + /// Create buffer and pass the buffer to a given kernel + virtual size_t Marshal( cl_kernel k, int argno, int, cl_program ) override + { + OpenCLZone zone; + double tmp = 0.0; + // Pass the scalar result back to the rest of the formula kernel + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": double: " << preciseFloat( tmp ) << " (PI)"); + cl_int err = clSetKernelArg(k, argno, sizeof(double), static_cast<void*>(&tmp)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; + } +}; + +class DynamicKernelRandomArgument : public DynamicKernelArgument +{ +public: + DynamicKernelRandomArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft ) : + DynamicKernelArgument(config, s, ft) { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + ss << "double " << mSymName; + } + virtual void GenDeclRef( outputstream& ss ) const override + { + ss << mSymName; + } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + ss << "int " << mSymName; + } + virtual std::string GenSlidingWindowDeclRef( bool = false ) const override + { + return mSymName + "_Random(" + mSymName + ")"; + } + virtual void GenSlidingWindowFunction( outputstream& ss ) override + { + // This string is from the pi_opencl_kernel.i file as + // generated when building the Random123 examples. Unused + // stuff has been removed, and the actual kernel is not the + // same as in the totally different use case of that example, + // of course. Only the code that calculates the counter-based + // random number and what it needs is left. + ss << "\ +\n\ +#ifndef DEFINED_RANDOM123_STUFF\n\ +#define DEFINED_RANDOM123_STUFF\n\ +\n\ +/*\n\ +Copyright 2010-2011, D. E. Shaw Research.\n\ +All rights reserved.\n\ +\n\ +Redistribution and use in source and binary forms, with or without\n\ +modification, are permitted provided that the following conditions are\n\ +met:\n\ +\n\ +* Redistributions of source code must retain the above copyright\n\ + notice, this list of conditions, and the following disclaimer.\n\ +\n\ +* Redistributions in binary form must reproduce the above copyright\n\ + notice, this list of conditions, and the following disclaimer in the\n\ + documentation and/or other materials provided with the distribution.\n\ +\n\ +* Neither the name of D. E. Shaw Research nor the names of its\n\ + contributors may be used to endorse or promote products derived from\n\ + this software without specific prior written permission.\n\ +\n\ +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\ +\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\ +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\ +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n\ +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n\ +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n\ +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n\ +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n\ +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n\ +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\ +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ +*/\n\ +\n\ +typedef uint uint32_t;\n\ +struct r123array2x32\n\ +{\n\ + uint32_t v[2];\n\ +};\n\ +enum r123_enum_threefry32x2\n\ +{\n\ + R_32x2_0_0 = 13,\n\ + R_32x2_1_0 = 15,\n\ + R_32x2_2_0 = 26,\n\ + R_32x2_3_0 = 6,\n\ + R_32x2_4_0 = 17,\n\ + R_32x2_5_0 = 29,\n\ + R_32x2_6_0 = 16,\n\ + R_32x2_7_0 = 24\n\ +};\n\ +inline uint32_t RotL_32 (uint32_t x, unsigned int N)\n\ + __attribute__ ((always_inline));\n\ +inline uint32_t\n\ +RotL_32 (uint32_t x, unsigned int N)\n\ +{\n\ + return (x << (N & 31)) | (x >> ((32 - N) & 31));\n\ +}\n\ +\n\ +typedef struct r123array2x32 threefry2x32_ctr_t;\n\ +typedef struct r123array2x32 threefry2x32_key_t;\n\ +typedef struct r123array2x32 threefry2x32_ukey_t;\n\ +inline threefry2x32_key_t\n\ +threefry2x32keyinit (threefry2x32_ukey_t uk)\n\ +{\n\ + return uk;\n\ +}\n\ +\n\ +inline threefry2x32_ctr_t threefry2x32_R (unsigned int Nrounds,\n\ + threefry2x32_ctr_t in,\n\ + threefry2x32_key_t k)\n\ + __attribute__ ((always_inline));\n\ +inline threefry2x32_ctr_t\n\ +threefry2x32_R (unsigned int Nrounds, threefry2x32_ctr_t in,\n\ + threefry2x32_key_t k)\n\ +{\n\ + threefry2x32_ctr_t X;\n\ + uint32_t ks[2 + 1];\n\ + int i;\n\ + ks[2] = 0x1BD11BDA;\n\ + for (i = 0; i < 2; i++) {\n\ + ks[i] = k.v[i];\n\ + X.v[i] = in.v[i];\n\ + ks[2] ^= k.v[i];\n\ + }\n\ + X.v[0] += ks[0];\n\ + X.v[1] += ks[1];\n\ + if (Nrounds > 0) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_0_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 1) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_1_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 2) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_2_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 3) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_3_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 3) {\n\ + X.v[0] += ks[1];\n\ + X.v[1] += ks[2];\n\ + X.v[1] += 1;\n\ + }\n\ + if (Nrounds > 4) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_4_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 5) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_5_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 6) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_6_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 7) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_7_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 7) {\n\ + X.v[0] += ks[2];\n\ + X.v[1] += ks[0];\n\ + X.v[1] += 2;\n\ + }\n\ + if (Nrounds > 8) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_0_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 9) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_1_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 10) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_2_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 11) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_3_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 11) {\n\ + X.v[0] += ks[0];\n\ + X.v[1] += ks[1];\n\ + X.v[1] += 3;\n\ + }\n\ + if (Nrounds > 12) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_4_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 13) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_5_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 14) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_6_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 15) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_7_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 15) {\n\ + X.v[0] += ks[1];\n\ + X.v[1] += ks[2];\n\ + X.v[1] += 4;\n\ + }\n\ + if (Nrounds > 16) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_0_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 17) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_1_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 18) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_2_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 19) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_3_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 19) {\n\ + X.v[0] += ks[2];\n\ + X.v[1] += ks[0];\n\ + X.v[1] += 5;\n\ + }\n\ + if (Nrounds > 20) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_4_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 21) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_5_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 22) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_6_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 23) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_7_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 23) {\n\ + X.v[0] += ks[0];\n\ + X.v[1] += ks[1];\n\ + X.v[1] += 6;\n\ + }\n\ + if (Nrounds > 24) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_0_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 25) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_1_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 26) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_2_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 27) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_3_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 27) {\n\ + X.v[0] += ks[1];\n\ + X.v[1] += ks[2];\n\ + X.v[1] += 7;\n\ + }\n\ + if (Nrounds > 28) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_4_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 29) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_5_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 30) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_6_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 31) {\n\ + X.v[0] += X.v[1];\n\ + X.v[1] = RotL_32 (X.v[1], R_32x2_7_0);\n\ + X.v[1] ^= X.v[0];\n\ + }\n\ + if (Nrounds > 31) {\n\ + X.v[0] += ks[2];\n\ + X.v[1] += ks[0];\n\ + X.v[1] += 8;\n\ + }\n\ + return X;\n\ +}\n\ +\n\ +enum r123_enum_threefry2x32\n\ +{ threefry2x32_rounds = 20 };\n\ +inline threefry2x32_ctr_t threefry2x32 (threefry2x32_ctr_t in,\n\ + threefry2x32_key_t k)\n\ + __attribute__ ((always_inline));\n\ +inline threefry2x32_ctr_t\n\ +threefry2x32 (threefry2x32_ctr_t in, threefry2x32_key_t k)\n\ +{\n\ + return threefry2x32_R (threefry2x32_rounds, in, k);\n\ +}\n\ +#endif\n\ +\n\ +"; + ss << "double " << mSymName << "_Random (int seed)\n\ +{\n\ + unsigned tid = get_global_id(0);\n\ + threefry2x32_key_t k = { {tid, 0xdecafbad} };\n\ + threefry2x32_ctr_t c = { {seed, 0xf00dcafe} };\n\ + c = threefry2x32_R(threefry2x32_rounds, c, k);\n\ + const double factor = 1./(" << SAL_MAX_UINT32 << ".0 + 1.0);\n\ + const double halffactor = 0.5*factor;\n\ + return c.v[0] * factor + halffactor;\n\ +}\n\ +"; + } + virtual size_t GetWindowSize() const override + { + return 1; + } + /// Create buffer and pass the buffer to a given kernel + virtual size_t Marshal( cl_kernel k, int argno, int, cl_program ) override + { + OpenCLZone zone; + cl_int seed = comphelper::rng::uniform_int_distribution(0, SAL_MAX_INT32); + // Pass the scalar result back to the rest of the formula kernel + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": cl_int: " << seed << "(RANDOM)"); + cl_int err = clSetKernelArg(k, argno, sizeof(cl_int), static_cast<void*>(&seed)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; + } +}; + +// Arguments that are actually compile-time constant string +class ConstStringArgument : public DynamicKernelArgument +{ +public: + ConstStringArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft ) : + DynamicKernelArgument(config, s, ft) { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + ss << "double " << mSymName; + } + virtual void GenDeclRef( outputstream& ss ) const override + { + ss << GenSlidingWindowDeclRef(); + } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + GenDecl(ss); + } + virtual std::string GenSlidingWindowDeclRef( bool = false ) const override + { + outputstream ss; + if (GetFormulaToken()->GetType() != formula::svString) + throw Unhandled(__FILE__, __LINE__); + FormulaToken* Tok = GetFormulaToken(); + ss << GetStringId(Tok->GetString().getData()); + return ss.str(); + } + virtual std::string GenIsString( bool = false ) const override + { + return "true"; + } + virtual size_t GetWindowSize() const override + { + return 1; + } + virtual size_t Marshal( cl_kernel k, int argno, int, cl_program ) override + { + FormulaToken* ref = mFormulaTree->GetFormulaToken(); + if (ref->GetType() != formula::svString) + { + throw Unhandled(__FILE__, __LINE__); + } + cl_double stringId = GetStringId(ref->GetString().getData()); + + // Pass the scalar result back to the rest of the formula kernel + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno + << ": stringId: " << stringId << " (" << DebugPeekData(ref) << ")" ); + cl_int err = clSetKernelArg(k, argno, sizeof(cl_double), static_cast<void*>(&stringId)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; + } +}; + +} // namespace + +// Marshal a string vector reference +size_t DynamicKernelStringArgument::Marshal( cl_kernel k, int argno, int, cl_program ) +{ + OpenCLZone zone; + FormulaToken* ref = mFormulaTree->GetFormulaToken(); + + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + cl_int err; + formula::VectorRefArray vRef; + size_t nStrings = 0; + if (ref->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*>(ref); + nStrings = pSVR->GetArrayLength(); + vRef = pSVR->GetArray(); + } + else if (ref->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken*>(ref); + nStrings = pDVR->GetArrayLength(); + vRef = pDVR->GetArrays()[mnIndex]; + } + size_t szHostBuffer = nStrings * sizeof(cl_double); + cl_double* pStringIdsBuffer = nullptr; + + if (vRef.mpStringArray != nullptr) + { + // Marshal strings. See GetStringId(). + mpClmem = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_ONLY) | CL_MEM_ALLOC_HOST_PTR, + szHostBuffer, nullptr, &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem << " size " << szHostBuffer); + + pStringIdsBuffer = static_cast<cl_double*>(clEnqueueMapBuffer( + kEnv.mpkCmdQueue, mpClmem, CL_TRUE, CL_MAP_WRITE, 0, + szHostBuffer, 0, nullptr, nullptr, &err)); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__); + + for (size_t i = 0; i < nStrings; i++) + { + if (vRef.mpStringArray[i]) + pStringIdsBuffer[i] = GetStringId(vRef.mpStringArray[i]); + else + rtl::math::setNan(&pStringIdsBuffer[i]); + } + } + else + { + if (nStrings == 0) + szHostBuffer = sizeof(cl_double); // a dummy small value + // Marshal as a buffer of NANs + mpClmem = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_ONLY) | CL_MEM_ALLOC_HOST_PTR, + szHostBuffer, nullptr, &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem << " size " << szHostBuffer); + + pStringIdsBuffer = static_cast<cl_double*>(clEnqueueMapBuffer( + kEnv.mpkCmdQueue, mpClmem, CL_TRUE, CL_MAP_WRITE, 0, + szHostBuffer, 0, nullptr, nullptr, &err)); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__); + + for (size_t i = 0; i < szHostBuffer / sizeof(cl_double); i++) + rtl::math::setNan(&pStringIdsBuffer[i]); + } + err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpClmem, + pStringIdsBuffer, 0, nullptr, nullptr); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueUnmapMemObject", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": cl_mem: " << mpClmem + << " (stringIds: " << DebugPeekDoubles(pStringIdsBuffer, nStrings) << " " + << DebugPeekData(ref,mnIndex) << ")"); + err = clSetKernelArg(k, argno, sizeof(cl_mem), static_cast<void*>(&mpClmem)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; +} + +std::string DynamicKernelStringArgument::GenIsString( bool nested ) const +{ + if( nested ) + return "!isnan(" + mSymName + "[gid0])"; + FormulaToken* ref = mFormulaTree->GetFormulaToken(); + size_t nStrings = 0; + if (ref->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*>(ref); + nStrings = pSVR->GetArrayLength(); + } + else if (ref->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken*>(ref); + nStrings = pDVR->GetArrayLength(); + } + else + return "!isnan(" + mSymName + "[gid0])"; + outputstream ss; + ss << "(gid0 < " << nStrings << "? !isnan(" << mSymName << "[gid0]):NAN)"; + return ss.str(); +} + +namespace { + +/// A mixed string/numeric vector +class DynamicKernelMixedArgument : public VectorRef +{ +public: + DynamicKernelMixedArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft ) : + VectorRef(config, s, ft), mStringArgument(config, s + "s", ft) { } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + VectorRef::GenSlidingWindowDecl(ss); + ss << ", "; + mStringArgument.GenSlidingWindowDecl(ss); + } + virtual void GenSlidingWindowFunction( outputstream& ) override { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + VectorRef::GenDecl(ss); + ss << ", "; + mStringArgument.GenDecl(ss); + } + virtual void GenDeclRef( outputstream& ss ) const override + { + VectorRef::GenDeclRef(ss); + ss << ","; + mStringArgument.GenDeclRef(ss); + } + virtual std::string GenSlidingWindowDeclRef( bool nested ) const override + { + outputstream ss; + ss << "(!isnan(" << VectorRef::GenSlidingWindowDeclRef(nested); + ss << ")?" << VectorRef::GenSlidingWindowDeclRef(nested); + ss << ":" << mStringArgument.GenSlidingWindowDeclRef(nested); + ss << ")"; + return ss.str(); + } + virtual std::string GenDoubleSlidingWindowDeclRef( bool nested = false ) const override + { + outputstream ss; + ss << VectorRef::GenSlidingWindowDeclRef( nested ); + return ss.str(); + } + virtual std::string GenStringSlidingWindowDeclRef( bool nested = false ) const override + { + outputstream ss; + ss << mStringArgument.GenSlidingWindowDeclRef( nested ); + return ss.str(); + } + virtual std::string GenIsString( bool nested = false ) const override + { + return mStringArgument.GenIsString( nested ); + } + virtual size_t Marshal( cl_kernel k, int argno, int vw, cl_program p ) override + { + int i = VectorRef::Marshal(k, argno, vw, p); + i += mStringArgument.Marshal(k, argno + i, vw, p); + return i; + } + +protected: + DynamicKernelStringArgument mStringArgument; +}; + +} + +template<class Base> +DynamicKernelSlidingArgument<Base>::DynamicKernelSlidingArgument( + const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, + std::shared_ptr<SlidingFunctionBase> CodeGen, int index) + : Base(config, s, ft, index) + , mpCodeGen(std::move(CodeGen)) +{ + FormulaToken* t = ft->GetFormulaToken(); + if (t->GetType() != formula::svDoubleVectorRef) + throw Unhandled(__FILE__, __LINE__); + mpDVR = static_cast<const formula::DoubleVectorRefToken*>(t); + bIsStartFixed = mpDVR->IsStartFixed(); + bIsEndFixed = mpDVR->IsEndFixed(); +} + +template<class Base> +bool DynamicKernelSlidingArgument<Base>::NeedParallelReduction() const +{ + assert(dynamic_cast<OpSumIfs*>(mpCodeGen.get())); + return GetWindowSize() > 100 && + ((GetStartFixed() && GetEndFixed()) || + (!GetStartFixed() && !GetEndFixed())); +} + +template<class Base> +std::string DynamicKernelSlidingArgument<Base>::GenSlidingWindowDeclRef( bool nested ) const +{ + size_t nArrayLength = mpDVR->GetArrayLength(); + outputstream ss; + if (!bIsStartFixed && !bIsEndFixed) + { + if (!nested) + ss << "((i+gid0) <" << nArrayLength << "?"; + ss << Base::GetName() << "[i + gid0]"; + if (!nested) + ss << ":NAN)"; + } + else + { + if (!nested) + ss << "(i <" << nArrayLength << "?"; + ss << Base::GetName() << "[i]"; + if (!nested) + ss << ":NAN)"; + } + return ss.str(); +} + +template<class Base> +size_t DynamicKernelSlidingArgument<Base>::GenReductionLoopHeader( outputstream& ss, bool& needBody ) +{ + assert(mpDVR); + size_t nCurWindowSize = mpDVR->GetRefRowSize(); + + if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + { + ss << "for (int i = "; + ss << "gid0; i < " << mpDVR->GetArrayLength(); + ss << " && i < " << nCurWindowSize << "; i++){\n\t\t"; + needBody = true; + return nCurWindowSize; + } + else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + { + ss << "for (int i = "; + ss << "0; i < " << mpDVR->GetArrayLength(); + ss << " && i < gid0+" << nCurWindowSize << "; i++){\n\t\t"; + needBody = true; + return nCurWindowSize; + } + else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + { + ss << "tmpBottom = " << mpCodeGen->GetBottom() << ";\n\t"; + ss << "{int i;\n\t"; + outputstream temp1, temp2; + int outLoopSize = UNROLLING_FACTOR; + if (nCurWindowSize / outLoopSize != 0) + { + ss << "for(int outLoop=0; outLoop<" << nCurWindowSize / outLoopSize << "; outLoop++){\n\t"; + for (int count = 0; count < outLoopSize; count++) + { + ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n\t"; + if (count == 0) + { + temp1 << "if(i + gid0 < " << mpDVR->GetArrayLength(); + temp1 << "){\n\t\t"; + temp1 << "tmp = legalize("; + temp1 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp"); + temp1 << ", tmp);\n\t\t\t"; + temp1 << "}\n\t"; + } + ss << temp1.str(); + } + ss << "}\n\t"; + } + // The residual of mod outLoopSize + for (size_t count = nCurWindowSize / outLoopSize * outLoopSize; count < nCurWindowSize; count++) + { + ss << "i = " << count << ";\n\t"; + if (count == nCurWindowSize / outLoopSize * outLoopSize) + { + temp2 << "if(i + gid0 < " << mpDVR->GetArrayLength(); + temp2 << "){\n\t\t"; + temp2 << "tmp = legalize("; + temp2 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp"); + temp2 << ", tmp);\n\t\t\t"; + temp2 << "}\n\t"; + } + ss << temp2.str(); + } + ss << "}\n"; + needBody = false; + return nCurWindowSize; + } + // (mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + else + { + ss << "\n\t"; + ss << "tmpBottom = " << mpCodeGen->GetBottom() << ";\n\t"; + ss << "{int i;\n\t"; + outputstream temp1, temp2; + int outLoopSize = UNROLLING_FACTOR; + if (nCurWindowSize / outLoopSize != 0) + { + ss << "for(int outLoop=0; outLoop<" << nCurWindowSize / outLoopSize << "; outLoop++){\n\t"; + for (int count = 0; count < outLoopSize; count++) + { + ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n\t"; + if (count == 0) + { + temp1 << "if(i < " << mpDVR->GetArrayLength(); + temp1 << "){\n\t\t"; + temp1 << "tmp = legalize("; + temp1 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp"); + temp1 << ", tmp);\n\t\t\t"; + temp1 << "}\n\t"; + } + ss << temp1.str(); + } + ss << "}\n\t"; + } + // The residual of mod outLoopSize + for (size_t count = nCurWindowSize / outLoopSize * outLoopSize; count < nCurWindowSize; count++) + { + ss << "i = " << count << ";\n\t"; + if (count == nCurWindowSize / outLoopSize * outLoopSize) + { + temp2 << "if(i < " << mpDVR->GetArrayLength(); + temp2 << "){\n\t\t"; + temp2 << "tmp = legalize("; + temp2 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp"); + temp2 << ", tmp);\n\t\t\t"; + temp2 << "}\n\t"; + } + ss << temp2.str(); + } + ss << "}\n"; + needBody = false; + return nCurWindowSize; + } +} + +template class DynamicKernelSlidingArgument<VectorRef>; +template class DynamicKernelSlidingArgument<VectorRefStringsToZero>; +template class DynamicKernelSlidingArgument<DynamicKernelStringArgument>; + +namespace { + +/// A mixed string/numeric vector +class DynamicKernelMixedSlidingArgument : public VectorRef +{ +public: + DynamicKernelMixedSlidingArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft, const std::shared_ptr<SlidingFunctionBase>& CodeGen, + int index ) : + VectorRef(config, s, ft), + mDoubleArgument(mCalcConfig, s, ft, CodeGen, index), + mStringArgument(mCalcConfig, s + "s", ft, CodeGen, index) { } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + mDoubleArgument.GenSlidingWindowDecl(ss); + ss << ", "; + mStringArgument.GenSlidingWindowDecl(ss); + } + virtual void GenSlidingWindowFunction( outputstream& ) override { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + mDoubleArgument.GenDecl(ss); + ss << ", "; + mStringArgument.GenDecl(ss); + } + virtual void GenDeclRef( outputstream& ss ) const override + { + mDoubleArgument.GenDeclRef(ss); + ss << ","; + mStringArgument.GenDeclRef(ss); + } + virtual std::string GenSlidingWindowDeclRef( bool nested ) const override + { + outputstream ss; + ss << "(!isnan(" << mDoubleArgument.GenSlidingWindowDeclRef(nested); + ss << ")?" << mDoubleArgument.GenSlidingWindowDeclRef(nested); + ss << ":" << mStringArgument.GenSlidingWindowDeclRef(nested); + ss << ")"; + return ss.str(); + } + virtual std::string GenDoubleSlidingWindowDeclRef( bool = false ) const override + { + outputstream ss; + ss << mDoubleArgument.GenSlidingWindowDeclRef(); + return ss.str(); + } + virtual std::string GenStringSlidingWindowDeclRef( bool = false ) const override + { + outputstream ss; + ss << mStringArgument.GenSlidingWindowDeclRef(); + return ss.str(); + } + virtual size_t Marshal( cl_kernel k, int argno, int vw, cl_program p ) override + { + int i = mDoubleArgument.Marshal(k, argno, vw, p); + i += mStringArgument.Marshal(k, argno + i, vw, p); + return i; + } + +protected: + DynamicKernelSlidingArgument<VectorRef> mDoubleArgument; + DynamicKernelSlidingArgument<DynamicKernelStringArgument> mStringArgument; +}; + +/// Holds the symbol table for a given dynamic kernel +class SymbolTable +{ +public: + typedef std::map<const formula::FormulaToken*, DynamicKernelArgumentRef> ArgumentMap; + // This avoids instability caused by using pointer as the key type + SymbolTable() : mCurId(0) { } + template <class T> + const DynamicKernelArgument* DeclRefArg(const ScCalcConfig& config, const FormulaTreeNodeRef&, + std::shared_ptr<SlidingFunctionBase> pCodeGen, int nResultSize); + /// Used to generate sliding window helpers + void DumpSlidingWindowFunctions( outputstream& ss ) + { + for (auto const& argument : mParams) + { + argument->GenSlidingWindowFunction(ss); + ss << "\n"; + } + } + /// Memory mapping from host to device and pass buffers to the given kernel as + /// arguments + void Marshal( cl_kernel, int, cl_program ); + +private: + unsigned int mCurId; + ArgumentMap mSymbols; + std::vector<DynamicKernelArgumentRef> mParams; +}; + +void SymbolTable::Marshal( cl_kernel k, int nVectorWidth, cl_program pProgram ) +{ + int i = 1; //The first argument is reserved for results + for (auto const& argument : mParams) + { + i += argument->Marshal(k, i, nVectorWidth, pProgram); + } +} + +} + +template<class Base> +ParallelReductionVectorRef<Base>::ParallelReductionVectorRef( + const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, + std::shared_ptr<SlidingFunctionBase> CodeGen, int index) + : Base(config, s, ft, index) + , mpCodeGen(std::move(CodeGen)) + , mpClmem2(nullptr) +{ + FormulaToken* t = ft->GetFormulaToken(); + if (t->GetType() != formula::svDoubleVectorRef) + throw Unhandled(__FILE__, __LINE__); + mpDVR = static_cast<const formula::DoubleVectorRefToken*>(t); + bIsStartFixed = mpDVR->IsStartFixed(); + bIsEndFixed = mpDVR->IsEndFixed(); +} + +template<class Base> +void ParallelReductionVectorRef<Base>::GenSlidingWindowFunction( outputstream& ss ) +{ + if (!dynamic_cast<OpAverage*>(mpCodeGen.get())) + { + std::string name = Base::GetName(); + ss << "__kernel void " << name; + ss << "_reduction(__global double* A, " + "__global double *result,int arrayLength,int windowSize){\n"; + ss << " double tmp, current_result =" << + mpCodeGen->GetBottom(); + ss << ";\n"; + ss << " int writePos = get_group_id(1);\n"; + ss << " int lidx = get_local_id(0);\n"; + ss << " __local double shm_buf[256];\n"; + if (mpDVR->IsStartFixed()) + ss << " int offset = 0;\n"; + else // if (!mpDVR->IsStartFixed()) + ss << " int offset = get_group_id(1);\n"; + if (mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + ss << " int end = windowSize;\n"; + else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + ss << " int end = offset + windowSize;\n"; + else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + ss << " int end = windowSize + get_group_id(1);\n"; + else if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + ss << " int end = windowSize;\n"; + ss << " end = min(end, arrayLength);\n"; + + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " int loop = arrayLength/512 + 1;\n"; + ss << " for (int l=0; l<loop; l++){\n"; + ss << " tmp = " << mpCodeGen->GetBottom() << ";\n"; + ss << " int loopOffset = l*512;\n"; + ss << " if((loopOffset + lidx + offset + 256) < end) {\n"; + ss << " tmp = legalize(" << mpCodeGen->Gen2( + "A[loopOffset + lidx + offset]", "tmp") << ", tmp);\n"; + ss << " tmp = legalize(" << mpCodeGen->Gen2( + "A[loopOffset + lidx + offset + 256]", "tmp") << ", tmp);\n"; + ss << " } else if ((loopOffset + lidx + offset) < end)\n"; + ss << " tmp = legalize(" << mpCodeGen->Gen2( + "A[loopOffset + lidx + offset]", "tmp") << ", tmp);\n"; + ss << " shm_buf[lidx] = tmp;\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " for (int i = 128; i >0; i/=2) {\n"; + ss << " if (lidx < i)\n"; + ss << " shm_buf[lidx] = "; + // Special case count + if (dynamic_cast<OpCount*>(mpCodeGen.get())) + ss << "shm_buf[lidx] + shm_buf[lidx + i];\n"; + else + ss << mpCodeGen->Gen2("shm_buf[lidx]", "shm_buf[lidx + i]") << ";\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " current_result ="; + if (dynamic_cast<OpCount*>(mpCodeGen.get())) + ss << "current_result + shm_buf[0]"; + else + ss << mpCodeGen->Gen2("current_result", "shm_buf[0]"); + ss << ";\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " result[writePos] = current_result;\n"; + ss << "}\n"; + } + else + { + std::string name = Base::GetName(); + /*sum reduction*/ + ss << "__kernel void " << name << "_sum"; + ss << "_reduction(__global double* A, " + "__global double *result,int arrayLength,int windowSize){\n"; + ss << " double tmp, current_result =" << + mpCodeGen->GetBottom(); + ss << ";\n"; + ss << " int writePos = get_group_id(1);\n"; + ss << " int lidx = get_local_id(0);\n"; + ss << " __local double shm_buf[256];\n"; + if (mpDVR->IsStartFixed()) + ss << " int offset = 0;\n"; + else // if (!mpDVR->IsStartFixed()) + ss << " int offset = get_group_id(1);\n"; + if (mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + ss << " int end = windowSize;\n"; + else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + ss << " int end = offset + windowSize;\n"; + else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + ss << " int end = windowSize + get_group_id(1);\n"; + else if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + ss << " int end = windowSize;\n"; + ss << " end = min(end, arrayLength);\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " int loop = arrayLength/512 + 1;\n"; + ss << " for (int l=0; l<loop; l++){\n"; + ss << " tmp = " << mpCodeGen->GetBottom() << ";\n"; + ss << " int loopOffset = l*512;\n"; + ss << " if((loopOffset + lidx + offset + 256) < end) {\n"; + ss << " tmp = legalize("; + ss << "(A[loopOffset + lidx + offset]+ tmp)"; + ss << ", tmp);\n"; + ss << " tmp = legalize((A[loopOffset + lidx + offset + 256]+ tmp)"; + ss << ", tmp);\n"; + ss << " } else if ((loopOffset + lidx + offset) < end)\n"; + ss << " tmp = legalize((A[loopOffset + lidx + offset] + tmp)"; + ss << ", tmp);\n"; + ss << " shm_buf[lidx] = tmp;\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " for (int i = 128; i >0; i/=2) {\n"; + ss << " if (lidx < i)\n"; + ss << " shm_buf[lidx] = "; + ss << "shm_buf[lidx] + shm_buf[lidx + i];\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " current_result ="; + ss << "current_result + shm_buf[0]"; + ss << ";\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " result[writePos] = current_result;\n"; + ss << "}\n"; + /*count reduction*/ + ss << "__kernel void " << name << "_count"; + ss << "_reduction(__global double* A, " + "__global double *result,int arrayLength,int windowSize){\n"; + ss << " double tmp, current_result =" << + mpCodeGen->GetBottom(); + ss << ";\n"; + ss << " int writePos = get_group_id(1);\n"; + ss << " int lidx = get_local_id(0);\n"; + ss << " __local double shm_buf[256];\n"; + if (mpDVR->IsStartFixed()) + ss << " int offset = 0;\n"; + else // if (!mpDVR->IsStartFixed()) + ss << " int offset = get_group_id(1);\n"; + if (mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + ss << " int end = windowSize;\n"; + else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + ss << " int end = offset + windowSize;\n"; + else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed()) + ss << " int end = windowSize + get_group_id(1);\n"; + else if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed()) + ss << " int end = windowSize;\n"; + ss << " end = min(end, arrayLength);\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " int loop = arrayLength/512 + 1;\n"; + ss << " for (int l=0; l<loop; l++){\n"; + ss << " tmp = " << mpCodeGen->GetBottom() << ";\n"; + ss << " int loopOffset = l*512;\n"; + ss << " if((loopOffset + lidx + offset + 256) < end) {\n"; + ss << " tmp = legalize((isnan(A[loopOffset + lidx + offset])?tmp:tmp+1.0)"; + ss << ", tmp);\n"; + ss << " tmp = legalize((isnan(A[loopOffset + lidx + offset+256])?tmp:tmp+1.0)"; + ss << ", tmp);\n"; + ss << " } else if ((loopOffset + lidx + offset) < end)\n"; + ss << " tmp = legalize((isnan(A[loopOffset + lidx + offset])?tmp:tmp+1.0)"; + ss << ", tmp);\n"; + ss << " shm_buf[lidx] = tmp;\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " for (int i = 128; i >0; i/=2) {\n"; + ss << " if (lidx < i)\n"; + ss << " shm_buf[lidx] = "; + ss << "shm_buf[lidx] + shm_buf[lidx + i];\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " current_result ="; + ss << "current_result + shm_buf[0];"; + ss << ";\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " result[writePos] = current_result;\n"; + ss << "}\n"; + } +} + +template<class Base> +std::string ParallelReductionVectorRef<Base>::GenSlidingWindowDeclRef( bool ) const +{ + outputstream ss; + if (!bIsStartFixed && !bIsEndFixed) + ss << Base::GetName() << "[i + gid0]"; + else + ss << Base::GetName() << "[i]"; + return ss.str(); +} + +template<class Base> +size_t ParallelReductionVectorRef<Base>::GenReductionLoopHeader( + outputstream& ss, int nResultSize, bool& needBody ) +{ + assert(mpDVR); + size_t nCurWindowSize = mpDVR->GetRefRowSize(); + std::string temp = Base::GetName() + "[gid0]"; + ss << "tmp = "; + // Special case count + if (dynamic_cast<OpAverage*>(mpCodeGen.get())) + { + ss << mpCodeGen->Gen2(temp, "tmp") << ";\n"; + ss << "nCount = nCount-1;\n"; + ss << "nCount = nCount +"; /*re-assign nCount from count reduction*/ + ss << Base::GetName() << "[gid0+" << nResultSize << "]" << ";\n"; + } + else if (dynamic_cast<OpCount*>(mpCodeGen.get())) + ss << temp << "+ tmp"; + else + ss << mpCodeGen->Gen2(temp, "tmp"); + ss << ";\n\t"; + needBody = false; + return nCurWindowSize; +} + +template<class Base> +size_t ParallelReductionVectorRef<Base>::Marshal( cl_kernel k, int argno, int w, cl_program mpProgram ) +{ + assert(Base::mpClmem == nullptr); + + OpenCLZone zone; + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + cl_int err; + size_t nInput = mpDVR->GetArrayLength(); + size_t nCurWindowSize = mpDVR->GetRefRowSize(); + // create clmem buffer + if (mpDVR->GetArrays()[Base::mnIndex].mpNumericArray == nullptr) + throw Unhandled(__FILE__, __LINE__); + double* pHostBuffer = const_cast<double*>( + mpDVR->GetArrays()[Base::mnIndex].mpNumericArray); + size_t szHostBuffer = nInput * sizeof(double); + Base::mpClmem = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_ONLY) | CL_MEM_USE_HOST_PTR, + szHostBuffer, + pHostBuffer, &err); + SAL_INFO("sc.opencl", "Created buffer " << Base::mpClmem << " size " << nInput << "*" << sizeof(double) << "=" << szHostBuffer << " using host buffer " << pHostBuffer); + + mpClmem2 = clCreateBuffer(kEnv.mpkContext, + CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, + sizeof(double) * w, nullptr, nullptr); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem2 << " size " << sizeof(double) << "*" << w << "=" << (sizeof(double)*w)); + + // reproduce the reduction function name + std::string kernelName; + if (!dynamic_cast<OpAverage*>(mpCodeGen.get())) + kernelName = Base::GetName() + "_reduction"; + else + kernelName = Base::GetName() + "_sum_reduction"; + cl_kernel redKernel = clCreateKernel(mpProgram, kernelName.c_str(), &err); + if (err != CL_SUCCESS) + throw OpenCLError("clCreateKernel", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created kernel " << redKernel << " with name " << kernelName << " in program " << mpProgram); + + // set kernel arg of reduction kernel + // TODO(Wei Wei): use unique name for kernel + cl_mem buf = Base::GetCLBuffer(); + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 0 << ": cl_mem: " << buf); + err = clSetKernelArg(redKernel, 0, sizeof(cl_mem), + static_cast<void*>(&buf)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 1 << ": cl_mem: " << mpClmem2); + err = clSetKernelArg(redKernel, 1, sizeof(cl_mem), &mpClmem2); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 2 << ": cl_int: " << nInput); + err = clSetKernelArg(redKernel, 2, sizeof(cl_int), static_cast<void*>(&nInput)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 3 << ": cl_int: " << nCurWindowSize); + err = clSetKernelArg(redKernel, 3, sizeof(cl_int), static_cast<void*>(&nCurWindowSize)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + // set work group size and execute + size_t global_work_size[] = { 256, static_cast<size_t>(w) }; + size_t const local_work_size[] = { 256, 1 }; + SAL_INFO("sc.opencl", "Enqueuing kernel " << redKernel); + err = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, redKernel, 2, nullptr, + global_work_size, local_work_size, 0, nullptr, nullptr); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueNDRangeKernel", err, __FILE__, __LINE__); + err = clFinish(kEnv.mpkCmdQueue); + if (CL_SUCCESS != err) + throw OpenCLError("clFinish", err, __FILE__, __LINE__); + if (dynamic_cast<OpAverage*>(mpCodeGen.get())) + { + /*average need more reduction kernel for count computing*/ + std::unique_ptr<double[]> pAllBuffer(new double[2 * w]); + double* resbuf = static_cast<double*>(clEnqueueMapBuffer(kEnv.mpkCmdQueue, + mpClmem2, + CL_TRUE, CL_MAP_READ, 0, + sizeof(double) * w, 0, nullptr, nullptr, + &err)); + if (err != CL_SUCCESS) + throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__); + + for (int i = 0; i < w; i++) + pAllBuffer[i] = resbuf[i]; + err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpClmem2, resbuf, 0, nullptr, nullptr); + if (err != CL_SUCCESS) + throw OpenCLError("clEnqueueUnmapMemObject", err, __FILE__, __LINE__); + + kernelName = Base::GetName() + "_count_reduction"; + redKernel = clCreateKernel(mpProgram, kernelName.c_str(), &err); + if (err != CL_SUCCESS) + throw OpenCLError("clCreateKernel", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created kernel " << redKernel << " with name " << kernelName << " in program " << mpProgram); + + // set kernel arg of reduction kernel + buf = Base::GetCLBuffer(); + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 0 << ": cl_mem: " << buf); + err = clSetKernelArg(redKernel, 0, sizeof(cl_mem), + static_cast<void*>(&buf)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 1 << ": cl_mem: " << mpClmem2); + err = clSetKernelArg(redKernel, 1, sizeof(cl_mem), &mpClmem2); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 2 << ": cl_int: " << nInput); + err = clSetKernelArg(redKernel, 2, sizeof(cl_int), static_cast<void*>(&nInput)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 3 << ": cl_int: " << nCurWindowSize); + err = clSetKernelArg(redKernel, 3, sizeof(cl_int), static_cast<void*>(&nCurWindowSize)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + // set work group size and execute + size_t global_work_size1[] = { 256, static_cast<size_t>(w) }; + size_t const local_work_size1[] = { 256, 1 }; + SAL_INFO("sc.opencl", "Enqueuing kernel " << redKernel); + err = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, redKernel, 2, nullptr, + global_work_size1, local_work_size1, 0, nullptr, nullptr); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueNDRangeKernel", err, __FILE__, __LINE__); + err = clFinish(kEnv.mpkCmdQueue); + if (CL_SUCCESS != err) + throw OpenCLError("clFinish", err, __FILE__, __LINE__); + resbuf = static_cast<double*>(clEnqueueMapBuffer(kEnv.mpkCmdQueue, + mpClmem2, + CL_TRUE, CL_MAP_READ, 0, + sizeof(double) * w, 0, nullptr, nullptr, + &err)); + if (err != CL_SUCCESS) + throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__); + for (int i = 0; i < w; i++) + pAllBuffer[i + w] = resbuf[i]; + err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpClmem2, resbuf, 0, nullptr, nullptr); + // FIXME: Is it intentional to not throw an OpenCLError even if the clEnqueueUnmapMemObject() fails? + if (CL_SUCCESS != err) + SAL_WARN("sc.opencl", "clEnqueueUnmapMemObject failed: " << openclwrapper::errorString(err)); + if (mpClmem2) + { + err = clReleaseMemObject(mpClmem2); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err)); + mpClmem2 = nullptr; + } + mpClmem2 = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_WRITE) | CL_MEM_COPY_HOST_PTR, + w * sizeof(double) * 2, pAllBuffer.get(), &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem2 << " size " << w << "*" << sizeof(double) << "=" << (w*sizeof(double)) << " copying host buffer " << pAllBuffer.get()); + } + // set kernel arg + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": cl_mem: " << mpClmem2); + err = clSetKernelArg(k, argno, sizeof(cl_mem), &mpClmem2); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; +} + +template<class Base> +ParallelReductionVectorRef<Base>::~ParallelReductionVectorRef() +{ + if (mpClmem2) + { + cl_int err; + err = clReleaseMemObject(mpClmem2); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err)); + mpClmem2 = nullptr; + } +} + +template class ParallelReductionVectorRef<VectorRef>; + +namespace { + +struct SumIfsArgs +{ + explicit SumIfsArgs(cl_mem x) : mCLMem(x), mConst(0.0) { } + explicit SumIfsArgs(double x) : mCLMem(nullptr), mConst(x) { } + cl_mem mCLMem; + double mConst; +}; + +/// Helper functions that have multiple buffers +class DynamicKernelSoPArguments : public DynamicKernelArgument +{ +public: + typedef std::vector<DynamicKernelArgumentRef> SubArgumentsType; + + DynamicKernelSoPArguments( const ScCalcConfig& config, + const std::string& s, const FormulaTreeNodeRef& ft, + std::shared_ptr<SlidingFunctionBase> pCodeGen, int nResultSize ); + + /// Create buffer and pass the buffer to a given kernel + virtual size_t Marshal( cl_kernel k, int argno, int nVectorWidth, cl_program pProgram ) override + { + OpenCLZone zone; + unsigned i = 0; + for (const auto& rxSubArgument : mvSubArguments) + { + i += rxSubArgument->Marshal(k, argno + i, nVectorWidth, pProgram); + } + if (OpSumIfs* OpSumCodeGen = dynamic_cast<OpSumIfs*>(mpCodeGen.get())) + { + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + cl_int err; + DynamicKernelArgument* Arg = mvSubArguments[0].get(); + DynamicKernelSlidingArgument<VectorRef>* slidingArgPtr = + static_cast<DynamicKernelSlidingArgument<VectorRef>*>(Arg); + mpClmem2 = nullptr; + + if (OpSumCodeGen->NeedReductionKernel()) + { + size_t nInput = slidingArgPtr->GetArrayLength(); + size_t nCurWindowSize = slidingArgPtr->GetWindowSize(); + std::vector<SumIfsArgs> vclmem; + + for (const auto& rxSubArgument : mvSubArguments) + { + if (VectorRef* VR = dynamic_cast<VectorRef*>(rxSubArgument.get())) + vclmem.emplace_back(VR->GetCLBuffer()); + else if (DynamicKernelConstantArgument* CA = dynamic_cast<DynamicKernelConstantArgument*>(rxSubArgument.get())) + vclmem.emplace_back(CA->GetDouble()); + else + vclmem.emplace_back(nullptr); + } + mpClmem2 = clCreateBuffer(kEnv.mpkContext, CL_MEM_READ_WRITE, + sizeof(double) * nVectorWidth, nullptr, &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpClmem2 << " size " << sizeof(double) << "*" << nVectorWidth << "=" << (sizeof(double)*nVectorWidth)); + + std::string kernelName = mvSubArguments[0]->GetName() + "_SumIfs_reduction"; + cl_kernel redKernel = clCreateKernel(pProgram, kernelName.c_str(), &err); + if (err != CL_SUCCESS) + throw OpenCLError("clCreateKernel", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created kernel " << redKernel << " with name " << kernelName << " in program " << pProgram); + + // set kernel arg of reduction kernel + for (size_t j = 0; j < vclmem.size(); j++) + { + if (vclmem[j].mCLMem) + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << j << ": cl_mem: " << vclmem[j].mCLMem); + else + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << j << ": double: " << preciseFloat( vclmem[j].mConst )); + err = clSetKernelArg(redKernel, j, + vclmem[j].mCLMem ? sizeof(cl_mem) : sizeof(double), + vclmem[j].mCLMem ? static_cast<void*>(&vclmem[j].mCLMem) : + static_cast<void*>(&vclmem[j].mConst)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + } + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << vclmem.size() << ": cl_mem: " << mpClmem2); + err = clSetKernelArg(redKernel, vclmem.size(), sizeof(cl_mem), static_cast<void*>(&mpClmem2)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << (vclmem.size() + 1) << ": cl_int: " << nInput); + err = clSetKernelArg(redKernel, vclmem.size() + 1, sizeof(cl_int), static_cast<void*>(&nInput)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << (vclmem.size() + 2) << ": cl_int: " << nCurWindowSize); + err = clSetKernelArg(redKernel, vclmem.size() + 2, sizeof(cl_int), static_cast<void*>(&nCurWindowSize)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + // set work group size and execute + size_t global_work_size[] = { 256, static_cast<size_t>(nVectorWidth) }; + size_t const local_work_size[] = { 256, 1 }; + SAL_INFO("sc.opencl", "Enqueuing kernel " << redKernel); + err = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, redKernel, 2, nullptr, + global_work_size, local_work_size, 0, nullptr, nullptr); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueNDRangeKernel", err, __FILE__, __LINE__); + + err = clFinish(kEnv.mpkCmdQueue); + if (CL_SUCCESS != err) + throw OpenCLError("clFinish", err, __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "Releasing kernel " << redKernel); + err = clReleaseKernel(redKernel); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseKernel failed: " << openclwrapper::errorString(err)); + + // Pass mpClmem2 to the "real" kernel + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": cl_mem: " << mpClmem2); + err = clSetKernelArg(k, argno, sizeof(cl_mem), static_cast<void*>(&mpClmem2)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + } + } + return i; + } + + virtual void GenSlidingWindowFunction( outputstream& ss ) override + { + for (DynamicKernelArgumentRef & rArg : mvSubArguments) + rArg->GenSlidingWindowFunction(ss); + mpCodeGen->GenSlidingWindowFunction(ss, mSymName, mvSubArguments); + } + virtual void GenDeclRef( outputstream& ss ) const override + { + for (size_t i = 0; i < mvSubArguments.size(); i++) + { + if (i) + ss << ","; + mvSubArguments[i]->GenDeclRef(ss); + } + } + virtual void GenDecl( outputstream& ss ) const override + { + for (SubArgumentsType::const_iterator it = mvSubArguments.begin(), e = mvSubArguments.end(); it != e; + ++it) + { + if (it != mvSubArguments.begin()) + ss << ", "; + (*it)->GenDecl(ss); + } + } + + virtual size_t GetWindowSize() const override + { + size_t nCurWindowSize = 0; + for (const auto & rSubArgument : mvSubArguments) + { + size_t nCurChildWindowSize = rSubArgument->GetWindowSize(); + nCurWindowSize = (nCurWindowSize < nCurChildWindowSize) ? + nCurChildWindowSize : nCurWindowSize; + } + return nCurWindowSize; + } + + /// When declared as input to a sliding window function + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + for (SubArgumentsType::const_iterator it = mvSubArguments.begin(), e = mvSubArguments.end(); it != e; + ++it) + { + if (it != mvSubArguments.begin()) + ss << ", "; + (*it)->GenSlidingWindowDecl(ss); + } + } + /// Generate either a function call to each children + /// or directly inline it if we are already inside a loop + virtual std::string GenSlidingWindowDeclRef( bool nested = false ) const override + { + outputstream ss; + if (!nested) + { + ss << mSymName << "_" << mpCodeGen->BinFuncName() << "("; + for (size_t i = 0; i < mvSubArguments.size(); i++) + { + if (i) + ss << ", "; + mvSubArguments[i]->GenDeclRef(ss); + } + ss << ")"; + } + else + { + if (mvSubArguments.size() != 2) + throw Unhandled(__FILE__, __LINE__); + bool bArgument1_NeedNested = + mvSubArguments[0]->GetFormulaToken()->GetType() + != formula::svSingleVectorRef; + bool bArgument2_NeedNested = + mvSubArguments[1]->GetFormulaToken()->GetType() + != formula::svSingleVectorRef; + ss << "("; + ss << mpCodeGen-> + Gen2(mvSubArguments[0] + ->GenSlidingWindowDeclRef(bArgument1_NeedNested), + mvSubArguments[1] + ->GenSlidingWindowDeclRef(bArgument2_NeedNested)); + ss << ")"; + } + return ss.str(); + } + virtual std::string DumpOpName() const override + { + std::string t = "_" + mpCodeGen->BinFuncName(); + for (const auto & rSubArgument : mvSubArguments) + t += rSubArgument->DumpOpName(); + return t; + } + virtual void DumpInlineFun( std::set<std::string>& decls, + std::set<std::string>& funs ) const override + { + mpCodeGen->BinInlineFun(decls, funs); + for (const auto & rSubArgument : mvSubArguments) + rSubArgument->DumpInlineFun(decls, funs); + } + virtual bool IsEmpty() const override + { + for (const auto & rSubArgument : mvSubArguments) + if( !rSubArgument->IsEmpty()) + return false; + return true; + } + virtual ~DynamicKernelSoPArguments() override + { + if (mpClmem2) + { + cl_int err; + err = clReleaseMemObject(mpClmem2); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err)); + mpClmem2 = nullptr; + } + } + +private: + SubArgumentsType mvSubArguments; + std::shared_ptr<SlidingFunctionBase> mpCodeGen; + cl_mem mpClmem2; +}; + +} + +static DynamicKernelArgumentRef SoPHelper( const ScCalcConfig& config, + const std::string& ts, const FormulaTreeNodeRef& ft, std::shared_ptr<SlidingFunctionBase> pCodeGen, + int nResultSize ) +{ + return std::make_shared<DynamicKernelSoPArguments>(config, ts, ft, std::move(pCodeGen), nResultSize); +} + +template<class Base> +static std::shared_ptr<DynamicKernelArgument> VectorRefFactory( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft, + std::shared_ptr<SlidingFunctionBase>& pCodeGen, + int index ) +{ + //Black lists ineligible classes here .. + // SUMIFS does not perform parallel reduction at DoubleVectorRef level + if (dynamic_cast<OpSumIfs*>(pCodeGen.get())) + { + // coverity[identical_branches] - only identical if Base happens to be VectorRef + if (index == 0) // the first argument of OpSumIfs cannot be strings anyway + return std::make_shared<DynamicKernelSlidingArgument<VectorRef>>(config, s, ft, pCodeGen, index); + return std::make_shared<DynamicKernelSlidingArgument<Base>>(config, s, ft, pCodeGen, index); + } + // AVERAGE is not supported yet + //Average has been supported by reduction kernel + /*else if (dynamic_cast<OpAverage*>(pCodeGen.get())) + { + return new DynamicKernelSlidingArgument<Base>(config, s, ft, pCodeGen, index); + }*/ + // MUL is not supported yet + else if (dynamic_cast<OpMul*>(pCodeGen.get())) + { + return std::make_shared<DynamicKernelSlidingArgument<Base>>(config, s, ft, pCodeGen, index); + } + // Sub is not a reduction per se + else if (dynamic_cast<OpSub*>(pCodeGen.get())) + { + return std::make_shared<DynamicKernelSlidingArgument<Base>>(config, s, ft, pCodeGen, index); + } + // Only child class of Reduction is supported + else if (!dynamic_cast<Reduction*>(pCodeGen.get())) + { + return std::make_shared<DynamicKernelSlidingArgument<Base>>(config, s, ft, pCodeGen, index); + } + + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken*>( + ft->GetFormulaToken()); + // Window being too small to justify a parallel reduction + if (pDVR->GetRefRowSize() < REDUCE_THRESHOLD) + return std::make_shared<DynamicKernelSlidingArgument<Base>>(config, s, ft, pCodeGen, index); + if (pDVR->IsStartFixed() == pDVR->IsEndFixed()) + return std::make_shared<ParallelReductionVectorRef<Base>>(config, s, ft, pCodeGen, index); + else // Other cases are not supported as well + return std::make_shared<DynamicKernelSlidingArgument<Base>>(config, s, ft, pCodeGen, index); +} + +DynamicKernelSoPArguments::DynamicKernelSoPArguments(const ScCalcConfig& config, + const std::string& s, const FormulaTreeNodeRef& ft, std::shared_ptr<SlidingFunctionBase> pCodeGen, int nResultSize ) : + DynamicKernelArgument(config, s, ft), mpCodeGen(pCodeGen), mpClmem2(nullptr) +{ + size_t nChildren = ft->Children.size(); + + for (size_t i = 0; i < nChildren; i++) + { + FormulaTreeNodeRef rChild = ft->Children[i]; + if (!rChild) + throw Unhandled(__FILE__, __LINE__); + FormulaToken* pChild = rChild->GetFormulaToken(); + if (!pChild) + throw Unhandled(__FILE__, __LINE__); + OpCode opc = pChild->GetOpCode(); + outputstream tmpname; + tmpname << s << "_" << i; + std::string ts = tmpname.str(); + switch (opc) + { + case ocPush: + if (pChild->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken*>(pChild); + + // The code below will split one svDoubleVectorRef into one subargument + // for each column of data, and then all these subarguments will be later + // passed to the code generating the function. Most of the code then + // simply treats each subargument as one argument to the function, and thus + // could break in this case. + // As a simple solution, simply prevent this case, unless the code in question + // explicitly claims it will handle this situation properly. + if( pDVR->GetArrays().size() > 1 ) + { + if( !pCodeGen->canHandleMultiVector()) + throw UnhandledToken(("Function '" + pCodeGen->BinFuncName() + + "' cannot handle multi-column DoubleRef").c_str(), __FILE__, __LINE__); + + SAL_INFO("sc.opencl", "multi-column DoubleRef"); + + } + + // FIXME: The Right Thing to do would be to compare the accumulated kernel + // parameter size against the CL_DEVICE_MAX_PARAMETER_SIZE of the device, but + // let's just do this sanity check for now. The kernel compilation will + // hopefully fail anyway if the size of parameters exceeds the limit and this + // sanity check is just to make us bail out a bit earlier. + + // The number 50 comes from the fact that the minimum size of + // CL_DEVICE_MAX_PARAMETER_SIZE is 256, which for 32-bit code probably means 64 + // of them. Round down a bit. + + if (pDVR->GetArrays().size() > 50) + throw UnhandledToken(("Kernel would have ridiculously many parameters (" + std::to_string(2 + pDVR->GetArrays().size()) + ")").c_str(), __FILE__, __LINE__); + + for (size_t j = 0; j < pDVR->GetArrays().size(); ++j) + { + SAL_INFO("sc.opencl", "i=" << i << " j=" << j << + " mpNumericArray=" << pDVR->GetArrays()[j].mpNumericArray << + " mpStringArray=" << pDVR->GetArrays()[j].mpStringArray << + " allStringsAreNull=" << (AllStringsAreNull(pDVR->GetArrays()[j].mpStringArray, pDVR->GetArrayLength())?"YES":"NO") << + " takeNumeric=" << (pCodeGen->takeNumeric()?"YES":"NO") << + " takeString=" << (pCodeGen->takeString()?"YES":"NO")); + + if (pDVR->GetArrays()[j].mpNumericArray && + pCodeGen->takeNumeric() && + pDVR->GetArrays()[j].mpStringArray && + pCodeGen->takeString()) + { + // Function takes numbers or strings, there are both + SAL_INFO("sc.opencl", "Numbers and strings"); + mvSubArguments.push_back( + std::make_shared<DynamicKernelMixedSlidingArgument>(mCalcConfig, + ts, ft->Children[i], mpCodeGen, j)); + } + else if (pDVR->GetArrays()[j].mpNumericArray && + pCodeGen->takeNumeric() && + (AllStringsAreNull(pDVR->GetArrays()[j].mpStringArray, pDVR->GetArrayLength()) + || mCalcConfig.meStringConversion == ScCalcConfig::StringConversion::ZERO + || pCodeGen->forceStringsToZero())) + { + // Function takes numbers, and either there + // are no strings, or there are strings but + // they are to be treated as zero + SAL_INFO("sc.opencl", "Numbers (no strings or strings treated as zero)"); + if(!AllStringsAreNull(pDVR->GetArrays()[j].mpStringArray, pDVR->GetArrayLength())) + { + mvSubArguments.push_back( + VectorRefFactory<VectorRefStringsToZero>(mCalcConfig, + ts, ft->Children[i], mpCodeGen, j)); + } + else + { + mvSubArguments.push_back( + VectorRefFactory<VectorRef>(mCalcConfig, + ts, ft->Children[i], mpCodeGen, j)); + } + } + else if (pDVR->GetArrays()[j].mpNumericArray == nullptr && + pCodeGen->takeNumeric() && + pDVR->GetArrays()[j].mpStringArray && + ( mCalcConfig.meStringConversion == ScCalcConfig::StringConversion::ZERO + || pCodeGen->forceStringsToZero())) + { + // Function takes numbers, and there are only + // strings, but they are to be treated as zero + SAL_INFO("sc.opencl", "Only strings even if want numbers but should be treated as zero"); + mvSubArguments.push_back( + VectorRefFactory<VectorRefStringsToZero>(mCalcConfig, + ts, ft->Children[i], mpCodeGen, j)); + } + else if (pDVR->GetArrays()[j].mpStringArray && + pCodeGen->takeString()) + { + // There are strings, and the function takes strings. + SAL_INFO("sc.opencl", "Strings only"); + mvSubArguments.push_back( + VectorRefFactory + <DynamicKernelStringArgument>(mCalcConfig, + ts, ft->Children[i], mpCodeGen, j)); + } + else if (AllStringsAreNull(pDVR->GetArrays()[j].mpStringArray, pDVR->GetArrayLength()) && + pDVR->GetArrays()[j].mpNumericArray == nullptr) + { + // There are only empty cells. Push as an + // array of NANs + SAL_INFO("sc.opencl", "Only empty cells"); + mvSubArguments.push_back( + VectorRefFactory<VectorRef>(mCalcConfig, + ts, ft->Children[i], mpCodeGen, j)); + } + else + { + SAL_INFO("sc.opencl", "Unhandled case, rejecting for OpenCL"); + throw UnhandledToken(("Unhandled numbers/strings combination for '" + + pCodeGen->BinFuncName() + "'").c_str(), __FILE__, __LINE__); + } + } + } + else if (pChild->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*>(pChild); + + SAL_INFO("sc.opencl", "i=" << i << + " mpNumericArray=" << pSVR->GetArray().mpNumericArray << + " mpStringArray=" << pSVR->GetArray().mpStringArray << + " allStringsAreNull=" << (AllStringsAreNull(pSVR->GetArray().mpStringArray, pSVR->GetArrayLength())?"YES":"NO") << + " takeNumeric=" << (pCodeGen->takeNumeric()?"YES":"NO") << + " takeString=" << (pCodeGen->takeString()?"YES":"NO")); + + if (pSVR->GetArray().mpNumericArray && + pCodeGen->takeNumeric() && + pSVR->GetArray().mpStringArray && + pCodeGen->takeString()) + { + // Function takes numbers or strings, there are both + SAL_INFO("sc.opencl", "Numbers and strings"); + mvSubArguments.push_back( + std::make_shared<DynamicKernelMixedArgument>(mCalcConfig, + ts, ft->Children[i])); + } + else if (pSVR->GetArray().mpNumericArray && + pCodeGen->takeNumeric() && + (AllStringsAreNull(pSVR->GetArray().mpStringArray, pSVR->GetArrayLength()) + || mCalcConfig.meStringConversion == ScCalcConfig::StringConversion::ZERO + || pCodeGen->forceStringsToZero())) + { + // Function takes numbers, and either there + // are no strings, or there are strings but + // they are to be treated as zero + SAL_INFO("sc.opencl", "Numbers (no strings or strings treated as zero)"); + if( !AllStringsAreNull(pSVR->GetArray().mpStringArray, pSVR->GetArrayLength())) + mvSubArguments.push_back( + std::make_shared<VectorRefStringsToZero>(mCalcConfig, ts, + ft->Children[i])); + else + mvSubArguments.push_back( + std::make_shared<VectorRef>(mCalcConfig, ts, + ft->Children[i])); + } + else if (pSVR->GetArray().mpNumericArray == nullptr && + pCodeGen->takeNumeric() && + pSVR->GetArray().mpStringArray && + (mCalcConfig.meStringConversion == ScCalcConfig::StringConversion::ZERO + || pCodeGen->forceStringsToZero())) + { + // Function takes numbers, and there are only + // strings, but they are to be treated as zero + SAL_INFO("sc.opencl", "Only strings even if want numbers but should be treated as zero"); + mvSubArguments.push_back( + std::make_shared<VectorRefStringsToZero>(mCalcConfig, ts, + ft->Children[i])); + } + else if (pSVR->GetArray().mpStringArray && + pCodeGen->takeString()) + { + // There are strings, and the function takes strings. + SAL_INFO("sc.opencl", "Strings only"); + mvSubArguments.push_back( + std::make_shared<DynamicKernelStringArgument>(mCalcConfig, + ts, ft->Children[i])); + } + else if (AllStringsAreNull(pSVR->GetArray().mpStringArray, pSVR->GetArrayLength()) && + pSVR->GetArray().mpNumericArray == nullptr) + { + // There are only empty cells. Push as an + // array of NANs + SAL_INFO("sc.opencl", "Only empty cells"); + mvSubArguments.push_back( + std::make_shared<VectorRef>(mCalcConfig, ts, + ft->Children[i])); + } + else + { + SAL_INFO("sc.opencl", "Unhandled case, rejecting for OpenCL"); + throw UnhandledToken(("Unhandled numbers/strings combination for '" + + pCodeGen->BinFuncName() + "'").c_str(), __FILE__, __LINE__); + } + } + else if (pChild->GetType() == formula::svDouble) + { + SAL_INFO("sc.opencl", "Constant number case"); + mvSubArguments.push_back( + std::make_shared<DynamicKernelConstantArgument>(mCalcConfig, ts, + ft->Children[i])); + } + else if (pChild->GetType() == formula::svString + && pCodeGen->takeString()) + { + SAL_INFO("sc.opencl", "Constant string case"); + mvSubArguments.push_back( + std::make_shared<ConstStringArgument>(mCalcConfig, ts, + ft->Children[i])); + } + else if (pChild->GetType() == formula::svString + && !pCodeGen->takeString() + && pCodeGen->takeNumeric() + && pCodeGen->forceStringsToZero()) + { + SAL_INFO("sc.opencl", "Constant string case, treated as zero"); + mvSubArguments.push_back( + DynamicKernelArgumentRef(new DynamicKernelStringToZeroArgument(mCalcConfig, ts, + ft->Children[i]))); + } + else + { + SAL_INFO("sc.opencl", "Unhandled operand, rejecting for OpenCL"); + throw UnhandledToken(("unhandled operand " + StackVarEnumToString(pChild->GetType()) + " for ocPush").c_str(), __FILE__, __LINE__); + } + break; + case ocPi: + mvSubArguments.push_back( + std::make_shared<DynamicKernelPiArgument>(mCalcConfig, ts, + ft->Children[i])); + break; + case ocRandom: + mvSubArguments.push_back( + std::make_shared<DynamicKernelRandomArgument>(mCalcConfig, ts, + ft->Children[i])); + break; +#define CASE(opcode, createCode) \ + case opcode: \ + mvSubArguments.push_back(SoPHelper(mCalcConfig, ts, ft->Children[i], createCode, nResultSize)); \ + break; + CASE(ocAbs, std::make_shared<OpAbs>()) + CASE(ocAdd, std::make_shared<OpSum>(nResultSize)) + CASE(ocAnd, std::make_shared<OpAnd>()) + CASE(ocArcCos, std::make_shared<OpArcCos>()) + CASE(ocArcCosHyp, std::make_shared<OpArcCosHyp>()) + CASE(ocArcCot, std::make_shared<OpArcCot>()) + CASE(ocArcCotHyp, std::make_shared<OpArcCotHyp>()) + CASE(ocArcSin, std::make_shared<OpArcSin>()) + CASE(ocArcSinHyp, std::make_shared<OpArcSinHyp>()) + CASE(ocArcTan, std::make_shared<OpArcTan>()) + CASE(ocArcTan2, std::make_shared<OpArcTan2>()) + CASE(ocArcTanHyp, std::make_shared<OpArcTanH>()) + CASE(ocAveDev, std::make_shared<OpAveDev>()) + CASE(ocAverage, std::make_shared<OpAverage>(nResultSize)) + CASE(ocAverageA, std::make_shared<OpAverageA>(nResultSize)) + CASE(ocAverageIf, std::make_shared<OpAverageIf>()) + CASE(ocAverageIfs, std::make_shared<OpAverageIfs>()) + CASE(ocB, std::make_shared<OpB>()) + CASE(ocBetaDist, std::make_shared<OpBetaDist>()) + CASE(ocBetaInv, std::make_shared<OpBetainv>()) + CASE(ocBinomDist, std::make_shared<OpBinomdist>()) + CASE(ocBitAnd, std::make_shared<OpBitAnd>()) + CASE(ocBitLshift, std::make_shared<OpBitLshift>()) + CASE(ocBitOr, std::make_shared<OpBitOr>()) + CASE(ocBitRshift, std::make_shared<OpBitRshift>()) + CASE(ocBitXor, std::make_shared<OpBitXor>()) + CASE(ocCeil, std::make_shared<OpCeil>()) + CASE(ocChiDist, std::make_shared<OpChiDist>()) + CASE(ocChiInv, std::make_shared<OpChiInv>()) + CASE(ocChiSqDist, std::make_shared<OpChiSqDist>()) + CASE(ocChiSqInv, std::make_shared<OpChiSqInv>()) + CASE(ocCombin, std::make_shared<OpCombin>()) + CASE(ocCombinA, std::make_shared<OpCombinA>()) + CASE(ocConfidence, std::make_shared<OpConfidence>()) + CASE(ocCorrel, std::make_shared<OpCorrel>()) + CASE(ocCos, std::make_shared<OpCos>()) + CASE(ocCosHyp, std::make_shared<OpCosh>()) + CASE(ocCosecant, std::make_shared<OpCsc>()) + CASE(ocCosecantHyp, std::make_shared<OpCscH>()) + CASE(ocCot, std::make_shared<OpCot>()) + CASE(ocCotHyp, std::make_shared<OpCoth>()) + CASE(ocCount, std::make_shared<OpCount>(nResultSize)) + CASE(ocCount2, std::make_shared<OpCountA>(nResultSize)) + CASE(ocCountIf, std::make_shared<OpCountIf>()) + CASE(ocCountIfs, std::make_shared<OpCountIfs>()) + CASE(ocCovar, std::make_shared<OpCovar>()) + CASE(ocCritBinom, std::make_shared<OpCritBinom>()) + CASE(ocDB, std::make_shared<OpDB>()) + CASE(ocDDB, std::make_shared<OpDDB>()) + CASE(ocDeg, std::make_shared<OpDeg>()) + CASE(ocDevSq, std::make_shared<OpDevSq>()) + CASE(ocDiv, std::make_shared<OpDiv>(nResultSize)) + CASE(ocEqual, std::make_shared<OpEqual>()) + CASE(ocEven, std::make_shared<OpEven>()) + CASE(ocExp, std::make_shared<OpExp>()) + CASE(ocExpDist, std::make_shared<OpExponDist>()) + CASE(ocFDist, std::make_shared<OpFdist>()) + CASE(ocFInv, std::make_shared<OpFInv>()) + CASE(ocFTest, std::make_shared<OpFTest>()) + CASE(ocFV, std::make_shared<OpFV>()) + CASE(ocFact, std::make_shared<OpFact>()) + CASE(ocFisher, std::make_shared<OpFisher>()) + CASE(ocFisherInv, std::make_shared<OpFisherInv>()) + CASE(ocFloor, std::make_shared<OpFloor>()) + CASE(ocForecast, std::make_shared<OpForecast>()) + CASE(ocGamma, std::make_shared<OpGamma>()) + CASE(ocGammaDist, std::make_shared<OpGammaDist>()) + CASE(ocGammaInv, std::make_shared<OpGammaInv>()) + CASE(ocGammaLn, std::make_shared<OpGammaLn>()) + CASE(ocGauss, std::make_shared<OpGauss>()) + CASE(ocGeoMean, std::make_shared<OpGeoMean>()) + CASE(ocGreater, std::make_shared<OpGreater>()) + CASE(ocGreaterEqual, std::make_shared<OpGreaterEqual>()) + CASE(ocHarMean, std::make_shared<OpHarMean>()) + CASE(ocHypGeomDist, std::make_shared<OpHypGeomDist>()) + CASE(ocIRR, std::make_shared<OpIRR>()) + CASE(ocISPMT, std::make_shared<OpISPMT>()) + CASE(ocIf, std::make_shared<OpIf>()) + CASE(ocInt, std::make_shared<OpInt>()) + CASE(ocIntercept, std::make_shared<OpIntercept>()) + CASE(ocIpmt, std::make_shared<OpIPMT>()) + CASE(ocIsEven, std::make_shared<OpIsEven>()) + CASE(ocIsOdd, std::make_shared<OpIsOdd>()) + CASE(ocKurt, std::make_shared<OpKurt>()) + CASE(ocLess, std::make_shared<OpLess>()) + CASE(ocLessEqual, std::make_shared<OpLessEqual>()) + CASE(ocLn, std::make_shared<OpLn>()) + CASE(ocLog, std::make_shared<OpLog>()) + CASE(ocLog10, std::make_shared<OpLog10>()) + CASE(ocLogInv, std::make_shared<OpLogInv>()) + CASE(ocLogNormDist, std::make_shared<OpLogNormDist>()) + CASE(ocMIRR, std::make_shared<OpMIRR>()) + CASE(ocMax, std::make_shared<OpMax>(nResultSize)) + CASE(ocMaxA, std::make_shared<OpMaxA>(nResultSize)) + CASE(ocMin, std::make_shared<OpMin>(nResultSize)) + CASE(ocMinA, std::make_shared<OpMinA>(nResultSize)) + CASE(ocMod, std::make_shared<OpMod>()) + CASE(ocMul, std::make_shared<OpMul>(nResultSize)) + CASE(ocNPV, std::make_shared<OpNPV>()) + CASE(ocNegBinomVert , std::make_shared<OpNegbinomdist>()) + CASE(ocNegSub, std::make_shared<OpNegSub>()) + CASE(ocNormDist, std::make_shared<OpNormdist>()) + CASE(ocNormInv, std::make_shared<OpNorminv>()) + CASE(ocNot, std::make_shared<OpNot>()) + CASE(ocNotEqual, std::make_shared<OpNotEqual>()) + CASE(ocNper, std::make_shared<OpNper>()) + CASE(ocOdd, std::make_shared<OpOdd>()) + CASE(ocOr, std::make_shared<OpOr>()) + CASE(ocPDuration, std::make_shared<OpPDuration>()) + CASE(ocPMT, std::make_shared<OpPMT>()) + CASE(ocPV, std::make_shared<OpPV>()) + CASE(ocPearson, std::make_shared<OpPearson>()) + CASE(ocPermut, std::make_shared<OpPermut>()) + CASE(ocPermutationA, std::make_shared<OpPermutationA>()) + CASE(ocPhi, std::make_shared<OpPhi>()) + CASE(ocPoissonDist, std::make_shared<OpPoisson>()) + CASE(ocPow, std::make_shared<OpPower>()) + CASE(ocPower, std::make_shared<OpPower>()) + CASE(ocPpmt, std::make_shared<OpPPMT>()) + CASE(ocProduct, std::make_shared<OpProduct>()) + CASE(ocRRI, std::make_shared<OpRRI>()) + CASE(ocRSQ, std::make_shared<OpRsq>()) + CASE(ocRad, std::make_shared<OpRadians>()) + CASE(ocRate, std::make_shared<OpRate>()) + CASE(ocRound, std::make_shared<OpRound>()) + CASE(ocRoundDown, std::make_shared<OpRoundDown>()) + CASE(ocRoundUp, std::make_shared<OpRoundUp>()) + CASE(ocSLN, std::make_shared<OpSLN>()) + CASE(ocSNormInv, std::make_shared<OpNormsinv>()) + CASE(ocSTEYX, std::make_shared<OpSTEYX>()) + CASE(ocSYD, std::make_shared<OpSYD>()) + CASE(ocSecant, std::make_shared<OpSec>()) + CASE(ocSecantHyp, std::make_shared<OpSecH>()) + CASE(ocSin, std::make_shared<OpSin>()) + CASE(ocSinHyp, std::make_shared<OpSinh>()) + CASE(ocSkew, std::make_shared<OpSkew>()) + CASE(ocSkewp, std::make_shared<OpSkewp>()) + CASE(ocSlope, std::make_shared<OpSlope>()) + CASE(ocSqrt, std::make_shared<OpSqrt>()) + CASE(ocStDev, std::make_shared<OpStDev>()) + CASE(ocStDevA, std::make_shared<OpStDevA>()) + CASE(ocStDevP, std::make_shared<OpStDevP>()) + CASE(ocStDevPA, std::make_shared<OpStDevPA>()) + CASE(ocStandard, std::make_shared<OpStandard>()) + CASE(ocStdNormDist, std::make_shared<OpNormsdist>()) + CASE(ocSub, std::make_shared<OpSub>(nResultSize)) + CASE(ocSum, std::make_shared<OpSum>(nResultSize)) + CASE(ocSumIf, std::make_shared<OpSumIf>()) + CASE(ocSumIfs, std::make_shared<OpSumIfs>()) + CASE(ocSumProduct, std::make_shared<OpSumProduct>()) + CASE(ocSumSQ, std::make_shared<OpSumSQ>()) + CASE(ocSumX2DY2, std::make_shared<OpSumX2PY2>()) + CASE(ocSumX2MY2, std::make_shared<OpSumX2MY2>()) + CASE(ocSumXMY2, std::make_shared<OpSumXMY2>()) + CASE(ocTDist, std::make_shared<OpTDist>()) + CASE(ocTInv, std::make_shared<OpTInv>()) + CASE(ocTTest, std::make_shared<OpTTest>()) + CASE(ocTan, std::make_shared<OpTan>()) + CASE(ocTanHyp, std::make_shared<OpTanH>()) + CASE(ocTrunc, std::make_shared<OpTrunc>()) + CASE(ocVBD, std::make_shared<OpVDB>()) + CASE(ocVLookup, std::make_shared<OpVLookup>()) + CASE(ocVar, std::make_shared<OpVar>()) + CASE(ocVarA, std::make_shared<OpVarA>()) + CASE(ocVarP, std::make_shared<OpVarP>()) + CASE(ocVarPA, std::make_shared<OpVarPA>()) + CASE(ocWeibull, std::make_shared<OpWeibull>()) + CASE(ocXor, std::make_shared<OpXor>()) + CASE(ocZTest, std::make_shared<OpZTest>()) +#undef CASE + case ocExternal: +#define EXTCASE( name, createCode ) \ + else if (pChild->GetExternal() == name) \ + { \ + mvSubArguments.push_back(SoPHelper(mCalcConfig, ts, ft->Children[i], createCode, nResultSize)); \ + } + + if(false) // start else-if chain + ; + EXTCASE("com.sun.star.sheet.addin.Analysis.getAccrint", std::make_shared<OpAccrint>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getAccrintm", std::make_shared<OpAccrintm>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getAmordegrc", std::make_shared<OpAmordegrc>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getAmorlinc", std::make_shared<OpAmorlinc>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getBesselj", std::make_shared<OpBesselj>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCoupdaybs", std::make_shared<OpCoupdaybs>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCoupdays", std::make_shared<OpCoupdays>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCoupdaysnc", std::make_shared<OpCoupdaysnc>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCoupncd", std::make_shared<OpCoupncd>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCoupnum", std::make_shared<OpCoupnum>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCouppcd", std::make_shared<OpCouppcd>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCumipmt", std::make_shared<OpCumipmt>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getCumprinc", std::make_shared<OpCumprinc>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getDisc", std::make_shared<OpDISC>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getDollarde", std::make_shared<OpDollarde>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getDollarfr", std::make_shared<OpDollarfr>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getDuration", std::make_shared<OpDuration_ADD>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getEffect", std::make_shared<OpEffective>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getFvschedule", std::make_shared<OpFvschedule>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getGestep", std::make_shared<OpGestep>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getIntrate", std::make_shared<OpINTRATE>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getIseven", std::make_shared<OpIsEven>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getIsodd", std::make_shared<OpIsOdd>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getMduration", std::make_shared<OpMDuration>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getMround", std::make_shared<OpMROUND>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getNominal", std::make_shared<OpNominal>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getOddlprice", std::make_shared<OpOddlprice>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getOddlyield", std::make_shared<OpOddlyield>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getPrice", std::make_shared<OpPrice>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getPricedisc", std::make_shared<OpPriceDisc>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getPricemat", std::make_shared<OpPriceMat>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getQuotient", std::make_shared<OpQuotient>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getReceived", std::make_shared<OpReceived>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getSeriessum", std::make_shared<OpSeriesSum>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getSqrtpi", std::make_shared<OpSqrtPi>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getTbilleq", std::make_shared<OpTbilleq>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getTbillprice", std::make_shared<OpTbillprice>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getTbillyield", std::make_shared<OpTbillyield>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getXirr", std::make_shared<OpXirr>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getXnpv", std::make_shared<OpXNPV>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getYield", std::make_shared<OpYield>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getYielddisc", std::make_shared<OpYielddisc>()) + EXTCASE("com.sun.star.sheet.addin.Analysis.getYieldmat", std::make_shared<OpYieldmat>()) + else + throw UnhandledToken(OUString("unhandled external " + pChild->GetExternal()).toUtf8().getStr(), __FILE__, __LINE__); + break; +#undef EXTCASE + + default: + throw UnhandledToken(OUString("unhandled opcode " + + formula::FormulaCompiler().GetOpCodeMap(com::sun::star::sheet::FormulaLanguage::ENGLISH)->getSymbol(opc) + + "(" + OUString::number(opc) + ")").toUtf8().getStr(), __FILE__, __LINE__); + } + } +} + +namespace { + +class DynamicKernel : public CompiledFormula +{ +public: + DynamicKernel( ScCalcConfig config, FormulaTreeNodeRef r, int nResultSize ); + virtual ~DynamicKernel() override; + + static std::shared_ptr<DynamicKernel> create( const ScCalcConfig& config, const ScTokenArray& rCode, int nResultSize ); + + /// OpenCL code generation + void CodeGen(); + + /// Produce kernel hash + std::string const & GetMD5(); + + /// Create program, build, and create kernel + /// TODO cache results based on kernel body hash + /// TODO: abstract OpenCL part out into OpenCL wrapper. + void CreateKernel(); + + /// Prepare buffers, marshal them to GPU, and launch the kernel + /// TODO: abstract OpenCL part out into OpenCL wrapper. + void Launch( size_t nr ); + + cl_mem GetResultBuffer() const { return mpResClmem; } + +private: + ScCalcConfig mCalcConfig; + FormulaTreeNodeRef mpRoot; + SymbolTable mSyms; + std::string mKernelSignature, mKernelHash; + std::string mFullProgramSrc; + cl_program mpProgram; + cl_kernel mpKernel; + cl_mem mpResClmem; // Results + std::set<std::string> inlineDecl; + std::set<std::string> inlineFun; + + int mnResultSize; +}; + +} + +DynamicKernel::DynamicKernel( ScCalcConfig config, FormulaTreeNodeRef x, int nResultSize ) : + mCalcConfig(std::move(config)), + mpRoot(std::move(x)), + mpProgram(nullptr), + mpKernel(nullptr), + mpResClmem(nullptr), + mnResultSize(nResultSize) {} + +DynamicKernel::~DynamicKernel() +{ + cl_int err; + if (mpResClmem) + { + err = clReleaseMemObject(mpResClmem); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err)); + } + if (mpKernel) + { + SAL_INFO("sc.opencl", "Releasing kernel " << mpKernel); + err = clReleaseKernel(mpKernel); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseKernel failed: " << openclwrapper::errorString(err)); + } + // mpProgram is not going to be released here -- it's cached. +} + +void DynamicKernel::CodeGen() +{ + // Traverse the tree of expression and declare symbols used + const DynamicKernelArgument* DK = mSyms.DeclRefArg<DynamicKernelSoPArguments>(mCalcConfig, mpRoot, std::make_shared<OpNop>(mnResultSize), mnResultSize); + + outputstream decl; + if (openclwrapper::gpuEnv.mnKhrFp64Flag) + { + decl << "#if __OPENCL_VERSION__ < 120\n"; + decl << "#pragma OPENCL EXTENSION cl_khr_fp64: enable\n"; + decl << "#endif\n"; + } + else if (openclwrapper::gpuEnv.mnAmdFp64Flag) + { + decl << "#pragma OPENCL EXTENSION cl_amd_fp64: enable\n"; + } + // preambles + decl << publicFunc; + DK->DumpInlineFun(inlineDecl, inlineFun); + for (const auto& rItem : inlineDecl) + { + decl << rItem; + } + + for (const auto& rItem : inlineFun) + { + decl << rItem; + } + mSyms.DumpSlidingWindowFunctions(decl); + mKernelSignature = DK->DumpOpName(); + decl << "__kernel void DynamicKernel" << mKernelSignature; + decl << "(__global double *result"; + if( !DK->IsEmpty()) + { + decl << ", "; + DK->GenSlidingWindowDecl(decl); + } + decl << ") {\n\tint gid0 = get_global_id(0);\n\tresult[gid0] = " << + DK->GenSlidingWindowDeclRef() << ";\n}\n"; + mFullProgramSrc = decl.str(); + SAL_INFO( + "sc.opencl.source", + (mKernelSignature[0] == '_' + ? mKernelSignature.substr(1, std::string::npos) : mKernelSignature) + << " program to be compiled:\n" << linenumberify(mFullProgramSrc)); +} + +std::string const & DynamicKernel::GetMD5() +{ + if (mKernelHash.empty()) + { + outputstream md5s; + // Compute MD5SUM of kernel body to obtain the name + sal_uInt8 result[RTL_DIGEST_LENGTH_MD5]; + rtl_digest_MD5( + mFullProgramSrc.c_str(), + mFullProgramSrc.length(), result, + RTL_DIGEST_LENGTH_MD5); + for (sal_uInt8 i : result) + { + md5s << std::hex << static_cast<int>(i); + } + mKernelHash = md5s.str(); + } + return mKernelHash; +} + +/// Build code +void DynamicKernel::CreateKernel() +{ + if (mpKernel) + // already created. + return; + + cl_int err; + std::string kname = "DynamicKernel" + mKernelSignature; + // Compile kernel here!!! + + OpenCLZone zone; + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + const char* src = mFullProgramSrc.c_str(); + static std::string lastOneKernelHash; + static std::string lastSecondKernelHash; + static cl_program lastOneProgram = nullptr; + static cl_program lastSecondProgram = nullptr; + std::string KernelHash = mKernelSignature + GetMD5(); + if (lastOneKernelHash == KernelHash && lastOneProgram) + { + mpProgram = lastOneProgram; + } + else if (lastSecondKernelHash == KernelHash && lastSecondProgram) + { + mpProgram = lastSecondProgram; + } + else + { // doesn't match the last compiled formula. + + if (lastSecondProgram) + { + SAL_INFO("sc.opencl", "Releasing program " << lastSecondProgram); + err = clReleaseProgram(lastSecondProgram); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseProgram failed: " << openclwrapper::errorString(err)); + lastSecondProgram = nullptr; + } + if (openclwrapper::buildProgramFromBinary("", + &openclwrapper::gpuEnv, KernelHash.c_str(), 0)) + { + mpProgram = openclwrapper::gpuEnv.mpArryPrograms[0]; + openclwrapper::gpuEnv.mpArryPrograms[0] = nullptr; + } + else + { + mpProgram = clCreateProgramWithSource(kEnv.mpkContext, 1, + &src, nullptr, &err); + if (err != CL_SUCCESS) + throw OpenCLError("clCreateProgramWithSource", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created program " << mpProgram); + + err = clBuildProgram(mpProgram, 1, + &openclwrapper::gpuEnv.mpDevID, "", nullptr, nullptr); + if (err != CL_SUCCESS) + { +#if OSL_DEBUG_LEVEL > 0 + if (err == CL_BUILD_PROGRAM_FAILURE) + { + cl_build_status stat; + cl_int e = clGetProgramBuildInfo( + mpProgram, openclwrapper::gpuEnv.mpDevID, + CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), + &stat, nullptr); + SAL_WARN_IF( + e != CL_SUCCESS, "sc.opencl", + "after CL_BUILD_PROGRAM_FAILURE," + " clGetProgramBuildInfo(CL_PROGRAM_BUILD_STATUS)" + " fails with " << openclwrapper::errorString(e)); + if (e == CL_SUCCESS) + { + size_t n; + e = clGetProgramBuildInfo( + mpProgram, openclwrapper::gpuEnv.mpDevID, + CL_PROGRAM_BUILD_LOG, 0, nullptr, &n); + SAL_WARN_IF( + e != CL_SUCCESS || n == 0, "sc.opencl", + "after CL_BUILD_PROGRAM_FAILURE," + " clGetProgramBuildInfo(CL_PROGRAM_BUILD_LOG)" + " fails with " << openclwrapper::errorString(e) << ", n=" << n); + if (e == CL_SUCCESS && n != 0) + { + std::vector<char> log(n); + e = clGetProgramBuildInfo( + mpProgram, openclwrapper::gpuEnv.mpDevID, + CL_PROGRAM_BUILD_LOG, n, log.data(), nullptr); + SAL_WARN_IF( + e != CL_SUCCESS || n == 0, "sc.opencl", + "after CL_BUILD_PROGRAM_FAILURE," + " clGetProgramBuildInfo(" + "CL_PROGRAM_BUILD_LOG) fails with " << openclwrapper::errorString(e)); + if (e == CL_SUCCESS) + SAL_WARN( + "sc.opencl", + "CL_BUILD_PROGRAM_FAILURE, status " << stat + << ", log \"" << log.data() << "\""); + } + } + } +#endif +#ifdef DBG_UTIL + SAL_WARN("sc.opencl", "Program failed to build, aborting."); + abort(); // make sure errors such as typos don't accidentally go unnoticed +#else + throw OpenCLError("clBuildProgram", err, __FILE__, __LINE__); +#endif + } + SAL_INFO("sc.opencl", "Built program " << mpProgram); + + // Generate binary out of compiled kernel. + openclwrapper::generatBinFromKernelSource(mpProgram, + (mKernelSignature + GetMD5()).c_str()); + } + lastSecondKernelHash = lastOneKernelHash; + lastSecondProgram = lastOneProgram; + lastOneKernelHash = KernelHash; + lastOneProgram = mpProgram; + } + mpKernel = clCreateKernel(mpProgram, kname.c_str(), &err); + if (err != CL_SUCCESS) + throw OpenCLError("clCreateKernel", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created kernel " << mpKernel << " with name " << kname << " in program " << mpProgram); +} + +void DynamicKernel::Launch( size_t nr ) +{ + OpenCLZone zone; + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + cl_int err; + // The results + mpResClmem = clCreateBuffer(kEnv.mpkContext, + cl_mem_flags(CL_MEM_READ_WRITE) | CL_MEM_ALLOC_HOST_PTR, + nr * sizeof(double), nullptr, &err); + if (CL_SUCCESS != err) + throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__); + SAL_INFO("sc.opencl", "Created buffer " << mpResClmem << " size " << nr << "*" << sizeof(double) << "=" << (nr*sizeof(double))); + + SAL_INFO("sc.opencl", "Kernel " << mpKernel << " arg " << 0 << ": cl_mem: " << mpResClmem << " (result)"); + err = clSetKernelArg(mpKernel, 0, sizeof(cl_mem), static_cast<void*>(&mpResClmem)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + // The rest of buffers + mSyms.Marshal(mpKernel, nr, mpProgram); + size_t global_work_size[] = { nr }; + SAL_INFO("sc.opencl", "Enqueuing kernel " << mpKernel); + err = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, mpKernel, 1, nullptr, + global_work_size, nullptr, 0, nullptr, nullptr); + if (CL_SUCCESS != err) + throw OpenCLError("clEnqueueNDRangeKernel", err, __FILE__, __LINE__); + err = clFlush(kEnv.mpkCmdQueue); + if (CL_SUCCESS != err) + throw OpenCLError("clFlush", err, __FILE__, __LINE__); +} + +// Symbol lookup. If there is no such symbol created, allocate one +// kernel with argument with unique name and return so. +// The template argument T must be a subclass of DynamicKernelArgument +template <typename T> +const DynamicKernelArgument* SymbolTable::DeclRefArg(const ScCalcConfig& config, + const FormulaTreeNodeRef& t, + std::shared_ptr<SlidingFunctionBase> pCodeGen, int nResultSize) +{ + FormulaToken* ref = t->GetFormulaToken(); + ArgumentMap::iterator it = mSymbols.find(ref); + if (it == mSymbols.end()) + { + // Allocate new symbols + outputstream ss; + ss << "tmp" << mCurId++; + DynamicKernelArgumentRef new_arg = std::make_shared<T>(config, ss.str(), t, std::move(pCodeGen), nResultSize); + mSymbols[ref] = new_arg; + mParams.push_back(new_arg); + return new_arg.get(); + } + else + { + return it->second.get(); + } +} + +FormulaGroupInterpreterOpenCL::FormulaGroupInterpreterOpenCL() {} + +FormulaGroupInterpreterOpenCL::~FormulaGroupInterpreterOpenCL() {} + +ScMatrixRef FormulaGroupInterpreterOpenCL::inverseMatrix( const ScMatrix& ) +{ + return nullptr; +} + +std::shared_ptr<DynamicKernel> DynamicKernel::create( const ScCalcConfig& rConfig, const ScTokenArray& rCode, int nResultSize ) +{ + // Constructing "AST" + FormulaTokenIterator aCode(rCode); + std::vector<FormulaToken*> aTokenVector; + std::map<FormulaToken*, FormulaTreeNodeRef> aHashMap; + FormulaToken* pCur; + while ((pCur = const_cast<FormulaToken*>(aCode.Next())) != nullptr) + { + OpCode eOp = pCur->GetOpCode(); + if (eOp != ocPush) + { + FormulaTreeNodeRef pCurNode = std::make_shared<FormulaTreeNode>(pCur); + sal_uInt8 nParamCount = pCur->GetParamCount(); + for (sal_uInt8 i = 0; i < nParamCount; i++) + { + if( aTokenVector.empty()) + return nullptr; + FormulaToken* pTempFormula = aTokenVector.back(); + aTokenVector.pop_back(); + if (pTempFormula->GetOpCode() != ocPush) + { + if (aHashMap.find(pTempFormula) == aHashMap.end()) + return nullptr; + pCurNode->Children.push_back(aHashMap[pTempFormula]); + } + else + { + FormulaTreeNodeRef pChildTreeNode = + std::make_shared<FormulaTreeNode>(pTempFormula); + pCurNode->Children.push_back(pChildTreeNode); + } + } + std::reverse(pCurNode->Children.begin(), pCurNode->Children.end()); + aHashMap[pCur] = pCurNode; + } + aTokenVector.push_back(pCur); + } + + FormulaTreeNodeRef Root = std::make_shared<FormulaTreeNode>(nullptr); + Root->Children.push_back(aHashMap[aTokenVector.back()]); + + auto pDynamicKernel = std::make_shared<DynamicKernel>(rConfig, Root, nResultSize); + + // OpenCL source code generation and kernel compilation + try + { + pDynamicKernel->CodeGen(); + pDynamicKernel->CreateKernel(); + } + catch (const UnhandledToken& ut) + { + SAL_INFO("sc.opencl", "Dynamic formula compiler: UnhandledToken: " << ut.mMessage << " at " << ut.mFile << ":" << ut.mLineNumber); + return nullptr; + } + catch (const InvalidParameterCount& ipc) + { + SAL_INFO("sc.opencl", "Dynamic formula compiler: InvalidParameterCount " << ipc.mParameterCount + << " at " << ipc.mFile << ":" << ipc.mLineNumber); + return nullptr; + } + catch (const OpenCLError& oce) + { + // I think OpenCLError exceptions are actually exceptional (unexpected), so do use SAL_WARN + // here. + SAL_WARN("sc.opencl", "Dynamic formula compiler: OpenCLError from " << oce.mFunction << ": " << openclwrapper::errorString(oce.mError) << " at " << oce.mFile << ":" << oce.mLineNumber); + + // OpenCLError used to go to the catch-all below, and not delete pDynamicKernel. Was that + // intentional, should we not do it here then either? + openclwrapper::kernelFailures++; + return nullptr; + } + catch (const Unhandled& uh) + { + SAL_INFO("sc.opencl", "Dynamic formula compiler: Unhandled at " << uh.mFile << ":" << uh.mLineNumber); + + // Unhandled used to go to the catch-all below, and not delete pDynamicKernel. Was that + // intentional, should we not do it here then either? + openclwrapper::kernelFailures++; + return nullptr; + } + catch (...) + { + // FIXME: Do we really want to catch random exceptions here? + SAL_WARN("sc.opencl", "Dynamic formula compiler: unexpected exception"); + openclwrapper::kernelFailures++; + return nullptr; + } + return pDynamicKernel; +} + +namespace { + +class CLInterpreterResult +{ + DynamicKernel* mpKernel; + + SCROW mnGroupLength; + + cl_mem mpCLResBuf; + double* mpResBuf; + +public: + CLInterpreterResult() : mpKernel(nullptr), mnGroupLength(0), mpCLResBuf(nullptr), mpResBuf(nullptr) {} + CLInterpreterResult( DynamicKernel* pKernel, SCROW nGroupLength ) : + mpKernel(pKernel), mnGroupLength(nGroupLength), mpCLResBuf(nullptr), mpResBuf(nullptr) {} + + bool isValid() const { return mpKernel != nullptr; } + + void fetchResultFromKernel() + { + if (!isValid()) + return; + + OpenCLZone zone; + + // Map results back + mpCLResBuf = mpKernel->GetResultBuffer(); + + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + + cl_int err; + mpResBuf = static_cast<double*>(clEnqueueMapBuffer(kEnv.mpkCmdQueue, + mpCLResBuf, + CL_TRUE, CL_MAP_READ, 0, + mnGroupLength * sizeof(double), 0, nullptr, nullptr, + &err)); + + if (err != CL_SUCCESS) + { + SAL_WARN("sc.opencl", "clEnqueueMapBuffer failed:: " << openclwrapper::errorString(err)); + mpResBuf = nullptr; + return; + } + SAL_INFO("sc.opencl", "Kernel results: cl_mem: " << mpResBuf << " (" << DebugPeekDoubles(mpResBuf, mnGroupLength) << ")"); + } + + bool pushResultToDocument( ScDocument& rDoc, const ScAddress& rTopPos ) + { + if (!mpResBuf) + return false; + + OpenCLZone zone; + + rDoc.SetFormulaResults(rTopPos, mpResBuf, mnGroupLength); + + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + + cl_int err; + err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpCLResBuf, mpResBuf, 0, nullptr, nullptr); + + if (err != CL_SUCCESS) + { + SAL_WARN("sc.opencl", "clEnqueueUnmapMemObject failed: " << openclwrapper::errorString(err)); + return false; + } + + return true; + } +}; + +class CLInterpreterContext +{ + std::shared_ptr<DynamicKernel> mpKernelStore; /// for managed kernel instance. + DynamicKernel* mpKernel; + + SCROW mnGroupLength; + +public: + explicit CLInterpreterContext(SCROW nGroupLength, std::shared_ptr<DynamicKernel> pKernel ) + : mpKernelStore(std::move(pKernel)) + , mpKernel(mpKernelStore.get()) + , mnGroupLength(nGroupLength) {} + + ~CLInterpreterContext() + { + DynamicKernelArgument::ClearStringIds(); + } + + bool isValid() const + { + return mpKernel != nullptr; + } + + CLInterpreterResult launchKernel() + { + if (!isValid()) + return CLInterpreterResult(); + + try + { + // Run the kernel. + mpKernel->Launch(mnGroupLength); + } + catch (const UnhandledToken& ut) + { + SAL_INFO("sc.opencl", "Dynamic formula compiler: UnhandledToken: " << ut.mMessage << " at " << ut.mFile << ":" << ut.mLineNumber); + openclwrapper::kernelFailures++; + return CLInterpreterResult(); + } + catch (const OpenCLError& oce) + { + SAL_WARN("sc.opencl", "Dynamic formula compiler: OpenCLError from " << oce.mFunction << ": " << openclwrapper::errorString(oce.mError) << " at " << oce.mFile << ":" << oce.mLineNumber); + openclwrapper::kernelFailures++; + return CLInterpreterResult(); + } + catch (const Unhandled& uh) + { + SAL_INFO("sc.opencl", "Dynamic formula compiler: Unhandled at " << uh.mFile << ":" << uh.mLineNumber); + openclwrapper::kernelFailures++; + return CLInterpreterResult(); + } + catch (...) + { + SAL_WARN("sc.opencl", "Dynamic formula compiler: unexpected exception"); + openclwrapper::kernelFailures++; + return CLInterpreterResult(); + } + + return CLInterpreterResult(mpKernel, mnGroupLength); + } +}; + + +CLInterpreterContext createCLInterpreterContext( const ScCalcConfig& rConfig, + const ScFormulaCellGroupRef& xGroup, const ScTokenArray& rCode ) +{ + return CLInterpreterContext(xGroup->mnLength, DynamicKernel::create(rConfig, rCode, xGroup->mnLength)); +} + +void genRPNTokens( ScDocument& rDoc, const ScAddress& rTopPos, ScTokenArray& rCode ) +{ + ScCompiler aComp(rDoc, rTopPos, rCode, rDoc.GetGrammar()); + // Disable special ordering for jump commands for the OpenCL interpreter. + aComp.EnableJumpCommandReorder(false); + aComp.CompileTokenArray(); // Regenerate RPN tokens. +} + +bool waitForResults() +{ + OpenCLZone zone; + openclwrapper::KernelEnv kEnv; + openclwrapper::setKernelEnv(&kEnv); + + cl_int err = clFinish(kEnv.mpkCmdQueue); + if (err != CL_SUCCESS) + SAL_WARN("sc.opencl", "clFinish failed: " << openclwrapper::errorString(err)); + + return err == CL_SUCCESS; +} + +} + +bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, + const ScAddress& rTopPos, ScFormulaCellGroupRef& xGroup, + ScTokenArray& rCode ) +{ + SAL_INFO("sc.opencl", "Interpret cell group " << rTopPos); + MergeCalcConfig(rDoc); + + genRPNTokens(rDoc, rTopPos, rCode); + + if( rCode.GetCodeLen() == 0 ) + return false; + + CLInterpreterContext aCxt = createCLInterpreterContext(maCalcConfig, xGroup, rCode); + if (!aCxt.isValid()) + return false; + + CLInterpreterResult aRes = aCxt.launchKernel(); + if (!aRes.isValid()) + return false; + + if (!waitForResults()) + return false; + + aRes.fetchResultFromKernel(); + + return aRes.pushResultToDocument(rDoc, rTopPos); +} + +} // namespace sc::opencl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_addin.cxx b/sc/source/core/opencl/op_addin.cxx new file mode 100644 index 0000000000..602ed2dfb3 --- /dev/null +++ b/sc/source/core/opencl/op_addin.cxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_addin.hxx" + +#include <formula/vectortoken.hxx> +#include <sstream> + +using namespace formula; + +namespace sc::opencl { + +void OpBesselj::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "N", 1, vSubArguments, ss ); + ss << " double f_2_DIV_PI = 2.0 / M_PI;\n"; + ss << " if( N < 0.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if (x == 0.0)\n"; + ss << " return (N == 0.0) ? 1.0 : 0.0;\n"; + ss << " double fSign = ((int)N % 2 == 1 && x < 0.0) ? -1.0 : 1.0;\n"; + ss << " double fX = fabs(x);\n"; + ss << " double fMaxIteration = 9000000.0;\n"; + ss << " double fEstimateIteration = fX * 1.5 + N;\n"; + ss << " bool bAsymptoticPossible = pow(fX,0.4) > N;\n"; + ss << " if (fEstimateIteration > fMaxIteration)\n"; + ss << " {\n"; + ss << " if (bAsymptoticPossible)\n"; + ss << " return fSign * sqrt(f_2_DIV_PI/fX)"; + ss << "* cos(fX-N*M_PI_2-M_PI_4);\n"; + ss << " else\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << " }\n"; + ss << " double epsilon = 1.0e-15;\n"; + ss << " bool bHasfound = false;\n"; + ss << " double k= 0.0;\n"; + ss << " double u ;\n"; + ss << " double m_bar;\n"; + ss << " double g_bar;\n"; + ss << " double g_bar_delta_u;\n"; + ss << " double g = 0.0;\n"; + ss << " double delta_u = 0.0;\n"; + ss << " double f_bar = -1.0;\n"; + ss << " if (N==0)\n"; + ss << " {\n"; + ss << " u = 1.0;\n"; + ss << " g_bar_delta_u = 0.0;\n"; + ss << " g_bar = - 2.0/fX; \n"; + ss << " delta_u = g_bar_delta_u / g_bar;\n"; + ss << " u = u + delta_u ;\n"; + ss << " g = -1.0 / g_bar; \n"; + ss << " f_bar = f_bar * g;\n"; + ss << " k = 2.0;\n"; + ss << " }\n"; + ss << " if (N!=0)\n"; + ss << " {\n"; + ss << " u=0.0;\n"; + ss << " for (k =1.0; k<= N-1; k = k + 1.0)\n"; + ss << " {\n"; + ss << " m_bar=2.0 * fmod(k-1.0, 2.0) * f_bar;\n"; + ss << " g_bar_delta_u = - g * delta_u - m_bar * u;\n"; + ss << " g_bar = m_bar - 2.0*k/fX + g;\n"; + ss << " delta_u = g_bar_delta_u / g_bar;\n"; + ss << " u = u + delta_u;\n"; + ss << " g = -1.0/g_bar;\n"; + ss << " f_bar=f_bar * g;\n"; + ss << " }\n"; + ss << " m_bar=2.0 * fmod(k-1.0, 2.0) * f_bar;\n"; + ss << " g_bar_delta_u = f_bar - g * delta_u - m_bar * u;\n"; + ss << " g_bar = m_bar - 2.0*k/fX + g;\n"; + ss << " delta_u = g_bar_delta_u / g_bar;\n"; + ss << " u = u + delta_u;\n"; + ss << " g = -1.0/g_bar;\n"; + ss << " f_bar = f_bar * g;\n"; + ss << " k = k + 1.0;\n"; + ss << " }\n"; + ss << " do\n"; + ss << " {\n"; + ss << " m_bar = 2.0 * fmod(k-1.0, 2.0) * f_bar;\n"; + ss << " g_bar_delta_u = - g * delta_u - m_bar * u;\n"; + ss << " g_bar = m_bar - 2.0*k/fX + g;\n"; + ss << " delta_u = g_bar_delta_u / g_bar;\n"; + ss << " u = u + delta_u;\n"; + ss << " g = -pow(g_bar,-1.0);\n"; + ss << " f_bar = f_bar * g;\n"; + ss << " bHasfound = (fabs(delta_u)<=fabs(u)*epsilon);\n"; + ss << " k = k + 1.0;\n"; + ss << " }\n"; + ss << " while (!bHasfound && k <= fMaxIteration);\n"; + ss << " if (bHasfound)\n"; + ss << " return u * fSign;\n"; + ss << " else\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << "}"; +} +void OpGestep::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp=0;\n"; + ss << " int gid0=get_global_id(0);\n"; + ss <<"\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + ss << " tmp =tmp0 >= tmp1 ? 1 : 0;\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_addin.hxx b/sc/source/core/opencl/op_addin.hxx new file mode 100644 index 0000000000..5a5799377c --- /dev/null +++ b/sc/source/core/opencl/op_addin.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +class OpBesselj: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Besselj"; } +}; +class OpGestep: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Gestep"; } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_array.cxx b/sc/source/core/opencl/op_array.cxx new file mode 100644 index 0000000000..47ae152185 --- /dev/null +++ b/sc/source/core/opencl/op_array.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_array.hxx" + +#include <formula/vectortoken.hxx> +#include <sstream> + +using namespace formula; + +namespace sc::opencl { + +void OpSumX2MY2::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp =0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, EmptyIsZero, + " tmp +=pow(arg1,2) - pow(arg2,2);\n" + ); + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpSumX2PY2::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp =0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, EmptyIsZero, + " tmp +=pow(arg1,2) + pow(arg2,2);\n" + ); + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpSumXMY2::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp =0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, EmptyIsZero, + " tmp +=pow((arg1-arg2),2);\n" + ); + ss << " return tmp;\n"; + ss << "}\n"; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_array.hxx b/sc/source/core/opencl/op_array.hxx new file mode 100644 index 0000000000..20ee011887 --- /dev/null +++ b/sc/source/core/opencl/op_array.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +class OpSumX2MY2: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SumX2MY2"; } +}; + +class OpSumX2PY2: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SumX2PY2"; } +}; + +class OpSumXMY2: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SumXMY2"; } +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_financial.cxx b/sc/source/core/opencl/op_financial.cxx new file mode 100644 index 0000000000..6ab2874dc7 --- /dev/null +++ b/sc/source/core/opencl/op_financial.cxx @@ -0,0 +1,1845 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_financial.hxx" + +#include <formula/vectortoken.hxx> +#include <sstream> + +using namespace formula; + +namespace sc::opencl { +// Definitions of inline functions +#include "op_financial_helpers.hxx" +#include "op_math_helpers.hxx" + +void OpRRI::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "nper", 0, vSubArguments, ss ); + GenerateArg( "pv", 1, vSubArguments, ss ); + GenerateArg( "fv", 2, vSubArguments, ss ); + ss << " if ( nper <= 0.0 || pv == 0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " tmp = pow(fv/pv,1.0/nper)-1;\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpNominal::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + ss << "double tmp = 0;\n\t"; + ss<<"if(tmp1==0)\n\t"; + ss<<"\treturn 0;\n\t"; + ss<<"tmp= 1.0 / tmp1;\n\t"; + ss<<"tmp=( pow( tmp0+ 1.0, tmp ) - 1.0 ) *"; + ss<<"tmp1;\n\t"; + ss << "return tmp;\n"; + ss << "}"; +} + +void OpDollarde::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = " << GetBottom() <<";\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + ss << "double fInt = " << GetBottom() <<";\n\t"; + GenerateArg( "dollar", 0, vSubArguments, ss ); + GenerateArg( "fFrac", 1, vSubArguments, ss ); + ss <<"fFrac = (int)fFrac;\n\t"; + ss << "tmp = modf( dollar , &fInt );\n\t"; + ss << "tmp /= fFrac;\n\t"; + ss << "tmp *= pow( 10.0 , ceil( log10(fFrac ) ) );\n\t"; + ss << "tmp += fInt;\t"; + ss << "\n\treturn tmp;\n"; + ss << "}"; +} + +void OpDollarfr::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = " << GetBottom() <<";\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + ss << "double fInt = " << GetBottom() <<";\n\t"; + GenerateArg( "dollar", 0, vSubArguments, ss ); + GenerateArg( "fFrac", 1, vSubArguments, ss ); + ss <<"fFrac = (int)fFrac;\n\t"; + ss << "tmp = modf( dollar , &fInt );\n\t"; + ss << "tmp *= fFrac;\n\t"; + ss << "tmp *= pow( 10.0 , -ceil( log10(fFrac ) ) );\n\t"; + ss << "tmp += fInt;\t"; + ss << "\n\treturn tmp;\n"; + ss << "}"; +} + +void OpDISC::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearFracDecl);decls.insert(DaysToDateDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + funs.insert(GetYearFrac);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); +} + +void OpDISC::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 5, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + GenerateArg( 4, vSubArguments, ss ); + ss << " int nNullDate = 693594;\n"; + ss << " tmp = 1.0 - arg2 / arg3;\n"; + ss << " tmp /="; + ss << " GetYearFrac(nNullDate, (int)arg0, (int)arg1, (int)arg4);\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpINTRATE::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearDiffDecl);decls.insert(GetDiffDateDecl); + decls.insert(DaysToDateDecl);decls.insert(GetNullDateDecl); + decls.insert(DateToDaysDecl);decls.insert(DaysInMonthDecl); + decls.insert(IsLeapYearDecl); + funs.insert(GetYearDiff);funs.insert(GetDiffDate); + funs.insert(DaysToDate);funs.insert(GetNullDate); + funs.insert(DateToDays);funs.insert(DaysInMonth); + funs.insert(IsLeapYear); +} + +void OpINTRATE::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 5, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + GenerateArg( 4, vSubArguments, ss ); + ss << " int nNullDate = GetNullDate();\n"; + ss << " tmp = ((arg3 / arg2) - 1) / GetYearDiff(nNullDate, (int)arg0,"; + ss << " (int)arg1,(int)arg4);\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpFV::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetFVDecl); + funs.insert(GetFV); +} + +void OpFV::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 5, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + GenerateArg( 4, vSubArguments, ss ); + ss << " tmp = GetFV(arg0, arg1, arg2, arg3, arg4);\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpIPMT::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetFVDecl); + funs.insert(GetFV); + decls.insert(GetPMTDecl); + funs.insert(GetPMT); + decls.insert(GetIpmtDecl); + funs.insert(GetIpmt); +} + +void OpIPMT::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fPer", 1, vSubArguments, ss ); + GenerateArg( "fNper", 2, vSubArguments, ss ); + GenerateArg( "fPv", 3, vSubArguments, ss ); + GenerateArgWithDefault( "fFv", 4, 0, vSubArguments, ss ); + GenerateArgWithDefault( "fPayInAdvance", 5, 0, vSubArguments, ss ); + ss << " if (fPer < 1.0 || fPer > fNper)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fPmt;\n"; + ss << " return GetIpmt(fRate, fPer, fNper, fPv, fFv, fPayInAdvance != 0, &fPmt);\n"; + ss << " }\n"; + ss << "}\n"; +} +void OpISPMT::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + ss << " tmp = arg3 * arg0 * ( arg1 - arg2) / arg2;\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpPDuration::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + ss << " if ( arg0 <= 0.0 || arg1 <= 0.0 || arg2 <= 0.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " tmp = log(arg2 / arg1) / log1p(arg0);\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpDuration_ADD::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetDurationDecl);decls.insert(lcl_GetcoupnumDecl); + decls.insert(GetYearFracDecl);decls.insert(DaysToDateDecl); + decls.insert(GetNullDateDecl);decls.insert(DateToDaysDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + funs.insert(GetDuration);funs.insert(lcl_Getcoupnum); + funs.insert(GetYearFrac);funs.insert(DaysToDate); + funs.insert(GetNullDate);funs.insert(DateToDays); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); +} + +void OpDuration_ADD::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + GenerateArg( 4, vSubArguments, ss ); + GenerateArg( 5, vSubArguments, ss ); + ss << " int nNullDate = GetNullDate();\n"; + ss << " tmp = GetDuration( nNullDate, (int)arg0, (int)arg1, arg2,"; + ss << " arg3, (int)arg4, (int)arg5);\n"; + ss << " return tmp;\n"; + ss << "}"; +} +void OpMDuration::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetDurationDecl);decls.insert(lcl_GetcoupnumDecl); + decls.insert(addMonthsDecl);decls.insert(checklessthanDecl); + decls.insert(setDayDecl);decls.insert(ScaDateDecl); + decls.insert(GetYearFracDecl);decls.insert(DaysToDateDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + funs.insert(GetDuration);funs.insert(lcl_Getcoupnum); + funs.insert(addMonths);funs.insert(checklessthan); + funs.insert(setDay);funs.insert(ScaDate); + funs.insert(GetYearFrac);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); +} + +void OpMDuration::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() << ";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + GenerateArg( 4, vSubArguments, ss ); + GenerateArg( 5, vSubArguments, ss ); + ss << " int nNullDate = 693594;\n"; + ss << " tmp = GetDuration( nNullDate, (int)arg0, (int)arg1, arg2,"; + ss << " arg3, (int)arg4, (int)arg5);\n"; + ss << " tmp = tmp * pow(1.0 + arg3 * pow((int)arg4, -1.0), -1);\n"; + ss << " return tmp;\n"; + ss << "}"; +} +void Fvschedule::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = 1.0;\n\t"; + ss << "int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + ss << "\t"; + GenerateRangeArg( 1, vSubArguments, ss, SkipEmpty, + " tmp *= arg + 1;\n" + ); + ss << "\t"; + ss << "return (double)tmp * arg0"; + ss << ";\n}"; +} +void Cumipmt::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetPMTDecl); decls.insert(GetFV); + funs.insert(GetPMT);funs.insert(GetFV); +} +void Cumipmt::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments & +vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fNumPeriouds", 1, vSubArguments, ss ); + GenerateArg( "fVal", 2, vSubArguments, ss ); + GenerateArg( "fStartPer", 3, vSubArguments, ss ); + GenerateArg( "fEndPer", 4, vSubArguments, ss ); + GenerateArg( "fPayType", 5, vSubArguments, ss ); + ss << " int nNumPeriods = (int)fNumPeriods;\n"; + ss << " int nStartPer = (int)fStartPer;\n"; + ss << " int nEndPer = (int)fEndPer;\n"; + ss << " int nPayType = (int)fPayType;\n"; + ss <<" double fPmt;\n"; + ss <<" fPmt = GetPMT( fRate, nNumPeriods, fVal, 0.0, nPayType != 0 );\n"; + ss <<" double tmp = 0.0;\n"; + ss <<" if( nStartPer == 1 )\n"; + ss <<" {\n"; + ss <<" if( nPayType <= 0 )\n"; + ss <<" tmp = -fVal;\n"; + ss <<" nStartPer++;\n"; + ss <<" }\n"; + ss <<" for( ; nStartPer<= nEndPer ; nStartPer++ )\n"; + ss <<" {\n"; + ss <<" if( nPayType > 0 )\n"; + ss <<" tmp += GetFV( fRate, nStartPer - 2 , "; + ss <<"fPmt, fVal, 1 ) - fPmt;\n"; + ss <<" else\n"; + ss <<" tmp += GetFV( fRate, nStartPer - 1 , "; + ss <<"fPmt, fVal, 0 );\n"; + ss <<" }\n"; + ss <<" tmp *= fRate;\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} + +void OpIRR::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " #define Epsilon 1.0E-7\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArgWithDefault( "fEstimated", 1, 0.1, vSubArguments, ss ); + ss << " double fEps = 1.0;\n"; + ss << " double xNew = 0.0, fNumerator = 0.0, fDenominator = 0.0;\n"; + ss << " double nCount = 0.0;\n"; + ss << " unsigned short nItCount = 0;\n"; + ss << " double x = fEstimated;\n"; + ss << " while (fEps > Epsilon && nItCount < 20)\n"; + ss << " {\n"; + ss << " nCount = 0.0; fNumerator = 0.0; fDenominator = 0.0;\n"; + GenerateRangeArg( 0, vSubArguments, ss, SkipEmpty, + " fNumerator += arg / pow(1.0 + x, nCount);\n" + " fDenominator+=-1*nCount*arg/pow(1.0+x,nCount+1.0);\n" + " nCount += 1;\n" + ); + ss << " xNew = x - fNumerator / fDenominator;\n"; + ss << " fEps = fabs(xNew - x);\n"; + ss << " x = xNew;\n"; + ss << " nItCount++;\n"; + ss << " }\n"; + ss << " if (fEstimated == 0.0 && fabs(x) < Epsilon)\n"; + ss << " x = 0.0;\n"; + ss << " if (fEps < Epsilon)\n"; + ss << " return x;\n"; + ss << " else\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << "}\n"; +} + +void XNPV::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double result = 0.0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "rate", 0, vSubArguments, ss ); + GenerateRangeArgElement( "dateNull", 2, "0", vSubArguments, ss, EmptyIsZero ); + GenerateRangeArgPair( 1, 2, vSubArguments, ss, SkipEmpty, + " result += arg1/(pow((rate+1),(arg2-dateNull)/365));\n" + ); + ss << " return result;\n"; + ss << "}"; +} + +void PriceMat::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearFracDecl);decls.insert(GetNullDateDecl); + decls.insert(DateToDaysDecl);decls.insert(DaysToDateDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + + funs.insert(GetYearFrac);funs.insert(GetNullDate); + funs.insert(DateToDays);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); +} +void PriceMat::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 5, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + ss << "double result=0;\n\t"; + ss<< "int nNullDate = GetNullDate( );\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fIssue", 2, vSubArguments, ss ); + GenerateArg( "rate", 3, vSubArguments, ss ); + GenerateArg( "yield", 4, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 5, 0, vSubArguments, ss ); + ss << "\t"; + ss <<"int settle = fSettle;\n\t"; + ss <<"int mat = fMat;\n\t"; + ss <<"int issue = fIssue;\n\t"; + ss <<"int nBase = fBase;\n\t"; + ss<< "double fIssMat = GetYearFrac( nNullDate, issue, mat, nBase);\n"; + ss<<"double fIssSet = GetYearFrac( nNullDate, issue, settle,nBase);\n"; + ss<<"double fSetMat = GetYearFrac( nNullDate, settle, mat, nBase);\n"; + ss<<"result = 1.0 + fIssMat * rate;\n\t"; + ss<<"result /= 1.0 + fSetMat * yield;\n\t"; + ss<<"result -= fIssSet * rate;\n\t"; + ss<<"result*= 100.0;\n\t"; + ss<<"return result;\n\t"; + ss<<"}\n"; +} + +void OpSYD::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "cost", 0, vSubArguments, ss ); + GenerateArg( "salvage", 1, vSubArguments, ss ); + GenerateArg( "life", 2, vSubArguments, ss ); + GenerateArg( "period", 3, vSubArguments, ss ); + ss << " double result=0;\n"; + ss <<" double tmpvalue = ((life*(life+1))/2.0);\n"; + ss <<" result = ((cost-salvage)*(life-period+1)/tmpvalue);\n"; + ss <<" return result;\n"; + ss <<"}\n"; +} + +void OpMIRR::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp;\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + ss << "double invest = arg1 + 1.0;\n\t"; + ss << "double reinvest = arg2 + 1.0;\n\t"; + ss << "double NPV_invest = 0.0;\n\t"; + ss << "double Pow_invest = 1.0;\n\t"; + ss << "double NPV_reinvest = 0.0;\n\t"; + ss << "double Pow_reinvest = 1.0;\n\t"; + ss << "int nCount = 0;\n\t"; + ss << "bool bHasPosValue = false;\n"; + ss << "bool bHasNegValue = false;\n"; + GenerateRangeArg( 0, vSubArguments, ss, SkipEmpty, + " if (arg > 0.0)\n" + " {\n" + " NPV_reinvest += arg * Pow_reinvest;\n" + " bHasPosValue = true;\n" + " }\n" + " else if (arg < 0.0)\n" + " {\n" + " NPV_invest += arg * Pow_invest;\n" + " bHasNegValue = true;\n" + " }\n" + " Pow_reinvest /= reinvest;\n" + " Pow_invest /= invest;\n" + " nCount++;\n" + ); + ss << "if ( !( bHasPosValue && bHasNegValue ) )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << "tmp = "; + ss << "-NPV_reinvest /NPV_invest * pow(reinvest,(double)nCount-1);\n\t"; + ss << "tmp = pow(tmp, 1.0 / (nCount - 1)) - 1.0;\n\t"; + ss << "return (double)tmp;\n"; + ss << "}"; +} + +void OpEffective::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() <<";\n"; + ss << " int gid0 = get_global_id(0);\n\t"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + ss << " tmp = pow(1.0 + arg0 / arg1, arg1)-1.0;\n"; + ss << " return tmp;\n"; + ss << "}"; +} + + void OpTbilleq::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetDiffDate360_Decl);decls.insert(GetDiffDate360Decl); + decls.insert(DateToDaysDecl);decls.insert(DaysToDate_LocalBarrierDecl); + decls.insert(DaysInMonthDecl);decls.insert(GetNullDateDecl); + decls.insert(IsLeapYearDecl); + funs.insert(GetDiffDate360_);funs.insert(GetDiffDate360); + funs.insert(DateToDays);funs.insert(DaysToDate_LocalBarrier); + funs.insert(DaysInMonth);funs.insert(GetNullDate); + funs.insert(IsLeapYear); +} +void OpTbilleq::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << " int gid0 = get_global_id(0);\n"; + ss << "double tmp = 0;\n\t"; + GenerateArg( "tmp000", 0, vSubArguments, ss ); + GenerateArg( "tmp001", 1, vSubArguments, ss ); + GenerateArg( "tmp002", 2, vSubArguments, ss ); + ss<<"tmp001+=1.0;\n"; + ss<<"int nDiff =GetDiffDate360(GetNullDate(),tmp000,tmp001,true);\n"; + ss<<"tmp =( 365 * tmp002 ) / ( 360 - ( tmp002 * ( nDiff ) ) );\n"; + ss << "return tmp;\n"; + ss << "}"; +} +void OpCumprinc::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetPMTDecl); decls.insert(GetFVDecl); + funs.insert(GetPMT);funs.insert(GetFV); +} +void OpCumprinc::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() <<";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fNumPeriouds", 1, vSubArguments, ss ); + GenerateArg( "fVal", 2, vSubArguments, ss ); + GenerateArg( "fStartPer", 3, vSubArguments, ss ); + GenerateArg( "fEndPer", 4, vSubArguments, ss ); + GenerateArg( "fPayType", 5, vSubArguments, ss ); + ss << " int nNumPeriods = (int)fNumPeriods;\n"; + ss << " int nStartPer = (int)fStartPer;\n"; + ss << " int nEndPer = (int)fEndPer;\n"; + ss << " int nPayType = (int)fPayType;\n"; + ss <<" double fPmt;\n"; + ss <<" fPmt = GetPMT( fRate, nNumPeriods,fVal,0.0,nPayType != 0 );\n"; + ss <<" if(nStartPer == 1)\n"; + ss <<" {\n"; + ss <<" if( nPayType <= 0 )\n"; + ss <<" tmp = fPmt + fVal * fRate;\n"; + ss <<" else\n"; + ss <<" tmp = fPmt;\n"; + ss <<" nStartPer=nStartPer+1;\n"; + ss <<" }\n"; + ss <<" for( int i = nStartPer ; i <= nEndPer ; i++ )\n"; + ss <<" {\n"; + ss <<" if( nPayType > 0 )\n"; + ss <<" tmp += fPmt - ( GetFV( fRate,i - 2,"; + ss <<"fPmt,fVal,1)- fPmt ) * fRate;\n"; + ss <<" else\n"; + ss <<" tmp += fPmt - GetFV( fRate, i - 1,"; + ss <<"fPmt,fVal,0 ) * fRate;\n"; + ss <<" }\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpAccrint::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); decls.insert(GetDiffDateDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate);funs.insert(GetDiffDate); +} +void OpAccrint::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 7, 7 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double tmp = 0;\n"; + GenerateArg( "fStartDate", 0, vSubArguments, ss ); + // 1 is ignored + GenerateArg( "fEndDate", 2, vSubArguments, ss ); + GenerateArg( "fRate", 3, vSubArguments, ss ); + GenerateArg( "fVal", 4, vSubArguments, ss ); + GenerateArg( "fFreq", 5, vSubArguments, ss ); + GenerateArg( "fMode", 6, vSubArguments, ss ); + ss << " int nStartDate = fStartDate;\n"; + ss << " int nEndDate = fEndDate;\n"; + ss << " int mode = fMode;\n"; + ss << " int freq = fFreq;\n"; + ss << " int nDays1stYear=0;\n"; + ss <<" int nNullDate=GetNullDate();\n"; + ss <<" int nTotalDays = GetDiffDate(nNullDate,nStartDate,"; + ss <<"nEndDate, mode,&nDays1stYear);\n"; + ss <<" tmp = fVal*fRate*convert_double(nTotalDays)"; + ss <<"/convert_double(nDays1stYear);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} + +void OpAccrintm::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); decls.insert(GetDiffDateDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate);funs.insert(GetDiffDate); +} +void OpAccrintm::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 5, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + ss << "double tmp = " << GetBottom() <<";\n\t"; + + GenerateArg( "fStartDate", 0, vSubArguments, ss ); + GenerateArg( "fEndDate", 1, vSubArguments, ss ); + GenerateArg( "fRate", 2, vSubArguments, ss ); + GenerateArg( "fVal", 3, vSubArguments, ss ); + GenerateArg( "fMode", 4, vSubArguments, ss ); + ss << " int nStartDate = fStartDate;\n"; + ss << " int nEndDate = fEndDate;\n"; + ss << " int mode = fMode;\n"; + ss <<"int nDays1stYear=0;\n\t"; + ss <<"int nNullDate=GetNullDate();\n\t"; + ss <<"int nTotalDays = GetDiffDate(nNullDate,nStartDate,"; + ss <<"nEndDate, mode,&nDays1stYear);\n\t"; + ss <<"tmp = fVal*fRate*convert_double(nTotalDays)"; + ss <<"/convert_double(nDays1stYear);\n\t"; + ss << "return tmp;\n"; + ss << "}"; +} + +void OpYield::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(getYield_Decl);decls.insert(getPriceDecl); + decls.insert(coupnumDecl);decls.insert(coupdaysncDecl); + decls.insert(coupdaybsDecl);decls.insert(coupdaysDecl); + decls.insert(lcl_GetcoupnumDecl);decls.insert(lcl_GetcoupdaysDecl); + decls.insert(lcl_GetcoupdaybsDecl);decls.insert(getDiffDecl); + decls.insert(getDaysInYearRangeDecl);decls.insert(GetDaysInYearDecl); + decls.insert(GetDaysInYearsDecl);decls.insert(getDaysInMonthRangeDecl); + decls.insert(addMonthsDecl);decls.insert(ScaDateDecl); + decls.insert(GetNullDateDecl);decls.insert(DateToDaysDecl); + decls.insert(DaysToDateDecl);decls.insert(DaysInMonthDecl); + decls.insert(IsLeapYearDecl);decls.insert(setDayDecl); + decls.insert(checklessthanDecl); + + funs.insert(getYield_);funs.insert(getPrice); + funs.insert(coupnum);funs.insert(coupdaysnc); + funs.insert(coupdaybs);funs.insert(coupdays); + funs.insert(lcl_Getcoupnum);funs.insert(lcl_Getcoupdays); + funs.insert(lcl_Getcoupdaybs);funs.insert(getDiff); + funs.insert(getDaysInYearRange);funs.insert(GetDaysInYear); + funs.insert(GetDaysInYears);funs.insert(getDaysInMonthRange); + funs.insert(addMonths);funs.insert(ScaDate); + funs.insert(GetNullDate);funs.insert(DateToDays); + funs.insert(DaysToDate);funs.insert(DaysInMonth); + funs.insert(IsLeapYear);decls.insert(setDay); + funs.insert(checklessthan); +} + +void OpYield::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 7, 7 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = 0;\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + GenerateArg( "tmp000", 0, vSubArguments, ss ); + GenerateArg( "tmp001", 1, vSubArguments, ss ); + GenerateArg( "tmp002", 2, vSubArguments, ss ); + GenerateArg( "tmp003", 3, vSubArguments, ss ); + GenerateArg( "tmp004", 4, vSubArguments, ss ); + GenerateArg( "tmp005", 5, vSubArguments, ss ); + GenerateArg( "tmp006", 6, vSubArguments, ss ); + ss << "tmp = getYield_("; + ss << "GetNullDate(),tmp000,tmp001,tmp002,tmp003,tmp004,tmp005,tmp006);\n\t "; + ss << "return tmp;\n"; + ss << "}"; +} + +void OpSLN::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "cost", 0, vSubArguments, ss ); + GenerateArg( "salvage", 1, vSubArguments, ss ); + GenerateArg( "life", 2, vSubArguments, ss ); + ss << " tmp = (cost-salvage)/life;\n"; + ss << " return tmp;\n"; + ss << "}"; +} + + void OpYieldmat::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearFracDecl);decls.insert(GetNullDateDecl); + decls.insert(DateToDaysDecl);decls.insert(DaysToDateDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + decls.insert(GetYieldmatDecl); + + funs.insert(GetYearFrac);funs.insert(GetNullDate); + funs.insert(DateToDays);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); + funs.insert(GetYieldmat); +} + +void OpYieldmat::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = 0;\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + GenerateArg( "tmp000", 0, vSubArguments, ss ); + GenerateArg( "tmp001", 1, vSubArguments, ss ); + GenerateArg( "tmp002", 2, vSubArguments, ss ); + GenerateArg( "tmp003", 3, vSubArguments, ss ); + GenerateArg( "tmp004", 4, vSubArguments, ss ); + GenerateArg( "tmp005", 5, vSubArguments, ss ); + ss << "tmp = GetYieldmat("; + ss<<"GetNullDate(),tmp000,tmp001,tmp002,tmp003,tmp004,tmp005);\n\t"; + ss << "return tmp;\n"; + ss << "}"; +} + +void OpPMT::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetPMTDecl); + funs.insert(GetPMT); +} + +void OpPMT::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss<< " double tmp = 0;\n"; + ss<< " int gid0 = get_global_id(0);\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fNper", 1, vSubArguments, ss ); + GenerateArg( "fPv", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fFv", 3, 0, vSubArguments, ss ); + GenerateArgWithDefault( "fPayInAdvance", 4, 0, vSubArguments, ss ); + ss << " return GetPMT( fRate, fNper, fPv, fFv, fPayInAdvance != 0 );\n"; + ss << "}"; +} + +void OpNPV::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 31 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0.0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " int nCount = 1;\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateRangeArgs( 1, vSubArguments.size() - 1, vSubArguments, ss, SkipEmpty, + " tmp += arg / pow( 1 + arg0, nCount );\n" + " nCount += 1;\n" + ); + ss << " return tmp;\n"; + ss << "}"; +} + + void OpPrice::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) + { + decls.insert(getPriceDecl); + decls.insert(IsLeapYearDecl);decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); + decls.insert(DateToDaysDecl); + decls.insert(ScaDateDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(addMonthsDecl);decls.insert(lcl_GetcoupnumDecl); + decls.insert(coupnumDecl); + decls.insert(DateToDaysDecl); + decls.insert(getDaysInMonthRangeDecl); + decls.insert(GetDaysInYearsDecl); decls.insert(GetDaysInYearDecl); + decls.insert(getDaysInYearRangeDecl); decls.insert(getDiffDecl); + decls.insert(coupdaybsDecl); + decls.insert(lcl_GetcoupdaysDecl); + decls.insert(lcl_GetcoupdaybsDecl); + decls.insert(coupdaysDecl); + decls.insert(coupdaysncDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(DateToDays); + funs.insert(ScaDate); + funs.insert(addMonths);funs.insert(getDaysInMonthRange); + funs.insert(GetDaysInYears);funs.insert(GetDaysInYear); + funs.insert(getDaysInYearRange);funs.insert(getDiff); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(lcl_Getcoupdaybs); + funs.insert(coupdaybs); + funs.insert(lcl_Getcoupdays); + funs.insert(coupdaysnc); + funs.insert(coupdays); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(lcl_Getcoupnum); + funs.insert(coupnum);funs.insert(getPrice); + } +void OpPrice::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 7 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss<<" double tmp = 0;\n"; + ss<<" int gid0 = get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArg( "tmp2", 2, vSubArguments, ss ); + GenerateArg( "tmp3", 3, vSubArguments, ss ); + GenerateArg( "tmp4", 4, vSubArguments, ss ); + GenerateArg( "tmp5", 5, vSubArguments, ss ); + GenerateArgWithDefault( "tmp6", 6, 0, vSubArguments, ss ); + ss << " if(tmp4*tmp5 == 0) return NAN;\n"; + ss << " tmp = getPrice(tmp0,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6);\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpOddlprice::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetOddlpriceDecl);decls.insert(GetDiffDateDecl); + decls.insert(GetYearDiffDecl);decls.insert(IsLeapYearDecl); + decls.insert(GetNullDateDecl);decls.insert(DateToDaysDecl); + decls.insert(DaysToDateDecl);decls.insert(DaysInMonthDecl); + decls.insert(GetYearFracDecl); + funs.insert(GetOddlprice);funs.insert(GetDiffDate); + funs.insert(GetYearDiff);funs.insert(IsLeapYear); + funs.insert(GetNullDate);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetYearFrac); +} +void OpOddlprice::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 7, 8 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" double tmp = 0;\n"; + ss <<" int gid0 = get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArg( "tmp2", 2, vSubArguments, ss ); + GenerateArg( "tmp3", 3, vSubArguments, ss ); + GenerateArg( "tmp4", 4, vSubArguments, ss ); + GenerateArg( "tmp5", 5, vSubArguments, ss ); + GenerateArg( "tmp6", 6, vSubArguments, ss ); + GenerateArgWithDefault( "tmp7", 7, 0, vSubArguments, ss ); + ss <<" int nNullDate = GetNullDate();\n"; + ss <<" tmp = GetOddlprice(nNullDate,tmp0,tmp1,"; + ss <<"tmp2,tmp3,tmp4,tmp5,tmp6,tmp7);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpOddlyield::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetDiffDateDecl);decls.insert(DaysToDateDecl); + decls.insert(GetYearDiffDecl);decls.insert(IsLeapYearDecl); + decls.insert(GetNullDateDecl);decls.insert(DateToDaysDecl); + decls.insert(DaysInMonthDecl); + decls.insert(GetYearFracDecl);decls.insert(GetOddlyieldDecl); + funs.insert(GetDiffDate);funs.insert(DaysToDate); + funs.insert(GetYearDiff);funs.insert(IsLeapYear); + funs.insert(GetNullDate);funs.insert(DaysInMonth); + funs.insert(DateToDays); + funs.insert(GetYearFrac);funs.insert(GetOddlyield); +} +void OpOddlyield::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 7, 8 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" double tmp = 0;\n"; + ss <<" int gid0 = get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArg( "tmp2", 2, vSubArguments, ss ); + GenerateArg( "tmp3", 3, vSubArguments, ss ); + GenerateArg( "tmp4", 4, vSubArguments, ss ); + GenerateArg( "tmp5", 5, vSubArguments, ss ); + GenerateArg( "tmp6", 6, vSubArguments, ss ); + GenerateArgWithDefault( "tmp7", 7, 0, vSubArguments, ss ); + ss <<" int nNullDate = GetNullDate();\n"; + ss <<" tmp = GetOddlyield(nNullDate,tmp0,tmp1"; + ss <<",tmp2,tmp3,tmp4,tmp5,tmp6,tmp7);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpPriceDisc::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearDiffDecl);decls.insert(getDiffDecl); + decls.insert(getDaysInYearRangeDecl);decls.insert(GetDaysInYearDecl); + decls.insert(GetDaysInYearsDecl);decls.insert(getDaysInMonthRangeDecl); + decls.insert(addMonthsDecl);decls.insert(ScaDateDecl); + decls.insert(GetNullDateDecl);decls.insert(DateToDaysDecl); + decls.insert(DaysToDateDecl);decls.insert(DaysInMonthDecl); + decls.insert(IsLeapYearDecl);decls.insert(GetDiffDateDecl); + funs.insert(GetYearDiff);funs.insert(getDiff); + funs.insert(getDaysInYearRange);funs.insert(GetDaysInYear); + funs.insert(GetDaysInYears);funs.insert(getDaysInMonthRange); + funs.insert(addMonths);funs.insert(ScaDate); + funs.insert(GetNullDate);funs.insert(DateToDays); + funs.insert(DaysToDate);funs.insert(DaysInMonth); + funs.insert(IsLeapYear);funs.insert(GetDiffDate); +} +void OpPriceDisc::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArg( "tmp2", 2, vSubArguments, ss ); + GenerateArg( "tmp3", 3, vSubArguments, ss ); + GenerateArgWithDefault( "tmp4", 4, 0, vSubArguments, ss ); + ss <<" int nNullDate = GetNullDate();\n"; + ss <<" tmp=tmp3* ( 1.0 -tmp2*GetYearDiff( nNullDate, "; + ss <<"tmp0,tmp1,tmp4));\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpNper::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fPmt", 1, vSubArguments, ss ); + GenerateArg( "fPV", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fFV", 3, 0, vSubArguments, ss ); + GenerateArgWithDefault( "fPayInAdvance", 4, 0, vSubArguments, ss ); + ss << " if ( fPV + fFV == 0.0 )\n"; + ss << " return 0.0;\n"; + ss << " else if (fRate == 0.0)\n"; + ss << " return -(fPV + fFV)/fPmt;\n"; + ss << " else if (fPayInAdvance != 0)\n"; + ss << " return log(-(fRate*fFV-fPmt*(1.0+fRate))/(fRate*fPV+fPmt*(1.0+fRate)))\n"; + ss << " / log1p(fRate);\n"; + ss << " else\n"; + ss << " return log(-(fRate*fFV-fPmt)/(fRate*fPV+fPmt)) / log1p(fRate);\n"; + ss << "}\n"; + } + +void OpPPMT::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetFVDecl); + funs.insert(GetFV); + decls.insert(GetPMTDecl); + funs.insert(GetPMT); + decls.insert(GetIpmtDecl); + funs.insert(GetIpmt); +} + +void OpPPMT::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double arg=0;\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fPer", 1, vSubArguments, ss ); + GenerateArg( "fNper", 2, vSubArguments, ss ); + GenerateArg( "fPv", 3, vSubArguments, ss ); + GenerateArgWithDefault( "fFv", 4, 0, vSubArguments, ss ); + GenerateArgWithDefault( "fPayInAdvance", 5, 0, vSubArguments, ss ); + ss << " if (fPer < 1.0 || fPer > fNper)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fPmt;\n"; + ss << " double fInterestPer = GetIpmt(fRate, fPer, fNper, fPv, fFv, fPayInAdvance != 0, &fPmt);\n"; + ss << " return fPmt - fInterestPer;\n"; + ss << " }\n"; + ss << "}\n"; +} + +void OpCoupdaybs::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); decls.insert(ScaDateDecl); + decls.insert(addMonthsDecl); decls.insert(getDaysInMonthRangeDecl); + decls.insert(GetDaysInYearsDecl); + decls.insert(getDaysInYearRangeDecl); decls.insert(getDiffDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(lcl_GetcoupdaybsDecl); + decls.insert(coupdaybsDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate);funs.insert(ScaDate); + funs.insert(addMonths);funs.insert(getDaysInMonthRange); + funs.insert(GetDaysInYears); + funs.insert(getDaysInYearRange);funs.insert(getDiff); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(lcl_Getcoupdaybs); + funs.insert(coupdaybs); +} +void OpCoupdaybs::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fFreq", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 3, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int nFreq = fFreq;\n"; + ss << " int nBase = fBase;\n"; + ss <<" tmp = coupdaybs(nSettle,nMat,nFreq,nBase);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} + +void OpCoupdays::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); decls.insert(ScaDateDecl); + decls.insert(addMonthsDecl); decls.insert(getDaysInMonthRangeDecl); + decls.insert(GetDaysInYearsDecl); decls.insert(GetDaysInYearDecl); + decls.insert(getDaysInYearRangeDecl); decls.insert(getDiffDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(lcl_GetcoupdaysDecl); + decls.insert(coupdaysDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate);funs.insert(ScaDate); + funs.insert(addMonths);funs.insert(getDaysInMonthRange); + funs.insert(GetDaysInYears);funs.insert(GetDaysInYear); + funs.insert(getDaysInYearRange);funs.insert(getDiff); + funs.insert(lcl_Getcoupdays); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(coupdays); +} +void OpCoupdays::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fFreq", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 3, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int nFreq = fFreq;\n"; + ss << " int nBase = fBase;\n"; + ss <<" tmp = coupdays(nSettle,nMat,nFreq,nBase);\n"; + ss <<" return tmp;\n"; + ss << "}"; +} +void OpCouppcd::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); + decls.insert(ScaDateDecl); + decls.insert(addMonthsDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(lcl_GetCouppcdDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate); + funs.insert(ScaDate); + funs.insert(addMonths); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(lcl_GetCouppcd); +} +void OpCouppcd::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fFreq", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 3, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int nFreq = fFreq;\n"; + ss << " int nBase = fBase;\n"; + ss <<" int nNullDate=693594;\n"; + ss <<" tmp = lcl_GetCouppcd(nNullDate,nSettle,nMat,nFreq,nBase);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpCoupncd::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); + decls.insert(ScaDateDecl); + decls.insert(addMonthsDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(lcl_GetCoupncdDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate); + funs.insert(ScaDate); + funs.insert(addMonths); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(lcl_GetCoupncd); +} +void OpCoupncd::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fFreq", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 3, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int nFreq = fFreq;\n"; + ss << " int nBase = fBase;\n"; + ss <<" int nNullDate=693594;\n"; + ss <<" tmp = lcl_GetCoupncd(nNullDate,nSettle,nMat,nFreq,nBase);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} + +void OpCoupdaysnc::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl); decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(DateToDaysDecl); + decls.insert(ScaDateDecl); + decls.insert(addMonthsDecl); decls.insert(getDaysInMonthRangeDecl); + decls.insert(GetDaysInYearsDecl); decls.insert(GetDaysInYearDecl); + decls.insert(getDaysInYearRangeDecl); decls.insert(getDiffDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(coupdaybsDecl); + decls.insert(lcl_GetcoupdaysDecl); + decls.insert(lcl_GetcoupdaybsDecl); + decls.insert(coupdaysDecl); + decls.insert(coupdaysncDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(DateToDays); + funs.insert(ScaDate); + funs.insert(addMonths);funs.insert(getDaysInMonthRange); + funs.insert(GetDaysInYears);funs.insert(GetDaysInYear); + funs.insert(getDaysInYearRange);funs.insert(getDiff); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(lcl_Getcoupdaybs); + funs.insert(coupdaybs); + funs.insert(lcl_Getcoupdays); + funs.insert(coupdaysnc); + funs.insert(coupdays); +} +void OpCoupdaysnc::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fFreq", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 3, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int nFreq = fFreq;\n"; + ss << " int nBase = fBase;\n"; + ss <<" tmp = coupdaysnc(nSettle,nMat,nFreq,nBase);\n"; + ss <<" return tmp;\n"; + ss << "}"; +} + +void OpCoupnum::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(IsLeapYearDecl);decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); + decls.insert(DateToDaysDecl); + decls.insert(ScaDateDecl); + decls.insert(setDayDecl);decls.insert(checklessthanDecl); + decls.insert(addMonthsDecl);decls.insert(lcl_GetcoupnumDecl); + decls.insert(coupnumDecl); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate); + funs.insert(DateToDays); + funs.insert(ScaDate); + funs.insert(setDay);funs.insert(checklessthan); + funs.insert(addMonths);funs.insert(lcl_Getcoupnum); + funs.insert(coupnum); +} +void OpCoupnum::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fFreq", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 3, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int nFreq = fFreq;\n"; + ss << " int nBase = fBase;\n"; + ss <<" tmp = coupnum(nSettle,nMat,nFreq,nBase);\n"; + ss <<" return tmp;\n"; + ss << "}"; +} +void OpAmordegrc::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(nCorrValDecl); decls.insert(RoundDecl); + decls.insert(IsLeapYearDecl);decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetNullDateDecl); decls.insert(GetYearFracDecl); + funs.insert(Round); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetNullDate);funs.insert(GetYearFrac); +} +void OpAmordegrc::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 7 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double tmp = " << GetBottom() <<";\n"; + GenerateArg( "fCost", 0, vSubArguments, ss ); + GenerateArg( "fDate", 1, vSubArguments, ss ); + GenerateArg( "fFirstPer", 2, vSubArguments, ss ); + GenerateArg( "fRestVal", 3, vSubArguments, ss ); + GenerateArg( "fPer", 4, vSubArguments, ss ); + GenerateArg( "fRate", 5, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 6, 0, vSubArguments, ss ); + ss << " int nDate = fDate;\n"; + ss << " int nFirstPer = fFirstPer;\n"; + ss << " int nBase = fBase;\n"; + ss <<" uint nPer = convert_int( fPer );\n"; + ss <<" double fUsePer = 1.0 / fRate;\n"; + ss <<" double fAmorCoeff;\n"; + ss <<" if( fUsePer < 3.0 )\n"; + ss <<" fAmorCoeff = 1.0;\n"; + ss <<" else if( fUsePer < 5.0 )\n"; + ss <<" fAmorCoeff = 1.5;\n"; + ss <<" else if( fUsePer <= 6.0 )\n"; + ss <<" fAmorCoeff = 2.0;\n"; + ss <<" else\n"; + ss <<" fAmorCoeff = 2.5;\n"; + ss <<" fRate *= fAmorCoeff;\n"; + ss <<" tmp = Round( GetYearFrac( 693594,"; + ss <<"nDate, nFirstPer, nBase ) * fRate * fCost);\n"; + ss <<" fCost = fCost-tmp;\n"; + ss <<" double fRest = fCost - fRestVal;\n"; + ss <<" for( uint n = 0 ; n < nPer ; n++ )\n"; + ss <<" {\n"; + ss <<" tmp = Round( fRate * fCost);\n"; + ss <<" fRest -= tmp;\n"; + ss <<" if( fRest < 0.0 )\n"; + ss <<" {\n"; + ss <<" switch( nPer - n )\n"; + ss <<" {\n"; + ss <<" case 0:\n"; + ss <<" case 1:\n"; + ss <<" tmp = Round( fCost * 0.5);\n"; + ss <<" default:\n"; + ss <<" tmp = 0.0;\n"; + ss <<" }\n"; + ss <<" }\n"; + ss <<" fCost -= tmp;\n"; + ss <<" }\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpAmorlinc::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(nCorrValDecl); decls.insert(RoundDecl); + decls.insert(IsLeapYearDecl);decls.insert(DaysInMonthDecl); + decls.insert(DaysToDateDecl); decls.insert(DateToDaysDecl); + decls.insert(GetYearFracDecl); + funs.insert(Round); + funs.insert(IsLeapYear);funs.insert(DaysInMonth); + funs.insert(DaysToDate);funs.insert(DateToDays); + funs.insert(GetYearFrac); +} +void OpAmorlinc::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 6, 7 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double tmp = 0;\n"; + GenerateArg( "fCost", 0, vSubArguments, ss ); + GenerateArg( "fDate", 1, vSubArguments, ss ); + GenerateArg( "fFirstPer", 2, vSubArguments, ss ); + GenerateArg( "fRestVal", 3, vSubArguments, ss ); + GenerateArg( "fPer", 4, vSubArguments, ss ); + GenerateArg( "fRate", 5, vSubArguments, ss ); + GenerateArgWithDefault( "fBase", 6, 0, vSubArguments, ss ); + ss << " int nDate = fDate;\n"; + ss << " int nFirstPer = fFirstPer;\n"; + ss << " int nBase = fBase;\n"; + ss <<" int nPer = convert_int( fPer );\n"; + ss <<" double fOneRate = fCost * fRate;\n"; + ss <<" double fCostDelta = fCost - fRestVal;\n"; + ss <<" double f0Rate = GetYearFrac( 693594,"; + ss <<"nDate, nFirstPer, nBase )* fRate * fCost;\n"; + ss <<" int nNumOfFullPeriods = (int)"; + ss <<"( ( fCost - fRestVal - f0Rate) / fOneRate );\n"; + ss <<" if( nPer == 0 )\n"; + ss <<" tmp = f0Rate;\n"; + ss <<" else if( nPer <= nNumOfFullPeriods )\n"; + ss <<" tmp = fOneRate;\n"; + ss <<" else if( nPer == nNumOfFullPeriods + 1 )\n"; + ss <<" tmp = fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;\n"; + ss <<" else\n"; + ss <<" tmp = 0.0;\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpReceived::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearDiffDecl);decls.insert(GetDiffDateDecl); + decls.insert(DaysToDateDecl);decls.insert(DaysInMonthDecl); + decls.insert(GetNullDateDecl);decls.insert(IsLeapYearDecl); + decls.insert(DateToDaysDecl); + funs.insert(GetDiffDate);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(GetNullDate); + funs.insert(DateToDays);funs.insert(IsLeapYear); + funs.insert(GetYearDiff); +} + +void OpReceived::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() <<";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fSettle", 0, vSubArguments, ss ); + GenerateArg( "fMat", 1, vSubArguments, ss ); + GenerateArg( "fInvest", 2, vSubArguments, ss ); + GenerateArg( "fDisc", 3, vSubArguments, ss ); + GenerateArgWithDefault( "fOB", 4, 0, vSubArguments, ss ); + ss << " int nSettle = fSettle;\n"; + ss << " int nMat = fMat;\n"; + ss << " int rOB = fOB;\n"; + ss << " double tmpvalue = (1.0-(fDisc"; + ss <<" * GetYearDiff( GetNullDate()"; + ss <<",nSettle,nMat,rOB)));\n"; + ss << " tmp = fInvest/tmpvalue;\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpYielddisc::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearFracDecl);decls.insert(GetNullDateDecl); + decls.insert(DateToDaysDecl);decls.insert(DaysToDateDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + + funs.insert(GetYearFrac);funs.insert(GetNullDate); + funs.insert(DateToDays);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); +} +void OpYielddisc::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT(5,5); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = 0;\n\t"; + ss << "int gid0 = get_global_id(0);\n"; + GenerateArg( "tmp000", 0, vSubArguments, ss ); + GenerateArg( "tmp001", 1, vSubArguments, ss ); + GenerateArg( "tmp002", 2, vSubArguments, ss ); + GenerateArg( "tmp003", 3, vSubArguments, ss ); + GenerateArg( "tmp004", 4, vSubArguments, ss ); + ss<< "\t"; + ss<< "if(tmp002 <= 0 || tmp003 <= 0 || tmp000 >= tmp001 )\n\t"; + ss<< " return CreateDoubleError(IllegalArgument);\n\t"; + ss<< "tmp = (tmp003/tmp002)-1;\n\t"; + ss << "tmp /= GetYearFrac( GetNullDate(),tmp000,tmp001,tmp004);\n\t"; + ss << "return tmp;\n"; + ss << "}"; +} + +void OpTbillprice::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetYearFracDecl); + decls.insert(DateToDaysDecl);decls.insert(DaysToDateDecl); + decls.insert(DaysInMonthDecl);decls.insert(IsLeapYearDecl); + + funs.insert(GetYearFrac); + funs.insert(DateToDays);funs.insert(DaysToDate); + funs.insert(DaysInMonth);funs.insert(IsLeapYear); +} + +void OpTbillprice::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double tmp = 0;\n"; + + ss << " int singleIndex = gid0;\n"; + ss << " int doubleIndex = gid0;\n"; + ss << " int i = gid0;\n"; + GenTmpVariables(ss,vSubArguments); + CheckAllSubArgumentIsNan(ss,vSubArguments); + + ss << " tmp1+=1.0;\n"; + ss << " double fFraction =GetYearFrac(693594,tmp0,tmp1,0);\n"; + ss << " tmp = 100.0 * ( 1.0 - tmp2 * fFraction );\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpRate::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(RateIterationDecl); + funs.insert(RateIteration); +} + +void OpRate::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fNper", 0, vSubArguments, ss ); + GenerateArg( "fPayment", 1, vSubArguments, ss ); + GenerateArg( "fPv", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fFv", 3, 0, vSubArguments, ss ); + GenerateArgWithDefault( "fPayType", 4, 0, vSubArguments, ss ); + ss << " bool bPayType = fPayType != 0;\n"; + if( vSubArguments.size() == 6 ) + { + GenerateArgWithDefault( "fGuess", 5, 0.1, vSubArguments, ss ); + ss << " double fOrigGuess = fGuess;\n"; + ss << " bool bDefaultGuess = false;\n"; + } + else + { + ss << " double fGuess = 0.1, fOrigGuess = 0.1;\n"; + ss << " bool bDefaultGuess = true;\n"; + } + ss << " if( fNper <= 0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " bool bValid = RateIteration(fNper, fPayment, fPv, fFv, bPayType, &fGuess);\n"; + ss << " if (!bValid)\n"; + ss << " {\n"; + ss << " if (bDefaultGuess)\n"; + ss << " {\n"; + ss << " double fX = fOrigGuess;\n"; + ss << " for (int nStep = 2; nStep <= 10 && !bValid; ++nStep)\n"; + ss << " {\n"; + ss << " fGuess = fX * nStep;\n"; + ss << " bValid = RateIteration( fNper, fPayment, fPv, fFv, bPayType, &fGuess);\n"; + ss << " if (!bValid)\n"; + ss << " {\n"; + ss << " fGuess = fX / nStep;\n"; + ss << " bValid = RateIteration( fNper, fPayment, fPv, fFv, bPayType, &fGuess);\n"; + ss << " }\n"; + ss << " }\n"; + ss << " }\n"; + ss << " if (!bValid)\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << " }\n"; + ss << " return fGuess;\n"; + ss << "}\n"; +} + +void OpTbillyield::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetDiffDate360Decl);decls.insert(IsLeapYearDecl); + decls.insert(DateToDaysDecl);decls.insert(DaysToDate_LocalBarrierDecl); + decls.insert(DaysInMonthDecl);decls.insert(GetNullDateDecl); + decls.insert(GetDiffDate360_Decl); + funs.insert(GetDiffDate360);funs.insert(DateToDays); + funs.insert(DaysToDate_LocalBarrier);funs.insert(IsLeapYear); + funs.insert(DaysInMonth);funs.insert(GetNullDate); + funs.insert(GetDiffDate360_); + +} + +void OpTbillyield::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double tmp = 0;\n"; + GenerateArg( "tmp000", 0, vSubArguments, ss ); + GenerateArg( "tmp001", 1, vSubArguments, ss ); + GenerateArg( "tmp002", 2, vSubArguments, ss ); + ss <<" int nDiff=GetDiffDate360(GetNullDate(),tmp000,tmp001,true);\n"; + ss <<" nDiff++;\n"; + ss <<" tmp=100.0;\n"; + ss <<" tmp = tmp / tmp002;\n"; + ss <<" tmp = tmp - 1.0;\n"; + ss <<" tmp = tmp / nDiff;\n"; + ss <<" tmp = tmp * 360.0;\n"; + ss <<" return tmp;\n"; + ss << "}\n"; +} + +void OpDDB::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(ScGetDDBDecl); + funs.insert(ScGetDDB); +} + +void OpDDB::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double tmp = 0;\n"; + GenerateArg( "fCost", 0, vSubArguments, ss ); + GenerateArg( "fSalvage", 1, vSubArguments, ss ); + GenerateArg( "fLife", 2, vSubArguments, ss ); + GenerateArg( "fPeriod", 3, vSubArguments, ss ); + GenerateArgWithDefault( "fFactor", 4, 2, vSubArguments, ss ); + ss << " if (fCost < 0.0 || fSalvage < 0.0 || fFactor <= 0.0 || fSalvage > fCost\n"; + ss << " || fPeriod < 1.0 || fPeriod > fLife)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return ScGetDDB( fCost, fSalvage, fLife, fPeriod, fFactor );\n"; + ss << "}\n"; +} + +void OpPV::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double result = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fRate", 0, vSubArguments, ss ); + GenerateArg( "fNper", 1, vSubArguments, ss ); + GenerateArg( "fPmt", 2, vSubArguments, ss ); + GenerateArgWithDefault( "fFv", 3, 0, vSubArguments, ss ); + GenerateArgWithDefault( "fPayInAdvance", 4, 0, vSubArguments, ss ); + ss << " double fPv;\n"; + ss << " if (fRate == 0.0)\n"; + ss << " fPv = fFv + fPmt * fNper;\n"; + ss << " else\n"; + ss << " {\n"; + ss << " if (fPayInAdvance != 0)\n"; + ss << " fPv = (fFv * pow(1.0 + fRate, -fNper))\n"; + ss << " + (fPmt * (1.0 - pow(1.0 + fRate, -fNper + 1.0)) / fRate)\n"; + ss << " + fPmt;\n"; + ss << " else\n"; + ss << " fPv = (fFv * pow(1.0 + fRate, -fNper))\n"; + ss << " + (fPmt * (1.0 - pow(1.0 + fRate, -fNper)) / fRate);\n"; + ss << " }\n"; + ss << " return -fPv;\n"; + ss << "}\n"; +} + +void OpVDB::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + decls.insert(ScGetDDBDecl);decls.insert(approx_equalDecl); + decls.insert(ScInterVDBDecl);decls.insert(VDBImplementDecl); + funs.insert(is_representable_integer); + funs.insert(ScGetDDB);funs.insert(approx_equal); + funs.insert(ScInterVDB);funs.insert(VDBImplement); +} + +void OpVDB::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 5, 7 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " int singleIndex = gid0;\n"; + ss << " double result = 0;\n"; + GenerateArg( "fCost", 0, vSubArguments, ss ); + GenerateArg( "fSalvage", 1, vSubArguments, ss ); + GenerateArg( "fLife", 2, vSubArguments, ss ); + GenerateArg( "fStart", 3, vSubArguments, ss ); + GenerateArg( "fEnd", 4, vSubArguments, ss ); + GenerateArgWithDefault( "fFactor", 5, 2, vSubArguments, ss ); + GenerateArgWithDefault( "fNoSwitch", 6, 0, vSubArguments, ss ); + ss << " if (fStart < 0.0 || fEnd < fStart || fEnd > fLife || fCost < 0.0\n"; + ss << " || fSalvage > fCost || fFactor <= 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return VDBImplement(fCost, fSalvage, fLife, fStart, fEnd, fFactor, fNoSwitch != 0);\n"; + ss << "}"; +} + +void OpXirr::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArgWithDefault( "fResultRate", 2, 0.1, vSubArguments, ss ); + ss << " if(fResultRate<=-1)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double fMaxEps = 1e-10;\n"; + ss << " int nMaxIter = 50;\n"; + ss << " int nIter = 0;\n"; + ss << " double fResultValue;\n"; + ss << " int nIterScan = 0;\n"; + ss << " bool bContLoop = false;\n"; + ss << " bool bResultRateScanEnd = false;\n"; + // Make 'V_0' and 'D_0' be the first elements of arguments 0 and 1. + GenerateRangeArgElement( "V_0", 0, "0", vSubArguments, ss, EmptyIsZero ); + GenerateRangeArgElement( "D_0", 1, "0", vSubArguments, ss, EmptyIsZero ); + ss << " do\n"; + ss << " {\n"; + ss << " if (nIterScan >=1)\n"; + ss << " fResultRate = -0.99 + (nIterScan -1)* 0.01;\n"; + ss << " do\n"; + ss << " {\n"; + ss << " double r = fResultRate + 1;\n"; + ss << " fResultValue = V_0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " fResultValue += arg1/pow(r,(arg2 - D_0)/365.0);\n" + , "1" // start from 2nd element + ); + ss << " double fResultValue2 = 0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " double E_i = (arg2 - D_0)/365.0;\n" + " fResultValue2 -= E_i * arg1 / pow(r,E_i + 1.0);\n" + , "1" // start from 2nd element + ); + ss << " double fNewRate = fResultRate - fResultValue / fResultValue2;\n"; + ss << " double fRateEps = fabs( fNewRate - fResultRate );\n"; + ss << " fResultRate = fNewRate;\n"; + ss << " bContLoop = (fRateEps > fMaxEps) && (fabs( fResultValue ) > fMaxEps);\n"; + ss << " } while( bContLoop && (++nIter < nMaxIter) );\n"; + ss << " nIter = 0;\n"; + ss << " if( isnan(fResultRate) || isinf(fResultRate) || isnan(fResultValue) || isinf(fResultValue))\n"; + ss << " bContLoop = true;\n"; + ss << " ++nIterScan;\n"; + ss << " bResultRateScanEnd = (nIterScan >= 200);\n"; + ss << " } while(bContLoop && !bResultRateScanEnd);\n"; + ss << " if( bContLoop )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return fResultRate;\n"; + ss << "}"; +} + +void OpDB::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "fCost", 0, vSubArguments, ss ); + GenerateArg( "fSalvage", 1, vSubArguments, ss ); + GenerateArg( "fLife", 2, vSubArguments, ss ); + GenerateArg( "fPeriod", 3, vSubArguments, ss ); + GenerateArgWithDefault( "fMonths", 4, 12, vSubArguments, ss ); + ss << " int nMonths = (int)fMonths;\n"; + ss << " if (fMonths < 1.0 || fMonths > 12.0 || fLife > 1200.0 || fSalvage < 0.0 ||\n"; + ss << " fPeriod > (fLife + 1.0) || fSalvage > fCost || fCost <= 0.0 ||\n"; + ss << " fLife <= 0 || fPeriod <= 0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double tmp = 0;\n"; + ss <<" double fDeprRate = 1.0 - pow(fSalvage / fCost, 1.0 / fLife);\n"; + ss <<" fDeprRate = ((int)(fDeprRate * 1000.0 + 0.5)) / 1000.0;\n"; + ss <<" double fFirstDeprRate = fCost * fDeprRate * nMonths / 12.0;\n"; + ss <<" double fDb = 0.0;\n"; + ss <<" if ((int)(fPeriod) == 1)\n"; + ss <<" fDb = fFirstDeprRate;\n"; + ss <<" else\n"; + ss <<" {\n"; + ss <<" double fSumDeprRate = fFirstDeprRate;\n"; + ss <<" double fMin = fLife;\n"; + ss <<" if (fMin > fPeriod) fMin = fPeriod;\n"; + ss <<" int nMax = (int)fMin;\n"; + ss <<" for (int i = 2; i <= nMax; i++)\n"; + ss <<" {\n"; + ss <<" fDb = (fCost - fSumDeprRate) * fDeprRate;\n"; + ss <<" fSumDeprRate += fDb;\n"; + ss <<" }\n"; + ss <<" if (fPeriod > fLife)\n"; + ss <<" fDb = ((fCost - fSumDeprRate)"; + ss <<"* fDeprRate * (12.0 - nMonths)) / 12.0;\n"; + ss <<" }\n"; + ss <<" tmp = fDb;\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_financial.hxx b/sc/source/core/opencl/op_financial.hxx new file mode 100644 index 0000000000..a834259722 --- /dev/null +++ b/sc/source/core/opencl/op_financial.hxx @@ -0,0 +1,559 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +class OpRRI: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "RRI"; } +}; + +class OpNominal: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "NOMINAL_ADD"; } +}; + +class OpDollarde:public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "Dollarde"; } + +}; + +class OpDollarfr:public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "Dollarfr"; } + +}; + +class OpDISC: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { return "DISC"; } +}; + +class OpINTRATE: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { return "INTRATE"; } +}; + +class OpFV: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { + return "FV"; } +}; + +class OpIPMT: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { + return "IPMT"; } +}; + +class OpISPMT: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "ISPMT"; } +}; + +class OpPDuration: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + + virtual std::string BinFuncName() const override { return "Duration"; } +}; + +class OpDuration_ADD: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { + return "Duration_ADD"; } +}; +class OpMDuration: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override {return "MDuration"; } +}; + +class Fvschedule: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override {return "Fvschedule"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class Cumipmt: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpIRR: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "IRR"; } +}; + +class OpMIRR: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual bool canHandleMultiVector() const override { return true; } + virtual std::string BinFuncName() const override { return "MIRR"; } +}; + +class OpXirr: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Xirr"; } +}; + +class XNPV: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; +}; + +class PriceMat: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; +class OpSYD: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "SYD"; } +}; + +class OpEffective:public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "Effect_Add"; } +}; + +class OpCumipmt: public Cumipmt +{ +public: + virtual std::string GetBottom() override { return "0"; } + virtual std::string BinFuncName() const override { return "Cumipmt"; } +}; + +class OpXNPV: public XNPV +{ +public: + virtual std::string GetBottom() override { return "0"; } + virtual std::string BinFuncName() const override { return "XNPV"; } + +}; + +class OpTbilleq: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "fTbilleq"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpCumprinc: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "cumprinc"; } +}; + +class OpAccrintm: public Normal +{ + public: + virtual std::string GetBottom() override { return "0"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Accrintm"; } +}; +class OpAccrint: public Normal +{ + public: + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Accrint"; } +}; + +class OpYield: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Yield"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpSLN: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SLN"; } +}; + +class OpFvschedule: public Fvschedule +{ +public: + virtual std::string GetBottom() override { return "0"; } + virtual std::string BinFuncName() const override { return "Fvschedule"; } +}; + +class OpYieldmat: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Yieldmat"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpPMT: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "PMT"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; +class OpNPV: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "NPV"; } + // doesn't handle svDoubleVectorRef properly, it should iterate horizontally + // virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpPrice: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Price"; } +}; + +class OpNper: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "NPER"; } +}; +class OpOddlprice: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>&, + std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Oddlprice"; } +}; +class OpOddlyield: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Oddlyield"; } +}; +class OpPriceDisc: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>&, + std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "PriceDisc"; } +}; +class OpPPMT: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "PPMT"; } +}; + +class OpCoupdaybs:public Normal +{ +public: + virtual std::string GetBottom() override { return "0";} + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Coupdaybs"; } + +}; + +class OpCoupdays:public Normal +{ +public: + virtual std::string GetBottom() override { return "0";} + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Coupdays";} + +}; + +class OpCoupdaysnc:public Normal +{ +public: + virtual std::string GetBottom() override { return "0";} + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Coupdaysnc"; } + +}; + +class OpCouppcd:public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Couppcd"; } + +}; + +class OpCoupncd:public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "Coupncd"; } + +}; + +class OpCoupnum:public Normal +{ +public: + virtual std::string GetBottom() override { return "0";} + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "Coupnum"; } + +}; +class OpDDB:public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "DDB"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; +class OpVDB: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "VDB"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; +class OpDB:public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "DB"; } +}; +class OpAmordegrc:public Normal +{ +public: + virtual std::string GetBottom() override { return "0";} + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "Amordegrc"; } +}; +class OpAmorlinc:public Normal +{ +public: + virtual std::string GetBottom() override { return "0";} + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "Amorlinc"; } +}; + +class OpReceived:public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Received"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpYielddisc: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Yielddisc"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpTbillprice: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "fTbillprice"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpPriceMat:public PriceMat +{ +public: + virtual std::string GetBottom() override { return "0"; } + virtual std::string BinFuncName() const override { return "PriceMat"; } +}; + +class OpRate: public Normal { +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual std::string GetBottom() override { return "0"; } + virtual std::string BinFuncName() const override { return "rate"; } +}; + +class OpTbillyield: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "fTbillyield"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpPV: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "PV"; } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_financial_helpers.hxx b/sc/source/core/opencl/op_financial_helpers.hxx new file mode 100644 index 0000000000..013334a045 --- /dev/null +++ b/sc/source/core/opencl/op_financial_helpers.hxx @@ -0,0 +1,1412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +const char GetPMTDecl[] = +"double GetPMT( double fRate, double fNper, double fPv, double fFv, bool bPayInAdvance);\n"; + +const char GetPMT[] = +"double GetPMT( double fRate, double fNper, double fPv, double fFv, bool bPayInAdvance )\n" +"{\n" +" double fPayment;\n" +" if (fRate == 0.0)\n" +" fPayment = (fPv + fFv) / fNper;\n" +" else\n" +" {\n" +" if (bPayInAdvance)\n" +" fPayment = (fFv + fPv * exp( fNper * log1p(fRate) ) ) * fRate\n" +" / (expm1( (fNper + 1) * log1p(fRate) ) - fRate);\n" +" else\n" +" fPayment = (fFv + fPv * exp(fNper * log1p(fRate) ) ) * fRate\n" +" / expm1( fNper * log1p(fRate) );\n" +" }\n" +" return -fPayment;\n" +"}\n"; + +const char GetIpmtDecl[] = +"double GetIpmt(double fRate, double fPer, double fNper, double fPv,\n" +" double fFv, bool bPayInAdvance, double* fPmt);\n"; + +const char GetIpmt[] = +"double GetIpmt(double fRate, double fPer, double fNper, double fPv,\n" +" double fFv, bool bPayInAdvance, double* fPmt)\n" +"{\n" +" *fPmt = GetPMT(fRate, fNper, fPv, fFv, bPayInAdvance);\n" +" double fIpmt;\n" +" if (fPer == 1.0)\n" +" {\n" +" if (bPayInAdvance)\n" +" fIpmt = 0.0;\n" +" else\n" +" fIpmt = -fPv;\n" +" }\n" +" else\n" +" {\n" +" if (bPayInAdvance)\n" +" fIpmt = GetFV(fRate, fPer-2.0, *fPmt, fPv, true) - *fPmt;\n" +" else\n" +" fIpmt = GetFV(fRate, fPer-1.0, *fPmt, fPv, false);\n" +" }\n" +" return fIpmt * fRate;\n" +"}\n"; + +const char GetFVDecl[] = +"double GetFV( double fRate, double fNper, double fPmt," +" double fPv, bool bPayInAdvance );\n"; + +const char GetFV[] = +"double GetFV( double fRate, double fNper, double fPmt," +" double fPv, bool bPayInAdvance )\n" +"{\n" +" double fFv;\n" +" if (fRate == 0.0)\n" +" fFv = fPv + fPmt * fNper;\n" +" else\n" +" {\n" +" double fTerm = pow(1.0 + fRate, fNper);\n" +" if (bPayInAdvance)\n" +" fFv = fPv * fTerm + fPmt*(1.0 + fRate)*(fTerm - 1.0)/fRate;\n" +" else\n" +" fFv = fPv * fTerm + fPmt*(fTerm - 1.0)/fRate;\n" +" }\n" +" return -fFv;\n" +"}\n"; + +const char IsLeapYearDecl[] = +"bool IsLeapYear( int n );\n"; + +const char IsLeapYear[] = +"bool IsLeapYear( int n )\n" +"{\n" +" return ( (( ( n % 4 ) == 0 ) && ( ( n % 100 ) != 0)) || ( ( n % 400 ) == " +"0 ) );\n" +"}\n"; + +const char DaysInMonthDecl[] = +"int DaysInMonth( int nMonth, int nYear );\n"; + +const char DaysInMonth[] = +"int DaysInMonth( int nMonth, int nYear )\n" +"{\n" +" int tmp = 0;\n" +" switch(nMonth)\n" +" {\n" +" case 1:\n" +" case 3:\n" +" case 5:\n" +" case 7:\n" +" case 8:\n" +" case 10:\n" +" case 12:\n" +" tmp = 31;\n" +" break;\n" +" case 4:\n" +" case 6:\n" +" case 9:\n" +" case 11:\n" +" tmp =30;\n" +" break;\n" +" case 2:\n" +" if ( IsLeapYear(nYear)==1)\n" +" tmp = 29;\n" +" else\n" +" tmp = 28;\n" +" break;\n" +" }\n" +" return tmp;\n" +"}\n"; + +const char DateToDaysDecl[] = +"int DateToDays( int nDay, int nMonth, int nYear );\n"; + +const char DateToDays[] = +"int DateToDays( int nDay, int nMonth, int nYear )\n" +"{\n" +" int nDays = (nYear-1) * 365;\n" +" nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);\n" +" for( int i = 1; i < nMonth; i++ )\n" +" nDays += DaysInMonth(i,nYear);\n" +" nDays += nDay;\n" +"\n" +" return nDays;\n" +"}\n"; + +const char GetNullDateDecl[] = +"int GetNullDate();\n"; + +const char GetNullDate[] = +"int GetNullDate()\n" +"{\n" +" return DateToDays(30,12,1899 );\n" +"}\n"; + +const char ScaDateDecl[] = +"void ScaDate( int nNullDate, int nDate, int nBase,int *nOrigDay, " +"int *nMonth,int *nYear,int *bLastDayMode,int *bLastDay," +"int *b30Days,int *bUSMode,int *nDay);\n"; + +const char ScaDate[] = +"void ScaDate( int nNullDate, int nDate, int nBase,int *nOrigDay, " +"int *nMonth,int *nYear,int *bLastDayMode,int *bLastDay," +"int *b30Days,int *bUSMode,int *nDay)\n" +"{\n" +" DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );\n" +" *bLastDayMode = (nBase != 5);\n" +" *bLastDay = (*nOrigDay >= DaysInMonth( *nMonth, *nYear ));\n" +" *b30Days = (nBase == 0) || (nBase == 4);\n" +" *bUSMode = (nBase == 0);\n" +" if( *b30Days)\n" +" {\n" +" *nDay = min( *nOrigDay, 30);\n" +" if( *bLastDay || (*nDay >=DaysInMonth( *nMonth, *nYear )) )\n" +" *nDay = 30;\n" +" }\n" +" else\n" +" {\n" +" int nLastDay = DaysInMonth( *nMonth, *nYear );\n" +" *nDay = *bLastDay ? nLastDay : min( *nOrigDay, nLastDay );\n" +" }\n" +"}\n"; + +const char lcl_GetCouppcdDecl[] = +"int lcl_GetCouppcd(int nNullDate,int nSettle,int nMat,int nFreq,int nBase);\n"; + +const char lcl_GetCouppcd[] = +"int lcl_GetCouppcd(int nNullDate,int nSettle, int nMat,int nFreq,int nBase)\n" +"{\n" +" int aDate = nMat;\n" +" int rDay=0,rMonth=0, rYear=0,rbLastDayMode=0, rbLastDay=0,rb30Days=0," +"rbUSMode=0,rnDay=0;\n" +" int sDay=0,sMonth=0, sYear=0,sbLastDayMode=0, sbLastDay=0,sb30Days=0," +"sbUSMode=0,snDay=0;\n" +" ScaDate( nNullDate,nSettle,nBase,&sDay,&sMonth,&sYear,&sbLastDayMode," +"&sbLastDay,&sb30Days,&sbUSMode,&snDay);\n" +" ScaDate( nNullDate,aDate,nBase,&rDay,&rMonth,&rYear,&rbLastDayMode," +"&rbLastDay,&rb30Days,&rbUSMode,&rnDay);\n" +" rYear=sYear;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" if(checklessthan(rYear,sYear,rMonth,sMonth,rnDay,snDay,rbLastDay," +"sbLastDay,rDay,sDay))\n" +" {\n" +" rYear+=1;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" }\n" +" while(checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay))\n" +" {\n" +" double d = -1*(12/nFreq);\n" +" addMonths(rb30Days,rbLastDay,&rnDay,rDay,&rMonth,d,&rYear);\n" +" }\n" +" int nLastDay = DaysInMonth( rMonth, rYear );\n" +" int nRealDay = (rbLastDayMode && rbLastDay) ? nLastDay :" +"min( nLastDay, rDay );\n" +" return DateToDays( nRealDay, rMonth, rYear ) - nNullDate;\n" +"}\n"; + +const char lcl_GetCoupncdDecl[] = +"int lcl_GetCoupncd(int nNullDate,int nSettle,int nMat,int nFreq,int nBase);\n"; + +const char lcl_GetCoupncd[] = +"int lcl_GetCoupncd(int nNullDate,int nSettle, int nMat,int nFreq,int nBase)\n" +"{\n" +" int aDate = nMat;\n" +" int rDay=0,rMonth=0, rYear=0,rbLastDayMode=0, rbLastDay=0,rb30Days=0," +"rbUSMode=0,rnDay=0;\n" +" int sDay=0,sMonth=0, sYear=0,sbLastDayMode=0, sbLastDay=0,sb30Days=0," +"sbUSMode=0,snDay=0;\n" +" ScaDate( nNullDate,nSettle,nBase,&sDay,&sMonth,&sYear,&sbLastDayMode," +"&sbLastDay,&sb30Days,&sbUSMode,&snDay);\n" +" ScaDate( nNullDate,aDate,nBase,&rDay,&rMonth,&rYear,&rbLastDayMode," +"&rbLastDay,&rb30Days,&rbUSMode,&rnDay);\n" +" rYear=sYear;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" if(checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay,rbLastDay" +",sDay,rDay))\n" +" {\n" +" rYear-=1;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" }\n" +" while(!checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay))\n" +" {\n" +" addMonths(rb30Days,rbLastDay,&rnDay,rDay,&rMonth,12/nFreq,&rYear);\n" +" }\n" +" int nLastDay = DaysInMonth( rMonth, rYear );\n" +" int nRealDay = (rbLastDayMode && rbLastDay) ? nLastDay :" +"min( nLastDay, rDay );\n" +" return DateToDays( nRealDay, rMonth, rYear ) - nNullDate;\n" +"}\n"; + +const char addMonthsDecl[] = +"void addMonths(int b30Days,int bLastDay,int *nDay,int nOrigDay," +"int *nMonth,int nMonthCount,int *year);\n"; + +const char addMonths[] = +"void addMonths(int b30Days,int bLastDay,int *nDay,int nOrigDay," +"int *nMonth,int nMonthCount,int *year)\n" +"{\n" +" int nNewMonth = nMonthCount + *nMonth;\n" +" if( nNewMonth > 12 )\n" +" {\n" +" --nNewMonth;\n" +" *year+=nNewMonth / 12 ;\n" +" *nMonth = ( nNewMonth % 12 ) + 1;\n" +" }\n" +" else if( nNewMonth < 1 )\n" +" {\n" +" *year+= nNewMonth / 12 - 1 ;\n" +" *nMonth = nNewMonth % 12 + 12 ;\n" +" }\n" +" else\n" +" *nMonth = nNewMonth ;\n" +" if( b30Days )\n" +" {\n" +" *nDay = min( nOrigDay, 30);\n" +" if( bLastDay || (*nDay >= DaysInMonth( *nMonth, *year )) )\n" +" *nDay = 30;\n" +" }\n" +" else\n" +" {\n" +" int nLastDay = DaysInMonth( *nMonth, *year );\n" +" *nDay = bLastDay ? nLastDay : min( nOrigDay, nLastDay );\n" +" }\n" +"}\n"; + +const char getDaysInMonthRangeDecl[] = +"int getDaysInMonthRange( int nFrom, int nTo,int b30Days,int year);\n"; + +const char getDaysInMonthRange[] = +"int getDaysInMonthRange( int nFrom, int nTo,int b30Days,int year)\n" +"{\n" +" if( nFrom > nTo )\n" +" return 0;\n" +" int nRet = 0;\n" +" if( b30Days )\n" +" nRet = (nTo - nFrom + 1) * 30;\n" +" else\n" +" {\n" +" for( int nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )\n" +" nRet += b30Days ? 30 : DaysInMonth( nMonthIx, year );\n" +" }\n" +" return nRet;\n" +"}\n"; + +const char GetDaysInYearsDecl[] = +"int GetDaysInYears( int nYear1, int nYear2 );\n"; + +const char GetDaysInYears[] = +"int GetDaysInYears( int nYear1, int nYear2 )\n" +"{\n" +" int nLeaps = 0;\n" +" for( int n = nYear1 ; n <= nYear2 ; n++ )\n" +" {\n" +" if( IsLeapYear( n ) )\n" +" nLeaps++;\n" +" }\n" +" int nSum = 1;\n" +" nSum += nYear2;\n" +" nSum -= nYear1;\n" +" nSum *= 365;\n" +" nSum += nLeaps;\n" +" return nSum;\n" +"}\n"; + +const char GetDaysInYearDecl[] = +"int GetDaysInYear( int nNullDate, int nDate, int nMode );\n"; + +const char GetDaysInYear[] = +"int GetDaysInYear( int nNullDate, int nDate, int nMode )\n" +"{\n" +" switch( nMode )\n" +" {\n" +" case 0:\n" +" case 2:\n" +" case 4:\n" +" return 360;\n" +" case 1:\n" +" {\n" +" int nD=0, nM=0, nY=0;\n" +" nDate += nNullDate;\n" +" DaysToDate( nDate, &nD, &nM, &nY );\n" +" return IsLeapYear( nY )? 366 : 365;\n" +" }\n" +" case 3:\n" +" return 365;\n" +" }\n" +"}\n"; + +const char getDaysInYearRangeDecl[] = +"int getDaysInYearRange( int nFrom, int nTo,int b30Days );\n"; + +const char getDaysInYearRange[] = +"int getDaysInYearRange( int nFrom, int nTo,int b30Days )\n" +"{\n" +" if( nFrom > nTo )\n" +" return 0;\n" +" return b30Days ? ((nTo - nFrom + 1) * 360) : GetDaysInYears( nFrom, nTo)" +";\n" +"}\n"; + +const char getDiffDecl[] = +"int getDiff(int rFrom,int rTo,int fDay,int fMonth,int fYear,int fbLastDayMode," +"int fbLastDay,int fb30Days,int fbUSMode,int fnDay,int tDay,int tMonth," +"int tYear,int tbLastDayMode,int tbLastDay,int tb30Days," +"int tbUSMode,int tnDay);\n"; + +const char getDiff[] = +"int getDiff(int rFrom,int rTo,int fDay,int fMonth,int fYear,int fbLastDayMode," +"int fbLastDay,int fb30Days,int fbUSMode,int fnDay,int tDay,int tMonth," +"int tYear,int tbLastDayMode,int tbLastDay,int tb30Days," +"int tbUSMode,int tnDay)\n" +"{\n" +" if(rFrom>rTo)\n" +" {\n" +" int d=fDay;fDay=tDay;tDay=d;\n" +" int m=fMonth;fMonth=tMonth;tMonth=m;\n" +" int y=fYear;fYear=tYear;tYear=y;\n" +" int a=fbLastDayMode;fbLastDayMode=tbLastDayMode;tbLastDayMode=a;\n" +" int b=fbLastDay;fbLastDay=tbLastDay;tbLastDay=b;\n" +" int c=fb30Days;fb30Days=tb30Days;tb30Days=c;\n" +" int e=fbUSMode;fbUSMode=tbUSMode;tbUSMode=e;\n" +" int f=fnDay;fnDay=tnDay;tnDay=f;\n" +" }\n" +" int nDiff=0;\n" +" if( tb30Days )\n" +" {\n" +" if( tbUSMode )\n" +" {\n" +" if( ((fMonth == 2) || (fnDay < 30)) && (tDay == 31) )\n" +" tnDay = 31;\n" +" else if( (tMonth == 2) && tbLastDay )\n" +" tnDay = DaysInMonth( 2, tYear );\n" +" }\n" +" else\n" +" {\n" +" if( (fMonth == 2) && (fnDay == 30) )\n" +" fnDay = DaysInMonth( 2, fYear );\n" +" if( (tMonth == 2) && (tnDay == 30) )\n" +" tnDay = DaysInMonth( 2, tYear );\n" +" }\n" +" }\n" +" if( (fYear < tYear) || ((fYear == tYear) && (fMonth < tMonth)) )\n" +" {\n" +" int d = fb30Days ? 30:DaysInMonth(fMonth,fYear);\n" +" nDiff = d- fnDay + 1;\n" +" fDay = fnDay = 1;\n" +" fbLastDay = 0;\n" +" addMonths(fb30Days,fbLastDay,&fnDay,fDay,&fMonth,1,&fYear);\n" +" if( fYear < tYear )\n" +" {\n" +" nDiff += getDaysInMonthRange( fMonth, 12,fb30Days,fYear);\n" +" addMonths(fb30Days,fbLastDay,&fnDay,fDay,&fMonth,13-fMonth,&fYear" +");\n" +" nDiff += getDaysInYearRange( fYear, tYear - 1,fb30Days);\n" +" fYear+=tYear - fYear;\n" +" }\n" +" nDiff += getDaysInMonthRange(fMonth, tMonth - 1,fb30Days ,fYear );\n" +" addMonths(fb30Days,fbLastDay,&fnDay,fDay,&fMonth,tMonth-fMonth,&fYear" +");\n" +" }\n" +" nDiff += tnDay - fnDay;\n" +" return nDiff > 0 ? nDiff : 0;\n" +"}\n"; + +const char lcl_GetcoupdaybsDecl[] = +"int lcl_Getcoupdaybs(int nNullDate,int nSettle,int nMat,int nFreq," +"int nBase);\n"; + +const char lcl_Getcoupdaybs[] = +"int lcl_Getcoupdaybs(int nNullDate,int nSettle,int nMat,int nFreq," +"int nBase)\n" +"{\n" +" int aDate = nMat;\n" +" int rDay=0,rMonth=0, rYear=0,rbLastDayMode=0, rbLastDay=0,rb30Days=0," +"rbUSMode=0,rnDay=0;\n" +" int sDay=0,sMonth=0, sYear=0,sbLastDayMode=0, sbLastDay=0,sb30Days=0," +"sbUSMode=0,snDay=0;\n" +" ScaDate( nNullDate,nSettle,nBase,&sDay,&sMonth,&sYear,&sbLastDayMode," +"&sbLastDay,&sb30Days,&sbUSMode,&snDay);\n" +" ScaDate( nNullDate,aDate,nBase,&rDay,&rMonth,&rYear,&rbLastDayMode," +"&rbLastDay,&rb30Days,&rbUSMode,&rnDay);\n" +" rYear=sYear;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" aDate=DateToDays( rnDay,rMonth,rYear);\n" +" if(checklessthan(rYear,sYear,rMonth,sMonth,rnDay,snDay,rbLastDay," +"sbLastDay,rDay,sDay))\n" +" {\n" +" rYear+=1;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" aDate=DateToDays( rnDay,rMonth,rYear );\n" +" }\n" +" while(checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay))\n" +" {\n" +" double d = -1*(12/nFreq);\n" +" addMonths(rb30Days,rbLastDay,&rnDay,rDay,&rMonth,d,&rYear);\n" +" aDate=DateToDays( rnDay,rMonth,rYear );\n" +" }\n" +" return getDiff( aDate,nSettle+nNullDate,rDay,rMonth,rYear,rbLastDayMode," +"rbLastDay,rb30Days,rbUSMode,rnDay,sDay,sMonth,sYear,sbLastDayMode,sbLastDay," +"sb30Days,sbUSMode, snDay);\n" +"}\n"; + +const char lcl_GetcoupdaysDecl[] = +"int lcl_Getcoupdays(int nNullDate,int nSettle, " +"int nMat,int nFreq,int nBase);\n"; + +const char lcl_Getcoupdays[] = +"int lcl_Getcoupdays(int nNullDate,int nSettle, " +"int nMat,int nFreq,int nBase)\n" +"{\n" +" int aDate = nMat;\n" +" int rDay=0,rMonth=0, rYear=0,rbLastDayMode=0, rbLastDay=0,rb30Days=0," +"rbUSMode=0,rnDay=0;\n" +" int sDay=0,sMonth=0, sYear=0,sbLastDayMode=0, sbLastDay=0,sb30Days=0," +"sbUSMode=0,snDay=0;\n" +" ScaDate( nNullDate,nSettle,nBase,&sDay,&sMonth,&sYear,&sbLastDayMode," +"&sbLastDay,&sb30Days,&sbUSMode,&snDay);\n" +" ScaDate( nNullDate,aDate,nBase,&rDay,&rMonth,&rYear,&rbLastDayMode," +"&rbLastDay,&rb30Days,&rbUSMode,&rnDay);\n" +" rYear=sYear;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" aDate=DateToDays( rnDay,rMonth,rYear);\n" +" if(checklessthan(rYear,sYear,rMonth,sMonth,rnDay,snDay,rbLastDay," +"sbLastDay,rDay,sDay))\n" +" {\n" +" rYear+=1;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" aDate=DateToDays( rnDay,rMonth,rYear );\n" +" }\n" +" while(checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay))\n" +" {\n" +" double d = -1*12/(double)nFreq;\n" +" addMonths(rb30Days,rbLastDay,&rnDay,rDay,&rMonth,d,&rYear);\n" +" aDate=DateToDays( rnDay,rMonth,rYear );\n" +" }\n" +" int aNextDate=aDate;int aDay=rDay,aMonth=rMonth, aYear=rYear;\n" +" int abLastDayMode=rbLastDayMode, abLastDay=rbLastDay,ab30Days=rb30Days," +"abUSMode=rbUSMode,anDay=rnDay;\n" +" int tmp = (int)(12/(double)nFreq);\n" +" addMonths(ab30Days,abLastDay,&anDay,aDay,&aMonth,tmp,&aYear);\n" +" return getDiff( aDate, aNextDate, rDay, rMonth, rYear, rbLastDayMode, " +"rbLastDay, rb30Days, rbUSMode, rnDay, aDay, aMonth, aYear, abLastDayMode," +"abLastDay, ab30Days, abUSMode, anDay);\n" +"}\n"; + +const char lcl_GetcoupnumDecl[] = +"double lcl_Getcoupnum(int nNullDate,int nSettle,int nMat,int nFreq,int" +" nBase);\n"; +const char lcl_Getcoupnum[] = +"double lcl_Getcoupnum(int nNullDate,int nSettle, int nMat,int nFreq,int" +" nBase)\n" +"{\n" +" int aDate = nMat;\n" +" int mDay=0,mMonth=0, mYear=0;\n" +" int rDay=0,rMonth=0, rYear=0,rbLastDayMode=0, rbLastDay=0,rb30Days=0," +"rbUSMode=0,rnDay=0;\n" +" int sDay=0,sMonth=0, sYear=0,sbLastDayMode=0, sbLastDay=0,sb30Days=0," +"sbUSMode=0,snDay=0;\n" +" ScaDate( nNullDate,nSettle,nBase,&sDay,&sMonth,&sYear,&sbLastDayMode," +"&sbLastDay,&sb30Days,&sbUSMode,&snDay);\n" +" ScaDate( nNullDate,aDate,nBase,&rDay,&rMonth,&rYear,&rbLastDayMode," +"&rbLastDay,&rb30Days,&rbUSMode,&rnDay);\n" +" mMonth = rMonth, mYear = rYear;\n" +" rYear=sYear;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" if(checklessthan(rYear,sYear,rMonth,sMonth,rnDay,snDay,rbLastDay," +"sbLastDay,rDay,sDay))\n" +" {\n" +" rYear+=1;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" }\n" +" int m= checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay);\n" +" while(m)\n" +" {\n" +" double d = -1*(12/nFreq);\n" +" addMonths(rb30Days,rbLastDay,&rnDay,rDay,&rMonth,d,&rYear);\n" +" m = checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay);\n" +" }\n" +" int n=(mYear-rYear)*12+mMonth-rMonth;\n" +" double tmp = (double)(n*nFreq)/12.0;\n" +" return tmp;\n" +"}\n"; + +const char setDayDecl[] = +"void setDay(int nOrigDay, int nMonth,int nYear,int bLastDay,int b30Days," +"int *nDay);\n"; +const char setDay[] = +"void setDay(int nOrigDay, int nMonth,int nYear,int bLastDay,int b30Days," +"int *nDay)\n" +"{\n" +" if( b30Days )\n" +" {\n" +" *nDay = min( nOrigDay, 30);\n" +" if( bLastDay || (*nDay >= DaysInMonth( nMonth, nYear )) )\n" +" *nDay = 30;\n" +" }\n" +" else\n" +" {\n" +" int nLastDay = DaysInMonth( nMonth, nYear );\n" +" *nDay = bLastDay ? nLastDay : min( nOrigDay, nLastDay );\n" +" }\n" +"}\n"; + +const char coupdaysDecl[] = +"double coupdays(int nSettle,int nMat,int nFreq,int nBase);\n"; + +const char coupdays[] = +"double coupdays(int nSettle,int nMat,int nFreq,int nBase)\n" +"{\n" +" int nNullDate=693594;\n" +" if( nBase == 1 )\n" +" return lcl_Getcoupdays(nNullDate, nSettle, nMat,nFreq, nBase);\n" +" else\n" +" return (double)GetDaysInYear(0,0,nBase)/(double)nFreq;\n" +"}\n"; + +const char coupdaybsDecl[] = +"double coupdaybs( int nSettle,int nMat,int nFreq,int nBase);\n"; + +const char coupdaybs[] = +"double coupdaybs( int nSettle,int nMat,int nFreq,int nBase)\n" +"{\n" +" int nNullDate=693594;\n" +" return lcl_Getcoupdaybs(nNullDate, nSettle, nMat,nFreq, nBase);\n" +"}\n"; + +const char coupdaysncDecl[] = +"double coupdaysnc( int nSettle,int nMat,int nFreq,int nBase);\n"; + +const char coupdaysnc[] = +"double coupdaysnc( int nSettle,int nMat,int nFreq,int nBase)\n" +"{\n" +" int nNullDate=693594;\n" +" if((nBase != 0) && (nBase != 4))\n" +" {\n" +" int aDate = nMat;\n" +" int rDay=0,rMonth=0, rYear=0,rbLastDayMode=0, rbLastDay=0,rb30Days=0," +"rbUSMode=0,rnDay=0;\n" +" int sDay=0,sMonth=0, sYear=0,sbLastDayMode=0, sbLastDay=0,sb30Days=0," +"sbUSMode=0,snDay=0;\n" +" ScaDate( nNullDate,aDate,nBase,&rDay,&rMonth,&rYear,&rbLastDayMode," +"&rbLastDay,&rb30Days,&rbUSMode,&rnDay);\n" +" ScaDate( nNullDate,nSettle,nBase,&sDay,&sMonth,&sYear,&sbLastDayMode," +"&sbLastDay,&sb30Days,&sbUSMode,&snDay);\n" +" rYear=sYear;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" aDate=DateToDays( rnDay,rMonth,rYear);\n" +" if(checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay,rbLastDay" +",sDay,rDay))\n" +" {\n" +" rYear-=1;\n" +" setDay(rDay,rMonth,rYear,rbLastDay,rb30Days,&rnDay);\n" +" aDate=DateToDays( rnDay,rMonth,rYear );\n" +" }\n" +" while(!checklessthan(sYear,rYear,sMonth,rMonth,snDay,rnDay,sbLastDay," +"rbLastDay,sDay,rDay))\n" +" {\n" +" addMonths(rb30Days,rbLastDay,&rnDay,rDay,&rMonth,12/nFreq,&rYear);\n" +" aDate=DateToDays( rnDay,rMonth,rYear );\n" +" }\n" +" return getDiff( nSettle+nNullDate,aDate,sDay,sMonth,sYear,sbLastDayMode, " +"sbLastDay, sb30Days, sbUSMode, snDay, rDay, rMonth, rYear, rbLastDayMode, " +"rbLastDay, rb30Days, rbUSMode, rnDay);\n" +" }\n" +" else\n" +" return coupdays(nSettle,nMat,nFreq,nBase)- coupdaybs( nSettle," +"nMat,nFreq,nBase);\n" +"}\n"; + +const char checklessthanDecl[] = +"int checklessthan(int aYear,int bYear,int aMonth,int bMonth,int anDay,int " +"bnDay,int abLastDay,int bbLastDay,int anOrigDay,int bnOrigDay);\n"; +const char checklessthan[] = +"int checklessthan(int aYear,int bYear,int aMonth,int bMonth,int anDay,int " +"bnDay,int abLastDay,int bbLastDay,int anOrigDay,int bnOrigDay)\n" +"{\n" +" if( aYear != bYear )\n" +" return aYear < bYear;\n" +" if( aMonth != bMonth )\n" +" return aMonth < bMonth;\n" +" if( anDay != bnDay )\n" +" return anDay < bnDay;\n" +" if( abLastDay || bbLastDay )\n" +" return !abLastDay && bbLastDay;\n" +" return anOrigDay < bnOrigDay;\n" +"}\n"; + +const char coupnumDecl[] = +"double coupnum( int nSettle,int nMat,int nFreq,int nBase);\n"; + +const char coupnum[] = +"double coupnum( int nSettle,int nMat,int nFreq,int nBase)\n" +"{\n" +" int nNullDate=693594;\n" +" return lcl_Getcoupnum(nNullDate,nSettle,nMat,nFreq,nBase);\n" +"}\n"; + +const char getPriceDecl[] = +"double getPrice(int nSettle, int nMat, double fRate, double fYield,\n" + "double fRedemp, int nFreq, int nBase );\n"; + +const char getPrice[] = +"double getPrice(int nSettle, int nMat, double fRate, double fYield,\n" + "double fRedemp, int nFreq, int nBase )\n" +"{\n" +" double fFreq = nFreq;\n" +" double fE = coupdays( nSettle, nMat, nFreq, nBase );\n" +" double fDSC_E = coupdaysnc( nSettle, nMat, nFreq, nBase ) / fE;\n" +" double fN = coupnum( nSettle, nMat, nFreq, nBase );\n" +" double fA = coupdaybs( nSettle, nMat, nFreq, nBase );\n" +" double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + " +"fDSC_E ) );\n" +" fRet -= 100.0 * fRate / fFreq * fA / fE;\n" +" double fT1 = 100.0 * fRate / fFreq;\n" +" double fT2 = 1.0 + fYield / fFreq;\n" +" for( double fK = 0.0 ; fK < fN ; fK+=1.0 )\n" +" fRet += fT1 / pow( fT2, fK + fDSC_E );\n" +" return fRet;\n" +"}\n"; + +const char getYield_Decl[] = +"double getYield_( int nNullDate, int nSettle, int nMat, double fCoup," +"double fPrice,double fRedemp, int nFreq, int nBase);\n"; + +const char getYield_[] = +"double getYield_( int nNullDate, int nSettle, int nMat, double fCoup," +"double fPrice,double fRedemp, int nFreq, int nBase )\n" +"{\n" +" double fRate = fCoup;\n" +" double fPriceN = 0.0;\n" +" double fYield1 = 0.0;\n" +" double fYield2 = 1.0;\n" +" double fPrice1 = getPrice(nSettle, nMat, fRate, fYield1, fRedemp, " +"nFreq, nBase );\n" +" double fPrice2 = getPrice(nSettle, nMat, fRate, fYield2, fRedemp, " +"nFreq, nBase );\n" +" double fYieldN = ( fYield2 - fYield1 ) * 0.5;\n" +" for( unsigned int nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ " +")\n" +" {\n" +" fPriceN = getPrice(nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, " +"nBase );\n" +" if( fPrice == fPrice1 )\n" +" return fYield1;\n" +" else if( fPrice == fPrice2 )\n" +" return fYield2;\n" +" else if( fPrice == fPriceN )\n" +" return fYieldN;\n" +" else if( fPrice < fPrice2 )\n" +" {\n" +" fYield2 *= 2.0;\n" +" fPrice2 = getPrice(nSettle, nMat, fRate, fYield2, fRedemp, nFreq" +", nBase );\n" +" fYieldN = ( fYield2 - fYield1 ) * 0.5;\n" +" }\n" +" else\n" +" {\n" +" if( fPrice < fPriceN )\n" +" {\n" +" fYield1 = fYieldN;\n" +" fPrice1 = fPriceN;\n" +" }\n" +" else\n" +" {\n" +" fYield2 = fYieldN;\n" +" fPrice2 = fPriceN;\n" +" }\n" +" fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 " +") / ( fPrice1 - fPrice2 ) );\n" +" }\n" +" }\n" +" return fYieldN;\n" +"}\n"; + +const char GetYieldmatDecl[] = + "double GetYieldmat( int nNullDate, int nSettle, int nMat, int nIssue,\n" + "double fRate, double fPrice, int nBase );\n"; + +const char GetYieldmat[] = + "double GetYieldmat( int nNullDate, int nSettle, int nMat, int nIssue,\n" + "double fRate, double fPrice, int nBase )\n" +"{\n" +" double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );\n" +" double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );\n" +" double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );\n" +" double y = 1.0 + fIssMat * fRate;\n" +" y =y / (fPrice / 100.0 + fIssSet * fRate);\n" +" y-=1.0;\n" +" y = y / fSetMat;\n" +" return y;\n" +"}\n"; + +const char GetDiffDate360_Decl[] = +"int GetDiffDate360_(\n" +" int nDay1, int nMonth1, int nYear1, bool bLeapYear1,\n" +" int nDay2, int nMonth2, int nYear2,\n" +" bool bUSAMethod );\n"; + +const char GetDiffDate360_[] = +"int GetDiffDate360_(\n" +" int nDay1, int nMonth1, int nYear1, bool bLeapYear1,\n" +" int nDay2, int nMonth2, int nYear2,\n" +" bool bUSAMethod )\n" +"{\n" +" if( nDay1 == 31 )\n" +" nDay1--;\n" +" else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 " +"&& !bLeapYear1 ) ) ) )\n" +" nDay1 = 30;\n" +" if( nDay2 == 31 )\n" +" {\n" +" if( bUSAMethod && nDay1 != 30 )\n" +" {\n" +" nDay2 = 1;\n" +" if( nMonth2 == 12 )\n" +" {\n" +" nYear2++;\n" +" nMonth2 = 1;\n" +" }\n" +" else\n" +" nMonth2++;\n" +" }\n" +" else\n" +" nDay2 = 30;\n" +" }\n" +" return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - " +"nYear1 * 360;\n" +"}\n"; + +const char GetDiffDate360Decl[] = +"int GetDiffDate360( int nNullDate, int nDate1, int nDate2," +"bool bUSAMethod);\n"; + +const char GetDiffDate360[] = +"int GetDiffDate360( int nNullDate, int nDate1, int nDate2," +"bool bUSAMethod )\n" +"{\n" +" nDate1 += nNullDate;\n" +" nDate2 += nNullDate;\n" +" int nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;\n" +" DaysToDate( nDate1, &nDay1, &nMonth1, &nYear1 );\n" +" DaysToDate( nDate2, &nDay2, &nMonth2, &nYear2 );\n" +" return GetDiffDate360_( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), " +"nDay2, nMonth2, nYear2, bUSAMethod );\n" +"}\n"; + +const char GetDurationDecl[] = +"double GetDuration( \n" +" int nNullDate, int nSettle, int nMat, double fCoup,\n" +" double fYield, int nFreq, int nBase );\n"; + +const char GetDuration[] = +"double GetDuration( \n" +" int nNullDate, int nSettle, int nMat, double fCoup,\n" +" double fYield, int nFreq, int nBase )\n" +" {\n" +" double fYearfrac = GetYearFrac(nNullDate,nSettle,nMat,nBase);\n" +" double fNumOfCoups = lcl_Getcoupnum(nNullDate,nSettle,nMat," +"nFreq,nBase);\n" +" double fDur = 0.0;\n" +" fCoup = fCoup * 100.0 / nFreq;\n" +" fYield = fYield / nFreq;\n" +" fYield += 1.0;\n" +" double nDiff = fYearfrac * nFreq - fNumOfCoups;\n" +" int t;\n" +" double tmp0 = 0, tmp1 = 0, tmp2 = 0;\n" +" for( t = 1 ; t < fNumOfCoups ; t++ ){\n" +" tmp0 = (t + nDiff) * ( fCoup ) ;\n" +" tmp1 = pow( fYield, t + nDiff ) ;\n" +" tmp2 = tmp0 / tmp1;\n" +" fDur += tmp2;\n" +" }\n" +" fDur += (fNumOfCoups + nDiff) * (fCoup + 100.0) * pow(pow(fYield," +" fNumOfCoups + nDiff ),-1);\n" +" double p = 0.0;\n" +" for( t = 1 ; t < fNumOfCoups ; t++ ){\n" +" tmp0 = pow( fYield, t + nDiff );\n" +" p += fCoup / tmp0;}\n" +" p += (fCoup + 100.0) / pow(fYield, fNumOfCoups + nDiff);\n" +" fDur = fDur / p;\n" +" fDur = fDur / nFreq;\n" +" return fDur;\n" +" }\n"; + +const char ScGetDDBDecl[] = +"double ScGetDDB(double fCost, double fSalvage, double fLife, double fPeriod," +"double fFactor);\n"; + +const char ScGetDDB[] = +"double ScGetDDB(double fCost, double fSalvage, double fLife, double fPeriod," +"double fFactor)\n" +"{\n" +" double fDdb, fRate, fOldValue, fNewValue;\n" +" fRate = fFactor / fLife;\n" +" if (fRate >= 1.0)\n" +" {\n" +" fRate = 1.0;\n" +" if (fPeriod == 1.0)\n" +" fOldValue = fCost;\n" +" else\n" +" fOldValue = 0.0;\n" +" }\n" +" else\n" +" fOldValue = fCost * pow(1.0 - fRate, fPeriod - 1.0);\n" +" fNewValue = fCost * pow(1.0 - fRate, fPeriod);\n" + +" if (fNewValue < fSalvage)\n" +" fDdb = fOldValue - fSalvage;\n" +" else\n" +" fDdb = fOldValue - fNewValue;\n" +" if (fDdb < 0.0)\n" +" fDdb = 0.0;\n" +" return fDdb;\n" +"}\n"; + +const char ScInterVDBDecl[] = +"double ScInterVDB(double fCost, double fSalvage, double fLife, double fLife1," +"double fPeriod, double fFactor);\n"; + +const char ScInterVDB[] = +"double ScInterVDB(double fCost, double fSalvage, double fLife, double fLife1," +"double fPeriod, double fFactor)\n" +"{\n" +" double fVdb=0;\n" +" double fIntEnd = ceil(fPeriod);\n" +" int nLoopEnd = fIntEnd;\n" + +" double fTerm, fSln;\n" +" double fSalvageValue = fCost - fSalvage;\n" +" int nNowSln = 0;\n" +" double fDdb;\n" +" int i;\n" +" fSln=0;\n" +" for ( i = 1; i <= nLoopEnd; i++)\n" +" {\n" +" if(!nNowSln)\n" +" {\n" +" fDdb = ScGetDDB(fCost, fSalvage, fLife, (double) i, fFactor);\n" +" fSln = fSalvageValue/ (fLife1 - (double) (i-1));\n" +" if (fSln > fDdb)\n" +" {\n" +" fTerm = fSln;\n" +" nNowSln = 1;\n" +" }\n" +" else\n" +" {\n" +" fTerm = fDdb;\n" +" fSalvageValue =fSalvageValue- fDdb;\n" +" }\n" +" }\n" +" else\n" +" {\n" +" fTerm = fSln;\n" +" }\n" + +" if ( i == nLoopEnd)\n" +" fTerm *= ( fPeriod + 1.0 - fIntEnd );\n" + +" fVdb += fTerm;\n" +" }\n" +" return fVdb;\n" +"}\n"; + +const char VDBImplementDecl[] = +"double VDBImplement(double fCost, double fSalvage, double fLife, double fStart" +", double fEnd, double fFactor, bool bNoSwitch);\n"; + +const char VDBImplement[] = +"double VDBImplement(double fCost, double fSalvage, double fLife, double fStart" +", double fEnd, double fFactor, bool bNoSwitch)\n" +"{\n" +" double fIntStart = floor(fStart);\n" +" double fIntEnd = ceil(fEnd);\n" +" long nLoopStart = (long)(fIntStart);\n" +" long nLoopEnd = (long)(fIntEnd);\n" +"\n" +" double fVdb = 0.0;\n" +" if (bNoSwitch)\n" +" {\n" +" for (long i = nLoopStart + 1; i <= nLoopEnd; i++)\n" +" {\n" +" double fTerm = ScGetDDB(fCost, fSalvage, fLife, i, fFactor);\n" +"\n" +" if ( i == nLoopStart+1 )\n" +" fTerm *= ( min( fEnd, fIntStart + 1.0 ) - fStart );\n" +" else if ( i == nLoopEnd )\n" +" fTerm *= ( fEnd + 1.0 - fIntEnd );\n" +"\n" +" fVdb += fTerm;\n" +" }\n" +" }\n" +" else\n" +" {\n" +" double fPart = 0.0;\n" +" if ( !approx_equal( fStart, fIntStart ) ||\n" +" !approx_equal( fEnd, fIntEnd ) )\n" +" {\n" +" if ( !approx_equal( fStart, fIntStart ) )\n" +" {\n" +" double fTempIntEnd = fIntStart + 1.0;\n" +" double fTempValue = fCost -\n" +" ScInterVDB( fCost, fSalvage, fLife, fLife, fIntStart, fFactor );\n" +" fPart += ( fStart - fIntStart ) *\n" +" ScInterVDB( fTempValue, fSalvage, fLife, fLife - fIntStart,\n" +" fTempIntEnd - fIntStart, fFactor);\n" +" }\n" +" if ( !approx_equal( fEnd, fIntEnd ) )\n" +" {\n" +" double fTempIntStart = fIntEnd - 1.0;\n" +" double fTempValue = fCost -\n" +" ScInterVDB( fCost, fSalvage, fLife, fLife, fTempIntStart, fFactor );\n" +" fPart += ( fIntEnd - fEnd ) *\n" +" ScInterVDB( fTempValue, fSalvage, fLife, fLife - fTempIntStart,\n" +" fIntEnd - fTempIntStart, fFactor);\n" +" }\n" +" }\n" +" fCost -= ScInterVDB( fCost, fSalvage, fLife, fLife, fIntStart, fFactor );\n" +" fVdb = ScInterVDB( fCost, fSalvage, fLife, fLife - fIntStart,\n" +" fIntEnd - fIntStart, fFactor);\n" +" fVdb -= fPart;\n" +" }\n" +" return fVdb;\n" +"}\n"; + +const char GetOddlpriceDecl[] = +"double GetOddlprice( int nNullDate, int nSettle, int nMat, int nLastCoup,\n" +" double fRate, double fYield, double fRedemp, int nFreq, int nBase );\n"; + +const char GetOddlprice[] = +"double GetOddlprice( int nNullDate, int nSettle, int nMat, int nLastCoup,\n" +" double fRate, double fYield, double fRedemp, int nFreq, int nBase )\n" +"{\n" +" double fFreq = nFreq ;\n" +" double fDCi = GetYearFrac( nNullDate, nLastCoup," +"nMat, nBase ) * fFreq;\n" +" double fDSCi = GetYearFrac( nNullDate, nSettle," +"nMat, nBase ) * fFreq;\n" +" double fAi = GetYearFrac( nNullDate, nLastCoup," +"nSettle, nBase ) * fFreq;\n" +" double p = fRedemp + fDCi * 100.0 * fRate / fFreq;\n" +" p /= fDSCi * fYield / fFreq + 1.0;\n" +" p -= fAi * 100.0 * fRate / fFreq;\n" +" return p;\n" +"}\n"; + +const char GetOddlyieldDecl[] = +"double GetOddlyield( int nNullDate, int nSettle, int nMat, int nLastCoup,\n" +" double fRate, double fPrice, double fRedemp, int nFreq, int nBase );\n"; + +const char GetOddlyield[] = +"double GetOddlyield( int nNullDate, int nSettle, int nMat, int nLastCoup,\n" +" double fRate, double fPrice, double fRedemp, int nFreq, int nBase ) \n" +"{\n" +" double fFreq = nFreq ;\n" +" double fDCi= GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;\n" +" double fDSCi= GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;\n" +" double fAi= GetYearFrac( nNullDate, nLastCoup, nSettle, nBase )*fFreq;\n" +" double y = fRedemp + fDCi * 100.0 * fRate / fFreq;\n" +" y /= fPrice + fAi * 100.0 * fRate / fFreq;\n" +" y -= 1.0;\n" +" y *= fFreq / fDSCi;\n" +" return y;\n" +"}\n"; + +const char GetYearFracDecl[] = +"double GetYearFrac( int nNullDate, int nStartDate, int nEndDate," +"int nMode );\n"; + +const char GetYearFrac[] = +"double GetYearFrac( int nNullDate, int nStartDate, int nEndDate," +"int nMode ) \n" +"{\n" +" if( nStartDate == nEndDate )\n" +" return 0.0; \n" +" if( nStartDate > nEndDate )\n" +" {\n" +" int n = nEndDate;\n" +" nEndDate = nStartDate;\n" +" nStartDate = n;\n" +" }\n" +" int nDate1 = nStartDate + nNullDate;\n" +" int nDate2 = nEndDate + nNullDate;\n" +" int nDay1, nDay2;\n" +" int nMonth1, nMonth2;\n" +" int nYear1, nYear2;\n" +" DaysToDate( nDate1, &nDay1, &nMonth1, &nYear1 );\n" +" DaysToDate( nDate2, &nDay2, &nMonth2, &nYear2 );\n" +" int nDayDiff;\n" +" switch( nMode )\n" +" {\n" +" case 0: \n" +" if ( nDay1 == 31 )\n" +" {\n" +" nDay1--;\n" +" }\n" +" if ( nDay1 == 30 && nDay2 == 31 )\n" +" {\n" +" nDay2--;\n" +" }\n" +" else\n" +" {\n" +" if ( nMonth1 == 2 && nDay1 == " +"( IsLeapYear( nYear1 ) ? 29 : 28 ) )\n" +" {\n" +" nDay1 = 30;\n" +" if ( nMonth2 == 2 && nDay2 == " +"( IsLeapYear( nYear2 ) ? 29 : 28 ) )\n" +" {\n" +" nDay2 = 30;\n" +" }\n" +" }\n" +" }\n" +" nDayDiff = ( nYear2 - nYear1 ) * 360 + " +"( nMonth2 - nMonth1 ) * 30 + ( nDay2 - nDay1 );\n" +" break;\n" +" case 1: \n" +" case 2: \n" +" case 3: \n" +" nDayDiff = nDate2 - nDate1;\n" +" break;\n" +" case 4: \n" +" if ( nDay1 == 31 )\n" +" {\n" +" nDay1--;\n" +" }\n" +" if ( nDay2 == 31 )\n" +" {\n" +" nDay2--;\n" +" }\n" +" nDayDiff = ( nYear2 - nYear1 ) * 360 + " +"( nMonth2 - nMonth1 ) * 30 + ( nDay2 - nDay1 );\n" +" break;\n" +" }\n" +" double nDaysInYear;\n" +" switch( nMode )\n" +" {\n" +" case 0: \n" +" case 2: \n" +" case 4: \n" +" nDaysInYear = 360;\n" +" break;\n" +" case 1: \n" +" {\n" +" bool isYearDifferent = ( nYear1 != nYear2 );\n" +" if ( isYearDifferent &&\n" +" ( ( nYear2 != nYear1 + 1 ) ||\n" +" ( nMonth1 < nMonth2 ) ||\n" +" ( nMonth1 == nMonth2 && nDay1 < nDay2 ) ) )\n" +" {\n" +" int nDayCount = 0;\n" +" for ( int i = nYear1; i <= nYear2; i++ )\n" +" nDayCount += ( IsLeapYear( i ) ? 366 : 365 );\n" +" nDaysInYear = ( double ) nDayCount / " +"( double ) ( nYear2 - nYear1 + 1 );\n" +" }\n" +" else\n" +" {\n" +" if ( isYearDifferent && IsLeapYear( nYear1 ) )\n" +" {\n" +" nDaysInYear = 366;\n" +" }\n" +" else\n" +" {\n" +" if ( ( IsLeapYear( nYear1 ) && nMonth1 <= 2 " +"&& nDay1 <= 29 ) ||\n" +" ( IsLeapYear( nYear2 ) && ( nMonth2 > 3 || " +"( nMonth2 == 2 && nDay1 == 29 ) ) ) )\n" +" {\n" +" nDaysInYear = 366;\n" +" }\n" +" else\n" +" {\n" +" nDaysInYear = 365;\n" +" for ( int i = nYear1; i <= nYear2; i++ )\n" +" {\n" +" if ( IsLeapYear( i ) )\n" +" {\n" +" nDaysInYear = 366;\n" +" break;\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }\n" +" break;\n" +" case 3: \n" +" nDaysInYear = 365;\n" +" break;\n" +" }\n" +" return (double)( nDayDiff ) / (nDaysInYear);\n" +"}\n"; + +const char DaysToDateDecl[] = +"void DaysToDate( int nDays, int *rDay, int* rMonth, int* rYear );\n"; + +const char DaysToDate[] = +"void DaysToDate( int nDays, int *rDay, int* rMonth, int* rYear )\n" +"{\n" +" int nTempDays;\n" +" int i = 0;\n" +" bool bCalc;\n" +" do\n" +" {\n" +" nTempDays = nDays;\n" +" *rYear = (int)((nTempDays / 365) - i);\n" +" nTempDays -= ((int) *rYear -1) * 365;\n" +" nTempDays -= ((*rYear -1) / 4) - ((*rYear -1) / 100) + ((*rYear -1)" +" / 400);\n" +" bCalc = false;\n" +" if ( nTempDays < 1 )\n" +" {\n" +" i++;\n" +" bCalc = true;\n" +" }\n" +" else\n" +" {\n" +" if ( nTempDays > 365 )\n" +" {\n" +" if ( (nTempDays != 366) || !IsLeapYear( *rYear ) )\n" +" {\n" +" i--;\n" +" bCalc = true;\n" +" }\n" +" }\n" +" }\n" +" }\n" +" while ( bCalc );\n" +" if(nTempDays != 0){\n" +" for (*rMonth = 1; (int)nTempDays > DaysInMonth( *rMonth, *rYear );" +" *rMonth += 1)\n" +" {\n" +" nTempDays -= DaysInMonth( *rMonth, *rYear ); \n" +" }\n" +" *rDay = (int)nTempDays;\n" +" }\n" +"}\n"; + +const char DaysToDate_LocalBarrierDecl[] = +"void DaysToDate( int nDays, int *rDay, int* rMonth, int* rYear );\n"; + +const char DaysToDate_LocalBarrier[] = +"void DaysToDate( int nDays, int *rDay, int* rMonth, int* rYear )\n" +"{\n" +" int nTempDays;\n" +" int i = 0;\n" +" bool bCalc;\n" +" do\n" +" {\n" +" nTempDays = nDays;\n" +" *rYear = (int)((nTempDays / 365) - i);\n" +" nTempDays -= ((int) *rYear -1) * 365;\n" +" nTempDays -= ((*rYear -1) / 4) - ((*rYear -1) / 100) + ((*rYear -1)" +" / 400);\n" +" bCalc = false;\n" +" if ( nTempDays < 1 )\n" +" {\n" +" i++;\n" +" bCalc = true;\n" +" }\n" +" else\n" +" {\n" +" if ( nTempDays > 365 )\n" +" {\n" +" if ( (nTempDays != 366) || !IsLeapYear( *rYear ) )\n" +" {\n" +" i--;\n" +" bCalc = true;\n" +" }\n" +" }\n" +" }\n" +" }\n" +" while ( bCalc );\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" if(nTempDays != 0){\n" +" for (*rMonth = 1; (int)nTempDays > DaysInMonth( *rMonth, *rYear );" +" *rMonth += 1)\n" +" {\n" +" nTempDays -= DaysInMonth( *rMonth, *rYear ); \n" +" }\n" +" *rDay = (int)nTempDays;\n" +" }\n" +"}\n"; + +const char GetYearDiffDecl[] = +"double GetYearDiff( int nNullDate, int nStartDate, int nEndDate," +"int nMode);\n"; + +const char GetYearDiff[] = +"double GetYearDiff( int nNullDate, int nStartDate, int nEndDate," +"int nMode )\n" +"{\n" +" int nDays1stYear;\n" +" int nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate," +"nMode, &" +"nDays1stYear );\n" +" return (double)(nTotalDays) / (double)nDays1stYear;\n" +"}\n"; + +const char GetDiffDateDecl[] = +"int GetDiffDate( int nNullDate, int nStartDate, int nEndDate, int nMode," +" int* pOptDaysIn1stYear );\n"; + +const char GetDiffDate[] = +"int GetDiffDate( int nNullDate, int nStartDate, int nEndDate, int nMode," +" int* pOptDaysIn1stYear )\n" +"{\n" +" bool bNeg = nStartDate > nEndDate;\n" +" if( bNeg )\n" +" {\n" +" int n = nEndDate;\n" +" nEndDate = nStartDate;\n" +" nStartDate = n;\n" +" }\n" +" int nRet;\n" +" switch( nMode )\n" +" {\n" +" case 0: \n" +" case 4: \n" +" {\n" +" int nD1, nM1, nY1, nD2, nM2, nY2;\n" +" nStartDate += nNullDate;\n" +" nEndDate += nNullDate;\n" +" DaysToDate( nStartDate, &nD1, &nM1, &nY1 );\n" +" DaysToDate( nEndDate, &nD2, &nM2, &nY2 );\n" +" bool bLeap = IsLeapYear( nY1 );\n" +" int nDays, nMonths;\n" +" nMonths = nM2 - nM1;\n" +" nDays = nD2 - nD1;\n" +" nMonths += ( nY2 - nY1 ) * 12;\n" +" nRet = nMonths * 30 + nDays;\n" +" if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )\n" +" nRet -= bLeap? 1 : 2;\n" +" if( pOptDaysIn1stYear )\n" +" *pOptDaysIn1stYear = 360;\n" +" }\n" +" break;\n" +" case 1: \n" +" if( pOptDaysIn1stYear )\n" +" {\n" +" int nD, nM, nY;\n" +" DaysToDate( nStartDate + nNullDate, &nD, &nM, &nY );\n" +" *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;\n" +" }\n" +" nRet = nEndDate - nStartDate;\n" +" break;\n" +" case 2: \n" +" nRet = nEndDate - nStartDate;\n" +" if( pOptDaysIn1stYear )\n" +" *pOptDaysIn1stYear = 360;\n" +" break;\n" +" case 3: \n" +" nRet = nEndDate - nStartDate;\n" +" if( pOptDaysIn1stYear )\n" +" *pOptDaysIn1stYear = 365;\n" +" break;\n" +" }\n" +" return bNeg? -nRet : nRet;\n" +"}\n"; + +const char RateIterationDecl[] = +"bool RateIteration( double fNper, double fPayment, double fPv," +" double fFv, bool bPayType, double* fGuess );\n"; + +const char RateIteration[] = +"bool RateIteration( double fNper, double fPayment, double fPv," +" double fFv, bool bPayType, double* fGuess )\n" +"{\n" +"#define SCdEpsilon 1.0E-7\n" +" bool bValid = true, bFound = false;\n" +" double fX, fXnew, fTerm, fTermDerivation;\n" +" double fGeoSeries, fGeoSeriesDerivation;\n" +" const int nIterationsMax = 150;\n" +" int nCount = 0;\n" +" const double fEpsilonSmall = 1.0E-14;\n" +" if ( bPayType )\n" +" {\n" +" fFv = fFv - fPayment;\n" +" fPv = fPv + fPayment;\n" +" }\n" +" if (fNper == round( fNper ))\n" +" {\n" +" fX = *fGuess;\n" +" while (!bFound && nCount < nIterationsMax)\n" +" {\n" +" double fPowN, fPowNminus1;\n" +" fPowNminus1 = pow( 1.0+fX, fNper-1.0);\n" +" fPowN = fPowNminus1 * (1.0+fX);\n" +" if (fX == 0.0)\n" +" {\n" +" fGeoSeries = fNper;\n" +" fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;\n" +" }\n" +" else\n" +" {\n" +" fGeoSeries = (fPowN-1.0)/fX;\n" +" fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;\n" +" }\n" +" fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;\n" +" fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;\n" +" if (fabs(fTerm) < fEpsilonSmall)\n" +" bFound = true;\n" +" else\n" +" {\n" +" if (fTermDerivation == 0.0)\n" +" fXnew = fX + 1.1 * SCdEpsilon;\n" +" else\n" +" fXnew = fX - fTerm / fTermDerivation;\n" +" nCount++;\n" +" bFound = (fabs(fXnew - fX) < SCdEpsilon);\n" +" fX = fXnew;\n" +" }\n" +" }\n" +" bValid = (fX > -1.0);\n" +" }\n" +" else\n" +" {\n" +" fX = (*fGuess < -1.0) ? -1.0 : *fGuess;\n" +" while (bValid && !bFound && nCount < nIterationsMax)\n" +" {\n" +" if (fX == 0.0)\n" +" {\n" +" fGeoSeries = fNper;\n" +" fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;\n" +" }\n" +" else\n" +" {\n" +" fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;\n" +" fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;\n" +" }\n" +" fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;\n" +" fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;\n" +" if (fabs(fTerm) < fEpsilonSmall)\n" +" bFound = true;\n" +" else\n" +" {\n" +" if (fTermDerivation == 0.0)\n" +" fXnew = fX + 1.1 * SCdEpsilon;\n" +" else\n" +" fXnew = fX - fTerm / fTermDerivation;\n" +" nCount++;\n" +" bFound = (fabs(fXnew - fX) < SCdEpsilon);\n" +" fX = fXnew;\n" +" bValid = (fX >= -1.0);\n" +" }\n" +" }\n" +" }\n" +" *fGuess = fX;\n" +" return bValid && bFound;\n" +"}\n"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_logical.cxx b/sc/source/core/opencl/op_logical.cxx new file mode 100644 index 0000000000..3a3869d591 --- /dev/null +++ b/sc/source/core/opencl/op_logical.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_logical.hxx" + +#include <formula/vectortoken.hxx> +#include <sstream> + +using namespace formula; + +namespace sc::opencl { + +void OpLogicalBinaryOperator::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " bool t = false;\n"; + for(size_t j = 0; j< vSubArguments.size(); j++) + { + GenerateArg( j, vSubArguments, ss ); + ss << " t = t " << openclOperator() << " (arg" << j << " != 0);\n"; + } + ss << " return t;\n"; + ss << "}\n"; +} + +void OpAnd::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " bool t = true;\n"; + for(size_t j = 0; j< vSubArguments.size(); j++) + { + GenerateArg( j, vSubArguments, ss, EmptyIsNan ); + // AND() with a svSingleVectorRef pointing to an empty cell skips that cell. + // See ScInterpreter::ScAnd(). + ss << " if( !isnan( arg" << j << " ))\n"; + ss << " t = t " << openclOperator() << " (arg" << j << " != 0);\n"; + } + ss << " return t;\n"; + ss << "}\n"; +} + +void OpNot::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + ss << " return arg0 == 0;\n"; + ss << "}\n"; +} + +void OpIf::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + if(vSubArguments.size()>1) + GenerateArg( 1, vSubArguments, ss ); + else + ss << " double arg1 = 1;\n"; + if(vSubArguments.size()>2) + GenerateArg( 2, vSubArguments, ss ); + else + ss << " double arg2 = 0;\n"; + + ss << " if(arg0 != 0)\n"; + ss << " return arg1;\n"; + ss << " else\n"; + ss << " return arg2;\n"; + ss << "}\n"; +} + +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_logical.hxx b/sc/source/core/opencl/op_logical.hxx new file mode 100644 index 0000000000..15659a0625 --- /dev/null +++ b/sc/source/core/opencl/op_logical.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +/// Implements OpAnd, OpOr, OpXor. +class OpLogicalBinaryOperator : public Normal +{ + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual bool canHandleMultiVector() const override { return true; } + /// The C operator implementing the function. + virtual const char* openclOperator() const = 0; +}; + +class OpAnd: public OpLogicalBinaryOperator +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "And"; } + virtual const char* openclOperator() const override { return "&&"; }; +}; + +class OpOr: public OpLogicalBinaryOperator +{ +public: + virtual std::string BinFuncName() const override { return "Or"; } + virtual const char* openclOperator() const override { return "||"; }; +}; + +class OpNot: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Not"; } +}; + +class OpXor: public OpLogicalBinaryOperator +{ +public: + virtual std::string BinFuncName() const override { return "Xor"; } + virtual const char* openclOperator() const override { return "^"; }; +}; + +class OpIf:public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "IF"; } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_math.cxx b/sc/source/core/opencl/op_math.cxx new file mode 100644 index 0000000000..d0e033f884 --- /dev/null +++ b/sc/source/core/opencl/op_math.cxx @@ -0,0 +1,1657 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_math.hxx" + +#include <formula/vectortoken.hxx> +#include "op_math_helpers.hxx" +#include <sstream> + +using namespace formula; + +namespace sc::opencl { + +void OpMathOneArgument::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateCode( ss ); + ss << "}"; +} + +void OpMathTwoArguments::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateCode( ss ); + ss << "}"; +} + +void OpCos::GenerateCode( outputstream& ss ) const +{ + ss << " return cos(arg0);\n"; +} + +void OpSec::GenerateCode( outputstream& ss ) const +{ + ss << " return 1.0 / cos(arg0);\n"; +} + +void OpSecH::GenerateCode( outputstream& ss ) const +{ + ss << " return 1.0 / cosh(arg0);\n"; +} + +void OpCosh::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(local_coshDecl); + funs.insert(local_cosh); +} + +void OpCosh::GenerateCode( outputstream& ss ) const +{ + ss << " return local_cosh(arg0);\n"; +} + +void OpCot::GenerateCode( outputstream& ss ) const +{ + ss << " arg0 = arg0 * M_1_PI;\n"; + ss << " return cospi(arg0) / sinpi(arg0);\n"; +} + +void OpCoth::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(local_cothDecl); + funs.insert(local_coth); +} + +void OpCoth::GenerateCode( outputstream& ss ) const +{ + ss << " return local_coth(arg0);\n"; +} + +void OpEven::GenerateCode( outputstream& ss ) const +{ + ss << " double tmp = fabs(arg0 / 2);\n"; + ss << " if ( trunc(tmp) == tmp )\n"; + ss << " tmp = tmp * 2;\n"; + ss << " else\n"; + ss << " tmp = (trunc(tmp) + 1) * 2;\n"; + ss << " if (arg0 < 0)\n"; + ss << " tmp = tmp * -1.0;\n"; + ss << " return tmp;\n"; +} + +void OpCsc::GenerateCode( outputstream& ss ) const +{ + ss << " return 1/sin(arg0);\n"; +} + +void OpCscH::GenerateCode( outputstream& ss ) const +{ + ss << " return 1/sinh(arg0);\n"; +} + +void OpExp::GenerateCode( outputstream& ss ) const +{ + ss << " return pow(M_E, arg0);\n"; +} + +void OpLog10::GenerateCode( outputstream& ss ) const +{ + ss << " return log10(arg0);\n"; +} + +void OpSinh::GenerateCode( outputstream& ss ) const +{ + ss << " return ( exp(arg0)-exp(-arg0) )/2;\n"; +} + +void OpSin::GenerateCode( outputstream& ss ) const +{ + ss << " arg0 = arg0 * M_1_PI;\n"; + ss << " return sinpi(arg0);\n"; +} + +void OpAbs::GenerateCode( outputstream& ss ) const +{ + ss << " return fabs(arg0);\n"; +} + +void OpArcCos::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(atan2Decl); + funs.insert(atan2Content); +} + +void OpArcCos::GenerateCode( outputstream& ss ) const +{ + ss << " return arctan2(sqrt(1.0 - pow(arg0, 2)), arg0);\n"; +} + +void OpArcCosHyp::GenerateCode( outputstream& ss ) const +{ + ss << " if( arg0 < 1 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return log( arg0 + pow( (pown(arg0, 2) - 1.0), 0.5));\n"; +} + +void OpTan::GenerateCode( outputstream& ss ) const +{ + ss << " arg0 = arg0 * M_1_PI;\n"; + ss << " return sinpi(arg0) / cospi(arg0);\n"; +} + +void OpTanH::GenerateCode( outputstream& ss ) const +{ + ss << " return tanh(arg0);\n"; +} + +void OpSqrt::GenerateCode( outputstream& ss ) const +{ + ss << " if( arg0 < 0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return sqrt(arg0);\n"; +} + +void OpArcCot::GenerateCode( outputstream& ss ) const +{ + ss << " return M_PI_2 - atan(arg0);\n"; +} + +void OpArcCotHyp::GenerateCode( outputstream& ss ) const +{ + ss << " return 0.5 * log(1 + 2 / (arg0 - 1.0));\n"; +} + +void OpArcSin::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(atan2Decl); + funs.insert(atan2Content); +} + +void OpArcSin::GenerateCode( outputstream& ss ) const +{ + ss << " return arctan2(arg0, sqrt(1.0 - pow(arg0, 2)));\n"; +} + +void OpArcSinHyp::GenerateCode( outputstream& ss ) const +{ + ss << " return log( arg0 + pow((pown(arg0, 2) + 1.0), 0.5));\n"; +} + +void OpArcTan::GenerateCode( outputstream& ss ) const +{ + ss << " return atan(arg0);\n"; +} + +void OpArcTanH::GenerateCode( outputstream& ss ) const +{ + ss << " double a = 1.0 + arg0;\n"; + ss << " double b = 1.0 - arg0;\n"; + ss << " return log(pow(a/b, 0.5));\n"; +} + +void OpLn::GenerateCode( outputstream& ss ) const +{ + ss << " return log1p(arg0-1);\n"; +} + +void OpInt::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(value_approxDecl); + funs.insert(value_approx); +} + +void OpInt::GenerateCode( outputstream& ss ) const +{ + ss << " return floor( value_approx( arg0 ));\n"; +} + +void OpNegSub::GenerateCode( outputstream& ss ) const +{ + ss << " return -arg0;\n"; +} + +void OpRadians::GenerateCode( outputstream& ss ) const +{ + ss << " return arg0 * M_PI / 180.0;\n"; +} + +void OpIsEven::GenerateCode( outputstream& ss ) const +{ + ss << " return (fmod(floor(fabs(arg0)), 2.0)<0.5);\n"; +} + +void OpIsOdd::GenerateCode( outputstream& ss ) const +{ + ss << " return !(fmod(floor(fabs(arg0)), 2.0)<0.5);\n"; +} + +void OpSqrtPi::GenerateCode( outputstream& ss ) const +{ + ss << " return (double)sqrt(arg0 * M_PI);\n"; +} + +void OpDeg::GenerateCode( outputstream& ss ) const +{ + ss << " return arg0 / M_PI * 180;;\n"; +} + +void OpFact::GenerateCode( outputstream& ss ) const +{ + ss << " arg0 = floor(arg0);\n"; + ss << " if (arg0 < 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else if (arg0 == 0.0)\n"; + ss << " return 1.0;\n"; + ss << " else if (arg0 <= 170.0)\n"; + ss << " {\n"; + ss << " double fTemp = arg0;\n"; + ss << " while (fTemp > 2.0)\n"; + ss << " {\n"; + ss << " fTemp = fTemp - 1;\n"; + ss << " arg0 = arg0 * fTemp;\n"; + ss << " }\n"; + ss << " }\n"; + ss << " else\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " return arg0;\n"; +} + +void OpOdd::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(Math_IntgDecl); + funs.insert(Math_Intg); +} + +void OpOdd::GenerateCode( outputstream& ss ) const +{ + ss << " double tmp;\n"; + ss << " if (arg0 > 0.0 ){\n"; + ss << " tmp=Intg(arg0);\n"; + ss << " if(tmp-trunc(tmp/2)*2 == 0)\n"; + ss << " tmp=tmp+1;\n"; + ss << " }else if (arg0 < 0.0 ){\n"; + ss << " tmp=Intg(arg0);\n"; + ss << " if(tmp-trunc(tmp/2)*2 == 0)\n"; + ss << " tmp=tmp-1.0;\n"; + ss << " }else\n"; + ss << " tmp=1.0;\n"; + ss << " return tmp;\n"; +} + +void OpMROUND::GenerateCode( outputstream& ss ) const +{ + ss<<" if(arg1==0)\n"; + ss<<" return arg1;\n"; + ss<<" tmp=arg1 * round(arg0 / arg1);\n"; + ss<<" return tmp;\n"; +} + +void OpCombinA::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(bikDecl); + funs.insert(bik); +} + +void OpCombinA::GenerateCode( outputstream& ss ) const +{ + ss << " arg0 = trunc(arg0);\n"; + ss << " arg1 = trunc(arg1);\n"; + ss << " if (arg0 < 0.0 || arg1 < 0.0 || arg1 > arg0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double tem;\n"; + ss << " if(arg0 >= arg1 && arg0 > 0 && arg1 > 0)\n"; + ss << " tem = bik(arg0+arg1-1,arg1);\n"; + ss << " else if(arg0 == 0 && arg1 == 0)\n"; + ss << " tem = 0;\n"; + ss << " else if(arg0 > 0 && arg1 == 0)\n"; + ss << " tem = 1;\n"; + ss << " else\n"; + ss << " tem = -1;\n"; + ss << " double i = tem - trunc(tem);\n"; + ss << " if(i < 0.5)\n"; + ss << " tem = trunc(tem);\n"; + ss << " else\n"; + ss << " tem = trunc(tem) + 1;\n"; + ss << " return tem;\n"; +} + +void OpCombin::GenerateCode( outputstream& ss ) const +{ + ss << " double result = -1.0;\n"; + ss << " double num = floor( arg0 );\n"; + ss << " double num_chosen = floor( arg1 );\n"; + ss << " if(num < 0 || num_chosen < 0 || num < num_chosen )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " result = select(result, 0.0, (ulong)(num < num_chosen));\n"; + ss << " result = select(result, 1.0, (ulong)(num_chosen == 0.0));\n"; + ss << " if(result == 0 || result ==1)\n"; + ss << " return result;\n"; + ss << " double4 db4num;\n"; + ss << " double4 db4num_chosen;\n"; + ss << " double4 db4result;\n"; + ss << " double2 db2result;\n"; + ss << " result = 1.0;\n"; + ss << " int loop = num_chosen/4;\n"; + ss << " for(int i=0; i<loop; i++)\n"; + ss << " {\n"; + ss << " db4num = (double4){num,\n"; + ss << " num-1.0,\n"; + ss << " num-2.0,\n"; + ss << " num-3.0};\n"; + ss << " db4num_chosen = (double4){num_chosen,\n"; + ss << " num_chosen-1.0,\n"; + ss << " num_chosen-2.0,\n"; + ss << " num_chosen-3.0};\n"; + ss << " db4result = db4num / db4num_chosen;\n"; + ss << " db2result = db4result.xy * db4result.zw;\n"; + ss << " result *= db2result.x * db2result.y;\n"; + ss << " num = num - 4.0;\n"; + ss << " num_chosen = num_chosen - 4.0;\n"; + ss << " }\n"; + ss << " while ( num_chosen > 0){\n"; + ss << " result *= num / num_chosen;\n"; + ss << " num = num - 1.0;\n"; + ss << " num_chosen = num_chosen - 1.0;\n"; + ss << " }\n"; + ss << " return result;\n"; +} + +void OpMod::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); + decls.insert(fsub_approxDecl); + funs.insert(fsub_approx); + decls.insert(value_approxDecl); + funs.insert(value_approx); +} + +void OpMod::GenerateCode( outputstream& ss ) const +{ + ss << " double fNum = arg0;\n"; + ss << " double fDenom = arg1;\n"; + ss << " if(fDenom == 0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " double fRes = fsub_approx( fNum, floor( value_approx( fNum / fDenom )) * fDenom );\n"; + ss << " if ( ( fDenom > 0 && fRes >= 0 && fRes < fDenom ) ||\n"; + ss << " ( fDenom < 0 && fRes <= 0 && fRes > fDenom ) )\n"; + ss << " return fRes;\n"; + ss << " return CreateDoubleError(NoValue);\n"; +} + +void OpPower::GenerateCode( outputstream& ss ) const +{ + ss << " return pow(arg0,arg1);\n"; +} + +void OpArcTan2::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(atan2Decl); + funs.insert(atan2Content); +} + +void OpArcTan2::GenerateCode( outputstream& ss ) const +{ + ss << " return arctan2(arg1, arg0);\n"; +} + +void OpBitAnd::GenerateCode( outputstream& ss ) const +{ + ss << " if( arg0 < 0 || arg1 < 0 || arg0 >= 281474976710656.0 || arg1 >= 281474976710656.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return (long)arg0 & (long)arg1;\n"; +} + +void OpBitOr::GenerateCode( outputstream& ss ) const +{ + ss << " if( arg0 < 0 || arg1 < 0 || arg0 >= 281474976710656.0 || arg1 >= 281474976710656.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return (long)arg0 | (long)arg1;\n"; +} + +void OpBitXor::GenerateCode( outputstream& ss ) const +{ + ss << " if( arg0 < 0 || arg1 < 0 || arg0 >= 281474976710656.0 || arg1 >= 281474976710656.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return (long)arg0 ^ (long)arg1;\n"; +} + +void OpBitLshift::GenerateCode( outputstream& ss ) const +{ + ss << " double num = floor( arg0 );\n"; + ss << " double shift_amount = floor( arg1 );\n"; + ss << " if( num < 0 || num >= 281474976710656.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return floor(shift_amount >= 0 ? "; + ss << "num * pow(2.0, shift_amount) : "; + ss << "num / pow(2.0, fabs(shift_amount)));\n"; +} + +void OpBitRshift::GenerateCode( outputstream& ss ) const +{ + ss << " double num = floor( arg0 );\n"; + ss << " double shift_amount = floor( arg1 );\n"; + ss << " if( num < 0 || num >= 281474976710656.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return floor("; + ss << "shift_amount >= 0 ? num / pow(2.0, shift_amount) : "; + ss << "num * pow(2.0, fabs(shift_amount)));\n"; +} + +void OpQuotient::GenerateCode( outputstream& ss ) const +{ + ss << " return trunc(arg0/arg1);\n"; +} + +void OpEqual::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); + decls.insert(cell_equalDecl); + funs.insert(cell_equal); +} + +void OpEqual::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss, EmptyIsNan, GenerateArgType ); + GenerateArg( 1, vSubArguments, ss, EmptyIsNan, GenerateArgType ); + ss << " return cell_equal( arg0, arg1, arg0_is_string, arg1_is_string );\n"; + ss << "}"; +} + +void OpNotEqual::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); + decls.insert(cell_equalDecl); + funs.insert(cell_equal); +} + +void OpNotEqual::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss, EmptyIsNan, GenerateArgType ); + GenerateArg( 1, vSubArguments, ss, EmptyIsNan, GenerateArgType ); + ss << " return !cell_equal( arg0, arg1, arg0_is_string, arg1_is_string );\n"; + ss << "}"; +} + +void OpLessEqual::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); +} + +void OpLessEqual::GenerateCode( outputstream& ss ) const +{ + ss << " return approx_equal( arg0, arg1 ) || arg0 <= arg1;\n"; +} + +void OpLess::GenerateCode( outputstream& ss ) const +{ + ss << " return arg0 < arg1;\n"; +} + +void OpGreaterEqual::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); +} + +void OpGreaterEqual::GenerateCode( outputstream& ss ) const +{ + ss << " return approx_equal( arg0, arg1 ) || arg0 >= arg1;\n"; +} + +void OpGreater::GenerateCode( outputstream& ss ) const +{ + ss << " return arg0 > arg1;\n"; +} + +void OpLog::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "arg0", 0, vSubArguments, ss ); + GenerateArgWithDefault( "arg1", 1, 10, vSubArguments, ss ); + ss << " return log10(arg0)/log10(arg1);;\n"; + ss << "}"; +} + +void OpCountIfs::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + FormulaToken *tmpCur = vSubArguments[0]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur); + size_t nCurWindowSize = pCurDVR->GetArrayLength() < + pCurDVR->GetRefRowSize() ? pCurDVR->GetArrayLength(): + pCurDVR->GetRefRowSize() ; + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + ss << " int tmp =0;\n"; + ss << " int loop;\n"; + GenTmpVariables(ss,vSubArguments); + + ss<< " int singleIndex =gid0;\n"; + int m=0; + + outputstream tmpss; + + for(size_t j=0;j<vSubArguments.size();j+=2,m++) + { + CheckSubArgumentIsNan(tmpss,vSubArguments,j); + CheckSubArgumentIsNan(ss,vSubArguments,j+1); + tmpss <<" if(isequal("; + tmpss <<"tmp"; + tmpss <<j; + tmpss <<" , "; + tmpss << "tmp"; + tmpss << j+1; + tmpss << ")){\n"; + } + tmpss << " tmp ++;\n"; + for(size_t j=0;j<vSubArguments.size();j+=2,m--) + { + for(int n = 0;n<m+1;n++) + { + tmpss << " "; + } + tmpss<< "}\n"; + } + UnrollDoubleVector(ss,tmpss,pCurDVR,nCurWindowSize); + + ss << "return tmp;\n"; + ss << "}"; +} + +void OpSumIfs::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + FormulaToken *tmpCur = vSubArguments[0]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur); + size_t nCurWindowSize = pCurDVR->GetArrayLength() < + pCurDVR->GetRefRowSize() ? pCurDVR->GetArrayLength(): + pCurDVR->GetRefRowSize() ; + + mNeedReductionKernel = vSubArguments[0]->NeedParallelReduction(); + if (mNeedReductionKernel) + { + // generate reduction functions + + ss << "__kernel void "; + ss << vSubArguments[0]->GetName(); + ss << "_SumIfs_reduction( "; + for (size_t i = 0; i < vSubArguments.size(); i++) + { + if (i) + ss << ","; + vSubArguments[i]->GenSlidingWindowDecl(ss); + } + ss << ", __global double *result,int arrayLength,int windowSize"; + + ss << ")\n{\n"; + ss << " double tmp =0;\n"; + ss << " int i ;\n"; + + GenTmpVariables(ss,vSubArguments); + ss << " double current_result = 0.0;\n"; + ss << " int writePos = get_group_id(1);\n"; + if (pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) + ss << " int offset = 0;\n"; + else if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + ss << " int offset = get_group_id(1);\n"; + else + throw Unhandled(__FILE__, __LINE__); + // actually unreachable + ss << " int lidx = get_local_id(0);\n"; + ss << " __local double shm_buf[256];\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " int loop = arrayLength/512 + 1;\n"; + ss << " for (int l=0; l<loop; l++){\n"; + ss << " tmp = 0.0;\n"; + ss << " int loopOffset = l*512;\n"; + + ss << " int p1 = loopOffset + lidx + offset, p2 = p1 + 256;\n"; + ss << " if (p2 < min(offset + windowSize, arrayLength)) {\n"; + ss << " tmp0 = 0.0;\n"; + int mm=0; + std::string p1 = "p1"; + std::string p2 = "p2"; + for(size_t j=1;j<vSubArguments.size();j+=2,mm++) + { + CheckSubArgumentIsNan2(ss,vSubArguments,j,p1); + CheckSubArgumentIsNan2(ss,vSubArguments,j+1,p1); + ss << ""; + ss <<" if(isequal("; + ss <<"tmp"; + ss <<j; + ss <<" , "; + ss << "tmp"; + ss << j+1; + ss << "))"; + ss << "{\n"; + } + CheckSubArgumentIsNan2(ss,vSubArguments,0,p1); + ss << " tmp += tmp0;\n"; + for(size_t j=1;j<vSubArguments.size();j+=2,mm--) + { + for(int n = 0;n<mm+1;n++) + { + ss << " "; + } + ss<< "}\n\n"; + } + mm=0; + for(size_t j=1;j<vSubArguments.size();j+=2,mm++) + { + CheckSubArgumentIsNan2(ss,vSubArguments,j,p2); + CheckSubArgumentIsNan2(ss,vSubArguments,j+1,p2); + ss <<" if(isequal("; + ss <<"tmp"; + ss <<j; + ss <<" , "; + ss << "tmp"; + ss << j+1; + ss << ")){\n"; + } + CheckSubArgumentIsNan2(ss,vSubArguments,0,p2); + ss << " tmp += tmp0;\n"; + for(size_t j=1;j< vSubArguments.size();j+=2,mm--) + { + for(int n = 0;n<mm+1;n++) + { + ss << " "; + } + ss<< "}\n"; + } + ss << " }\n"; + + ss << " else if (p1 < min(arrayLength, offset + windowSize)) {\n"; + mm=0; + for(size_t j=1;j<vSubArguments.size();j+=2,mm++) + { + CheckSubArgumentIsNan2(ss,vSubArguments,j,p1); + CheckSubArgumentIsNan2(ss,vSubArguments,j+1,p1); + + ss <<" if(isequal("; + ss <<"tmp"; + ss <<j; + ss <<" , "; + ss << "tmp"; + ss << j+1; + ss << ")){\n"; + } + CheckSubArgumentIsNan2(ss,vSubArguments,0,p1); + ss << " tmp += tmp0;\n"; + for(size_t j=1;j<vSubArguments.size();j+=2,mm--) + { + for(int n = 0;n<mm+1;n++) + { + ss << " "; + } + ss<< "}\n\n"; + } + + ss << " }\n"; + ss << " shm_buf[lidx] = tmp;\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " for (int i = 128; i >0; i/=2) {\n"; + ss << " if (lidx < i)\n"; + ss << " shm_buf[lidx] += shm_buf[lidx + i];\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + ss << " if (lidx == 0)\n"; + ss << " current_result += shm_buf[0];\n"; + ss << " barrier(CLK_LOCAL_MEM_FENCE);\n"; + ss << " }\n"; + + ss << " if (lidx == 0)\n"; + ss << " result[writePos] = current_result;\n"; + ss << "}\n"; + }// finish generate reduction code + // generate functions as usual + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + ss << " double tmp =0;\n"; + if (!mNeedReductionKernel) + { + ss << " int i ;\n"; + GenTmpVariables(ss,vSubArguments); + ss << " for (i = "; + if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) { + ss << "gid0; i < "<< nCurWindowSize <<"; i++)\n"; + } else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) { + ss << "0; i < gid0+"<< nCurWindowSize <<"; i++)\n"; + } else { + ss << "0; i < "<< nCurWindowSize <<"; i++)\n"; + } + ss << " {\n"; + if(!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss<< " int doubleIndex =i+gid0;\n"; + }else + { + ss<< " int doubleIndex =i;\n"; + } + ss<< " int singleIndex =gid0;\n"; + int m=0; + for(size_t j=1;j<vSubArguments.size();j+=2,m++) + { + CheckSubArgumentIsNan(ss,vSubArguments,j); + CheckSubArgumentIsNan(ss,vSubArguments,j+1); + ss <<" if(isequal("; + ss <<"tmp"; + ss <<j; + ss <<" , "; + ss << "tmp"; + ss << j+1; + ss << ")){\n"; + } + CheckSubArgumentIsNan(ss,vSubArguments,0); + ss << " tmp += tmp0;\n"; + for(size_t j=1;j<=vSubArguments.size();j+=2,m--) + { + for(int n = 0;n<m+1;n++) + { + ss << " "; + } + ss<< "}\n"; + } + } + if (mNeedReductionKernel) + { + ss << "tmp ="; + vSubArguments[0]->GenDeclRef(ss); + ss << "[gid0];\n"; + } + ss << "return tmp;\n"; + ss << "}"; +} + +void OpAverageIfs::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + FormulaToken *tmpCur = vSubArguments[0]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur); + size_t nCurWindowSize = pCurDVR->GetArrayLength() < + pCurDVR->GetRefRowSize() ? pCurDVR->GetArrayLength(): + pCurDVR->GetRefRowSize() ; + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + ss << " double tmp =0;\n"; + ss << " int count=0;\n"; + ss << " int loop;"; + GenTmpVariables(ss,vSubArguments); + ss<< " int singleIndex =gid0;\n"; + int m=0; + outputstream tmpss; + for(size_t j=1;j<vSubArguments.size();j+=2,m++) + { + CheckSubArgumentIsNan(tmpss,vSubArguments,j); + CheckSubArgumentIsNan(ss,vSubArguments,j+1); + tmpss <<" if(isequal("; + tmpss <<"tmp"; + tmpss <<j; + tmpss <<" , "; + tmpss << "tmp"; + tmpss << j+1; + tmpss << ")){\n"; + } + CheckSubArgumentIsNan(tmpss,vSubArguments,0); + tmpss << " tmp += tmp0;\n"; + tmpss << " count++;\n"; + for(size_t j=1;j<vSubArguments.size();j+=2,m--) + { + for(int n = 0;n<m+1;n++) + { + tmpss << " "; + } + tmpss<< "}\n"; + } + + UnrollDoubleVector(ss,tmpss,pCurDVR,nCurWindowSize); + + ss << " if(count!=0)\n"; + ss << " tmp=tmp/count;\n"; + ss << " else\n"; + ss << " tmp= 0 ;\n"; + ss << "return tmp;\n"; + ss << "}"; +} + +void OpRound::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(nCorrValDecl); + decls.insert(RoundDecl); + funs.insert(Round); +} + +void OpRound::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "value", 0, vSubArguments, ss ); + if(vSubArguments.size() ==1) + ss << " return round(value);\n"; + else + { + GenerateArg( "fDec", 1, vSubArguments, ss ); + ss << " int dec = floor( fDec );\n"; + ss << " if( dec < -20 || dec > 20 )\n"; + ss << " return CreateDoubleError( IllegalArgument );\n"; + ss << " if( dec == 0 )\n"; + ss << " return round(value);\n"; + ss << " double orig_value = value;\n"; + ss << " value = fabs(value);\n"; + ss << " double multiply = pown(10.0, dec);\n"; + ss << " double tmp = value*multiply;\n"; + ss << " tmp = Round( tmp );\n"; + ss << " return copysign(tmp/multiply, orig_value);\n"; + } + ss << "}"; +} + +void OpRoundUp::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "value", 0, vSubArguments, ss ); + GenerateArgWithDefault( "fDec", 1, 0, vSubArguments, ss ); + ss << " int dec = floor( fDec );\n"; + ss << " if( dec < -20 || dec > 20 )\n"; + ss << " return CreateDoubleError( IllegalArgument );\n"; + ss << " double orig_value = value;\n"; + ss << " value = fabs(value);\n"; + ss << " double multiply = pown(10.0, dec);\n"; + ss << " double tmp = value*multiply;\n"; + ss << " double integral;\n"; + // The pown() above increases rounding error, so compensate for it here. + // If the fractional part is close above zero, adjusted for rounding error, + // the number just needs to be rounded (=truncated). + ss << " if( modf( tmp, &integral ) / multiply < 1e-12 )\n"; + ss << " tmp = integral;\n"; + ss << " else\n"; + ss << " tmp = integral + 1;\n"; + ss << " return copysign(tmp/multiply, orig_value);\n"; + ss << "}"; +} + +void OpRoundDown::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "value", 0, vSubArguments, ss ); + GenerateArgWithDefault( "fDec", 1, 0, vSubArguments, ss ); + ss << " int dec = floor( fDec );\n"; + ss << " if( dec < -20 || dec > 20 )\n"; + ss << " return CreateDoubleError( IllegalArgument );\n"; + ss << " double orig_value = value;\n"; + ss << " value = fabs(value);\n"; + ss << " double multiply = pown(10.0, dec);\n"; + ss << " double tmp = value*multiply;\n"; + ss << " double integral;\n"; + // The pown() above increases rounding error, so compensate for it here. + // If the fractional part is close below one, adjusted for rounding error, + // the number just needs to be rounded (=truncated + 1). + ss << " if(( 1 - modf( tmp, &integral )) / multiply < 1e-12 )\n"; + ss << " tmp = integral + 1;\n"; + ss << " else\n"; + ss << " tmp = integral;\n"; + ss << " return copysign(tmp/multiply, orig_value);\n"; + ss << "}"; +} + +void OpCountIf::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double vara, varb;\n"; + ss << " int varc = 0;\n"; + FormulaToken *tmpCur = vSubArguments[1]->GetFormulaToken(); + assert(tmpCur); + if(ocPush == vSubArguments[1]->GetFormulaToken()->GetOpCode()) + { + if(tmpCur->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* tmpCurDVR= + static_cast< + const formula::SingleVectorRefToken *>(tmpCur); + ss << " varb = "; + ss << vSubArguments[1]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if(isnan(varb)||(gid0>="; + ss << tmpCurDVR->GetArrayLength(); + ss << "))\n"; + ss << " varb = 0;\n"; + } + else if(tmpCur->GetType() == formula::svDouble) + { + ss << " varb = "; + ss << tmpCur->GetDouble() << ";\n"; + } + } + else + { + ss << " varb = "; + ss << vSubArguments[1]->GenSlidingWindowDeclRef(); + ss << ";\n"; + } + tmpCur = vSubArguments[0]->GetFormulaToken(); + assert(tmpCur); + if(ocPush == vSubArguments[0]->GetFormulaToken()->GetOpCode()) + { + //TODO DoubleVector + if (tmpCur->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken *>(tmpCur); + size_t nCurWindowSize = pDVR->GetRefRowSize(); + ss << " for (int i = "; + if (!pDVR->IsStartFixed() && pDVR->IsEndFixed()) + { + ss << "gid0; i < " << pDVR->GetArrayLength(); + ss << " && i < " << nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed()) + { + ss << "0; i < " << pDVR->GetArrayLength(); + ss << " && i < gid0+"<< nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed()) + { + ss << "0; i + gid0 < " << pDVR->GetArrayLength(); + ss << " && i < "<< nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + else + { + ss << "0; i < "<< nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + ss << " vara = "; + ss << vSubArguments[0]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if (isnan(vara))\n"; + ss << " continue;\n"; + ss << " (vara == varb) && varc++;\n"; + ss << " }\n"; + } + else if(tmpCur->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* tmpCurDVR= + static_cast< + const formula::SingleVectorRefToken *>(tmpCur); + ss << " vara = "; + ss << vSubArguments[0]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if(isnan(vara)||(gid0>="; + ss << tmpCurDVR->GetArrayLength(); + ss << "))\n"; + ss << " return 0;\n"; + ss << " (vara == varb) && varc++;\n"; + } + } + ss << " return varc;\n"; + ss << "}"; +} + +void OpSumIf::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double vara, varb, varc, sum = 0.0f;\n"; + int flag = 3 == vSubArguments.size() ? 2 : 0; + FormulaToken *tmpCur = vSubArguments[1]->GetFormulaToken(); + assert(tmpCur); + if(ocPush == vSubArguments[1]->GetFormulaToken()->GetOpCode()) + { + if(tmpCur->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* tmpCurDVR= + static_cast< + const formula::SingleVectorRefToken *>(tmpCur); + ss << " varb = "; + ss << vSubArguments[1]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if(isnan(varb)||(gid0>="; + ss << tmpCurDVR->GetArrayLength(); + ss << "))\n"; + ss << " varb = 0;\n"; + } + else if(tmpCur->GetType() == formula::svDouble) + { + ss << " varb = "; + ss << tmpCur->GetDouble() << ";\n"; + } + } + else + { + ss << " varb = "; + ss << vSubArguments[1]->GenSlidingWindowDeclRef(); + ss << ";\n"; + } + tmpCur = vSubArguments[0]->GetFormulaToken(); + assert(tmpCur); + if(ocPush == vSubArguments[0]->GetFormulaToken()->GetOpCode()) + { + //TODO DoubleVector + if (tmpCur->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken *>(tmpCur); + size_t nCurWindowSize = pDVR->GetRefRowSize(); + ss << " for (int i = "; + if (!pDVR->IsStartFixed() && pDVR->IsEndFixed()) + { + ss << "gid0; i < " << pDVR->GetArrayLength(); + ss << " && i < " << nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed()) + { + ss << "0; i < " << pDVR->GetArrayLength(); + ss << " && i < gid0+"<< nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed()) + { + ss << "0; i + gid0 < " << pDVR->GetArrayLength(); + ss << " && i < "<< nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + else + { + ss << "0; i < "<< nCurWindowSize << "; ++i)\n"; + ss << " {\n"; + } + ss << " vara = "; + ss << vSubArguments[0]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if (isnan(vara))\n"; + ss << " continue;\n"; + ss << " varc = "; + ss << vSubArguments[flag]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if (isnan(varc))\n"; + ss << " varc = 0.0f;\n"; + ss << " (vara == varb)&&(sum = sum + varc);\n"; + ss << " }\n"; + } + else if(tmpCur->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* tmpCurDVR= + static_cast< + const formula::SingleVectorRefToken *>(tmpCur); + ss << " vara = "; + ss << vSubArguments[0]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if(isnan(vara)||(gid0>="; + ss << tmpCurDVR->GetArrayLength(); + ss << "))\n"; + ss << " return 0;\n"; + ss << " int i = 0;\n"; + ss << " varc = "; + ss << vSubArguments[flag]->GenSlidingWindowDeclRef(); + ss << ";\n"; + ss << " if(isnan(varc)||(gid0>="; + ss << tmpCurDVR->GetArrayLength(); + ss << "))\n"; + ss << " varc = 0.0f;\n"; + + ss << " (vara == varb)&&(sum = sum + varc);\n"; + + } + } + ss << " return sum;\n"; + ss << "}"; +} + +void OpFloor::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "arg0", 0, vSubArguments, ss ); + GenerateArg( "arg1", 1, vSubArguments, ss ); + GenerateArgWithDefault( "arg2", 2, 0, vSubArguments, ss ); + ss << " if(isnan(arg0) || isnan(arg1))\n"; + ss << " return 0;\n"; + ss << " if(isnan(arg2))\n"; + ss << " arg2 = 0.0;\n"; + ss << " if(arg0*arg1<0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if(arg1 == 0.0)\n"; + ss << " return 0.0;\n"; + ss << " else if(arg2==0.0&&arg0<0.0)\n"; + ss << " return (trunc(arg0/arg1)+1)*arg1;\n"; + ss << " else\n"; + ss << " return trunc(arg0/arg1)*arg1;\n"; + ss << "}\n"; +} + +void OpSumSQ::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double sum = 0.0f, arg;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " sum += pown(arg, 2);\n" + ); + ss << " return sum;\n"; + ss << "}"; +} + +void OpCeil::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "num", 0, vSubArguments, ss ); + GenerateArg( "significance", 1, vSubArguments, ss ); + GenerateArgWithDefault( "bAbs", 2, 0, vSubArguments, ss ); + ss << " if(num*significance < 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if(significance == 0.0)\n"; + ss << " return 0.0;\n"; + ss << " return "; + ss << "( !(int)bAbs && num < 0.0 ? floor( num / significance ) : "; + ss << "ceil( num / significance ) )"; + ss << "*significance;\n"; + ss << "}"; +} + +void OpProduct::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double product=1.0;\n"; + ss << " int count = 0;\n\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " product = product*arg;\n" + " ++count;\n" + ); + ss << " if(count == 0)\n"; + ss << " return 0;\n"; + ss << " return product;\n"; + ss << "}"; +} + +void OpAverageIf::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp =0;\n"; + ss << " double count=0;\n"; + ss << " int singleIndex =gid0;\n"; + ss << " int doubleIndex;\n"; + ss << " int i ;\n"; + ss << " int j ;\n"; + GenTmpVariables(ss,vSubArguments); + + unsigned paraOneIsDoubleVector = 0; + unsigned paraOneWidth = 1; + unsigned paraTwoWidth = 1; + unsigned loopTimes = 0; + + if(vSubArguments[0]->GetFormulaToken()->GetType() == formula::svDoubleVectorRef) + { + paraOneIsDoubleVector = 1; + FormulaToken *tmpCur0 = vSubArguments[0]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR0= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur0); + paraOneWidth = pCurDVR0->GetArrays().size(); + loopTimes = paraOneWidth; + if(paraOneWidth > 1) + { + throw Unhandled(__FILE__, __LINE__); + } + } + + if(vSubArguments[paraOneWidth]->GetFormulaToken()->GetType() == + formula::svDoubleVectorRef) + + { + FormulaToken *tmpCur1 = vSubArguments[1]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR1= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur1); + paraTwoWidth = pCurDVR1->GetArrays().size(); + if(paraTwoWidth > 1) + { + throw Unhandled(__FILE__, __LINE__); + } + ss << " i = "; + if (!pCurDVR1->IsStartFixed() && pCurDVR1->IsEndFixed()) { + ss << "gid0;\n"; + } else { + ss << "0;\n"; + } + if(!pCurDVR1->IsStartFixed() && !pCurDVR1->IsEndFixed()) + { + ss << " doubleIndex =i+gid0;\n"; + }else + { + ss << " doubleIndex =i;\n"; + } + } + + CheckSubArgumentIsNan(ss,vSubArguments,paraOneWidth); + + unsigned paraThreeIndex = paraOneWidth + paraTwoWidth; + if(vSubArguments.size() > paraThreeIndex) + { + if(vSubArguments[paraThreeIndex]->GetFormulaToken()->GetType() == + formula::svDoubleVectorRef) + { + FormulaToken *tmpCur2 = + vSubArguments[paraThreeIndex]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR2= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur2); + unsigned paraThreeWidth = pCurDVR2->GetArrays().size(); + if(paraThreeWidth > 1) + { + throw Unhandled(__FILE__, __LINE__); + } + } + } + + if(paraOneIsDoubleVector) + { + unsigned loopIndex = 0; + FormulaToken *tmpCur0 = vSubArguments[0]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR0= static_cast<const + formula::DoubleVectorRefToken *>(tmpCur0); + size_t nCurWindowSize = pCurDVR0->GetArrayLength() < + pCurDVR0->GetRefRowSize() ? pCurDVR0->GetArrayLength(): + pCurDVR0->GetRefRowSize() ; + + for(loopIndex =0; loopIndex < loopTimes; loopIndex++) + { + ss << " for (i = "; + if (!pCurDVR0->IsStartFixed() && pCurDVR0->IsEndFixed()) { + ss << "gid0; i < "<< nCurWindowSize <<"; i++)\n"; + } else if (pCurDVR0->IsStartFixed() && !pCurDVR0->IsEndFixed()) { + ss << "0; i < gid0+"<< nCurWindowSize <<"; i++)\n"; + } else { + ss << "0; i < "<< nCurWindowSize <<"; i++)\n"; + } + ss << " {\n"; + if(!pCurDVR0->IsStartFixed() && !pCurDVR0->IsEndFixed()) + { + ss << " doubleIndex =i+gid0;\n"; + }else + { + ss << " doubleIndex =i;\n"; + } + + CheckSubArgumentIsNan(ss,vSubArguments, loopIndex); + + ss << " if ( isequal( tmp"; + ss << loopIndex<<" , tmp"<<paraOneWidth<<") ) \n"; + ss << " {\n"; + if(vSubArguments.size() == paraThreeIndex) + ss << " tmp += tmp"<<loopIndex<<";\n"; + else + { + CheckSubArgumentIsNan(ss,vSubArguments, + paraThreeIndex+loopIndex); + ss << " tmp += tmp"; + ss << paraThreeIndex+loopIndex<<";\n"; + } + ss << " count+=1.0;\n"; + ss << " }\n"; + ss << " }\n"; + } + } + else + { + CheckSubArgumentIsNan(ss,vSubArguments, 0); + ss << " if ( isequal( tmp0 , tmp1 ) ) \n"; + ss << " {\n"; + if(vSubArguments.size() == 2) + ss << " tmp += tmp0;\n"; + else + { + CheckSubArgumentIsNan(ss,vSubArguments,2); + ss << " tmp += tmp2;\n"; + } + ss << " count+=1.0;\n"; + ss << " }\n"; + } + + ss << " if(count!=0)\n"; + ss << " tmp=tmp/count;\n"; + ss << " else\n"; + ss << " tmp= 0 ;\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpSeriesSum::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT(4,4); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double var[3], coeff, res = 0.0f;\n"; + GenerateArg( "var0", 0, vSubArguments, ss ); + GenerateArg( "var1", 1, vSubArguments, ss ); + GenerateArg( "var2", 2, vSubArguments, ss ); + ss << " if( var0 == 0 && var1 == 0 )\n"; + ss << " return CreateDoubleError(NoValue);\n"; // pow(0,0) + ss << " var[0] = var0;\n"; + ss << " var[1] = var1;\n"; + ss << " var[2] = var2;\n"; + ss << " int j = 0;\n"; + GenerateRangeArg( 3, vSubArguments, ss, SkipEmpty, + " double coeff = arg;\n" + " res = res + coeff * pow(var[0], var[1] + j * var[2]);\n" + " ++j;\n" + ); + ss << " return res;\n"; + ss << "}"; +} + +void SumOfProduct::GenSlidingWindowFunction( outputstream& ss, + const std::string& sSymName, SubArguments& vSubArguments ) +{ + size_t nCurWindowSize = 0; + FormulaToken* tmpCur = nullptr; + const formula::DoubleVectorRefToken* pCurDVR = nullptr; + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + for (size_t i = 0; i < vSubArguments.size(); i++) + { + size_t nCurChildWindowSize = vSubArguments[i]->GetWindowSize(); + nCurWindowSize = (nCurWindowSize < nCurChildWindowSize) ? + nCurChildWindowSize : nCurWindowSize; + tmpCur = vSubArguments[i]->GetFormulaToken(); + if (ocPush == tmpCur->GetOpCode()) + { + pCurDVR = static_cast<const formula::DoubleVectorRefToken*>(tmpCur); + if (pCurDVR->IsStartFixed() != pCurDVR->IsEndFixed()) + throw Unhandled(__FILE__, __LINE__); + } + } + ss << " double tmp = 0.0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + + ss << "\tint i;\n\t"; + ss << "int currentCount0;\n"; + for (size_t i = 0; i < vSubArguments.size() - 1; i++) + ss << "int currentCount" << i + 1 << ";\n"; + outputstream temp3, temp4; + int outLoopSize = UNROLLING_FACTOR; + if (nCurWindowSize / outLoopSize != 0) + { + ss << "for(int outLoop=0; outLoop<" << + nCurWindowSize / outLoopSize << "; outLoop++){\n\t"; + for (int count = 0; count < outLoopSize; count++) + { + ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n"; + if (count == 0) + { + for (size_t i = 0; i < vSubArguments.size(); i++) + { + tmpCur = vSubArguments[i]->GetFormulaToken(); + if (ocPush == tmpCur->GetOpCode()) + { + pCurDVR = static_cast<const formula::DoubleVectorRefToken*>(tmpCur); + if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + temp3 << " currentCount"; + temp3 << i; + temp3 << " =i+gid0+1;\n"; + } + else + { + temp3 << " currentCount"; + temp3 << i; + temp3 << " =i+1;\n"; + } + } + } + + temp3 << "tmp = fsum("; + for (size_t i = 0; i < vSubArguments.size(); i++) + { + if (i) + temp3 << "*"; + if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode()) + { + temp3 << "("; + temp3 << "(currentCount"; + temp3 << i; + temp3 << ">"; + if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*> + (vSubArguments[i]->GetFormulaToken()); + temp3 << pSVR->GetArrayLength(); + temp3 << ")||isnan(" << vSubArguments[i] + ->GenSlidingWindowDeclRef(); + temp3 << ")?0:"; + temp3 << vSubArguments[i]->GenSlidingWindowDeclRef(); + temp3 << ")"; + } + else if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pSVR = + static_cast<const formula::DoubleVectorRefToken*> + (vSubArguments[i]->GetFormulaToken()); + temp3 << pSVR->GetArrayLength(); + temp3 << ")||isnan(" << vSubArguments[i] + ->GenSlidingWindowDeclRef(true); + temp3 << ")?0:"; + temp3 << vSubArguments[i]->GenSlidingWindowDeclRef(true); + temp3 << ")"; + } + + } + else + temp3 << vSubArguments[i]->GenSlidingWindowDeclRef(true); + } + temp3 << ", tmp);\n\t"; + } + ss << temp3.str(); + } + ss << "}\n\t"; + } + //The residual of mod outLoopSize + for (size_t count = nCurWindowSize / outLoopSize * outLoopSize; + count < nCurWindowSize; count++) + { + ss << "i =" << count << ";\n"; + if (count == nCurWindowSize / outLoopSize * outLoopSize) + { + for (size_t i = 0; i < vSubArguments.size(); i++) + { + tmpCur = vSubArguments[i]->GetFormulaToken(); + if (ocPush == tmpCur->GetOpCode()) + { + pCurDVR = static_cast<const formula::DoubleVectorRefToken*>(tmpCur); + if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + temp4 << " currentCount"; + temp4 << i; + temp4 << " =i+gid0+1;\n"; + } + else + { + temp4 << " currentCount"; + temp4 << i; + temp4 << " =i+1;\n"; + } + } + } + + temp4 << "tmp = fsum("; + for (size_t i = 0; i < vSubArguments.size(); i++) + { + if (i) + temp4 << "*"; + if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode()) + { + temp4 << "("; + temp4 << "(currentCount"; + temp4 << i; + temp4 << ">"; + if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast<const formula::SingleVectorRefToken*> + (vSubArguments[i]->GetFormulaToken()); + temp4 << pSVR->GetArrayLength(); + temp4 << ")||isnan(" << vSubArguments[i] + ->GenSlidingWindowDeclRef(); + temp4 << ")?0:"; + temp4 << vSubArguments[i]->GenSlidingWindowDeclRef(); + temp4 << ")"; + } + else if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pSVR = + static_cast<const formula::DoubleVectorRefToken*> + (vSubArguments[i]->GetFormulaToken()); + temp4 << pSVR->GetArrayLength(); + temp4 << ")||isnan(" << vSubArguments[i] + ->GenSlidingWindowDeclRef(true); + temp4 << ")?0:"; + temp4 << vSubArguments[i]->GenSlidingWindowDeclRef(true); + temp4 << ")"; + } + + } + else + { + temp4 << vSubArguments[i] + ->GenSlidingWindowDeclRef(true); + } + } + temp4 << ", tmp);\n\t"; + } + ss << temp4.str(); + } + ss << "return tmp;\n"; + ss << "}"; +} + +void OpSum::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); + decls.insert(fsum_approxDecl); + funs.insert(fsum_approx); +} + +void OpSub::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); + decls.insert(fsub_approxDecl); + funs.insert(fsub_approx); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_math.hxx b/sc/source/core/opencl/op_math.hxx new file mode 100644 index 0000000000..92f9701eef --- /dev/null +++ b/sc/source/core/opencl/op_math.hxx @@ -0,0 +1,673 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +/// Implements functions in the form of FUNC(x), e.g. COS(). +/// The function should take one simple argument (i.e. no ranges). +class OpMathOneArgument : public Normal +{ + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + /// This writes out OpenCL code returning the computed value, the argument is "arg0". + virtual void GenerateCode( outputstream& ss ) const = 0; +}; + +/// Implements functions in the form of FUNC(x1, x2), e.g. ATAN2(). +/// The function should take exactly two simple arguments (i.e. no ranges). +class OpMathTwoArguments : public Normal +{ + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + /// This writes out OpenCL code returning the computed value, the arguments are "arg0" and "arg1". + virtual void GenerateCode( outputstream& ss ) const = 0; +}; + + +class OpCos: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Cos"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSec: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Sec"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSecH: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "SecH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpMROUND: public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "MROUND"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpCsc: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Csc"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSumIfs final : public CheckVariables +{ +public: + OpSumIfs(): CheckVariables(), mNeedReductionKernel(false) {} + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SumIfs"; } + bool NeedReductionKernel() const { return mNeedReductionKernel; } +private: + bool mNeedReductionKernel; +}; + +class OpCosh: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Cosh"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSinh: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Sinh"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSin: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Sin"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpAbs: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScAbs"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcCos: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScACos"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcCosHyp : public OpMathOneArgument +{ +public: + virtual std::string GetBottom() override { return "1.0"; } + virtual std::string BinFuncName() const override { return "ScACosH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpTan: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Tan"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpTanH: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "TanH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSqrt: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Sqrt"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcCot : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScACot"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcCotHyp : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScACotH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcSin : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScASin"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcSinHyp : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScASinH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcTan2 : public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScATan2"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcTan : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScATan"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpArcTanH : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "ScATanH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpBitAnd : public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScBitAnd"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpBitOr : public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScBitOr"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpBitXor : public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScBitXor"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpBitLshift : public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScBitLshift"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpBitRshift : public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScBitRshift"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpLn: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Ln"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpRound: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Round"; } + virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override; +}; +class OpRoundUp: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "RoundUp"; } +}; +class OpRoundDown: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "RoundDown"; } +}; +class OpTrunc: public OpRoundDown +{ +public: + virtual std::string BinFuncName() const override { return "Trunc"; } +}; +class OpInt: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Int"; } + virtual void GenerateCode( outputstream& ss ) const override; + virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override; +}; + +class OpRadians: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Radians"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpIsEven: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "IsEven"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpIsOdd: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "IsOdd"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpCot: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Cot"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSumSQ: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "SumSQ"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpCoth: public OpMathOneArgument +{ +public: + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Coth"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpPower: public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "Power"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpOdd: public OpMathOneArgument +{ +public: + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "Odd"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpFloor: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Floor"; } +}; + +class OpCscH: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "CscH"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpCeil:public Normal{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string GetBottom() override { return "0.0"; } + virtual std::string BinFuncName() const override { return "ScCeil"; } +}; + +class OpExp: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Exp"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpLog10: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Log10"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpEven: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Even"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpAverageIfs: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "AverageIfs"; } +}; +class OpCountIfs: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "CountIfs"; } +}; +class OpMod: public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "Mod"; } + virtual void GenerateCode( outputstream& ss ) const override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpProduct: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Product"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpSqrtPi: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "SqrtPi"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpCombinA: public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "Combina"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpLog: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "Log"; } +}; + +class OpCombin: public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "ScCombin"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpAverageIf: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + + virtual std::string BinFuncName() const override { return "AverageIf"; } +}; +class OpDeg: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Degrees"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpCountIf: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Countif"; } +}; +class OpFact : public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "Fact"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpSeriesSum: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SeriesSum"; } + virtual bool canHandleMultiVector() const override { return true; } +}; +class OpSumIf: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "SumIf"; } +}; + +class OpQuotient: public OpMathTwoArguments +{ +public: + virtual std::string BinFuncName() const override { return "Quotient"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpNegSub: public OpMathOneArgument +{ +public: + virtual std::string BinFuncName() const override { return "NegSub"; } + virtual void GenerateCode( outputstream& ss ) const override; +}; + +class OpEqual : public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "eq"; } + virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override; + virtual bool takeString() const override { return true; } +}; + +class OpNotEqual : public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "neq"; } + virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override; + virtual bool takeString() const override { return true; } +}; + +class OpLessEqual : public OpMathTwoArguments +{ +public: + virtual void GenerateCode( outputstream& ss ) const override; + virtual std::string BinFuncName() const override { return "le"; } + virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override; +}; + +class OpLess : public OpMathTwoArguments +{ +public: + virtual void GenerateCode( outputstream& ss ) const override; + virtual std::string BinFuncName() const override { return "lt"; } +}; + +class OpGreaterEqual : public OpMathTwoArguments +{ +public: + virtual void GenerateCode( outputstream& ss ) const override; + virtual std::string BinFuncName() const override { return "ge"; } + virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override; +}; + +class OpGreater : public OpMathTwoArguments +{ +public: + virtual void GenerateCode( outputstream& ss ) const override; + virtual std::string BinFuncName() const override { return "gt"; } +}; + +class SumOfProduct : public SlidingFunctionBase +{ +public: + virtual void GenSlidingWindowFunction( outputstream& ss, + const std::string& sSymName, SubArguments& vSubArguments ) override; + virtual bool takeString() const override { return false; } + virtual bool takeNumeric() const override { return true; } +}; + +class OpSumProduct : public SumOfProduct +{ +public: + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + return lhs + "*" + rhs; + } + virtual std::string BinFuncName() const override { return "fsop"; } +}; + +/// operator traits +class OpNop : public Reduction +{ +public: + explicit OpNop(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "0"; } + virtual std::string Gen2( const std::string& lhs, const std::string& ) const override + { + return lhs; + } + virtual std::string BinFuncName() const override { return "nop"; } +}; + +class OpSum : public Reduction +{ +public: + explicit OpSum(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "0"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + outputstream ss; + ss << "fsum_approx((" << lhs << "),(" << rhs << "))"; + return ss.str(); + } + virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual std::string BinFuncName() const override { return "fsum"; } + // All arguments are simply summed, so it doesn't matter if SvDoubleVector is split. + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpSub : public Reduction +{ +public: + explicit OpSub(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "0"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + return "fsub_approx(" + lhs + "," + rhs + ")"; + } + virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual std::string BinFuncName() const override { return "fsub"; } +}; + +class OpMul : public Reduction +{ +public: + explicit OpMul(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "1"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + return lhs + "*" + rhs; + } + virtual std::string BinFuncName() const override { return "fmul"; } + virtual bool ZeroReturnZero() override { return true; } +}; + +/// Technically not a reduction, but fits the framework. +class OpDiv : public Reduction +{ +public: + explicit OpDiv(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "1.0"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + return "(" + rhs + "==0 ? CreateDoubleError(DivisionByZero) : (" + lhs + "/" + rhs + ") )"; + } + virtual std::string BinFuncName() const override { return "fdiv"; } + + virtual bool HandleNaNArgument( outputstream& ss, unsigned argno, SubArguments& vSubArguments ) const override + { + if (argno == 1) + { + ss << + "if (isnan(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ")) {\n" + " return CreateDoubleError(DivisionByZero);\n" + "}\n"; + return true; + } + else if (argno == 0) + { + ss << + "if (isnan(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ") &&\n" + " !(isnan(" << vSubArguments[1]->GenSlidingWindowDeclRef() << ") || " << vSubArguments[1]->GenSlidingWindowDeclRef() << " == 0)) {\n" + " return 0;\n" + "}\n"; + } + return false; + } + +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_math_helpers.hxx b/sc/source/core/opencl/op_math_helpers.hxx new file mode 100644 index 0000000000..24aa73c560 --- /dev/null +++ b/sc/source/core/opencl/op_math_helpers.hxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +const char Math_IntgDecl[] ="double Intg(double n);\n"; +const char Math_Intg[] = +"double Intg(double n)\n" +"{\n" +" if(trunc(n)==n )\n" +" return n;\n" +" else if(n<0)\n" +" return trunc(n)-1;\n" +" else\n" +" return trunc(n)+1;\n" +"}\n"; + +const char nCorrValDecl[] ="double constant nCorrVal[]" +"= {0, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, " +"9e-8,9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14, 9e-15};\n"; + +const char RoundDecl[] = "double Round(double fValue);\n"; + +const char Round[] = +"double Round(double fValue)\n" +"{\n" +" if ( fValue == 0.0 )\n" +" return fValue;\n" +"\n" +" double fFac = 0;\n" +" int nExp;\n" +" if ( fValue > 0.0 )\n" +" nExp = ( floor( log10( fValue ) ) );\n" +" else\n" +" nExp = 0;\n" +" int nIndex = 15 - nExp;\n" +" if ( nIndex > 15 )\n" +" nIndex = 15;\n" +" else if ( nIndex <= 1 )\n" +" nIndex = 0;\n" +" fValue = floor( fValue + 0.5 + nCorrVal[nIndex] );\n" +" return fValue;\n" +"}\n"; + +const char bikDecl[] = "double bik(double n,double k);\n"; +const char bik[] = +"double bik(double n,double k)\n" +"{\n" +" double nVal1 = n;\n" +" double nVal2 = k;\n" +" n = n - 1;\n" +" k = k - 1;\n" +" while (k > 0)\n" +" {\n" +" nVal1 = nVal1 * n;\n" +" nVal2 = nVal2 * k;\n" +" k = k - 1;\n" +" n = n - 1;\n" +" }\n" +" return (nVal1 / nVal2);\n" +"}\n"; + +const char local_cothDecl[] = "double local_coth(double n);\n"; +const char local_coth[] = +"double local_coth(double n)\n" +"{\n" +" double a = exp(n);\n" +" double b = exp(-n);\n" +" double nVal = (a + b) / (a - b);\n" +" return nVal;\n" +"}\n"; + +const char local_coshDecl[] = "double local_cosh(double n);\n"; +const char local_cosh[] = +"double local_cosh(double n)\n" +"{\n" +" double nVal = (exp(n) + exp(-n)) / 2;\n" +" return nVal;\n" +"}\n"; +const char atan2Decl[] = "double arctan2(double y, double x);\n"; +const char atan2Content[] = +"double arctan2(double y, double x)\n" +"{\n" +" if(y==0.0)\n" +" return x >= 0 ? 0.0 : M_PI;\n" +" double a,num,den,tmpPi;\n" +" int flag;\n" +" tmpPi = 0;\n" +" if (fabs(x) >= fabs(y))\n" +" {\n" +" num = y;\n" +" den = x;\n" +" flag = 1;\n" +" if (x < 0.0)\n" +" tmpPi = M_PI;\n" +" }\n" +" if(fabs(x) < fabs(y))\n" +" {\n" +" num = x;\n" +" den = y;\n" +" flag = -1;\n" +" tmpPi = M_PI_2;\n" +" }\n" +" a = atan(num/den);\n" +" a = flag==1?a:-a;\n" +" a = a + (y >= 0.0 ? tmpPi : -tmpPi);\n" +" return a;\n" +"}\n"; + +const char is_representable_integerDecl[] = "int is_representable_integer(double a);\n"; +const char is_representable_integer[] = +"int is_representable_integer(double a) {\n" +" long kMaxInt = (1L << 53) - 1;\n" +" if (a <= (double)kMaxInt)\n" +" {\n" +" long nInt = (long)a;\n" +" double fInt;\n" +" return (nInt <= kMaxInt &&\n" +" (!((fInt = (double)nInt) < a) && !(fInt > a)));\n" +" }\n" +" return 0;\n" +"}\n"; + +const char approx_equalDecl[] = "int approx_equal(double a, double b);\n"; +const char approx_equal[] = +"int approx_equal(double a, double b) {\n" +" double e48 = 1.0 / (16777216.0 * 16777216.0);\n" +" double e44 = e48 * 16.0;\n" +" if (a == b)\n" +" return 1;\n" +" if (a == 0.0 || b == 0.0)\n" +" return 0;\n" +" double d = fabs(a - b);\n" +" if (!isfinite(d))\n" +" return 0; // Nan or Inf involved\n" +" if (d > ((a = fabs(a)) * e44) || d > ((b = fabs(b)) * e44))\n" +" return 0;\n" +" if (is_representable_integer(d) && is_representable_integer(a) && is_representable_integer(b))\n" +" return 0; // special case for representable integers.\n" +" return (d < a * e48 && d < b * e48);\n" +"}\n"; + +const char fsum_approxDecl[] = "double fsum_approx(double a, double b);\n"; +const char fsum_approx[] = +"double fsum_approx(double a, double b) {\n" +" if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0))\n" +" && approx_equal( a, -b ) )\n" +" return 0.0;\n" +" return a + b;\n" +"}\n"; + +const char fsub_approxDecl[] = "double fsub_approx(double a, double b);\n"; +const char fsub_approx[] = +"double fsub_approx(double a, double b) {\n" +" if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approx_equal( a, b ) )\n" +" return 0.0;\n" +" return a - b;\n" +"}\n"; + +const char value_approxDecl[] = "double value_approx( double fValue );\n"; +const char value_approx[] = +"double value_approx( double fValue )\n" +"{\n" +" const double fBigInt = 2199023255552.0;\n" +" if (fValue == 0.0 || fValue == HUGE_VAL || !isfinite(fValue))\n" +" return fValue;\n" +" double fOrigValue = fValue;\n" +" fValue = fabs(fValue);\n" +" if (fValue > fBigInt)\n" +" return fOrigValue;\n" +" if (is_representable_integer(fValue))\n" // TODO? || getBitsInFracPart(fValue) <= 11)\n" +" return fOrigValue;\n" +" int nExp = (int)(floor(log10(fValue)));\n" +" nExp = 14 - nExp;\n" +" double fExpValue = pow(10.0,nExp);\n" +" fValue *= fExpValue;\n" +" if (!isfinite(fValue))\n" +" return fOrigValue;\n" +" fValue = round(fValue);\n" +" fValue /= fExpValue;\n" +" if (!isfinite(fValue))\n" +" return fOrigValue;\n" +" return copysign(fValue, fOrigValue);\n" +"}\n"; + +// This compares two cell contents, including possible string equalities (based on string ids +// coming from DynamicKernelArgument::GetStringId()). +// The EmptyIsZero conversion must not be have been done for the arguments. +const char cell_equalDecl[] = "bool cell_equal(double a, double b, bool a_is_string, bool b_is_string);\n"; +const char cell_equal[] = +"bool cell_equal(double a, double b, bool a_is_string, bool b_is_string) {\n" +" if( !a_is_string && !b_is_string )\n" +" return approx_equal( isnan(a) ? 0 : a, isnan(b) ? 0 : b );\n" +" if( a_is_string && b_is_string )\n" +" return a == b;\n" +// empty strings and empty cells compare equal +" if(( a_is_string && a == 0 && isnan(b)) || ( b_is_string && b == 0 && isnan(a)))\n" +" return true;\n" +" return false;\n" +"}\n"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_spreadsheet.cxx b/sc/source/core/opencl/op_spreadsheet.cxx new file mode 100644 index 0000000000..db99a1e7cf --- /dev/null +++ b/sc/source/core/opencl/op_spreadsheet.cxx @@ -0,0 +1,286 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_spreadsheet.hxx" + +#include <rtl/math.hxx> +#include <formula/vectortoken.hxx> + +#include <algorithm> +#include <sstream> + +using namespace formula; + +namespace sc::opencl { + +void OpVLookup::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp = CreateDoubleError(NOTAVAILABLE);\n"; + ss << " double intermediate = DBL_MAX;\n"; + ss << " int singleIndex = gid0;\n"; + ss << " int rowNum = -1;\n"; + + GenTmpVariables(ss,vSubArguments); + int arg=0; + CheckSubArgumentIsNan(ss,vSubArguments,arg++); + int secondParaWidth = 1; + + // tdf#99512 - for now only allow non-dynamic indices (the + // common-case) to validate consistent return types vs. the input. + int index = 0; + int indexArg = vSubArguments.size() - 2; + if (vSubArguments[indexArg]->GetFormulaToken()->GetType() == formula::svDouble) + { + const formula::FormulaDoubleToken *dblToken = static_cast<const FormulaDoubleToken *>(vSubArguments[indexArg]->GetFormulaToken()); + index = ::rtl::math::approxFloor(dblToken->GetDouble()); + } + + if (vSubArguments[1]->GetFormulaToken()->GetType() != formula::svDoubleVectorRef) + throw Unhandled(__FILE__, __LINE__); // unusual vlookup. + + FormulaToken *tmpCur = vSubArguments[1]->GetFormulaToken(); + const formula::DoubleVectorRefToken*pCurDVR = static_cast<const formula::DoubleVectorRefToken *>(tmpCur); + const std::vector<VectorRefArray> items = pCurDVR->GetArrays(); + + secondParaWidth = items.size(); + + if (index < 1 || index > secondParaWidth) + throw Unhandled(__FILE__, __LINE__); // oob index. + + if (items[index - 1].mpStringArray) + { + rtl_uString **pStrings = items[index - 1].mpStringArray; + for (size_t i = 0; i < pCurDVR->GetArrayLength(); ++i) + { + if (pStrings[i] != nullptr) + { // TODO: the GroupTokenConverter should do better. + throw Unhandled(__FILE__, __LINE__); // mixed arguments. + } + } + } + + + arg += secondParaWidth; + CheckSubArgumentIsNan(ss,vSubArguments,arg++); + + if (vSubArguments.size() == static_cast<unsigned int>(3+(secondParaWidth-1))) + { + ss << " double tmp"; + ss << 3+(secondParaWidth-1); + ss << "= 1;\n"; + } + else + { + CheckSubArgumentIsNan(ss,vSubArguments,arg++); + } + + if (vSubArguments[1]->GetFormulaToken()->GetType() == formula::svDoubleVectorRef) + { + tmpCur = vSubArguments[1]->GetFormulaToken(); + pCurDVR = static_cast<const formula::DoubleVectorRefToken *>(tmpCur); + size_t nCurWindowSize = std::min(pCurDVR->GetArrayLength(), pCurDVR->GetRefRowSize()); + const int unrollSize = 8; + + ss << "\n"; + ss << " int loop = "; + if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) + { + ss << "("<<nCurWindowSize<<" - gid0)/"; + ss << unrollSize<<";\n"; + } + else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << "("<<nCurWindowSize<<" + gid0)/"; + ss << unrollSize<<";\n"; + } + else + { + ss << nCurWindowSize<<"/"<< unrollSize<<";\n"; + } + + ss << " if(tmp"; + ss << 3+(secondParaWidth-1); + ss << " == 0) /* unsorted vlookup */\n"; + ss << " {\n"; + + for( int sorted = 0; sorted < 2; ++sorted ) // sorted vs unsorted vlookup cases + { + if( sorted == 1 ) + { + ss << " }\n"; + ss << " else\n"; + ss << " { /* sorted vlookup */ \n"; + } + + ss << " for ( int j = 0;j< loop; j++)\n"; + ss << " {\n"; + ss << " int i = "; + if (!pCurDVR->IsStartFixed()&& pCurDVR->IsEndFixed()) + { + ss << "gid0 + j * "<< unrollSize <<";\n"; + } + else + { + ss << "j * "<< unrollSize <<";\n"; + } + if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << " int doubleIndex = i+gid0;\n"; + } + else + { + ss << " int doubleIndex = i;\n"; + } + + for (int j = 0;j < unrollSize; j++) + { + CheckSubArgumentIsNan(ss,vSubArguments,1); + + if( sorted == 1 ) + { + ss << " if((tmp0 - tmp1)>=0 && intermediate > (tmp0 -tmp1))\n"; + ss << " {\n"; + ss << " rowNum = doubleIndex;\n"; + ss << " intermediate = tmp0 - tmp1;\n"; + ss << " }\n"; + ss << " i++;\n"; + ss << " doubleIndex++;\n"; + } + else + { + ss << " if(tmp0 == tmp1)\n"; + ss << " {\n"; + ss << " rowNum = doubleIndex;\n"; + ss << " break;\n"; + ss << " }\n"; + ss << " i++;\n"; + ss << " doubleIndex++;\n"; + } + } + ss << " }\n\n"; + } + + ss << " }\n"; + ss << " if(rowNum!=-1)\n"; + ss << " {\n"; + for (int j = 0; j < secondParaWidth; j++) + { + ss << " if(tmp"; + ss << 2+(secondParaWidth-1); + ss << " == "; + ss << j+1; + ss << ")\n"; + ss << " tmp = "; + vSubArguments[1+j]->GenDeclRef(ss); + ss << "[rowNum];\n"; + } + ss << " return tmp;\n"; + ss << " }\n"; + + ss << " if(tmp"; + ss << 3+(secondParaWidth-1); + ss << " == 0) /* unsorted vlookup */\n"; + ss << " {\n"; + + for( int sorted = 0; sorted < 2; ++sorted ) // sorted vs unsorted vlookup cases + { + if( sorted == 1 ) + { + ss << " }\n"; + ss << " else\n"; + ss << " { /* sorted vlookup */ \n"; + } + + ss << " for (int i = "; + if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) + { + ss << "gid0 + loop *"<<unrollSize<<"; i < "; + ss << nCurWindowSize <<"; i++)\n"; + } + else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << "0 + loop *"<<unrollSize<<"; i < gid0+"; + ss << nCurWindowSize <<"; i++)\n"; + } + else + { + ss << "0 + loop *"<<unrollSize<<"; i < "; + ss << nCurWindowSize <<"; i++)\n"; + } + ss << " {\n"; + if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << " int doubleIndex = i+gid0;\n"; + } + else + { + ss << " int doubleIndex = i;\n"; + } + CheckSubArgumentIsNan(ss,vSubArguments,1); + + if( sorted == 1 ) + { + ss << " if((tmp0 - tmp1)>=0 && intermediate > (tmp0 -tmp1))\n"; + ss << " {\n"; + ss << " rowNum = doubleIndex;\n"; + ss << " intermediate = tmp0 - tmp1;\n"; + ss << " }\n"; + } + else + { + ss << " if(tmp0 == tmp1)\n"; + ss << " {\n"; + ss << " rowNum = doubleIndex;\n"; + ss << " break;\n"; + ss << " }\n"; + } + ss << " }\n\n"; + } + + ss << " }\n"; + ss << " if(rowNum!=-1)\n"; + ss << " {\n"; + + for (int j = 0; j < secondParaWidth; j++) + { + ss << " if(tmp"; + ss << 2+(secondParaWidth-1); + ss << " == "; + ss << j+1; + ss << ")\n"; + ss << " tmp = "; + vSubArguments[1+j]->GenDeclRef(ss); + ss << "[rowNum];\n"; + } + ss << " return tmp;\n"; + ss << " }\n"; + } + else + { + CheckSubArgumentIsNan(ss,vSubArguments,1); + ss << " if(tmp3 == 1)\n"; + ss << " {\n"; + ss << " tmp = tmp1;\n"; + ss << " }else\n"; + ss << " {\n"; + ss << " if(tmp0 == tmp1)\n"; + ss << " tmp = tmp1;\n"; + ss << " }\n"; + } + ss << " return tmp;\n"; + ss << "}"; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_spreadsheet.hxx b/sc/source/core/opencl/op_spreadsheet.hxx new file mode 100644 index 0000000000..2d76fb8fe4 --- /dev/null +++ b/sc/source/core/opencl/op_spreadsheet.hxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +class OpVLookup: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "VLookup"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_statistical.cxx b/sc/source/core/opencl/op_statistical.cxx new file mode 100644 index 0000000000..4c79d162e6 --- /dev/null +++ b/sc/source/core/opencl/op_statistical.cxx @@ -0,0 +1,2161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "op_statistical.hxx" + +#include <formula/vectortoken.hxx> +#include <sstream> +#include "op_statistical_helpers.hxx" + +using namespace formula; + +#include "op_math_helpers.hxx" + +namespace sc::opencl { + +void OpZTest::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(phiDecl); + funs.insert(phi); + decls.insert(taylorDecl); + funs.insert(taylor); + decls.insert(gaussDecl); + funs.insert(gauss); +} +void OpZTest::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSum = 0.0;\n"; + ss << " double fSumSqr = 0.0;\n"; + ss << " double mue = 0.0;\n"; + ss << " double fCount = 0.0;\n"; + GenerateRangeArg( 0, vSubArguments, ss, SkipEmpty, + " fSum += arg;\n" + " fSumSqr += arg * arg;\n" + " fCount += 1.0;\n" + ); + ss << " if(fCount <= 1.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " mue = fSum / fCount;\n"; + GenerateArg( "mu", 1, vSubArguments, ss ); + if(vSubArguments.size() == 3) + { + GenerateArg( "sigma", 2, vSubArguments, ss ); + ss << " if(sigma <= 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return 0.5 - gauss((mue-mu)*sqrt(fCount)/sigma);\n"; + } + else + { + ss << " double sigma = (fSumSqr-fSum*fSum/fCount)/(fCount-1.0);\n"; + ss << " if(sigma == 0.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " return 0.5 - gauss((mue-mu)/sqrt(sigma/fCount));\n"; + } + ss << "}\n"; +} + +void OpTTest::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl); + funs.insert(""); + decls.insert(fMaxGammaArgumentDecl); + funs.insert(""); + decls.insert(lcl_getLanczosSumDecl); + funs.insert(lcl_getLanczosSum); + decls.insert(GetBetaDecl); + funs.insert(GetBeta); + decls.insert(GetLogBetaDecl); + funs.insert(GetLogBeta); + decls.insert(GetBetaDistPDFDecl); + funs.insert(GetBetaDistPDF); + decls.insert(lcl_GetBetaHelperContFracDecl); + funs.insert(lcl_GetBetaHelperContFrac); + decls.insert(GetBetaDistDecl); + funs.insert(GetBetaDist); + decls.insert(GetTDistDecl); + funs.insert(GetTDist); +} + +void OpTTest::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSum1 = 0.0;\n"; + ss << " double fSum2 = 0.0;\n"; + ss << " double fSumSqr1 = 0.0;\n"; + ss << " double fSumSqr2 = 0.0;\n"; + ss << " double fCount1 = 0.0;\n"; + ss << " double fCount2 = 0.0;\n"; + ss << " double fT = 0.0;\n"; + ss << " double fF = 0.0;\n"; + GenerateArg( "mode", 2, vSubArguments, ss ); + GenerateArg( "type", 3, vSubArguments, ss ); + ss << " mode = floor(mode);\n"; + ss << " type = floor(type);\n"; + ss << " if(mode != 1.0 && mode != 2.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if(type != 1.0 && type != 2.0 && type != 3.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + + ss << " if(type == 1.0)\n"; + ss << " {\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " fSum1 += arg1;\n" + " fSum2 += arg2;\n" + " fSumSqr1 += (arg1 - arg2)*(arg1 - arg2);\n" + " fCount1 += 1;\n" + ); + ss << " if(fCount1 < 1.0)\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " double divider = sqrt(fCount1 * fSumSqr1 - (fSum1-fSum2)*(fSum1-fSum2));\n"; + ss << " if(divider == 0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " fT = sqrt(fCount1-1.0) * fabs(fSum1 - fSum2) / divider;\n"; + ss << " fF = fCount1 - 1.0;\n"; + ss << " }\n"; + ss << " if(type == 2.0 || type == 3.0)\n"; + ss << " {\n"; + GenerateRangeArg( 0, vSubArguments, ss, SkipEmpty, + " fSum1 += arg;\n" + " fSumSqr1 += arg * arg;\n" + " fCount1 += 1;\n" + ); + GenerateRangeArg( 1, vSubArguments, ss, SkipEmpty, + " fSum2 += arg;\n" + " fSumSqr2 += arg * arg;\n" + " fCount2 += 1;\n" + ); + ss << " if (fCount1 < 2.0 || fCount2 < 2.0)\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " }\n"; + ss << " if(type == 3.0)\n"; + ss << " {\n"; + ss << " double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)\n"; + ss << " /(fCount1-1.0)/fCount1;\n"; + ss << " double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)\n"; + ss << " /(fCount2-1.0)/fCount2;\n"; + ss << " if (fS1 + fS2 == 0.0)\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " fT = fabs(fSum1/fCount1 - fSum2/fCount2)\n"; + ss << " /sqrt(fS1+fS2);\n"; + ss << " double c = fS1/(fS1+fS2);\n"; + ss << " fF = 1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)\n"; + ss << " /(fCount2-1.0));\n"; + ss << " }\n"; + ss << " if(type == 2.0)\n"; + ss << " {\n"; + ss << " double fS1 = (fSumSqr1 - fSum1*fSum1/fCount1)\n"; + ss << " /(fCount1 - 1.0);\n"; + ss << " double fS2 = (fSumSqr2 - fSum2*fSum2/fCount2)\n"; + ss << " /(fCount2 - 1.0);\n"; + ss << " fT = fabs( fSum1/fCount1 - fSum2/fCount2 )\n"; + ss << " /sqrt( (fCount1-1.0)*fS1 + (fCount2-1.0)*fS2 )\n"; + ss << " *sqrt( fCount1*fCount2*(fCount1+fCount2-2)\n"; + ss << " /(fCount1+fCount2) );\n"; + ss << " fF = fCount1 + fCount2 - 2;\n"; + ss << " }\n"; + ss << " double tdist=GetTDist(fT, fF);\n"; + ss << " if (mode==1)\n"; + ss << " return tdist;\n"; + ss << " else\n"; + ss << " return 2.0*tdist;\n"; + ss << "}\n"; +} + +void OpTDist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl); + funs.insert(""); + decls.insert(fMaxGammaArgumentDecl); + funs.insert(""); + decls.insert(lcl_getLanczosSumDecl); + funs.insert(lcl_getLanczosSum); + decls.insert(GetBetaDecl); + funs.insert(GetBeta); + decls.insert(GetLogBetaDecl); + funs.insert(GetLogBeta); + decls.insert(GetBetaDistPDFDecl); + funs.insert(GetBetaDistPDF); + decls.insert(lcl_GetBetaHelperContFracDecl); + funs.insert(lcl_GetBetaHelperContFrac); + decls.insert(GetBetaDistDecl); + funs.insert(GetBetaDist); + decls.insert(GetTDistDecl); + funs.insert(GetTDist); +} +void OpTDist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "fDF", 1, vSubArguments, ss ); + GenerateArg( "fFlag", 2, vSubArguments, ss ); + ss << " fDF = floor( fDF );\n"; + ss << " fFlag = floor( fFlag );\n"; + ss << " if(fDF < 1.0 || x < 0.0 || (fFlag != 1.0 && fFlag != 2.0))\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double R = GetTDist(x, fDF);\n"; + ss << " if (fFlag == 1.0)\n"; + ss << " return R;\n"; + ss << " else\n"; + ss << " return 2.0 * R;\n"; + ss << "}\n"; +} + +void OpExponDist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "rx", 0, vSubArguments, ss ); + GenerateArg( "rlambda", 1, vSubArguments, ss ); + GenerateArg( "rkum", 2, vSubArguments, ss ); + ss <<" if(rlambda <= 0.0)\n"; + ss <<" return CreateDoubleError(IllegalArgument);\n"; + ss <<" else if(rkum == 0)\n"; + ss <<" {\n"; + ss <<" if(rx >= 0)\n"; + ss <<" tmp = rlambda*exp(-rlambda*rx);\n"; + ss <<" else\n"; + ss <<" tmp = 0.0;\n"; + ss <<" }\n"; + ss <<" else\n"; + ss <<" {\n"; + ss <<" if(rx > 0)\n"; + ss <<" tmp = 1.0 - exp(-rlambda*rx);\n"; + ss <<" else\n"; + ss <<" tmp = 0.0;\n"; + ss <<" }\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} +void OpFdist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(GetFDistDecl);decls.insert(GetBetaDistDecl); + decls.insert(GetBetaDecl);decls.insert(fMaxGammaArgumentDecl); + decls.insert(lcl_GetBetaHelperContFracDecl); + decls.insert(GetBetaDistPDFDecl); + decls.insert(GetLogBetaDecl);decls.insert(lcl_getLanczosSumDecl); + decls.insert(fMachEpsDecl); + funs.insert(GetFDist);funs.insert(GetBetaDist); + funs.insert(GetBeta); + funs.insert(lcl_GetBetaHelperContFrac);funs.insert(GetBetaDistPDF); + funs.insert(GetLogBeta); + funs.insert(lcl_getLanczosSum); +} +void OpFdist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = 0;\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "rX", 0, vSubArguments, ss ); + GenerateArg( "rF1", 1, vSubArguments, ss ); + GenerateArg( "rF2", 2, vSubArguments, ss ); + ss <<" rF1 = floor(rF1);\n"; + ss <<" rF2 = floor(rF2);\n"; + ss <<" if (rX < 0.0 || rF1 < 1.0 || rF2 < 1.0 || rF1 >= 1.0E10 ||"; + ss <<"rF2 >= 1.0E10)\n"; + ss <<" return CreateDoubleError(IllegalArgument);\n"; + ss <<" tmp = GetFDist(rX, rF1, rF2);\n"; + ss <<" return tmp;\n"; + ss <<"}"; +} + +void OpStandard::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "mu", 1, vSubArguments, ss ); + GenerateArg( "sigma", 2, vSubArguments, ss ); + ss << " if(sigma < 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else if(sigma == 0.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " else\n"; + ss << " return (x - mu)/sigma;\n"; + ss << "}"; +} + +void OpWeibull::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "alpha", 1, vSubArguments, ss ); + GenerateArg( "beta", 2, vSubArguments, ss ); + GenerateArg( "kum", 3, vSubArguments, ss ); + ss << " if(alpha <= 0.0 || beta <=0.0 || x < 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if (kum == 0.0)\n"; + ss << " return alpha/pow(beta,alpha)*pow(x,alpha-1.0)*\n"; + ss << " exp(-pow(x/beta,alpha));\n"; + ss << " else\n"; + ss << " return 1.0 - exp(-pow(x/beta,alpha));\n"; + ss << "}\n"; +} + +void OpTInv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl); + funs.insert(""); + decls.insert(fMaxGammaArgumentDecl); + funs.insert(""); + decls.insert(lcl_getLanczosSumDecl); + funs.insert(lcl_getLanczosSum); + decls.insert(GetBetaDecl); + funs.insert(GetBeta); + decls.insert(GetLogBetaDecl); + funs.insert(GetLogBeta); + decls.insert(GetBetaDistPDFDecl); + funs.insert(GetBetaDistPDF); + decls.insert(lcl_GetBetaHelperContFracDecl); + funs.insert(lcl_GetBetaHelperContFrac); + decls.insert(GetBetaDistDecl); + funs.insert(GetBetaDist); + decls.insert(GetTDistDecl); + funs.insert(GetTDist); + decls.insert(GetValueDecl); + funs.insert(GetValue); + decls.insert(lcl_HasChangeOfSignDecl); + funs.insert(lcl_HasChangeOfSign); + decls.insert(lcl_IterateInverseDecl); + funs.insert(lcl_IterateInverse); +} + +void OpTInv::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "fDF", 1, vSubArguments, ss ); + ss << " fDF = floor(fDF);\n"; + ss << " if (x > 1.0||fDF < 1.0 || fDF > 1.0E10 || x <= 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " bool bConvError;\n"; + ss << " double fVal = lcl_IterateInverse(\n"; + ss << " fDF*0.5, fDF, &bConvError,x,fDF );\n"; + ss << " if (bConvError)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return fVal;\n"; + ss << "}\n"; +} + +void OpFisher::GenSlidingWindowFunction( outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + ss << " if (fabs(arg0) >= 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double tmp=0.5*log((1+arg0)/(1-arg0));\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpFisherInv::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + ss << " double tmp=tanh(arg0);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpGamma::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + ss << " double tmp=tgamma(arg0);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpNegbinomdist::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "f", 0, vSubArguments, ss ); + GenerateArg( "s", 1, vSubArguments, ss ); + GenerateArg( "p", 2, vSubArguments, ss ); + ss << " f = floor( f );\n"; + ss << " s = floor( s );\n"; + ss << " if ((f + s) <= 1.0 || p < 0.0 || p > 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double q = 1.0 - p;\n"; + ss << " double fFactor = pow(p,s);\n"; + ss << " for(int i=0; i<f; i++)\n"; + ss << " fFactor *= (i+s)/(i+1.0)*q;\n"; + ss << " return fFactor;\n"; + ss << "}\n"; +} + +void OpGammaLn::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss <<"int gid0=get_global_id(0);\n\t"; + GenerateArg( 0, vSubArguments, ss ); + ss << "double tmp=lgamma(arg0);\n\t"; + ss << "return tmp;\n"; + ss << "}\n"; +} +void OpGauss::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(taylorDecl);decls.insert(phiDecl); + decls.insert(gaussDecl); + funs.insert(taylor);funs.insert(phi); + funs.insert(gauss); +} + +void OpGauss::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments & +vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + ss << " double tmp=gauss(arg0);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpGeoMean::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments & +vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double nVal=0.0;\n"; + ss << " double tmp = 0;\n"; + ss << " int length;\n"; + ss << " int totallength=0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " if( arg < 0 )\n" + " return CreateDoubleError(IllegalArgument);\n" + " if( arg == 0 )\n" + " return 0;\n" + " nVal += log(arg);\n" + " ++totallength;\n" + ); + ss << " return exp(nVal/totallength);\n"; + ss << "}"; +} + +void OpHarMean::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments & +vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double nVal=0.0;\n"; + ss << " double tmp = 0;\n"; + ss << " int length;\n"; + ss << " int totallength=0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " if( arg <= 0 )\n" + " return CreateDoubleError(IllegalArgument);\n" + " nVal += (1.0 / arg);\n" + " ++totallength;\n" + ); + ss << " return totallength/nVal;\n"; + ss << "}"; +} + +void OpConfidence::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(gaussinvDecl); + funs.insert(gaussinv); +} + +void OpConfidence::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() <<";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "alpha", 0, vSubArguments, ss ); + GenerateArg( "sigma", 1, vSubArguments, ss ); + GenerateArg( "size", 2, vSubArguments, ss ); + ss << " double rn = floor(size);\n"; + ss << " if(sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0"; + ss << "|| rn < 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else\n"; + ss << " tmp = gaussinv(1.0 - alpha / 2.0) * sigma / sqrt( rn );\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpCritBinom::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(MinDecl); + funs.insert(""); +} + +void OpCritBinom::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp = " << GetBottom() <<";\n"; + ss << " int gid0 = get_global_id(0);\n"; + GenerateArg( "n", 0, vSubArguments, ss ); + GenerateArg( "p", 1, vSubArguments, ss ); + GenerateArg( "alpha", 2, vSubArguments, ss ); + ss << " double rn = floor(n);\n"; + ss << " if (rn < 0.0 || alpha < 0.0 || alpha > 1.0 || p < 0.0"; + ss << " || p > 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else if ( alpha == 0 )\n"; + ss << " return 0;\n"; + ss << " else if ( alpha == 1 )\n"; + ss << " return p == 0 ? 0 : rn;\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double rq = (0.5 - p) + 0.5;\n"; + ss << " double fFactor = pow(rq, rn);\n"; + ss << " if (fFactor <= Min)\n"; + ss << " {\n"; + ss << " fFactor = pow(p, rn);\n"; + ss << " if (fFactor <= Min)\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fSum = 1.0 - fFactor;\n"; + ss << " uint max =(uint)(rn), i;\n"; + ss << " for (i = 0; i < max && fSum >= alpha; i++)\n"; + ss << " {\n"; + ss << " fFactor *= (rn - i) / (double)(i + 1) * rq / p;\n"; + ss << " fSum -= fFactor;\n"; + ss << " }\n"; + ss << " tmp = (rn - i);\n"; + ss << " }\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fSum = fFactor;\n"; + ss << " uint max = (uint)(rn), i;\n"; + ss << " for (i = 0; i < max && fSum < alpha; i++)\n"; + ss << " {\n"; + ss << " fFactor *= (rn - i) / (double)(i + 1) *"; + ss << " p / rq;\n"; + ss << " fSum += fFactor;\n"; + ss << " }\n"; + ss << " tmp = (i);\n"; + ss << " }\n"; + ss << " }\n"; + ss << " return tmp;\n"; + ss << "}"; +} + +void OpChiInv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl); + funs.insert(""); + decls.insert(fBigInvDecl); + funs.insert(""); + decls.insert(fHalfMachEpsDecl); + funs.insert(""); + decls.insert(lcl_IterateInverseChiInvDecl); + funs.insert(lcl_IterateInverseChiInv); + decls.insert(GetChiDistDecl); + funs.insert(GetChiDist); + decls.insert(lcl_HasChangeOfSignDecl); + funs.insert(lcl_HasChangeOfSign); + decls.insert(GetUpRegIGammaDecl); + funs.insert(GetUpRegIGamma); + decls.insert(GetGammaContFractionDecl); + funs.insert(GetGammaContFraction); + decls.insert(GetGammaSeriesDecl); + funs.insert(GetGammaSeries); +} +void OpChiInv::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp;\n"; + ss << " int gid0=get_global_id(0);\n"; + ss <<"\n "; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + ss << " tmp1 = floor(tmp1);"; + ss << " if (tmp1 < 1.0 || tmp0 <= 0.0 || tmp0 > 1.0 )\n"; + ss << " {\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " }\n"; + ss << " bool bConvError;\n"; + ss << " double fVal = lcl_IterateInverseChiInv"; + ss << "(tmp0, tmp1, tmp1*0.5, tmp1, &bConvError);\n"; + ss << " if(bConvError)\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << " return fVal;\n"; + ss << "}\n"; +} +void OpNormdist::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT(3,4); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "mue", 1, vSubArguments, ss ); + GenerateArg( "sigma", 2, vSubArguments, ss ); + GenerateArg( "c", 3, vSubArguments, ss ); + ss << "if(sigma <= 0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << "double mid,tmp;\n"; + ss << "mid = (x - mue)/sigma;\n"; + ss << "if(c)\n"; + ss << " tmp = 0.5 *erfc(-mid * 0.7071067811865475);\n"; + ss << "else \n"; + ss <<" tmp=(0.39894228040143268*exp(-pow(mid,2)/2.0))/sigma;\n"; + ss << "return tmp;\n"; + ss << "}\n"; +} +void OpNormsdist::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + ss << " double tmp = 0.5 * erfc((-1)*x * 0.7071067811865475);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpPermut::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + ss <<" double tmp = 1 ;\n"; + GenerateArg( "inA", 0, vSubArguments, ss ); + GenerateArg( "inB", 1, vSubArguments, ss ); + ss << " inA = floor( inA );\n"; + ss << " inB = floor( inB );\n"; + ss << " if (inA < 0.0 || inB < 0.0 || inB > inA)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " for( int i = 0; i<inB; i++)\n"; + ss << " {\n"; + ss << " tmp *= inA ;\n"; + ss << " inA = inA - 1.0;\n"; + ss << " }\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} +void OpPermutationA::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss <<" int gid0=get_global_id(0);\n"; + ss <<" double tmp = 1.0;\n"; + GenerateArg( "inA", 0, vSubArguments, ss ); + GenerateArg( "inB", 1, vSubArguments, ss ); + ss << " inA = floor( inA );\n"; + ss << " inB = floor( inB );\n"; + ss << " if (inA < 0.0 || inB < 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return pow(inA, inB);\n"; + ss << "}\n"; +} + +void OpPhi::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + ss << " double tmp = 0.39894228040143268 * exp((-1)*pow(x,2) / 2.0);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpNorminv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(gaussinvDecl); + funs.insert(gaussinv); +} + +void OpNorminv::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "mue", 1, vSubArguments, ss ); + GenerateArg( "sigma", 2, vSubArguments, ss ); + ss << " if (sigma <= 0.0 || x < 0.0 || x > 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else if (x == 0.0 || x == 1.0)\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " return gaussinv(x)*sigma + mue;\n"; + ss << "}\n"; +} + +void OpNormsinv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(gaussinvDecl); + funs.insert(gaussinv); +} + +void OpNormsinv:: GenSlidingWindowFunction + (outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + ss << " if (x < 0.0 || x > 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else if (x == 0.0 || x == 1.0)\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " return gaussinv(x);\n"; + ss << "}\n"; +} + +void OpLogInv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(gaussinvDecl); + funs.insert(gaussinv); +} + +void OpLogInv:: GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp;\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArgWithDefault( "mue", 1, 0, vSubArguments, ss ); + GenerateArgWithDefault( "sigma", 2, 1, vSubArguments, ss ); + ss << " if ( sigma <= 0.0 || x <= 0.0 || x >= 1.0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " return exp(mue+sigma*gaussinv(x));\n"; + ss << "}\n"; +} + +void OpLogNormDist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArgWithDefault( "mue", 1, 0, vSubArguments, ss ); + GenerateArgWithDefault( "sigma", 2, 1, vSubArguments, ss ); + GenerateArgWithDefault( "fCumulative", 3, 1, vSubArguments, ss ); + ss << " if (sigma <= 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double tmp;\n"; + ss << " double temp = (log(x)-mue)/sigma;\n"; + ss << " if(fCumulative != 0)\n"; + ss << " {\n"; + ss << " if(x<=0)\n"; + ss << " tmp = 0.0;\n"; + ss << " else\n"; + ss << " tmp = 0.5 * erfc(-temp * 0.7071067811865475);\n"; + ss << " }\n"; + ss << " else\n"; + ss << " if(x<=0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else\n"; + ss << " tmp = (0.39894228040143268 * exp((-1)*pow(temp, 2)"; + ss << " / 2.0))/(sigma*x);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} + +void OpGammaDist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fBigInvDecl);decls.insert(fLogDblMaxDecl); + decls.insert(fHalfMachEpsDecl);decls.insert(fMaxGammaArgumentDecl); + decls.insert(GetGammaSeriesDecl);decls.insert(GetGammaContFractionDecl); + decls.insert(GetLowRegIGammaDecl);decls.insert(GetGammaDistDecl); + decls.insert(GetGammaDistPDFDecl); + funs.insert(GetGammaSeries);funs.insert(GetGammaContFraction); + funs.insert(GetLowRegIGamma);funs.insert(GetGammaDist); + funs.insert(GetGammaDistPDF); +} + +void OpGammaDist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArgWithDefault( "arg3", 3, 1, vSubArguments, ss ); + ss << " if(arg1 <= 0 || arg2 <= 0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " double tmp;\n"; + ss << " if (arg3)\n"; + ss << " tmp=GetGammaDist( arg0, arg1, arg2);\n"; + ss << " else\n"; + ss << " tmp=GetGammaDistPDF( arg0, arg1, arg2);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} +void OpChiDist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fBigInvDecl); + funs.insert(""); + decls.insert(fHalfMachEpsDecl); + funs.insert(""); + decls.insert(GetUpRegIGammaDecl); + funs.insert(GetUpRegIGamma); + decls.insert(GetGammaSeriesDecl); + funs.insert(GetGammaSeries); + decls.insert(GetGammaContFractionDecl); + funs.insert(GetGammaContFraction); + decls.insert(GetChiDistDecl); + funs.insert(GetChiDist); +} +void OpChiDist::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double fx,fDF,tmp=0;\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + ss << " fx = tmp0;\n"; + ss << " fDF = floor(tmp1);\n"; + ss << " if(fDF < 1.0)\n"; + ss << " {\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " }\n"; + ss << " tmp = GetChiDist( fx, fDF);\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} +void OpBinomdist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl); + funs.insert(""); + decls.insert(MinDecl); + funs.insert(""); + decls.insert(fMaxGammaArgumentDecl); + funs.insert(""); + decls.insert(GetBinomDistPMFDecl); + funs.insert(GetBinomDistPMF); + decls.insert(GetBetaDistDecl); + funs.insert(GetBetaDist); + decls.insert(lcl_GetBinomDistRangeDecl); + funs.insert(lcl_GetBinomDistRange); + decls.insert(lcl_GetBetaHelperContFracDecl); + funs.insert(lcl_GetBetaHelperContFrac); + decls.insert(GetBetaDistPDFDecl); + funs.insert(GetBetaDistPDF); + decls.insert(GetLogBetaDecl); + funs.insert(GetLogBeta); + decls.insert(GetBetaDecl); + funs.insert(GetBeta); + decls.insert(lcl_getLanczosSumDecl); + funs.insert(lcl_getLanczosSum); +} +void OpBinomdist::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArg( "tmp2", 2, vSubArguments, ss ); + GenerateArg( "tmp3", 3, vSubArguments, ss ); + ss << " tmp0 = floor(tmp0);\n"; + ss << " tmp1 = floor(tmp1);\n"; + ss << " double rq = (0.5 - tmp2) + 0.5;\n"; + ss << " if (tmp1 < 0.0 || tmp0 < 0.0 || tmp0 > tmp1 ||"; + ss << "tmp2 < 0.0 || tmp2 > 1.0)\n"; + ss << " {\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " }\n"; + ss << " if(tmp2 == 0.0)\n"; + ss << " return ( (tmp0 == 0.0 || tmp3) ? 1.0 : 0.0 );\n"; + ss << " if(tmp2 == 1.0)\n"; + ss << " return ( (tmp0 == tmp1) ? 1.0 : 0.0);\n"; + ss << " if(!tmp3)\n"; + ss << " return ( GetBinomDistPMF(tmp0, tmp1, tmp2));\n"; + ss << " else \n"; + ss << " {\n"; + ss << " if(tmp0 == tmp1)\n"; + ss << " return 1.0;\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fFactor = pow(rq,tmp1);\n"; + ss << " if(tmp0 == 0.0)\n"; + ss << " return (fFactor);\n"; + ss << " else if(fFactor <= Min)\n"; + ss << " {\n"; + ss << " fFactor = pow(tmp2,tmp1);\n"; + ss << " if(fFactor <= Min)\n"; + ss << " return GetBetaDist"; + ss << "(rq, tmp1 - tmp0, tmp0 + 1.0);\n"; + ss << " else\n"; + ss << " {\n"; + ss << " if(fFactor > fMachEps)\n"; + ss << " {\n"; + ss << " double fSum = 1.0 - fFactor;\n"; + ss << " unsigned int max = "; + ss << "(unsigned int)((tmp1 - tmp0)-1);\n"; + ss << " for (uint i = 0; i < max && fFactor > 0.0;"; + ss << " i++)\n"; + ss << " {\n"; + ss << " fFactor *= (tmp1 - i)/(i + 1)*rq/tmp2;\n"; + ss << " fSum -= fFactor;\n"; + ss << " }\n"; + ss << " return ( (fSum < 0.0) ? 0.0 : fSum );\n"; + ss << " }\n"; + ss << " else \n"; + ss << " return (lcl_GetBinomDistRange"; + ss << "(tmp1, tmp1 - tmp0, tmp1, fFactor, rq, tmp2));\n"; + ss << " }\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double rtmp = ( lcl_GetBinomDistRange"; + ss << "(tmp1, 0.0, tmp0, fFactor, tmp2, rq));\n"; + ss << " return rtmp;\n"; + ss << " }\n"; + ss << " }\n"; + ss << " }\n"; + ss << "}\n"; +} + +void OpChiSqDist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMaxGammaArgumentDecl);decls.insert(GetChiSqDistCDFDecl); + decls.insert(GetChiSqDistPDFDecl);decls.insert(GetLowRegIGammaDecl); + decls.insert(GetGammaContFractionDecl);decls.insert(GetGammaSeriesDecl); + decls.insert(fHalfMachEpsDecl); + decls.insert(fBigInvDecl); + + funs.insert(GetGammaContFraction);funs.insert(GetChiSqDistCDF); + funs.insert(GetChiSqDistPDF);funs.insert(GetLowRegIGamma); + funs.insert(GetGammaSeries); +} + +void OpChiSqDist::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments & +vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double result = 0;\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArgWithDefault( "tmp2", 2, 1, vSubArguments, ss ); + ss << " tmp1 = floor(tmp1);\n"; + ss << " if(tmp1 < 1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else\n"; + ss << " {\n"; + ss << " if(tmp2)\n"; + ss << " result =GetChiSqDistCDF(tmp0,tmp1);\n"; + ss << " else\n"; + ss << " result =GetChiSqDistPDF(tmp0,tmp1);\n"; + ss << " }\n"; + ss << " return result;\n"; + ss << "}"; +} + + void OpChiSqInv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMaxGammaArgumentDecl);decls.insert(GetChiSqDistCDFDecl); + decls.insert(GetLowRegIGammaDecl);decls.insert(lcl_IterateInverseChiSQInvDecl); + decls.insert(GetGammaContFractionDecl);decls.insert(GetGammaSeriesDecl); + decls.insert(fHalfMachEpsDecl); + decls.insert(fBigInvDecl);decls.insert(lcl_HasChangeOfSignDecl); + decls.insert(fMachEpsDecl); + + funs.insert(GetGammaContFraction);funs.insert(GetChiSqDistCDF); + funs.insert(GetLowRegIGamma);funs.insert(lcl_HasChangeOfSign); + funs.insert(GetGammaSeries);funs.insert(lcl_IterateInverseChiSQInv); +} + +void OpChiSqInv::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments & +vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double result = 0;\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + ss << " tmp1 = floor(tmp1);\n"; + ss << " bool bConvError;\n"; + ss << " if(tmp1 < 1.0 || tmp0 < 0 || tmp0>=1.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " else\n"; + ss << " {\n"; + ss << " result =lcl_IterateInverseChiSQInv( tmp0, tmp1,"; + ss << "tmp1*0.5, tmp1, &bConvError );\n"; + ss << " }\n"; + ss << " if(bConvError)\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << " return result;\n"; + ss << "}"; +} + +void OpGammaInv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fBigInvDecl);decls.insert(fHalfMachEpsDecl); + decls.insert(GetGammaSeriesDecl);decls.insert(GetGammaContFractionDecl); + decls.insert(GetGammaInvValueDecl); + funs.insert(GetGammaSeries);funs.insert(GetGammaContFraction); + funs.insert(GetGammaInvValue); +} + +void OpGammaInv::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp;\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + ss << " if( arg0 < 0 || arg0 >= 1 || arg1 <= 0 || arg2 <= 0 )\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if (arg0 == 0.0)\n" + " {\n" + " tmp=0.0;\n" + " return tmp;\n" + " }\n" + " else\n" + " {\n" + " bool bConvError;\n" + " double fStart = arg1 * arg2;\n" + " double fAx=fStart*0.5;\n" + " double fBx=fStart;\n" + " bConvError = false;\n" + " double fYEps = 1.0E-307;\n" + " double fXEps = 2.22045e-016;\n" + " double fAy = arg0-GetGammaInvValue(arg1,arg2,fAx);\n" + " double fBy = arg0-GetGammaInvValue(arg1,arg2,fBx);\n" + " double fTemp;\n" + " unsigned short nCount;\n" + " for (nCount = 0; nCount < 1000 && !((fAy < 0.0 && fBy > 0.0)" + " || (fAy > 0.0 && fBy < 0.0)); nCount++)\n" + " {\n" + " if (fabs(fAy) <= fabs(fBy))\n" + " {\n" + " fTemp = fAx;\n" + " fAx += 2.0 * (fAx - fBx);\n" + " if (fAx < 0.0)\n" + " fAx = 0.0;\n" + " fBx = fTemp;\n" + " fBy = fAy;\n" + " fAy = arg0-GetGammaInvValue(arg1,arg2,fAx);\n" + " }\n" + " else\n" + " {\n" + " fTemp = fBx;\n" + " fBx += 2.0 * (fBx - fAx);\n" + " fAx = fTemp;\n" + " fAy = fBy;\n" + " fBy = arg0-GetGammaInvValue(arg1,arg2,fBx);\n" + " }\n" + " }\n" + " if (fAy == 0.0)\n" + " {\n" + " tmp = fAx;\n" + " return tmp;\n" + " }\n" + " if (fBy == 0.0)\n" + " {\n" + " tmp = fBx;\n" + " return tmp;\n" + " }\n" + " if (!((fAy < 0.0 && fBy > 0.0) || (fAy > 0.0 && fBy < 0.0)))\n" + " {\n" + " bConvError = true;\n" + " tmp = 0.0;\n" + " return tmp;\n" + " }\n" + " double fPx = fAx;\n" + " double fPy = fAy;\n" + " double fQx = fBx;\n" + " double fQy = fBy;\n" + " double fRx = fAx;\n" + " double fRy = fAy;\n" + " double fSx = 0.5 * (fAx + fBx);\n" + " bool bHasToInterpolate = true;\n" + " nCount = 0;\n" + " while ( nCount < 500 && fabs(fRy) > fYEps &&" + "(fBx-fAx) > fmax( fabs(fAx), fabs(fBx)) * fXEps )\n" + " {\n" + " if (bHasToInterpolate)\n" + " {\n" + " if (fPy!=fQy && fQy!=fRy && fRy!=fPy)\n" + " {\n" + " fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy)" + "+ fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy)" + "+ fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy);\n" + " bHasToInterpolate = (fAx < fSx) && (fSx < fBx);\n" + " }\n" + " else\n" + " bHasToInterpolate = false;\n" + " }\n" + " if(!bHasToInterpolate)\n" + " {\n" + " fSx = 0.5 * (fAx + fBx);\n" + " fPx = fAx; fPy = fAy;\n" + " fQx = fBx; fQy = fBy;\n" + " bHasToInterpolate = true;\n" + " }\n" + " fPx = fQx; fQx = fRx; fRx = fSx;\n" + " fPy = fQy; fQy = fRy;\n" + " fRy = arg0-GetGammaInvValue(arg1,arg2,fSx);\n" + " if ((fAy < 0.0 && fRy > 0.0) || (fAy > 0.0 && fRy < 0.0))\n" + " {\n" + " fBx = fRx;\n" + " fBy = fRy;\n" + " }\n" + " else\n" + " {\n" + " fAx = fRx;\n" + " fAy = fRy;\n" + " }\n" + " bHasToInterpolate = bHasToInterpolate && (fabs(fRy)" + " * 2.0 <= fabs(fQy));\n" + " ++nCount;\n" + " }\n" + " tmp = fRx;\n" + " return tmp;\n" + " }\n" + "}\n"; +} +void OpFInv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl);decls.insert(fMaxGammaArgumentDecl); + decls.insert(lcl_getLanczosSumDecl);decls.insert(GetBetaDecl); + decls.insert(GetLogBetaDecl);decls.insert(GetBetaDistPDFDecl); + decls.insert(lcl_GetBetaHelperContFracDecl);decls.insert(GetFInvValueDecl); + funs.insert(lcl_getLanczosSum);funs.insert(GetBeta); + funs.insert(GetLogBeta);funs.insert(GetBetaDistPDF); + funs.insert(lcl_GetBetaHelperContFrac);funs.insert(GetFInvValue); +} + +void OpFInv::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp;\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + ss << " double fF2=floor(arg2);\n" + " double fF1=floor(arg1);\n" + " if( arg0 <= 0 || arg1 < 1 || arg2 < 1 || arg1 >= 1.0e10 || arg2 >= 1.0e10 || arg0 > 1 )\n" + " return CreateDoubleError(IllegalArgument);\n" + " double fAx=fF1*0.5;\n" + " double fBx=fF1;\n" + " const double fYEps = 1.0E-307;\n" + " const double fXEps = 2.22045e-016;\n" + " double fAy = arg0-GetFInvValue(fF1,fF2,fAx);\n" + " double fBy = arg0-GetFInvValue(fF1,fF2,fBx);\n" + " double fTemp;\n" + " unsigned short nCount;\n" + " for (nCount = 0; nCount < 1000 && !((fAy < 0.0 && fBy > 0.0)" + " || (fAy > 0.0 && fBy < 0.0)); nCount++)\n" + " {\n" + " if (fabs(fAy) <= fabs(fBy))\n" + " {\n" + " fTemp = fAx;\n" + " fAx += 2.0 * (fAx - fBx);\n" + " if (fAx < 0.0)\n" + " fAx = 0.0;\n" + " fBx = fTemp;\n" + " fBy = fAy;\n" + " fAy = arg0-GetFInvValue(fF1,fF2,fAx);\n" + " }\n" + " else\n" + " {\n" + " fTemp = fBx;\n" + " fBx += 2.0 * (fBx - fAx);\n" + " fAx = fTemp;\n" + " fAy = fBy;\n" + " fBy = arg0-GetFInvValue(fF1,fF2,fBx);\n" + " }\n" + " }\n" + " if (fAy == 0.0)\n" + " {\n" + " tmp = fAx;\n" + " return tmp;\n" + " }\n" + " if (fBy == 0.0)\n" + " {\n" + " tmp = fBx;\n" + " return tmp;\n" + " }\n" + " if (!((fAy < 0.0 && fBy > 0.0) || (fAy > 0.0 && fBy < 0.0)))\n" + " return CreateDoubleError(NoConvergence);\n" + " double fPx = fAx;\n" + " double fPy = fAy;\n" + " double fQx = fBx;\n" + " double fQy = fBy;\n" + " double fRx = fAx;\n" + " double fRy = fAy;\n" + " double fSx = 0.5 * (fAx + fBx);\n" + " bool bHasToInterpolate = true;\n" + " nCount = 0;\n" + " while ( nCount < 500 && fabs(fRy) > fYEps &&" + "(fBx-fAx) > fmax( fabs(fAx), fabs(fBx)) * fXEps )\n" + " {\n" + " if (bHasToInterpolate)\n" + " {\n" + " if (fPy!=fQy && fQy!=fRy && fRy!=fPy)\n" + " {\n" + " fSx = fPx * fRy * fQy / (fRy-fPy)" + " / (fQy-fPy)+fRx * fQy * fPy / (fQy-fRy)" + " / (fPy-fRy)+ fQx * fPy * fRy / (fPy-fQy)" + " / (fRy-fQy);\n" + " bHasToInterpolate = (fAx < fSx) && (fSx < fBx);\n" + " }\n" + " else\n" + " bHasToInterpolate = false;\n" + " }\n" + " if(!bHasToInterpolate)\n" + " {\n" + " fSx = 0.5 * (fAx + fBx);\n" + " fPx = fAx; fPy = fAy;\n" + " fQx = fBx; fQy = fBy;\n" + " bHasToInterpolate = true;\n" + " }\n" + " fPx = fQx; fQx = fRx; fRx = fSx;\n" + " fPy = fQy; fQy = fRy;\n" + " fRy = arg0-GetFInvValue(fF1,fF2,fSx);\n" + " if ((fAy < 0.0 && fRy > 0.0) || (fAy > 0.0 && fRy < 0.0))\n" + " {\n" + " fBx = fRx; fBy = fRy;\n" + " }\n" + " else\n" + " {\n" + " fAx = fRx; fAy = fRy;\n" + " }\n" + " bHasToInterpolate = bHasToInterpolate && (fabs(fRy)" + " * 2.0 <= fabs(fQy));\n" + " ++nCount;\n" + " }\n" + " tmp = fRx;\n" + " return tmp;" + "}"; +} +void OpFTest::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl);decls.insert(fMaxGammaArgumentDecl); + decls.insert(lcl_getLanczosSumDecl);decls.insert(GetBetaDecl); + decls.insert(GetLogBetaDecl);decls.insert(GetBetaDistPDFDecl); + decls.insert(lcl_GetBetaHelperContFracDecl);decls.insert(GetBetaDistDecl); + decls.insert(GetFDistDecl); + funs.insert(lcl_getLanczosSum);funs.insert(GetBeta); + funs.insert(GetLogBeta);funs.insert(GetBetaDistPDF); + funs.insert(lcl_GetBetaHelperContFrac);funs.insert(GetBetaDist); + funs.insert(GetFDist); +} +void OpFTest::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSum1 = 0.0;\n"; + ss << " double fSumSqr1 = 0.0;\n"; + ss << " double fSum2 = 0.0;\n"; + ss << " double fSumSqr2 = 0.0;\n"; + ss << " double fLength1 = 0.0;\n"; + ss << " double fLength2 = 0.0;\n"; + ss << " double tmp = 0;\n"; + GenerateRangeArg( 0, vSubArguments, ss, SkipEmpty, + " fSum1 += arg;\n" + " fSumSqr1 += arg * arg;\n" + " fLength1 += 1;\n" + ); + GenerateRangeArg( 1, vSubArguments, ss, SkipEmpty, + " fSum2 += arg;\n" + " fSumSqr2 += arg * arg;\n" + " fLength2 += 1;\n" + ); + ss << " if(fLength1 < 2 || fLength2 < 2)\n" + " return CreateDoubleError(NoValue);\n" + " double fS1 = (fSumSqr1-fSum1*fSum1/fLength1)/(fLength1-1.0);\n" + " double fS2 = (fSumSqr2-fSum2*fSum2/fLength2)/(fLength2-1.0);\n" + " if(fS1 == 0 || fS2 == 0)\n" + " return CreateDoubleError(NoValue);\n" + " double fF, fF1, fF2;\n" + " if (fS1 > fS2)\n" + " {\n" + " fF = fS1/fS2;\n" + " fF1 = fLength1-1.0;\n" + " fF2 = fLength2-1.0;\n" + " }\n" + " else\n" + " {\n" + " fF = fS2/fS1;\n" + " fF1 = fLength2-1.0;\n" + " fF2 = fLength1-1.0;\n" + " }\n" + " double fFcdf = GetFDist(fF, fF1, fF2);\n" + " return 2.0*min(fFcdf, 1 - fFcdf);\n"; + ss << "}"; +} +void OpB::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + //decls.insert(fBigInvDecl);decls.insert(fLogDblMaxDecl); + decls.insert(GetBinomDistPMFDecl);decls.insert(MinDecl); + decls.insert(fMachEpsDecl);decls.insert(fMaxGammaArgumentDecl); + decls.insert(GetBetaDistDecl);decls.insert(GetBetaDistPDFDecl); + decls.insert(lcl_GetBetaHelperContFracDecl);decls.insert(GetLogBetaDecl); + decls.insert(lcl_getLanczosSumDecl); decls.insert(GetBetaDecl); + funs.insert(GetBinomDistPMF);funs.insert(lcl_GetBinomDistRange); + funs.insert(GetBetaDist);funs.insert(GetBetaDistPDF); + funs.insert(lcl_GetBetaHelperContFrac);funs.insert(GetLogBeta); + funs.insert(lcl_getLanczosSum);funs.insert(GetBeta); +} + +void OpB::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 4 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double min = 2.22507e-308;\n"; + ss << " double tmp;\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArg( 3, vSubArguments, ss ); + ss << " double rxs = floor(arg2);\n" + " double rxe = floor(arg3);\n" + " double rn = floor(arg0);\n" + " double rq = (0.5 - arg1) + 0.5;\n" + " bool bIsValidX = (0.0 <= rxs && rxs <= rxe && rxe <= rn);\n" + " if (bIsValidX && 0.0 < arg1 && arg1 < 1.0)\n" + " {\n" + " if (rxs == rxe)\n" + " tmp = GetBinomDistPMF(rxs, rn, arg1);\n" + " else\n" + " {\n" + " double fFactor = pow(rq, rn);\n" + " if (fFactor > min)\n" + " tmp =" + " lcl_GetBinomDistRange(rn, rxs, rxe, fFactor, arg1, rq);\n" + " else\n" + " {\n" + " fFactor = pow(arg1, rn);\n" + " if (fFactor > min)\n" + " {\n" + " tmp =" + "lcl_GetBinomDistRange(rn, rn - rxe, rn - rxs, fFactor, rq, arg1);\n" + " }\n" + " else\n" + " tmp =" + "GetBetaDist(rq, rn - rxe, rxe + 1.0)" + "- GetBetaDist(rq, rn - rxs + 1, rxs);\n" + " }\n" + " }\n" + " }\n" + " else\n" + " {\n" + " if (bIsValidX)\n" + " {\n" + " if (arg1 == 0.0)\n" + " tmp = (rxs == 0.0 ? 1.0 : 0.0);\n" + " else if (arg1 == 1.0)\n" + " tmp = (rxe == rn ? 1.0 : 0.0);\n" + " else\n" + " {\n" + " tmp = DBL_MIN;\n" + " }\n" + " }\n" + " else\n" + " {\n" + " tmp = DBL_MIN;\n" + " }\n" + " }\n" + " return tmp;" + "}\n"; +} +void OpBetaDist::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl);decls.insert(fMaxGammaArgumentDecl); + decls.insert(GetBetaDistDecl);decls.insert(GetBetaDistPDFDecl); + decls.insert(lcl_GetBetaHelperContFracDecl);decls.insert(GetLogBetaDecl); + decls.insert(GetBetaDecl);decls.insert(lcl_getLanczosSumDecl); + funs.insert(GetBetaDist);funs.insert(GetBetaDistPDF); + funs.insert(lcl_GetBetaHelperContFrac);funs.insert(GetLogBeta); + funs.insert(GetBeta);funs.insert(lcl_getLanczosSum); +} +void OpPoisson::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fHalfMachEpsDecl); + funs.insert(""); + decls.insert(fMaxGammaArgumentDecl); + funs.insert(""); + decls.insert(fBigInvDecl); + funs.insert(""); + decls.insert(GetLogGammaDecl); + funs.insert(GetLogGamma); + decls.insert(lcl_GetLogGammaHelperDecl); + funs.insert(lcl_GetLogGammaHelper); + decls.insert(lcl_GetGammaHelperDecl); + funs.insert(lcl_GetGammaHelper); + decls.insert(lcl_getLanczosSumDecl); + funs.insert(lcl_getLanczosSum); + decls.insert(GetUpRegIGammaDecl); + funs.insert(GetUpRegIGamma); + decls.insert(GetGammaContFractionDecl); + funs.insert(GetGammaContFraction); + decls.insert(GetGammaSeriesDecl); + funs.insert(GetGammaSeries); +} +void OpPoisson::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 3 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " double tmp;\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "lambda", 1, vSubArguments, ss ); + GenerateArgWithDefault( "bCumulative", 2, 1, vSubArguments, ss ); + ss << " x = floor(x);\n"; + ss << " if (lambda <= 0.0 || x < 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " if (!bCumulative)\n"; + ss << " {\n"; + ss << " if(lambda == 0.0)\n"; + ss << " {\n"; + ss << " return 0;\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " if (lambda >712)\n"; + ss << " {\n"; + ss << " tmp = (exp(x*log(lambda)-lambda-GetLogGamma(x+1.0)));\n"; + ss << " return tmp;\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fPoissonVar = 1.0;\n"; + ss << " for ( int f = 0; f < x; ++f )\n"; + ss << " fPoissonVar *= lambda / ( (double)f + 1.0 );\n"; + ss << " tmp = ( fPoissonVar * exp( -lambda ) );\n"; + ss << " return tmp;\n"; + ss << " }\n"; + ss << " }\n"; + ss << " } \n"; + ss << " else\n"; + ss << " {\n"; + ss << " if (lambda == 0.0)\n"; + ss << " {\n"; + ss << " return 1;\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " if (lambda > 712 )\n"; + ss << " {\n"; + ss << " tmp = (GetUpRegIGamma(x+1.0,lambda));\n"; + ss << " return tmp;\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " if (x >= 936.0)\n"; + ss << " {\n"; + ss << " return 1;\n"; + ss << " }\n"; + ss << " else\n"; + ss << " {\n"; + ss << " double fSummand = exp(-lambda);\n"; + ss << " double fSum = fSummand;\n"; + ss << " int nEnd = (int) (x + 0.5);\n"; + ss << " for (int i = 1; i <= nEnd; i++)\n"; + ss << " {\n"; + ss << " fSummand = (fSummand*lambda)/((double)i);\n"; + ss << " fSum += fSummand;\n"; + ss << " }\n"; + ss << " tmp = fSum;\n"; + ss << " return tmp;\n"; + ss << " }\n"; + ss << " }\n"; + ss << " }\n"; + ss << " }\n"; + ss << "}\n"; +} + +void OpBetaDist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 6 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + ss << " double tmp;\n"; + GenerateArg( 0, vSubArguments, ss ); + GenerateArg( 1, vSubArguments, ss ); + GenerateArg( 2, vSubArguments, ss ); + GenerateArgWithDefault( "arg3", 3, 0, vSubArguments, ss ); + GenerateArgWithDefault( "arg4", 4, 1, vSubArguments, ss ); + GenerateArgWithDefault( "arg5", 5, 1, vSubArguments, ss ); + ss << " double fScale = arg4 - arg3;\n" + " if (fScale <= 0.0 || arg1 <= 0.0 || arg2 <= 0.0)\n" + " return CreateDoubleError(IllegalArgument);\n" + " if (arg5)\n" + " {\n" + " if (arg0< arg3)\n" + " {\n" + " tmp = 0.0;\n" + " return tmp;\n" + " }\n" + " if (arg0 > arg4)\n" + " {\n" + " tmp = 1.0;\n" + " return tmp;\n" + " }\n" + " arg0 = (arg0-arg3)/fScale;\n" + " tmp = GetBetaDist(arg0, arg1, arg2);\n" + " }\n" + " else\n" + " {\n" + " if (arg0 < arg3 || arg0 > arg4 )\n" + " {\n" + " tmp = 0.0;\n" + " return tmp;\n" + " }\n" + " arg0 = (arg0 - arg3)/fScale;\n" + " tmp = GetBetaDistPDF(arg0, arg1, arg2)/fScale;\n" + " }\n"; + ss << " return tmp;\n"; + ss << "}\n"; +} +void OpBetainv::BinInlineFun(std::set<std::string>& decls, + std::set<std::string>& funs) +{ + decls.insert(fMachEpsDecl); + funs.insert(""); + decls.insert(fMaxGammaArgumentDecl); + funs.insert(""); + decls.insert(lcl_IterateInverseBetaInvDecl); + funs.insert(lcl_IterateInverseBetaInv); + decls.insert(GetBetaDistDecl); + funs.insert(GetBetaDist); + decls.insert(lcl_HasChangeOfSignDecl); + funs.insert(lcl_HasChangeOfSign); + decls.insert(lcl_HasChangeOfSignDecl); + funs.insert(lcl_HasChangeOfSign); + decls.insert(lcl_HasChangeOfSignDecl); + funs.insert(lcl_HasChangeOfSign); + decls.insert(lcl_GetBetaHelperContFracDecl); + funs.insert(lcl_GetBetaHelperContFrac); + decls.insert(GetBetaDistPDFDecl); + funs.insert(GetBetaDistPDF); + decls.insert(GetLogBetaDecl); + funs.insert(GetLogBeta); + decls.insert(GetBetaDecl); + funs.insert(GetBeta); + decls.insert(lcl_getLanczosSumDecl); + funs.insert(lcl_getLanczosSum); +} +void OpBetainv::GenSlidingWindowFunction( + outputstream &ss,const std::string &sSymName, + SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "tmp0", 0, vSubArguments, ss ); + GenerateArg( "tmp1", 1, vSubArguments, ss ); + GenerateArg( "tmp2", 2, vSubArguments, ss ); + GenerateArgWithDefault( "tmp3", 3, 0, vSubArguments, ss ); + GenerateArgWithDefault( "tmp4", 4, 1, vSubArguments, ss ); + ss << " if (tmp0 < 0.0 || tmp0 > 1.0 ||"; + ss << "tmp3 >= tmp4 || tmp1 <= 0.0 || tmp2 <= 0.0)\n"; + ss << " {\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + ss << " }\n"; + ss << " bool bConvError;\n"; + ss << " double fVal = lcl_IterateInverseBetaInv"; + ss << "(tmp0, tmp1, tmp2, 0.0, 1.0, &bConvError);\n"; + ss << " if(bConvError)\n"; + ss << " return CreateDoubleError(NoConvergence);\n"; + ss << " return (tmp3 + fVal*(tmp4 - tmp3));\n"; + ss << "}\n"; +} +void OpDevSq::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double vSum = 0.0;\n"; + ss << " double vMean = 0.0;\n"; + ss << " int cnt = 0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " vSum += arg;\n" + " ++cnt;\n" + ); + ss << " vMean = vSum / cnt;\n"; + ss << " vSum = 0.0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " vSum += ( arg - vMean ) * ( arg - vMean );\n" + ); + ss << " return vSum;\n"; + ss << "}\n"; +} + +void OpHypGeomDist::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 4, 5 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0=get_global_id(0);\n"; + GenerateArg( "x", 0, vSubArguments, ss ); + GenerateArg( "n", 1, vSubArguments, ss ); + GenerateArg( "M", 2, vSubArguments, ss ); + GenerateArg( "N", 3, vSubArguments, ss ); + GenerateArgWithDefault( "fCumulative", 4, 0, vSubArguments, ss ); + ss << + " x = floor(x);\n" + " n = floor(n);\n" + " M = floor(M);\n" + " N = floor(N);\n" + " double num[9];\n" + " double tmp = 0;\n" + " if( (x < 0.0) || (n < x) || (N < n) ||" + "(N < M) || (M < 0.0) )\n" + " {\n" + " return CreateDoubleError(IllegalArgument);\n" + " }\n" + " for(int i = (fCumulative ? 0 : x); i <= x; ++i )\n" + " {\n" + " if( (M < i) || (i < n - N + M) )\n" + " continue;\n" + " num[0]=M;\n" + " num[1]=i;\n" + " num[2]=M-i;\n" + " num[3]=N-M;\n" + " num[4]=n-i;\n" + " num[5]=N-M-n+i;\n" + " num[6]=N;\n" + " num[7]=n;\n" + " num[8]=N-n;\n" + " for(int i=0;i<9;i++)\n" + " {\n" + " if(num[i]<171)\n" + " {\n" + " if(num[i]==0)\n" + " num[i]=0;\n" + " else\n" + " num[i]=log(tgamma(num[i])*num[i]);\n" + " }\n" + " else\n" + " num[i]=0.5*log(2.0*M_PI)+(num[i]+0.5)*log(num[i])-num[i]+\n" + " (1.0/(12.0*num[i])-1.0/(360*pow(num[i],3)));\n" + " }\n" + " tmp+=pow(M_E,(num[0]+num[3]+num[7]+num[8]-num[1]-num[2]-num[4]-num[5]-num[6]));\n" + " }\n" + " return tmp;\n"; + ss << "}\n"; +} + +void OpAveDev:: GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double sum=0.0;\n"; + ss << " double totallength=0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " sum += arg;\n" + " ++totallength;\n" + ); + ss << " double mean = sum / totallength;\n"; + ss << " sum = 0.0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " sum += fabs(arg-mean);\n" + ); + ss << " return sum/totallength;\n"; + ss << "}"; +} + +// Block of functions OpCovar-OpRsq that are rather similar. + +void OpCovar::GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSumX = 0.0;\n"; + ss << " double fSumY = 0.0;\n"; + ss << " double fMeanX = 0.0;\n"; + ss << " double fMeanY = 0.0;\n"; + ss << " double fSumDeltaXDeltaY = 0.0;\n"; + ss << " double fCount = 0.0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " fSumX += arg1;\n" + " fSumY += arg2;\n" + " fCount += 1.0;\n" + ); + ss << " if( fCount < 1 )\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " fMeanX = fSumX / fCount;\n"; + ss << " fMeanY = fSumY / fCount;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " fSumDeltaXDeltaY +=(arg1-fMeanX)*(arg2-fMeanY);\n" + ); + ss << " return fSumDeltaXDeltaY / fCount;\n"; + ss << "}\n"; +} + +void OpForecast::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 3, 3 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 2 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSumX = 0.0;\n"; + ss << " double fSumY = 0.0;\n"; + ss << " double fMeanX = 0.0;\n"; + ss << " double fMeanY = 0.0;\n"; + ss << " double fSumDeltaXDeltaY = 0.0;\n"; + ss << " double fSumSqrDeltaX = 0.0;\n"; + ss << " double fCount = 0.0;\n"; + GenerateArg( "arg0", 0, vSubArguments, ss ); + GenerateRangeArgPair( 1, 2, vSubArguments, ss, SkipEmpty, + // note that arg1 -> Y, arg2 -> X + " fSumX += arg2;\n" + " fSumY += arg1;\n" + " fCount += 1.0;\n" + ); + ss << " if( fCount < 1 )\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " fMeanX = fSumX / fCount;\n"; + ss << " fMeanY = fSumY / fCount;\n"; + GenerateRangeArgPair( 1, 2, vSubArguments, ss, SkipEmpty, + " fSumDeltaXDeltaY +=(arg2-fMeanX)*(arg1-fMeanY);\n" + " fSumSqrDeltaX += (arg2-fMeanX)*(arg2-fMeanX);\n" + ); + ss << " if(fSumSqrDeltaX == 0.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " return fMeanY + fSumDeltaXDeltaY / fSumSqrDeltaX * (arg0 - fMeanX);\n"; + ss << "}\n"; +} + +void OpInterceptSlopeBase::GenerateCode( outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments, const char* finalComputeCode ) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSumX = 0.0;\n"; + ss << " double fSumY = 0.0;\n"; + ss << " double fMeanX = 0.0;\n"; + ss << " double fMeanY = 0.0;\n"; + ss << " double fSumDeltaXDeltaY = 0.0;\n"; + ss << " double fSumSqrDeltaX = 0.0;\n"; + ss << " double fCount = 0.0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + // note that arg1 -> Y, arg2 -> X + " fSumX += arg2;\n" + " fSumY += arg1;\n" + " fCount += 1.0;\n" + ); + ss << " if( fCount < 1 )\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " fMeanX = fSumX / fCount;\n"; + ss << " fMeanY = fSumY / fCount;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " fSumDeltaXDeltaY +=(arg2-fMeanX)*(arg1-fMeanY);\n" + " fSumSqrDeltaX += (arg2-fMeanX)*(arg2-fMeanX);\n" + ); + ss << finalComputeCode; + ss << "}\n"; +} + +void OpIntercept::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments, + " if(fSumSqrDeltaX == 0.0)\n" + " return CreateDoubleError(DivisionByZero);\n" + " return fMeanY - (fSumDeltaXDeltaY/fSumSqrDeltaX)*fMeanX;\n" + ); +} + +void OpSlope::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments, + " if(fSumSqrDeltaX == 0.0)\n" + " return CreateDoubleError(DivisionByZero);\n" + " return fSumDeltaXDeltaY / fSumSqrDeltaX;\n" + ); +} + +void OpPearsonCovarBase::GenerateCode( outputstream &ss, const std::string &sSymName, + SubArguments &vSubArguments, double minimalCountValue, const char* finalComputeCode ) +{ + CHECK_PARAMETER_COUNT( 2, 2 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 0 ); + CHECK_PARAMETER_DOUBLEVECTORREF( 1 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSumX = 0.0;\n"; + ss << " double fSumY = 0.0;\n"; + ss << " double fMeanX = 0.0;\n"; + ss << " double fMeanY = 0.0;\n"; + ss << " double fSumDeltaXDeltaY = 0.0;\n"; + ss << " double fSumSqrDeltaX = 0.0;\n"; + ss << " double fSumSqrDeltaY = 0.0;\n"; + ss << " double fCount = 0.0;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + // note that arg1 -> Y, arg2 -> X + " fSumX += arg2;\n" + " fSumY += arg1;\n" + " fCount += 1.0;\n" + ); + ss << " if( fCount < " << minimalCountValue <<" )\n"; + ss << " return CreateDoubleError(NoValue);\n"; + ss << " fMeanX = fSumX / fCount;\n"; + ss << " fMeanY = fSumY / fCount;\n"; + GenerateRangeArgPair( 0, 1, vSubArguments, ss, SkipEmpty, + " fSumDeltaXDeltaY +=(arg2-fMeanX)*(arg1-fMeanY);\n" + " fSumSqrDeltaX += (arg2-fMeanX)*(arg2-fMeanX);\n" + " fSumSqrDeltaY += (arg1-fMeanY)*(arg1-fMeanY);\n" + ); + ss << finalComputeCode; + ss << "}\n"; +} + +void OpPearson::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments, 1, + " if (fSumSqrDeltaX == 0 || fSumSqrDeltaY == 0)\n" + " return CreateDoubleError(DivisionByZero);\n" + " return ( fSumDeltaXDeltaY / sqrt( fSumSqrDeltaX * fSumSqrDeltaY));\n" + ); +} + +void OpSTEYX::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments, 3, + " if(fSumSqrDeltaX == 0.0)\n" + " return CreateDoubleError(DivisionByZero);\n" + " return sqrt((fSumSqrDeltaY - fSumDeltaXDeltaY * \n" + " fSumDeltaXDeltaY / fSumSqrDeltaX)\n" + " /(fCount - 2.0));\n" + ); +} + +void OpRsq::GenSlidingWindowFunction( + outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + // This is basically pow(OpPearson,2) + GenerateCode( ss, sSymName, vSubArguments, 1, + " if (fSumSqrDeltaX == 0 || fSumSqrDeltaY == 0)\n" + " return CreateDoubleError(DivisionByZero);\n" + " return ( fSumDeltaXDeltaY * fSumDeltaXDeltaY / (fSumSqrDeltaX * fSumSqrDeltaY));\n" + ); +} + +void OpVarStDevBase::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(is_representable_integerDecl); + funs.insert(is_representable_integer); + decls.insert(approx_equalDecl); + funs.insert(approx_equal); + decls.insert(fsub_approxDecl); + funs.insert(fsub_approx); +} + +void OpVarStDevBase::GenerateCode(outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) +{ + CHECK_PARAMETER_COUNT( 1, 30 ); + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; // this must be matched by whoever calls this function + ss << " int gid0 = get_global_id(0);\n"; + ss << " double fSum = 0.0;\n"; + ss << " double fCount = 0.0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " fSum += arg;\n" + " fCount += 1.0;\n" + ); + ss << " if (fCount == 0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " double fMean = fSum / fCount;\n"; + ss << " double vSum = 0.0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " vSum += pown( fsub_approx(arg, fMean), 2 );\n" + ); +} + +void OpVar::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if (fCount <= 1.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " else\n"; + ss << " return vSum / (fCount - 1.0);\n"; + ss << "}\n"; +} + +void OpVarP::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if (fCount == 0.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " else\n"; + ss << " return vSum / fCount;\n"; + ss << "}\n"; +} + +void OpStDev::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if (fCount <= 1.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " else\n"; + ss << " return sqrt(vSum / (fCount - 1.0));\n"; + ss << "}\n"; +} + +void OpStDevP::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if (fCount <= 0.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " else\n"; + ss << " return sqrt(vSum / fCount);\n"; + ss << "}\n"; +} + +void OpSkew::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if(fCount <= 2.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " double fStdDev = sqrt(vSum / (fCount - 1.0));\n"; + ss << " double dx = 0.0;\n"; + ss << " double xcube = 0.0;\n"; + ss << " if(fStdDev == 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " dx = fsub_approx(arg, fMean) / fStdDev;\n" + " xcube = xcube + dx * dx * dx;\n" + ); + ss << " return ((xcube * fCount) / (fCount - 1.0)) / (fCount - 2.0);\n"; + ss << "}\n"; +} + +void OpSkewp::GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if(fCount <= 2.0)\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " double fStdDev = sqrt(vSum / fCount);\n"; + ss << " double dx = 0.0;\n"; + ss << " double xcube = 0.0;\n"; + ss << " if(fStdDev == 0.0)\n"; + ss << " return CreateDoubleError(IllegalArgument);\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " dx = fsub_approx(arg, fMean) / fStdDev;\n" + " xcube = xcube + dx * dx * dx;\n" + ); + ss << " return xcube / fCount;\n"; + ss << "}\n"; +} + +void OpKurt:: GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) +{ + GenerateCode( ss, sSymName, vSubArguments ); + ss << " if( fCount < 4 )\n"; + ss << " return CreateDoubleError(DivisionByZero);\n"; + ss << " double fStdDev = sqrt(vSum / (fCount - 1.0));\n"; + ss << " double dx = 0.0;\n"; + ss << " double xpower4 = 0.0;\n"; + GenerateRangeArgs( vSubArguments, ss, SkipEmpty, + " dx = (arg -fMean) / fStdDev;\n" + " xpower4 = xpower4 + (dx * dx * dx * dx);\n" + ); + ss<< " double k_d = (fCount - 2.0) * (fCount - 3.0);\n"; + ss<< " double k_l = fCount * (fCount + 1.0) / ((fCount - 1.0) * k_d);\n"; + ss<< " double k_t = 3.0 * (fCount - 1.0) * (fCount - 1.0) / k_d;\n"; + ss<< " return xpower4 * k_l - k_t;\n"; + ss << "}"; +} + +void OpMin::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(fmin_countDecl); + funs.insert(fmin_count); +} + +void OpMax::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(fmax_countDecl); + funs.insert(fmax_count); +} + +void OpAverage::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) +{ + decls.insert(fsum_countDecl); + funs.insert(fsum_count); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_statistical.hxx b/sc/source/core/opencl/op_statistical.hxx new file mode 100644 index 0000000000..827c6a0456 --- /dev/null +++ b/sc/source/core/opencl/op_statistical.hxx @@ -0,0 +1,632 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "opbase.hxx" +#include "utils.hxx" + +namespace sc::opencl { + +class OpStandard: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Standard"; } +}; +class OpExponDist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "ExponDist"; } +}; +class OpZTest: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "ZTest"; } +}; +class OpWeibull: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Weibull"; } +}; +class OpFdist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "Fdist"; } +}; +class OpTDist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "TDist"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; +}; +class OpTInv: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "TInv"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; +}; +class OpTTest: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "TTest"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; +}; +class OpFisher: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Fisher"; } +}; + +class OpFisherInv: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "FisherInv"; } +}; + +class OpGamma: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Gamma"; } +}; + +class OpNegbinomdist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpNegbinomdist"; } +}; + +class OpGammaLn: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "GammaLn"; } +}; + +class OpGauss: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + virtual std::string BinFuncName() const override { return "Gauss"; } +}; + +class OpGeoMean: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "GeoMean"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpHarMean: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "HarMean"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpNormdist:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpNormdist"; } +}; +class OpNormsdist:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpNormsdist"; } +}; +class OpNorminv:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpNorminv"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; +}; +class OpNormsinv:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpNormsinv"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; +}; +class OpPhi:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpPhi"; } +}; + +class OpPermut:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpPermut"; } +}; +class OpPermutationA:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpPermutationA";} +}; + +class OpConfidence: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { return "Confidence"; } +}; +class OpLogInv: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "LogInv"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; +}; +class OpCritBinom: public Normal +{ +public: + virtual std::string GetBottom() override { return "0"; } + + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& , + std::set<std::string>& ) override; + + virtual std::string BinFuncName() const override { return "CritBinom"; } +}; +class OpLogNormDist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "LogNormdist"; } +}; +class OpGammaDist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual std::string BinFuncName() const override { return "GammaDist"; } +}; +class OpHypGeomDist:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpHypGeomDist"; } +}; +class OpChiDist:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "OpChiDist"; } +}; +class OpBinomdist:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "OpBinomdist"; } +}; +class OpChiSqDist: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "ChiSqDist"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; + +class OpChiSqInv: public CheckVariables +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "ChiSqInv"; } + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) override; +}; +class OpChiInv:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "OpChiInv"; } +}; +class OpPoisson:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "OpPoisson"; } +}; + +class OpGammaInv: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs +) override; + virtual std::string BinFuncName() const override { return "GammaInv"; } +}; +class OpFInv: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs +) override; + virtual std::string BinFuncName() const override { return "FInv"; } +}; +class OpFTest: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs +) override; + virtual std::string BinFuncName() const override { return "FTest"; } +}; +class OpDevSq: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "DevSq"; } + virtual bool canHandleMultiVector() const override { return true; } +}; +class OpB: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs +) override; + virtual std::string BinFuncName() const override { return "B"; } +}; +class OpBetaDist: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs +) override; + virtual std::string BinFuncName() const override { return "BetaDist"; } +}; +class OpBetainv:public Normal{ + public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; + virtual std::string BinFuncName() const override { return "OpBetainv"; } +}; + +class OpAveDev: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "AveDev"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpCovar: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream& ss, + const std::string &sSymName, SubArguments& vSubArguments) override; + virtual std::string BinFuncName() const override { return "Covar"; } +}; + +class OpForecast: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Forecast"; } +}; + +class OpInterceptSlopeBase: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override = 0; +protected: + void GenerateCode( outputstream& ss, const std::string &sSymName, + SubArguments &vSubArguments, const char* finalComputeCode ); +}; + +class OpIntercept: public OpInterceptSlopeBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Intercept"; } +}; + +class OpSlope: public OpInterceptSlopeBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Slope"; } +}; + +class OpPearsonCovarBase: public Normal +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override = 0; +protected: + void GenerateCode( outputstream& ss, const std::string &sSymName, + SubArguments &vSubArguments, double minimalCountValue, const char* finalComputeCode ); +}; + +class OpPearson: public OpPearsonCovarBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpPearson"; } +}; + +class OpCorrel: public OpPearson // they are identical +{ +public: + virtual std::string BinFuncName() const override { return "Correl"; } +}; + +class OpSTEYX: public OpPearsonCovarBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "STEYX"; } +}; + +class OpRsq: public OpPearsonCovarBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "OpRsq"; } +}; + +class OpVarStDevBase : public Normal +{ +public: + virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual bool canHandleMultiVector() const override { return true; } +protected: + // Generates function setup and checks, then generates a loop that will calculate + // fMean and fCount from all arguments (ranges) and then a second loop that will + // calculate vSum (pown(fsub_approx(arg,fMean),2)) from all arguments. + void GenerateCode( outputstream& ss, const std::string& sSymName, SubArguments &vSubArguments ); +}; + +class OpVar: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Var"; } +}; + +class OpVarP: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "VarP"; } +}; + +class OpStDev: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "StDev"; } +}; + +class OpStDevP: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "StDevP"; } +}; + +class OpSkew: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Skew"; } +}; + +class OpSkewp: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Skewp"; } +}; + +class OpKurt: public OpVarStDevBase +{ +public: + virtual void GenSlidingWindowFunction(outputstream &ss, + const std::string &sSymName, SubArguments &vSubArguments) override; + virtual std::string BinFuncName() const override { return "Kurt"; } +}; + +class OpMin : public Reduction +{ +public: + explicit OpMin(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "NAN"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + return "fmin_count(" + lhs + "," + rhs + ", &nCount)"; + } + virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual std::string BinFuncName() const override { return "min"; } + virtual bool isMinOrMax() const override { return true; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpMax : public Reduction +{ +public: + explicit OpMax(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "NAN"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + return "fmax_count(" + lhs + "," + rhs + ", &nCount)"; + } + virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual std::string BinFuncName() const override { return "max"; } + virtual bool isMinOrMax() const override { return true; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpAverage : public Reduction +{ +public: + explicit OpAverage(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "0"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + outputstream ss; + ss << "fsum_count(" << lhs << "," << rhs << ", &nCount)"; + return ss.str(); + } + virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override; + virtual std::string BinFuncName() const override { return "average"; } + virtual bool isAverage() const override { return true; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpCount : public Reduction +{ +public: + explicit OpCount(int nResultSize) : Reduction(nResultSize) {} + + virtual std::string GetBottom() override { return "0"; } + virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override + { + outputstream ss; + ss << "(isnan(" << lhs << ")?" << rhs << ":" << rhs << "+1.0)"; + return ss.str(); + } + virtual std::string BinFuncName() const override { return "fcount"; } + virtual bool canHandleMultiVector() const override { return true; } +}; + +class OpCountA: public OpCount +{ +public: + explicit OpCountA(int nResultSize) : OpCount(nResultSize) {} + virtual std::string BinFuncName() const override { return "OpCountA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpMaxA: public OpMax +{ +public: + explicit OpMaxA(int nResultSize) : OpMax(nResultSize) {} + virtual std::string BinFuncName() const override { return "OpMaxA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpMinA : public OpMin +{ +public: + explicit OpMinA(int nResultSize) : OpMin(nResultSize) {} + virtual std::string BinFuncName() const override { return "OpMinA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpVarA: public OpVar +{ +public: + virtual std::string BinFuncName() const override { return "OpVarA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpVarPA: public OpVarP +{ +public: + virtual std::string BinFuncName() const override { return "OpVarPA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpStDevPA: public OpStDevP +{ +public: + virtual std::string BinFuncName() const override { return "OpStDevPA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpAverageA: public OpAverage +{ +public: + explicit OpAverageA(int nResultSize) : OpAverage(nResultSize) {} + virtual std::string BinFuncName() const override { return "OpAverageA"; } + virtual bool forceStringsToZero() const override { return true; } +}; +class OpStDevA: public OpStDev +{ +public: + virtual std::string BinFuncName() const override { return "OpStDevA"; } + virtual bool forceStringsToZero() const override { return true; } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/op_statistical_helpers.hxx b/sc/source/core/opencl/op_statistical_helpers.hxx new file mode 100644 index 0000000000..54914e1127 --- /dev/null +++ b/sc/source/core/opencl/op_statistical_helpers.hxx @@ -0,0 +1,1383 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +const char MinDecl[] = "#define Min 2.22507e-308\n"; +const char fBigInvDecl[] ="#define fBigInv 2.22045e-016\n"; +const char fMachEpsDecl[] ="#define fMachEps 2.22045e-016\n"; +const char fLogDblMaxDecl[] ="#define fLogDblMax log(1.79769e+308)\n"; +const char fHalfMachEpsDecl[] ="#define fHalfMachEps 0.5*2.22045e-016\n"; +const char fMaxGammaArgumentDecl[] = +"#define fMaxGammaArgument 171.624376956302\n"; +const char GetValueDecl[] = +"double GetValue( double x,double fp,double fDF );\n"; +const char GetValue[] = +"double GetValue( double x,double fp,double fDF )\n" +"{\n" +" return fp - 2 * GetTDist(x, fDF);\n" +"}\n"; +const char fmin_countDecl[] = "double fmin_count(double a, double b, __private int *p);\n"; +const char fmin_count[] = +"double fmin_count(double a, double b, __private int *p) {\n" +" double result = fmin(a, b);\n" +" bool t = isnan(result);\n" +" (*p) += t?0:1;\n" +" return result;\n" +"}\n"; +const char fmax_countDecl[] = "double fmax_count(double a, double b, __private int *p);\n"; +const char fmax_count[] = +"double fmax_count(double a, double b, __private int *p) {\n" +" double result = fmax(a, b);\n" +" bool t = isnan(result);\n" +" (*p) += t?0:1;\n" +" return result;\n" +"}\n"; +const char fsum_countDecl[] = "double fsum_count(double a, double b, __private int *p);\n"; +const char fsum_count[] = +"double fsum_count(double a, double b, __private int *p) {\n" +" bool t = isnan(a);\n" +" (*p) += t?0:1;\n" +" return t?b:a+b;\n" +"}\n"; +const char GetGammaSeriesDecl[] = +"double GetGammaSeries( double fA, double fX );\n"; +const char GetGammaSeries[] = +"double GetGammaSeries( double fA, double fX )\n" +"{\n" +" double fDenomfactor = fA;\n" +" double fSummand = 1.0/fA;\n" +" double fSum = fSummand;\n" +" int nCount=1;\n" +" do\n" +" {\n" +" fDenomfactor = fDenomfactor + 1.0;\n" +" fSummand = fSummand * fX/fDenomfactor;\n" +" fSum = fSum + fSummand;\n" +" nCount = nCount+1;\n" +" } while ( fSummand/fSum > fHalfMachEps && nCount<=10000);\n" +" if (nCount>10000)\n" +" {\n" +" }\n" +" return fSum;\n" +"}\n"; +const char GetGammaContFractionDecl[] = "double GetGammaContFraction( double " +"fA, double fX );\n"; +const char GetGammaContFraction[] = +"double GetGammaContFraction( double fA, double fX )\n" +"{\n" +" double fBig = 1.0/fBigInv;\n" +" double fCount = 0.0;\n" +" double fNum = 0.0;\n" +" double fY = 1.0 - fA;\n" +" double fDenom = fX + 2.0-fA;\n" +" double fPk = 0.0;\n" +" double fPkm1 = fX + 1.0;\n" +" double fPkm2 = 1.0;\n" +" double fQk = 1.0;\n" +" double fQkm1 = fDenom * fX;\n" +" double fQkm2 = fX;\n" +" double fApprox = fPkm1/fQkm1;\n" +" bool bFinished = false;\n" +" double fR = 0.0;\n" +" do\n" +" {\n" +" fCount = fCount +1.0;\n" +" fY = fY+ 1.0;\n" +" fNum = fY * fCount;\n" +" fDenom = fDenom +2.0;\n" +" fPk = fPkm1 * fDenom - fPkm2 * fNum;\n" +" fQk = fQkm1 * fDenom - fQkm2 * fNum;\n" +" if (fQk != 0.0)\n" +" {\n" +" fR = fPk/fQk;\n" +" bFinished = (fabs( (fApprox - fR)/fR ) <= fHalfMachEps);\n" +" fApprox = fR;\n" +" }\n" +" fPkm2 = fPkm1;\n" +" fPkm1 = fPk;\n" +" fQkm2 = fQkm1;\n" +" fQkm1 = fQk;\n" +" if (fabs(fPk) > fBig)\n" +" {\n" +" fPkm2 = fPkm2 * fBigInv;\n" +" fPkm1 = fPkm1 * fBigInv;\n" +" fQkm2 = fQkm2 * fBigInv;\n" +" fQkm1 = fQkm1 * fBigInv;\n" +" }\n" +" } while (!bFinished && fCount<10000);\n" +" if (!bFinished)\n" +" {\n" +" }\n" +" return fApprox;\n" +"}\n"; +const char GetLowRegIGammaDecl[] = "double GetLowRegIGamma( double " +"fA, double fX );\n"; +const char GetLowRegIGamma[] = +"double GetLowRegIGamma( double fA, double fX )\n" +"{\n" +" double fLnFactor = fA * log(fX) - fX - lgamma(fA);\n" +" double fFactor = exp(fLnFactor);\n" +" if (fX>fA+1.0) \n" +" return 1.0 - fFactor * GetGammaContFraction(fA,fX);\n" +" else\n" +" return fFactor * GetGammaSeries(fA,fX);\n" +"}\n"; +const char GetGammaDistDecl[] = "double GetGammaDist( double fX, double " +"fAlpha, double fLambda );\n"; +const char GetGammaDist[] = +"double GetGammaDist( double fX, double fAlpha, double fLambda )\n" +"{\n" +" if (fX <= 0.0)\n" +" return 0.0;\n" +" else\n" +" return GetLowRegIGamma( fAlpha, fX / fLambda);\n" +"}\n"; +const char GetGammaDistPDFDecl[] = "double GetGammaDistPDF( double fX" +", double fAlpha, double fLambda );\n"; +const char GetGammaDistPDF[] = +"double GetGammaDistPDF( double fX, double fAlpha, double fLambda )\n" +"{\n" +" if (fX < 0.0)\n" +" return 0.0;\n" +" else if (fX == 0)\n" +" {\n" +" if (fAlpha < 1.0)\n" +" {\n" +" return HUGE_VAL;\n" +" }\n" +" else if (fAlpha == 1)\n" +" {\n" +" return (1.0 / fLambda);\n" +" }\n" +" else\n" +" {\n" +" return 0.0;\n" +" }\n" +" }\n" +" else\n" +" {\n" +" double fXr = fX / fLambda;\n" +" if (fXr > 1.0)\n" +" {\n" +" if (log(fXr) * (fAlpha-1.0) < fLogDblMax &&" +"fAlpha < fMaxGammaArgument)\n" +" {\n" +" return pow( fXr, fAlpha-1.0) * exp(-fXr) / " +"fLambda / tgamma(fAlpha);\n" +" }\n" +" else\n" +" {\n" +" return exp( (fAlpha-1.0) * log(fXr) - fXr - " +"log(fLambda) - lgamma(fAlpha));\n" +" }\n" +" }\n" +" else\n" +" {\n" +" if (fAlpha<fMaxGammaArgument)\n" +" {\n" +" return pow( fXr, fAlpha-1.0) * exp(-fXr) / " +"fLambda / tgamma(fAlpha);\n" +" }\n" +" else\n" +" {\n" +" return pow( fXr, fAlpha-1.0) * exp(-fXr) / " +"fLambda / exp( lgamma(fAlpha));\n" +" }\n" +" }\n" +" }\n" +"}\n"; +const char GetBetaDistDecl[] = +"double GetBetaDist(double fXin, double fAlpha, double fBeta);\n"; +const char GetBetaDist[] = +"double GetBetaDist(double fXin, double fAlpha, double fBeta)\n" +"{\n" +" if (fXin <= 0.0)\n" +" return 0.0;\n" +" if (fXin >= 1.0)\n" +" return 1.0;\n" +" if (fBeta == 1.0)\n" +" return pow(fXin, fAlpha);\n" +" if (fAlpha == 1.0)\n" +" return -expm1(fBeta * log1p(-fXin));\n" +" double fResult;\n" +" double fY = (0.5-fXin)+0.5;\n" +" double flnY = log1p(-fXin);\n" +" double fX = fXin;\n" +" double flnX = log(fXin);\n" +" double fA = fAlpha;\n" +" double fB = fBeta;\n" +" bool bReflect = fXin > fAlpha/(fAlpha+fBeta);\n" +" if (bReflect)\n" +" {\n" +" fA = fBeta;\n" +" fB = fAlpha;\n" +" fX = fY;\n" +" fY = fXin;\n" +" flnX = flnY;\n" +" flnY = log(fXin);\n" +" }\n" +" fResult = lcl_GetBetaHelperContFrac(fX,fA,fB)/fA;\n" +" double fP = fA/(fA+fB);\n" +" double fQ = fB/(fA+fB);\n" +" if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97)\n" +" fResult *= GetBetaDistPDF(fX,fA,fB)*fX*fY;\n" +" else\n" +" fResult *= pow(exp(1.0),(fA*flnX + fB*flnY - GetLogBeta(fA,fB)));\n" +" if (bReflect)\n" +" fResult = 0.5 - fResult + 0.5;\n" +" if (fResult > 1.0)\n" +" fResult = 1.0;\n" +" if (fResult < 0.0)\n" +" fResult = 0.0;\n" +" return fResult;\n" +"}\n"; + +const char GetFDistDecl[] = + "double GetFDist(double x, double fF1, double fF2);\n"; +const char GetFDist[] = +"double GetFDist(double x, double fF1, double fF2)\n" +"{\n" +" double arg = fF2/(fF2+fF1*x);\n" +" double alpha = fF2/2.0;\n" +" double beta = fF1/2.0;\n" +" return (GetBetaDist(arg, alpha, beta));\n" +"}\n"; +const char GetGammaInvValueDecl[] = "double" +" GetGammaInvValue(double fAlpha,double fBeta,double fX1 );\n"; +const char GetGammaInvValue[] = +"double GetGammaInvValue(double fAlpha,double fBeta,double fX1 )\n" +"{\n" +" if (fX1 <= 0.0)\n" +" return 0.0;\n" +" else\n" +" {\n" +" double fX=fX1/fBeta;\n" +" double fLnFactor = fAlpha * log(fX) - fX - lgamma(fAlpha);\n" +" double fFactor = exp(fLnFactor);\n" +" if (fX>fAlpha+1.0)\n" +" return 1.0 - fFactor * GetGammaContFraction(fAlpha,fX);\n" +" else\n" +" return fFactor * GetGammaSeries(fAlpha,fX);\n" +" }\n" +"}\n"; +const char GetFInvValueDecl[] = "double GetFInvValue(double fF1,double fF2" +",double fX1 );"; +const char GetFInvValue[] = +"double GetFInvValue(double fF1,double fF2,double fX1 )\n" +"{\n" +" double arg = fF2/(fF2+fF1*fX1);\n" +" double alpha = fF2/2.0;\n" +" double beta = fF1/2.0;\n" +" double fXin,fAlpha,fBeta;\n" +" fXin=arg;fAlpha=alpha;fBeta=beta;\n" +" if (fXin <= 0.0)\n" +" return 0.0;\n" +" if (fXin >= 1.0)\n" +" return 1.0;\n" +" if (fBeta == 1.0)\n" +" return pow(fXin, fAlpha);\n" +" if (fAlpha == 1.0)\n" +" return -expm1(fBeta * log1p(-fXin));\n" +" double fResult;\n" +" double fY = (0.5-fXin)+0.5;\n" +" double flnY = log1p(-fXin);\n" +" double fX = fXin;\n" +" double flnX = log(fXin);\n" +" double fA = fAlpha;\n" +" double fB = fBeta;\n" +" bool bReflect = fXin > fAlpha/(fAlpha+fBeta);\n" +" if (bReflect)\n" +" {\n" +" fA = fBeta;\n" +" fB = fAlpha;\n" +" fX = fY;\n" +" fY = fXin;\n" +" flnX = flnY;\n" +" flnY = log(fXin);\n" +" }\n" +" fResult = lcl_GetBetaHelperContFrac(fX,fA,fB);\n" +" fResult = fResult/fA;\n" +" double fP = fA/(fA+fB);\n" +" double fQ = fB/(fA+fB);\n" +" double fTemp;\n" +" if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97)\n" +" fTemp = GetBetaDistPDF(fX,fA,fB)*fX*fY;\n" +" else\n" +" fTemp = exp(fA*flnX + fB*flnY - GetLogBeta(fA,fB));\n" +" fResult *= fTemp;\n" +" if (bReflect)\n" +" fResult = 0.5 - fResult + 0.5;\n" +" if (fResult > 1.0)\n" +" fResult = 1.0;\n" +" if (fResult < 0.0)\n" +" fResult = 0.0;\n" +" return fResult;\n" +"}\n"; +const char GetBinomDistPMFDecl[] = + "double GetBinomDistPMF(double x, double n, double p);"; +const char GetBinomDistPMF[] = +"double GetBinomDistPMF(double x, double n, double p)\n" +"{\n" +" double q = (0.5 - p) + 0.5;\n" +" double fFactor = pow(q, n);\n" +" if (fFactor <= Min)\n" +" {\n" +" fFactor = pow(p, n);\n" +" if (fFactor <= Min)\n" +" return GetBetaDistPDF(p, x + 1.0, n - x + 1.0)/(n + 1.0);\n" +" else\n" +" {\n" +" uint max = (uint)(n - x);\n" +" for (uint i = 0; i < max && fFactor > 0.0; ++i)\n" +" fFactor *= (n - i)/(double)(i + 1)*q/p;\n" +" return fFactor;\n" +" }\n" +" }\n" +" else\n" +" {\n" +" uint max = (uint)x;\n" +" for (uint i = 0; i < max && fFactor > 0.0; ++i)\n" +" fFactor *= (n - i)/(double)(i + 1)*p/q;\n" +" return fFactor;\n" +" }\n" +"}\n"; + +const char lcl_GetBinomDistRangeDecl[] = + "double lcl_GetBinomDistRange(double n, \n" +"double xs, double xe, double fFactor, double p, double q);"; +const char lcl_GetBinomDistRange[] = +"double lcl_GetBinomDistRange(double n, double xs, double xe,\n" +" double fFactor, double p, double q)\n" +"{\n" +" uint i;\n" +" double fSum;\n" +" uint nXs = (uint)xs;\n" +" for (i = 1; i <= nXs && fFactor > 0.0; ++i)\n" +" fFactor *= (n - i + 1)/(double)(i)*p/q;\n" +" fSum = fFactor;\n" +" uint nXe =(uint)xe;\n" +" for (i = nXs + 1; i <= nXe && fFactor > 0.0; ++i)\n" +" {\n" +" fFactor *= (n - i + 1)/(double)(i)*p/q;\n" +" fSum += fFactor;\n" +" }\n" +" return (fSum > 1.0) ? 1.0 : fSum;\n" +"}\n"; + +const char GetLogGammaDecl[] = "double GetLogGamma(double fZ);\n"; +const char GetLogGamma[] = +"double GetLogGamma(double fZ)\n" +"{\n" +" if (fZ >= fMaxGammaArgument)\n" +" return lcl_GetLogGammaHelper(fZ);\n" +" if (fZ >= 1.0)\n" +" return log(lcl_GetGammaHelper(fZ));\n" +" if (fZ >= 0.5)\n" +" return log( lcl_GetGammaHelper(fZ+1) / fZ);\n" +" return lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log(fZ);\n" +"}\n"; + +const char GetChiDistDecl[] = "double GetChiDist(double fX, double fDF);\n"; +const char GetChiDist[] = +"double GetChiDist(double fX, double fDF)\n" +"{\n" +" if (fX <= 0.0)\n" +" return 1.0;\n" +" else\n" +" return GetUpRegIGamma( fDF/2.0, fX/2.0);\n" +"}\n"; + +const char GetChiSqDistCDFDecl[] = +"double GetChiSqDistCDF(double fX, double fDF);\n"; +const char GetChiSqDistCDF[] = +"double GetChiSqDistCDF(double fX, double fDF)\n" +"{\n" +" if (fX <= 0.0)\n" +" return 0.0;" +" else\n" +" return GetLowRegIGamma( fDF/2.0, fX/2.0);\n" +"}\n"; + +const char GetChiSqDistPDFDecl[] = +"double GetChiSqDistPDF(double fX, double fDF);\n"; +const char GetChiSqDistPDF[] = +"double GetChiSqDistPDF(double fX, double fDF)\n" +"{\n" +" double fValue;\n" +" if (fX <= 0.0)\n" +" return 0.0;\n" +" if (fDF*fX > 1391000.0)\n" +" {\n" +" fValue = exp((0.5*fDF - 1) * log(fX*0.5) - 0.5 * fX - log(2.0)" +" - lgamma(0.5*fDF));\n" +" }\n" +" else\n" +" {\n" +" double fCount;\n" +" if (fmod(fDF,2.0)<0.5)\n" +" {\n" +" fValue = 0.5;\n" +" fCount = 2.0;\n" +" }\n" +" else\n" +" {\n" +" fValue = 1.0/sqrt(fX*2*M_PI);\n" +" fCount = 1.0;\n" +" }\n" +" while ( fCount < fDF)\n" +" {\n" +" fValue *= (fX / fCount);\n" +" fCount += 2.0;\n" +" }\n" +" if (fX>=1425.0)\n" +" fValue = exp(log(fValue)-fX/2);\n" +" else\n" +" fValue *= exp(-fX/2);\n" +" }\n" +" return fValue;\n" +"}\n"; + +const char lcl_IterateInverseBetaInvDecl[] = +"static double lcl_IterateInverseBetaInv(double fp, double fAlpha, \n" +" double fBeta, double fAx, double fBx, bool *rConvError );\n"; +const char lcl_IterateInverseBetaInv[] = +"static double lcl_IterateInverseBetaInv(double fp, double fAlpha, \n" +" double fBeta, double fAx, double fBx, bool *rConvError )\n" +"{\n" +" *rConvError = false;\n" +" double fYEps = 1.0E-307;\n" +" double fXEps = fMachEps;\n" +" if(!(fAx < fBx))\n" +" {\n" +" //print error\n" +" }\n" +" double fAy = fp - GetBetaDist(fAx, fAlpha, fBeta);\n" +" double fBy = fp - GetBetaDist(fBx, fAlpha, fBeta);\n" +" double fTemp;\n" +" unsigned short nCount;\n" +" for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy);" +" nCount++)\n" +" {\n" +" if (fabs(fAy) <= fabs(fBy))\n" +" {\n" +" fTemp = fAx;\n" +" fAx += 2.0 * (fAx - fBx);\n" +" if (fAx < 0.0)\n" +" fAx = 0.0;\n" +" fBx = fTemp;\n" +" fBy = fAy;\n" +" fAy = fp - GetBetaDist(fAx, fAlpha, fBeta);\n" +" }\n" +" else\n" +" {\n" +" fTemp = fBx;\n" +" fBx += 2.0 * (fBx - fAx);\n" +" fAx = fTemp;\n" +" fAy = fBy;\n" +" fBy = fp - GetBetaDist(fBx, fAlpha, fBeta);\n" +" }\n" +" }\n" +" if (fAy == 0.0)\n" +" return fAx;\n" +" if (fBy == 0.0)\n" +" return fBx;\n" +" if (!lcl_HasChangeOfSign( fAy, fBy))\n" +" {\n" +" *rConvError = true;\n" +" return 0.0;\n" +" }\n" +" double fPx = fAx;\n" +" double fPy = fAy;\n" +" double fQx = fBx;\n" +" double fQy = fBy;\n" +" double fRx = fAx;\n" +" double fRy = fAy;\n" +" double fSx = 0.5 * (fAx + fBx);\n" +" bool bHasToInterpolate = true;\n" +" nCount = 0;\n" +" while ( nCount < 500 && fabs(fRy) > fYEps &&\n" +" (fBx-fAx) > fmax( fabs(fAx), fabs(fBx)) * fXEps )\n" +" {\n" +" if (bHasToInterpolate)\n" +" {\n" +" if (fPy!=fQy && fQy!=fRy && fRy!=fPy)\n" +" {\n" +" fSx = fPx*fRy*fQy/(fRy-fPy)/(fQy-fPy)\n" +" + fRx*fQy*fPy/(fQy-fRy)/(fPy-fRy)\n" +" + fQx*fPy*fRy/(fPy-fQy)/(fRy-fQy);\n" +" bHasToInterpolate = (fAx < fSx) && (fSx < fBx);\n" +" }\n" +" else\n" +" bHasToInterpolate = false;\n" +" }\n" +" if(!bHasToInterpolate)\n" +" {\n" +" fSx = 0.5 * (fAx + fBx);\n" +" fPx = fAx; fPy = fAy;\n" +" fQx = fBx; fQy = fBy;\n" +" bHasToInterpolate = true;\n" +" }\n" +" fPx = fQx; fQx = fRx; fRx = fSx;\n" +" fPy = fQy; fQy = fRy; fRy = fp - GetBetaDist(fSx, fAlpha, fBeta);\n" +" if (lcl_HasChangeOfSign( fAy, fRy))\n" +" {\n" +" fBx = fRx; fBy = fRy;\n" +" }\n" +" else\n" +" {\n" +" fAx = fRx; fAy = fRy;\n" +" }\n" +" bHasToInterpolate = bHasToInterpolate && (fabs(fRy) *" +" 2.0 <= fabs(fQy));\n" +" ++nCount;\n" +" }\n" +" return fRx;\n" +"}\n"; + +const char lcl_IterateInverseChiInvDecl[] = +"static double lcl_IterateInverseChiInv" +"(double fp, double fdf, double fAx, double fBx, bool *rConvError);\n"; +const char lcl_IterateInverseChiInv[] = +"static double lcl_IterateInverseChiInv" +"(double fp, double fdf, double fAx, double fBx, bool *rConvError)\n" +"{\n" +" *rConvError = false;\n" +" double fYEps = 1.0E-307;\n" +" double fXEps = fMachEps;\n" +" if(!(fAx < fBx))\n" +" {\n" +" //print error\n" +" }" +" double fAy = fp - GetChiDist(fAx, fdf);\n" +" double fBy = fp - GetChiDist(fBx, fdf);\n" +" double fTemp;\n" +" unsigned short nCount;\n" +" for (nCount = 0; nCount < 1000 && " +"!lcl_HasChangeOfSign(fAy,fBy); nCount++)\n" +" {\n" +" if (fabs(fAy) <= fabs(fBy))\n" +" {\n" +" fTemp = fAx;\n" +" fAx += 2.0 * (fAx - fBx);\n" +" if (fAx < 0.0)\n" +" fAx = 0.0;\n" +" fBx = fTemp;\n" +" fBy = fAy;\n" +" fAy = fp - GetChiDist(fAx, fdf);\n" +" }\n" +" else\n" +" {\n" +" fTemp = fBx;\n" +" fBx += 2.0 * (fBx - fAx);\n" +" fAx = fTemp;\n" +" fAy = fBy;\n" +" fBy = fp - GetChiDist(fBx, fdf);\n" +" }\n" +" }\n" +" if (fAy == 0.0)\n" +" return fAx;\n" +" if (fBy == 0.0)\n" +" return fBx;\n" +" if (!lcl_HasChangeOfSign( fAy, fBy))\n" +" {\n" +" *rConvError = true;\n" +" return 0.0;\n" +" }\n" +" double fPx = fAx;\n" +" double fPy = fAy;\n" +" double fQx = fBx;\n" +" double fQy = fBy;\n" +" double fRx = fAx;\n" +" double fRy = fAy;\n" +" double fSx = 0.5 * (fAx + fBx);\n" +" bool bHasToInterpolate = true;\n" +" nCount = 0;\n" +" while ( nCount < 500 && fabs(fRy) > fYEps &&\n" +" (fBx-fAx) > fmax( fabs(fAx), fabs(fBx)) * fXEps )\n" +" {\n" +" if (bHasToInterpolate)\n" +" {\n" +" if (fPy!=fQy && fQy!=fRy && fRy!=fPy)\n" +" {\n" +" fSx = fPx * fRy * fQy/(fRy-fPy)/(fQy-fPy)\n" +" + fRx * fQy * fPy/(fQy-fRy)/(fPy-fRy)\n" +" + fQx * fPy * fRy/(fPy-fQy)/(fRy-fQy);\n" +" bHasToInterpolate = (fAx < fSx) && (fSx < fBx);\n" +" }\n" +" else\n" +" bHasToInterpolate = false;\n" +" }\n" +" if(!bHasToInterpolate)\n" +" {\n" +" fSx = 0.5 * (fAx + fBx);\n" +" fPx = fAx; fPy = fAy;\n" +" fQx = fBx; fQy = fBy;\n" +" bHasToInterpolate = true;\n" +" }\n" +" fPx = fQx; fQx = fRx; fRx = fSx;\n" +" fPy = fQy; fQy = fRy; fRy = fp - GetChiDist(fSx, fdf);\n" +" if (lcl_HasChangeOfSign( fAy, fRy))\n" +" {\n" +" fBx = fRx; fBy = fRy;\n" +" }\n" +" else\n" +" {\n" +" fAx = fRx; fAy = fRy;\n" +" }\n" +" bHasToInterpolate = bHasToInterpolate && (fabs(fRy)" +" * 2.0 <= fabs(fQy));\n" +" ++nCount;\n" +" }\n" +" return fRx;\n" +"}\n"; + +const char lcl_IterateInverseChiSQInvDecl[] = +"static double lcl_IterateInverseChiSQInv( double fp, double fdf, \n" +" double fAx, double fBx, bool *rConvError );\n"; +const char lcl_IterateInverseChiSQInv[] = +"static double lcl_IterateInverseChiSQInv( double fp, double fdf, \n" +" double fAx, double fBx, bool *rConvError )\n" +"{\n" +" *rConvError = false;\n" +" double fYEps = 1.0E-307;\n" +" double fXEps = fMachEps;\n" + +" if(!(fAx < fBx))\n" +" {\n" +" //print error\n" +" }\n" +" double fAy = fp - GetChiSqDistCDF(fAx, fdf);\n" +" double fBy = fp - GetChiSqDistCDF(fBx, fdf);\n" +" double fTemp;\n" +" unsigned short nCount;\n" +" for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy);" +" nCount++)\n" +" {\n" +" if (fabs(fAy) <= fabs(fBy))\n" +" {\n" +" fTemp = fAx;\n" +" fAx += 2.0 * (fAx - fBx);\n" +" if (fAx < 0.0)\n" +" fAx = 0.0;\n" +" fBx = fTemp;\n" +" fBy = fAy;\n" +" fAy = fp - GetChiSqDistCDF(fAx, fdf);\n" +" }\n" +" else\n" +" {\n" +" fTemp = fBx;\n" +" fBx += 2.0 * (fBx - fAx);\n" +" fAx = fTemp;\n" +" fAy = fBy;\n" +" fBy = fp - GetChiSqDistCDF(fBx, fdf);\n" +" }\n" +" }\n" +" if (fAy == 0.0)\n" +" return fAx;\n" +" if (fBy == 0.0)\n" +" return fBx;\n" +" if (!lcl_HasChangeOfSign( fAy, fBy))\n" +" {\n" +" *rConvError = true;\n" +" return 0.0;\n" +" }\n" +" double fPx = fAx;\n" +" double fPy = fAy;\n" +" double fQx = fBx;\n" +" double fQy = fBy;\n" +" double fRx = fAx;\n" +" double fRy = fAy;\n" +" double fSx = 0.5 * (fAx + fBx);\n" +" bool bHasToInterpolate = true;\n" +" nCount = 0;\n" +" while ( nCount < 500 && fabs(fRy) > fYEps &&\n" +" (fBx-fAx) > fmax( fabs(fAx), fabs(fBx)) * fXEps )\n" +" {\n" +" if (bHasToInterpolate)\n" +" {\n" +" if (fPy!=fQy && fQy!=fRy && fRy!=fPy)\n" +" {\n" +" fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy)\n" +" + fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy)\n" +" + fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy);\n" +" bHasToInterpolate = (fAx < fSx) && (fSx < fBx);\n" +" }\n" +" else\n" +" bHasToInterpolate = false;\n" +" }\n" +" if(!bHasToInterpolate)\n" +" {\n" +" fSx = 0.5 * (fAx + fBx);\n" +" fPx = fAx; fPy = fAy;\n" +" fQx = fBx; fQy = fBy;\n" +" bHasToInterpolate = true;\n" +" }\n" +" fPx = fQx; fQx = fRx; fRx = fSx;\n" +" fPy = fQy; fQy = fRy; fRy = fp - GetChiSqDistCDF(fSx, fdf);\n" +" if (lcl_HasChangeOfSign( fAy, fRy))\n" +" {\n" +" fBx = fRx; fBy = fRy;\n" +" }\n" +" else\n" +" {\n" +" fAx = fRx; fAy = fRy;\n" +" }\n" +" bHasToInterpolate = bHasToInterpolate && (fabs(fRy) * 2.0" +" <= fabs(fQy));\n" +" ++nCount;\n" +" }\n" +" return fRx;\n" +"}\n"; + +const char gaussinvDecl[] = "double gaussinv(double x);\n"; +const char gaussinv[] = +"double gaussinv(double x)\n" +"{\n" +" double q,t,z;\n" +" q=x-0.5;\n" +" if(fabs(q)<=.425)\n" +" {\n" +" t=0.180625-q*q;\n" +" z=\n" +" q*\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" t*2509.0809287301226727+33430.575583588128105\n" +" )\n" +" *t+67265.770927008700853\n" +" )\n" +" *t+45921.953931549871457\n" +" )\n" +" *t+13731.693765509461125\n" +" )\n" +" *t+1971.5909503065514427\n" +" )\n" +" *t+133.14166789178437745\n" +" )\n" +" *t+3.387132872796366608\n" +" )\n" +" /\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" t*5226.495278852854561+28729.085735721942674\n" +" )\n" +" *t+39307.89580009271061\n" +" )\n" +" *t+21213.794301586595867\n" +" )\n" +" *t+5394.1960214247511077\n" +" )\n" +" *t+687.1870074920579083\n" +" )\n" +" *t+42.313330701600911252\n" +" )\n" +" *t+1.0);\n" +" }\n" +" else\n" +" {\n" +" if(q>0) t=1-x;\n" +" else t=x;\n" +" t=sqrt(-log(t));\n" +" if(t<=5.0)\n" +" {\n" +" t+=-1.6;\n" +" z=\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" t*7.7454501427834140764e-4+0.0227238449892691845833\n" +" )\n" +" *t+0.24178072517745061177\n" +" )\n" +" *t+1.27045825245236838258\n" +" )\n" +" *t+3.64784832476320460504\n" +" )\n" +" *t+5.7694972214606914055\n" +" )\n" +" *t+4.6303378461565452959\n" +" )\n" +" *t+1.42343711074968357734\n" +" )\n" +" /\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" t*1.05075007164441684324e-9+5.475938084995344946e-4\n" +" )\n" +" *t+0.0151986665636164571966\n" +" )\n" +" *t+0.14810397642748007459\n" +" )\n" +" *t+0.68976733498510000455\n" +" )\n" +" *t+1.6763848301838038494\n" +" )\n" +" *t+2.05319162663775882187\n" +" )\n" +" *t+1.0);\n" +" }\n" +" else\n" +" {\n" +" t+=-5.0;\n" +" z=\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" t*2.01033439929228813265e-7+2.71155556874348757815e-5\n" +" )\n" +" *t+0.0012426609473880784386\n" +" )\n" +" *t+0.026532189526576123093\n" +" )\n" +" *t+0.29656057182850489123\n" +" )\n" +" *t+1.7848265399172913358\n" +" )\n" +" *t+5.4637849111641143699\n" +" )\n" +" *t+6.6579046435011037772\n" +" )\n" +" /\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" (\n" +" t*2.04426310338993978564e-15+1.4215117583164458887e-7\n" +" )\n" +" *t+1.8463183175100546818e-5\n" +" )\n" +" *t+7.868691311456132591e-4\n" +" )\n" +" *t+0.0148753612908506148525\n" +" )\n" +" *t+0.13692988092273580531\n" +" )\n" +" *t+0.59983220655588793769\n" +" )\n" +" *t+1.0);\n" +" }\n" +" if(q<0.0) z=-z;\n" +" }\n" +" return z;\n" +"}\n"; + +const char lcl_GetLogGammaHelperDecl[] = +"static double lcl_GetLogGammaHelper(double fZ);\n"; +const char lcl_GetLogGammaHelper[] = +"static double lcl_GetLogGammaHelper(double fZ)\n" +"{\n" +" double fg = 6.024680040776729583740234375;\n" +" double fZgHelp = fZ + fg - 0.5;\n" +" return log( lcl_getLanczosSum(fZ)) + (fZ-0.5) * log(fZgHelp) - fZgHelp;\n" +"}\n"; +const char lcl_GetGammaHelperDecl[] = +"static double lcl_GetGammaHelper(double fZ);\n"; +const char lcl_GetGammaHelper[] = +"static double lcl_GetGammaHelper(double fZ)\n" +"{\n" +" double fGamma = lcl_getLanczosSum(fZ);\n" +" double fg = 6.024680040776729583740234375;\n" +" double fZgHelp = fZ + fg - 0.5;\n" +" double fHalfpower = pow( fZgHelp, fZ/2 - 0.25);\n" +" fGamma *= fHalfpower;\n" +" fGamma = fGamma/exp(fZgHelp);\n" +" fGamma *= fHalfpower;\n" +" fGamma = 120.4;\n" +" if (fZ <= 20.0 && fZ == (int)fZ)\n" +" {\n" +" fGamma = (int)(fGamma+0.5);\n" +" }\n" +" return fGamma;\n" +"}\n"; +const char lcl_getLanczosSumDecl[] = +"static double lcl_getLanczosSum(double fZ);\n"; +const char lcl_getLanczosSum[] = +"static double lcl_getLanczosSum(double fZ) \n" +"{ \n" +" double fNum[13] ={ \n" +" 23531376880.41075968857200767445163675473, \n" +" 42919803642.64909876895789904700198885093, \n" +" 35711959237.35566804944018545154716670596, \n" +" 17921034426.03720969991975575445893111267, \n" +" 6039542586.35202800506429164430729792107, \n" +" 1439720407.311721673663223072794912393972, \n" +" 248874557.8620541565114603864132294232163, \n" +" 31426415.58540019438061423162831820536287, \n" +" 2876370.628935372441225409051620849613599, \n" +" 186056.2653952234950402949897160456992822, \n" +" 8071.672002365816210638002902272250613822, \n" +" 210.8242777515793458725097339207133627117, \n" +" 2.506628274631000270164908177133837338626 \n" +" }; \n" +" double fDenom[13] = { \n" +" 0,\n" +" 39916800,\n" +" 120543840,\n" +" 150917976,\n" +" 105258076,\n" +" 45995730,\n" +" 13339535,\n" +" 2637558,\n" +" 357423,\n" +" 32670,\n" +" 1925,\n" +" 66,\n" +" 1\n" +" };\n" +" double fSumNum;\n" +" double fSumDenom;\n" +" int nI;\n" +" if (fZ<=1.0)\n" +" {\n" +" fSumNum = fNum[12];\n" +" fSumDenom = fDenom[12];\n" +" nI = 11;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 10;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 9;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 8;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 7;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 6;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 5;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 4;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 3;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 2;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 1;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" nI = 0;\n" +" fSumNum = fSumNum*fZ+fNum[nI];\n" +" fSumDenom = fSumDenom*fZ+fDenom[nI];\n" +" }\n" +" if (fZ>1.0)\n" +" {\n" +" double fZInv = 1.0/fZ;\n" +" fSumNum = fNum[0];\n" +" fSumDenom = fDenom[0];\n" +" nI = 1;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 2;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 3;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 4;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 5;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 6;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 7;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 8;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 9;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 10;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 11;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" nI = 12;\n" +" fSumNum = fSumNum*fZInv+fNum[nI];\n" +" fSumDenom = fSumDenom*fZInv+fDenom[nI];\n" +" }\n" +" return fSumNum/fSumDenom;\n" +"}\n"; + +const char GetUpRegIGammaDecl[] = +" double GetUpRegIGamma( double fA, double fX ) ;\n"; +const char GetUpRegIGamma[] = +"double GetUpRegIGamma( double fA, double fX )\n" +"{\n" +" double fLnFactor= fA*log(fX)-fX-lgamma(fA);\n" +" double fFactor = exp(fLnFactor); \n" +" if (fX>fA+1.0) \n" +" return fFactor * GetGammaContFraction(fA,fX);\n" +" else \n" +" return 1.0 -fFactor * GetGammaSeries(fA,fX);\n" +"}\n"; + +const char lcl_HasChangeOfSignDecl[] = +"static inline bool lcl_HasChangeOfSign( double u, double w );\n"; +const char lcl_HasChangeOfSign[] = +"static inline bool lcl_HasChangeOfSign( double u, double w )\n" +"{\n" +" return (u < 0.0 && w > 0.0) || (u > 0.0 && w < 0.0);\n" +"}\n"; + +const char GetTDistDecl[] =" double GetTDist(double T, double fDF);\n"; +const char GetTDist[] = +"double GetTDist(double T, double fDF)\n" +"{\n" +" return 0.5 * GetBetaDist(fDF/(fDF+T*T),fDF/2.0, 0.5);\n" +"}\n"; + +const char GetBetaDecl[] =" double GetBeta(double fAlpha, double fBeta);\n"; +const char GetBeta[] = +"double GetBeta(double fAlpha, double fBeta)\n" +"{\n" +" double fA;\n" +" double fB;\n" +" fAlpha>fBeta?(fA = fAlpha,fB = fBeta):(fA = fBeta,fB = fAlpha);\n" +" double fAB = fA + fB;\n" + +" if (fAB < fMaxGammaArgument)\n" +" return tgamma(fA)/tgamma(fAB)*tgamma(fB);\n" +" double fgm = 5.524680040776729583740234375;\n" +" double fLanczos = lcl_getLanczosSum(fA)*lcl_getLanczosSum(fB)\n" +" /lcl_getLanczosSum(fAB);\n" +" fLanczos *= sqrt(((fAB + fgm)/(fA + fgm))/(fB + fgm));\n" +" return fLanczos * pow(exp(1.0),(-fA*log1p(fB/(fA + fgm)))" +" - fB*log1p(fA/(fB + fgm)) - fgm);\n" +"}\n"; + +const char GetLogBetaDecl[] = +" double GetLogBeta(double fAlpha, double fBeta);\n"; +const char GetLogBeta[] = +"double GetLogBeta(double fAlpha, double fBeta)\n" +"{\n" +" double fA;\n" +" double fB;\n" +" fAlpha>fBeta?(fA = fAlpha,fB = fBeta):(fA = fBeta,fB = fAlpha);\n" +" double fgm = 5.524680040776729583740234375;\n" + +" double fLanczos = lcl_getLanczosSum(fA)*lcl_getLanczosSum(fB)\n" +" /lcl_getLanczosSum(fA + fB);\n" +" double fResult= -fA *log1p(fB/(fA + fgm))" +"-fB *log1p(fA/(fB + fgm))-fgm;\n" +" fResult += log(fLanczos)+0.5*(log(fA + fB + fgm) - log(fA + fgm)\n" +" - log(fB + fgm));\n" +" return fResult;\n" +"}\n"; + +const char GetBetaDistPDFDecl[] = +"double GetBetaDistPDF(double fX, double fA, double fB);\n"; +const char GetBetaDistPDF[] = +"double GetBetaDistPDF(double fX, double fA, double fB)\n" +"{\n" +" if (fA == 1.0) \n" +" {\n" +" if (fB == 1.0)\n" +" return 1.0;\n" +" if (fB == 2.0)\n" +" return -2.0*fX + 2.0;\n" +" if (fX == 1.0 && fB < 1.0)\n" +" {\n" +" return HUGE_VAL;\n" +" }\n" +" if (fX <= 0.01)\n" +" return fB + fB * expm1((fB-1.0) * log1p(-fX));\n" +" else \n" +" return fB * pow(0.5-fX+0.5,fB-1.0);\n" +" }\n" +" if (fB == 1.0) \n" +" {\n" +" if (fA == 2.0)\n" +" return fA * fX;\n" +" if (fX == 0.0 && fA < 1.0)\n" +" {\n" +" return HUGE_VAL;\n" +" }\n" +" return fA * pow(fX,fA-1);\n" +" }\n" +" if (fX <= 0.0)\n" +" {\n" +" if (fA < 1.0 && fX == 0.0)\n" +" {\n" +" return HUGE_VAL;\n" +" }\n" +" else\n" +" return 0.0;\n" +" }\n" +" if (fX >= 1.0)\n" +" {\n" +" if (fB < 1.0 && fX == 1.0)\n" +" {\n" +" return HUGE_VAL;\n" +" }\n" +" else \n" +" return 0.0;\n" +" }\n" +" double fLogDblMax = log( 1.79769e+308 );\n" +" double fLogDblMin = log( 2.22507e-308 );\n" +" double fLogY = (fX < 0.1) ? log1p(-fX) : log(0.5-fX+0.5);\n" +" double fLogX = log(fX);\n" +" double fAm1LogX = (fA-1.0) * fLogX;\n" +" double fBm1LogY = (fB-1.0) * fLogY;\n" +" double fLogBeta = GetLogBeta(fA,fB);\n" +" if ( fAm1LogX < fLogDblMax && fAm1LogX > fLogDblMin\n" +" && fBm1LogY < fLogDblMax && fBm1LogY > fLogDblMin\n" +" && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin\n" +" && fAm1LogX + fBm1LogY < fLogDblMax && fAm1LogX + fBm1LogY > \n" +" fLogDblMin)\n" +" return pow(fX,fA-1.0)*pow(0.5-fX+0.5,fB-1.0)/GetBeta(fA,fB);\n" +" else \n" +" return exp( fAm1LogX + fBm1LogY - fLogBeta);\n" +"}\n"; + +const char lcl_GetBetaHelperContFracDecl[] = +"double lcl_GetBetaHelperContFrac(double fX, double fA, double fB);\n"; +const char lcl_GetBetaHelperContFrac[] = +"double lcl_GetBetaHelperContFrac(double fX, double fA, double fB)\n" +"{ \n" + +" double a1, b1, a2, b2, fnorm, apl2m, d2m, d2m1, cfnew, cf;\n" +" a1 = 1.0; b1 = 1.0;\n" +" b2 = 1.0 - (fA+fB)/(fA+1.0)*fX;\n" +" b2==0.0?(a2 = 0.0,fnorm = 1.0,cf = 1.0):\n" +" (a2 = 1.0,fnorm = 1.0/b2,cf = a2*fnorm);\n" +" cfnew = 1.0;\n" +" double rm = 1.0;\n" +" double fMaxIter = 50000.0;\n" +" bool bfinished = false;\n" +" do\n" +" {\n" +" apl2m = fA + 2.0*rm;\n" +" d2m = (rm*(fB-rm))*fX/(apl2m*(apl2m-1.0));\n" +" d2m1 = -((fA+rm)*(fA+rm+fB))*fX/(apl2m*(apl2m+1.0));\n" +" a1 = (a2+d2m*a1)*fnorm;\n" +" b1 = (b2+d2m*b1)*fnorm;\n" +" a2 = a1 + d2m1*a2*fnorm;\n" +" b2 = b1 + d2m1*b2*fnorm;\n" +" if (b2 != 0.0) \n" +" {\n" +" fnorm = 1.0/b2;\n" +" cfnew = a2*fnorm;\n" +" bfinished = (fabs(cf-cfnew) < fabs(cf)*fMachEps);\n" +" }\n" +" cf = cfnew;\n" +" rm += 1.0;\n" +" }\n" +" while (rm < fMaxIter && !bfinished);\n" +" return cf;\n" +"}\n"; + +const char lcl_IterateInverseDecl[] = +"double lcl_IterateInverse(" +"double fAx, double fBx, bool* rConvError,double fp,double fDF );\n"; +const char lcl_IterateInverse[] = +"double lcl_IterateInverse( " +"double fAx, double fBx, bool* rConvError,double fp,double fDF )\n" +"{\n" +" *rConvError = false;\n" +" double fYEps = 1.0E-307;\n" +" double fXEps =DBL_EPSILON;\n" +" if(fAx>fBx)\n" +" return DBL_MAX;\n" +" double fAy = GetValue(fAx,fp,fDF);\n" +" double fBy = GetValue(fBx,fp,fDF);\n" +" double fTemp;\n" +" unsigned short nCount;\n" +" double inter;\n" +" bool sign;\n" +" for (nCount =0;nCount<1000&&!lcl_HasChangeOfSign(fAy,fBy);nCount++)\n" +" {\n" +" inter = 2.0 * (fAx - fBx);\n" +" if (fabs(fAy) <= fabs(fBy)) \n" +" {\n" +" sign = true;\n" +" fTemp = fAx;\n" +" fAx += inter;\n" +" if (fAx < 0.0)\n" +" fAx = 0.0;\n" +" fBx = fTemp;\n" +" fBy = fAy;\n" +" fTemp = fAx;\n" +" }\n" +" else\n" +" {\n" +" sign = false;\n" +" fTemp = fBx;\n" +" fBx -= inter;\n" +" fAx = fTemp;\n" +" fAy = fBy;\n" +" fTemp = fBx;\n" +" }\n" +" fTemp = GetValue(fTemp,fp,fDF);\n" +" sign?(fAy = fTemp):(fBy = fTemp);\n" +" }\n" +" if (fAy == 0.0)\n" +" return fAx;\n" +" if (fBy == 0.0)\n" +" return fBx;\n" +" if (!lcl_HasChangeOfSign( fAy, fBy))\n" +" {\n" +" *rConvError = true;\n" +" return 0.0;\n" +" }\n" +" double fPx = fAx;\n" +" double fPy = fAy;\n" +" double fQx = fBx;\n" +" double fQy = fBy;\n" +" double fRx = fAx;\n" +" double fRy = fAy;\n" +" double fSx = 0.5 * (fAx + fBx); \n" +" bool bHasToInterpolate = true;\n" +" nCount = 0;\n" +" while ( nCount < 500 && fabs(fRy) > fYEps &&\n" +" (fBx-fAx) > max( fabs(fAx), fabs(fBx)) * fXEps )\n" +" {\n" +" if (bHasToInterpolate)\n" +" {\n" +" if (fPy!=fQy && fQy!=fRy && fRy!=fPy)\n" +" {\n" +" fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy)\n" +" + fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy)\n" +" + fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy);\n" +" bHasToInterpolate = (fAx < fSx) && (fSx < fBx);\n" +" }\n" +" else\n" +" bHasToInterpolate = false;\n" +" }\n" +" if(!bHasToInterpolate)\n" +" {\n" +" fSx = 0.5 * (fAx + fBx);\n" +" \n" +" fPx = fAx; fPy = fAy;\n" +" fQx = fBx; fQy = fBy;\n" +" bHasToInterpolate = true;\n" +" }\n" +" fPx = fQx; fQx = fRx; fRx = fSx;\n" +" fPy = fQy; fQy = fRy; fRy = GetValue(fSx,fp,fDF);\n" +" lcl_HasChangeOfSign( fAy, fRy)?(fBx = fRx,fBy = fRy):\n" +" (fAx = fRx,fAy = fRy);\n" +" bHasToInterpolate =\n" +" bHasToInterpolate && (fabs(fRy) * 2.0 <= fabs(fQy));\n" +" ++nCount;\n" +" }\n" +" return fRx;\n" +"}\n"; +const char phiDecl[] = +"double phi(double x);\n"; +const char phi[] = +"double phi(double x)\n" +"{\n" +" return 0.39894228040143268 * exp(-(x * x) / 2.0);\n" +"}\n"; +const char taylorDecl[] = +"double taylor(double* pPolynom, uint nMax, double x);\n"; +const char taylor[] = +"double taylor(double* pPolynom, uint nMax, double x)\n" +"{\n" +" double nVal = pPolynom[nMax];\n" +" for (short i = nMax-1; i >= 0; i--)\n" +" {\n" +" nVal = pPolynom[i] + (nVal * x);\n" +" }\n" +" return nVal;\n" +"}"; +const char gaussDecl[] = "double gauss(double x);\n"; +const char gauss[] = +"double gauss(double x)\n" +"{\n" +" double xAbs = fabs(x);\n" +" uint xShort = (uint)(floor(xAbs));\n" +" double nVal = 0.0;\n" +" if (xShort == 0)\n" +" {\n" +" double t0[] =\n" +" { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,\n" +" -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,\n" +" 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,\n" +" 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };\n" +" nVal = taylor(t0, 11, (xAbs * xAbs)) * xAbs;\n" +" }\n" +" else if ((xShort >= 1) && (xShort <= 2))\n" +" {\n" +" double t2[] =\n" +" { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,\n" +" 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,\n" +" 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,\n" +" 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,\n" +" 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,\n" +" -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,\n" +" -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,\n" +" -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };\n" +" nVal = taylor(t2, 23, (xAbs - 2.0));\n" +" }\n" +" else if ((xShort >= 3) && (xShort <= 4))\n" +" {\n" +" double t4[] =\n" +" { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,\n" +" 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,\n" +" -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,\n" +" -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,\n" +" 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,\n" +" 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,\n" +" 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };\n" +" nVal = taylor(t4, 20, (xAbs - 4.0));\n" +" }\n" +" else\n" +" {\n" +" double asympt[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };\n" +" nVal = 0.5 + phi(xAbs) * taylor(asympt, 4, 1.0/(xAbs * xAbs))/xAbs;\n" +" }\n" +" if (x < 0.0)\n" +" return -nVal;\n" +" else\n" +" return nVal;\n" +"}\n"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/opbase.cxx b/sc/source/core/opencl/opbase.cxx new file mode 100644 index 0000000000..4ea248daaa --- /dev/null +++ b/sc/source/core/opencl/opbase.cxx @@ -0,0 +1,884 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <opencl/openclwrapper.hxx> +#include <formula/vectortoken.hxx> +#include <rtl/string.hxx> +#include <sal/log.hxx> +#include <utility> +#include <unordered_map> + +#include "opbase.hxx" + +using namespace formula; + +namespace sc::opencl { + +UnhandledToken::UnhandledToken( + const char* m, std::string fn, int ln ) : + mMessage(m), mFile(std::move(fn)), mLineNumber(ln) {} + +OpenCLError::OpenCLError( std::string function, cl_int error, std::string file, int line ) : + mFunction(std::move(function)), mError(error), mFile(std::move(file)), mLineNumber(line) +{ + // Not sure if this SAL_INFO() is useful; the place in + // CLInterpreterContext::launchKernel() where OpenCLError is + // caught already uses SAL_WARN() to display it. + + // SAL_INFO("sc.opencl", "OpenCL error: " << openclwrapper::errorString(mError)); +} + +Unhandled::Unhandled( std::string fn, int ln ) : + mFile(std::move(fn)), mLineNumber(ln) {} + +InvalidParameterCount::InvalidParameterCount( int parameterCount, std::string file, int ln ) : + mParameterCount(parameterCount), mFile(std::move(file)), mLineNumber(ln) {} + +DynamicKernelArgument::DynamicKernelArgument( const ScCalcConfig& config, std::string s, + FormulaTreeNodeRef ft ) : + mCalcConfig(config), mSymName(std::move(s)), mFormulaTree(std::move(ft)) { } + +std::string DynamicKernelArgument::GenDoubleSlidingWindowDeclRef( bool ) const +{ + return std::string(""); +} + +/// When Mix, it will be called +std::string DynamicKernelArgument::GenStringSlidingWindowDeclRef( bool ) const +{ + return std::string(""); +} + +/// Generate use/references to the argument +void DynamicKernelArgument::GenDeclRef( outputstream& ss ) const +{ + ss << mSymName; +} + +void DynamicKernelArgument::GenSlidingWindowFunction( outputstream& ) {} + +FormulaToken* DynamicKernelArgument::GetFormulaToken() const +{ + return mFormulaTree->GetFormulaToken(); +} + +std::string DynamicKernelArgument::DumpOpName() const +{ + return std::string(""); +} + +void DynamicKernelArgument::DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const {} + +const std::string& DynamicKernelArgument::GetName() const +{ + return mSymName; +} + +bool DynamicKernelArgument::NeedParallelReduction() const +{ + return false; +} + +// Strings and OpenCL: +// * Strings are non-trivial types and so passing them to OpenCL and handling them there +// would be rather complex. However, in practice most string operations are checking +// string equality, so only such string usage is supported (other cases will be +// handled by Calc core when they get rejected for OpenCL). +// * Strings from Calc core come from svl::SharedString, which already ensures that +// equal strings have equal rtl_uString. +// * Strings are passed to opencl as integer IDs, each uniquely identifying a different +// string. +// * OpenCL code generally handles all values as doubles, so merely converting rtl_uString* +// to double could lead to loss of precision (double can store 52bits of precision). +// This could lead to two strings possibly being considered equal by mistake (unlikely, +// but not impossible). Therefore all rtl_uString* are mapped to internal integer IDs. +// * Functions that can handle strings properly should override OpBase::takeString() +// to return true. They should +// * Empty string Id is 0. Empty cell Id is NAN. +// * Since strings are marshalled as doubles too, it is important to check whether a value +// is a real double or a string. Use e.g. GenerateArgType to generate also 'xxx_is_string' +// variable, there is cell_equal() function to compare two cells. + +static std::unordered_map<const rtl_uString*, int>* stringIdsMap; + +int DynamicKernelArgument::GetStringId( const rtl_uString* string ) +{ + assert( string != nullptr ); + if( string->length == 0 ) + return 0; + if( stringIdsMap == nullptr ) + stringIdsMap = new std::unordered_map<const rtl_uString*, int>; + int newId = stringIdsMap->size() + 1; + auto aItInsertedPair = stringIdsMap->insert( std::pair( string, newId )); + return aItInsertedPair.first->second; +} + +void DynamicKernelArgument::ClearStringIds() +{ + delete stringIdsMap; + stringIdsMap = nullptr; +} + +VectorRef::VectorRef( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int idx ) : + DynamicKernelArgument(config, s, ft), mpClmem(nullptr), mnIndex(idx), forceStringsToZero( false ) +{ + if (mnIndex) + { + outputstream ss; + ss << mSymName << "s" << mnIndex; + mSymName = ss.str(); + } +} + +VectorRef::~VectorRef() +{ + if (mpClmem) + { + cl_int err; + err = clReleaseMemObject(mpClmem); + SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err)); + } +} + +/// Generate declaration +void VectorRef::GenDecl( outputstream& ss ) const +{ + ss << "__global double *" << mSymName; +} + +/// When declared as input to a sliding window function +void VectorRef::GenSlidingWindowDecl( outputstream& ss ) const +{ + VectorRef::GenDecl(ss); +} + +/// When referenced in a sliding window function +std::string VectorRef::GenSlidingWindowDeclRef( bool nested ) const +{ + outputstream ss; + formula::SingleVectorRefToken* pSVR = + dynamic_cast<formula::SingleVectorRefToken*>(DynamicKernelArgument::GetFormulaToken()); + if (pSVR && !nested) + ss << "(gid0 < " << pSVR->GetArrayLength() << "?"; + ss << mSymName << "[gid0]"; + if (pSVR && !nested) + ss << ":NAN)"; + return ss.str(); +} + +void VectorRef::GenSlidingWindowFunction( outputstream& ) {} + +size_t VectorRef::GetWindowSize() const +{ + FormulaToken* pCur = mFormulaTree->GetFormulaToken(); + assert(pCur); + if (const formula::DoubleVectorRefToken* pCurDVR = + dynamic_cast<const formula::DoubleVectorRefToken*>(pCur)) + { + return pCurDVR->GetRefRowSize(); + } + else if (dynamic_cast<const formula::SingleVectorRefToken*>(pCur)) + { + // Prepare intermediate results (on CPU for now) + return 1; + } + else + { + throw Unhandled(__FILE__, __LINE__); + } +} + +std::string VectorRef::DumpOpName() const +{ + return std::string(""); +} + +void VectorRef::DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const {} + +const std::string& VectorRef::GetName() const +{ + return mSymName; +} + +cl_mem VectorRef::GetCLBuffer() const +{ + return mpClmem; +} + +bool VectorRef::NeedParallelReduction() const +{ + return false; +} + +VectorRefStringsToZero::VectorRefStringsToZero( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft, int index ) + : VectorRef( config, s, ft, index ) +{ + forceStringsToZero = true; +} + +void SlidingFunctionBase::GenerateArg( const char* name, int arg, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, GenerateArgTypeType generateType ) +{ + assert( arg < int( vSubArguments.size())); + FormulaToken *token = vSubArguments[arg]->GetFormulaToken(); + if( token == nullptr ) + throw Unhandled( __FILE__, __LINE__ ); + if(token->GetOpCode() == ocPush) + { + if(token->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* svr = + static_cast<const formula::SingleVectorRefToken *>(token); + ss << " double " << name << " = NAN;\n"; + if( generateType == GenerateArgType ) + ss << " bool " << name << "_is_string = false;\n"; + ss << " if (gid0 < " << svr->GetArrayLength() << ")\n"; + if( generateType == GenerateArgType ) + ss << " {\n"; + ss << " " << name << " = "; + ss << vSubArguments[arg]->GenSlidingWindowDeclRef( true ) << ";\n"; + if( generateType == GenerateArgType ) + { + ss << " " << name << "_is_string = "; + ss << vSubArguments[arg]->GenIsString( true ) << ";\n"; + ss << " }\n"; + } + switch( empty ) + { + case EmptyIsZero: + ss << " if( isnan( " << name << " ))\n"; + ss << " " << name << " = 0;\n"; + break; + case EmptyIsNan: + break; + case SkipEmpty: + abort(); + break; + } + } + else if(token->GetType() == formula::svDouble) + { + ss << " double " << name << " = " << token->GetDouble() << ";\n"; + if( generateType == GenerateArgType ) + ss << " bool " << name << "_is_string = " + << vSubArguments[arg]->GenIsString() << ";\n"; + } + else if(token->GetType() == formula::svString) + { + if( forceStringsToZero()) + assert( dynamic_cast<DynamicKernelStringToZeroArgument*>(vSubArguments[arg].get())); + else if( !takeString()) + throw Unhandled( __FILE__, __LINE__ ); + ss << " double " << name << " = 0.0;\n"; + if( generateType == GenerateArgType ) + ss << " bool " << name << "_is_string = " + << vSubArguments[arg]->GenIsString() << ";\n"; + } + else + throw Unhandled( __FILE__, __LINE__ ); + } + else + { + ss << " double " << name << " = "; + ss << vSubArguments[arg]->GenSlidingWindowDeclRef() << ";\n"; + if( generateType == GenerateArgType ) + ss << " bool " << name << "_is_string = " + << vSubArguments[arg]->GenIsString() << ";\n"; + } +} + +void SlidingFunctionBase::GenerateArg( int arg, SubArguments& vSubArguments, outputstream& ss, + EmptyArgType empty, GenerateArgTypeType generateType ) +{ + OString buf = "arg" + OString::number(arg); + GenerateArg( buf.getStr(), arg, vSubArguments, ss, empty, generateType ); +} + +void SlidingFunctionBase::GenerateArgWithDefault( const char* name, int arg, double def, + SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty ) +{ + if( arg < int(vSubArguments.size())) + GenerateArg( name, arg, vSubArguments, ss, empty ); + else + ss << " double " << name << " = " << def << ";\n"; +} + +void SlidingFunctionBase::GenerateRangeArgs( int firstArg, int lastArg, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code ) +{ + assert( firstArg >= 0 ); + assert( firstArg <= lastArg ); + assert( lastArg < int( vSubArguments.size())); + for( int i = firstArg; + i <= lastArg; + ++i ) + { + FormulaToken *token = vSubArguments[i]->GetFormulaToken(); + if( token == nullptr ) + throw Unhandled( __FILE__, __LINE__ ); + if(token->GetOpCode() == ocPush) + { + if (token->GetType() == formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken *>(token); + GenerateDoubleVectorLoopHeader( ss, pDVR, nullptr ); + ss << " double arg = "; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(); + ss << ";\n"; + switch( empty ) + { + case EmptyIsZero: + ss << " if( isnan( arg ))\n"; + ss << " arg = 0;\n"; + break; + case EmptyIsNan: + break; + case SkipEmpty: + ss << " if( isnan( arg ))\n"; + ss << " continue;\n"; + break; + } + ss << code; + ss << " }\n"; + } + else if (token->GetType() == formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pSVR = + static_cast< const formula::SingleVectorRefToken*>(token); + ss << " if (gid0 < " << pSVR->GetArrayLength() << ")\n"; + ss << " {\n"; + ss << " double arg = "; + ss << vSubArguments[i]->GenSlidingWindowDeclRef() << ";\n"; + switch( empty ) + { + case EmptyIsZero: + ss << " if( isnan( arg ))\n"; + ss << " arg = 0;\n"; + ss << code; + break; + case EmptyIsNan: + ss << code; + break; + case SkipEmpty: + ss << " if( !isnan( arg ))\n"; + ss << " {\n"; + ss << code; + ss << " }\n"; + break; + } + ss << " }\n"; + } + else if(token->GetType() == formula::svDouble) + { + ss << " {\n"; + ss << " double arg = " << token->GetDouble() << ";\n"; + ss << code; + ss << " }\n"; + } + else if(token->GetType() == formula::svString) + { + assert( dynamic_cast<DynamicKernelStringToZeroArgument*>(vSubArguments[i].get())); + ss << " {\n"; + ss << " double arg = 0.0;\n"; + ss << code; + ss << " }\n"; + } + else + throw Unhandled( __FILE__, __LINE__ ); + } + else + { + ss << " {\n"; + ss << " double arg = "; + ss << vSubArguments[i]->GenSlidingWindowDeclRef() << ";\n"; + ss << code; + ss << " }\n"; + } + } +} + +void SlidingFunctionBase::GenerateRangeArgs( SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code ) +{ + GenerateRangeArgs( 0, vSubArguments.size() - 1, vSubArguments, ss, empty, code ); +} + +void SlidingFunctionBase::GenerateRangeArg( int arg, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code ) +{ + GenerateRangeArgs( arg, arg, vSubArguments, ss, empty, code ); +} + +void SlidingFunctionBase::GenerateRangeArgPair( int arg1, int arg2, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff ) +{ + assert( arg1 >= 0 && arg1 < int (vSubArguments.size())); + assert( arg2 >= 0 && arg2 < int (vSubArguments.size())); + assert( arg1 != arg2 ); + FormulaToken *token1 = vSubArguments[arg1]->GetFormulaToken(); + if( token1 == nullptr ) + throw Unhandled( __FILE__, __LINE__ ); + FormulaToken *token2 = vSubArguments[arg2]->GetFormulaToken(); + if( token2 == nullptr ) + throw Unhandled( __FILE__, __LINE__ ); + if(token1->GetType() != formula::svDoubleVectorRef + || token2->GetType() != formula::svDoubleVectorRef) + { + throw Unhandled( __FILE__, __LINE__ ); + } + const formula::DoubleVectorRefToken* pDVR1 = + static_cast<const formula::DoubleVectorRefToken *>(token1); + const formula::DoubleVectorRefToken* pDVR2 = + static_cast<const formula::DoubleVectorRefToken *>(token2); + + size_t nCurWindowSize1 = pDVR1->GetRefRowSize(); + size_t nCurWindowSize2 = pDVR2->GetRefRowSize(); + + if(nCurWindowSize1 != nCurWindowSize2) + throw Unhandled( __FILE__, __LINE__ ); + if(pDVR1->IsStartFixed() != pDVR2->IsStartFixed() + || pDVR1->IsEndFixed() != pDVR2->IsEndFixed()) + { + throw Unhandled( __FILE__, __LINE__ ); + } + + // If either of the ranges ends with empty cells, it will not include those last + // nan values (its GetArrayLength() will be less than its GetRefRowSize(). + // If we skip empty cells, just iterate until both ranges have elements, but if + // we need to iterate even over empty cells, so use the longer one. + // FIXME: If both ranges end with empty cells, this does not actually iterate + // over all empty cells. + const formula::DoubleVectorRefToken* loopDVR; + bool checkBounds; + if( empty == SkipEmpty ) + { + loopDVR = pDVR1->GetArrayLength() < pDVR2->GetArrayLength() ? pDVR1 : pDVR2; + checkBounds = false; + } + else + { + loopDVR = pDVR1->GetArrayLength() > pDVR2->GetArrayLength() ? pDVR1 : pDVR2; + checkBounds = true; + } + GenerateDoubleVectorLoopHeader( ss, loopDVR, firstElementDiff ); + ss << " double arg1 = "; + ss << vSubArguments[arg1]->GenSlidingWindowDeclRef(!checkBounds) << ";\n"; + ss << " double arg2 = "; + ss << vSubArguments[arg2]->GenSlidingWindowDeclRef(!checkBounds) << ";\n"; + switch( empty ) + { + case EmptyIsZero: + ss << " if( isnan( arg1 ))\n"; + ss << " arg1 = 0;\n"; + ss << " if( isnan( arg2 ))\n"; + ss << " arg2 = 0;\n"; + break; + case EmptyIsNan: + break; + case SkipEmpty: + ss << " if( isnan( arg1 ) || isnan( arg2 ))\n"; + ss << " continue;\n"; + break; + } + ss << code; + ss << " }\n"; +} + +void SlidingFunctionBase::GenerateRangeArgElement( const char* name, int arg, const char* element, + SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty ) +{ + assert( arg >= 0 && arg < int (vSubArguments.size())); + FormulaToken *token = vSubArguments[arg]->GetFormulaToken(); + if( token == nullptr ) + throw Unhandled( __FILE__, __LINE__ ); + if(token->GetType() != formula::svDoubleVectorRef) + throw Unhandled( __FILE__, __LINE__ ); + const formula::DoubleVectorRefToken* pDVR = + static_cast<const formula::DoubleVectorRefToken *>(token); + ss << " double " << name << " = NAN;\n"; + ss << " {\n"; + // GenSlidingWindowDeclRef() may refer to 'i' variable. + ss << " int i = 0;\n"; + ss << " if( "; + if( !pDVR->IsStartFixed()) + ss << "gid0 + "; + ss << element << " < " << pDVR->GetArrayLength() << " )\n"; + ss << " " << name << " = " << vSubArguments[arg]->GenSlidingWindowDeclRef(true) << ";\n"; + ss << " }\n"; + switch( empty ) + { + case EmptyIsZero: + ss << " if( isnan( " << name << " ))\n"; + ss << " " << name << " = 0;\n"; + break; + case EmptyIsNan: + break; + case SkipEmpty: + abort(); + break; + } +} + +void SlidingFunctionBase::GenerateDoubleVectorLoopHeader( outputstream& ss, + const formula::DoubleVectorRefToken* pDVR, const char* firstElementDiff ) +{ + size_t nCurWindowSize = pDVR->GetRefRowSize(); + std::string startDiff; + if( firstElementDiff ) + startDiff = std::string( " + " ) + firstElementDiff; + ss << " for (int i = "; + if (!pDVR->IsStartFixed() && pDVR->IsEndFixed()) + { + ss << "gid0" << startDiff << "; i < " << pDVR->GetArrayLength(); + ss << " && i < " << nCurWindowSize << "; i++)\n"; + ss << " {\n"; + } + else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed()) + { + ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength(); + ss << " && i < gid0+" << nCurWindowSize << "; i++)\n"; + ss << " {\n"; + } + else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed()) + { + ss << "0" << startDiff << "; i + gid0 < " << pDVR->GetArrayLength(); + ss << " && i < " << nCurWindowSize << "; i++)\n"; + ss << " {\n"; + } + else + { + ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength() << "; i++)\n"; + ss << " {\n"; + } +} + +void SlidingFunctionBase::GenerateFunctionDeclaration( const std::string& sSymName, + SubArguments& vSubArguments, outputstream& ss ) +{ + ss << "\ndouble " << sSymName; + ss << "_"<< BinFuncName() <<"("; + for (size_t i = 0; i < vSubArguments.size(); i++) + { + if (i) + ss << ", "; + vSubArguments[i]->GenSlidingWindowDecl(ss); + } + ss << ")\n"; +} + +void Normal::GenSlidingWindowFunction( + outputstream& ss, const std::string& sSymName, SubArguments& vSubArguments ) +{ + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n\t"; + ss << "double tmp = " << GetBottom() << ";\n\t"; + ss << "int gid0 = get_global_id(0);\n\t"; + ss << "tmp = "; + std::vector<std::string> argVector; + for (size_t i = 0; i < vSubArguments.size(); i++) + argVector.push_back(vSubArguments[i]->GenSlidingWindowDeclRef()); + ss << Gen(argVector); + ss << ";\n\t"; + ss << "return tmp;\n"; + ss << "}"; +} + +void CheckVariables::GenTmpVariables( + outputstream& ss, const SubArguments& vSubArguments ) +{ + for (size_t i = 0; i < vSubArguments.size(); i++) + { + ss << " double tmp"; + ss << i; + ss << ";\n"; + } +} + +void CheckVariables::CheckSubArgumentIsNan( outputstream& ss, + SubArguments& vSubArguments, int argumentNum ) +{ + int i = argumentNum; + if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svSingleVectorRef) + { + const formula::SingleVectorRefToken* pTmpDVR1 = + static_cast<const formula::SingleVectorRefToken*>(vSubArguments[i]->GetFormulaToken()); + ss << " if(singleIndex>="; + ss << pTmpDVR1->GetArrayLength(); + ss << " ||"; + ss << "isnan("; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(true); + ss << "))\n"; + ss << " tmp"; + ss << i; + ss << "=0;\n else \n"; + ss << " tmp"; + ss << i; + ss << "="; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(true); + ss << ";\n"; + } + if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svDoubleVectorRef) + { + const formula::DoubleVectorRefToken* pTmpDVR2 = + static_cast<const formula::DoubleVectorRefToken*>(vSubArguments[i]->GetFormulaToken()); + ss << " if(doubleIndex>="; + ss << pTmpDVR2->GetArrayLength(); + ss << " ||"; + ss << "isnan("; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(); + ss << "))\n"; + ss << " tmp"; + ss << i; + ss << "=0;\n else \n"; + ss << " tmp"; + ss << i; + ss << "="; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(); + ss << ";\n"; + } + if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble || + vSubArguments[i]->GetFormulaToken()->GetOpCode() != ocPush) + { + ss << " if("; + ss << "isnan("; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(); + ss << "))\n"; + ss << " tmp"; + ss << i; + ss << "=0;\n else \n"; + ss << " tmp"; + ss << i; + ss << "="; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(); + ss << ";\n"; + + } + +} + +void CheckVariables::CheckSubArgumentIsNan2( outputstream& ss, + SubArguments& vSubArguments, int argumentNum, const std::string& p ) +{ + int i = argumentNum; + if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble) + { + ss << " tmp"; + ss << i; + ss << "="; + vSubArguments[i]->GenDeclRef(ss); + ss << ";\n"; + return; + } + + ss << " tmp"; + ss << i; + ss << "= fsum("; + vSubArguments[i]->GenDeclRef(ss); + if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svDoubleVectorRef) + ss << "[" << p.c_str() << "]"; + else if (vSubArguments[i]->GetFormulaToken()->GetType() == + formula::svSingleVectorRef) + ss << "[get_group_id(1)]"; + ss << ", 0);\n"; +} + +void CheckVariables::CheckAllSubArgumentIsNan( + outputstream& ss, SubArguments& vSubArguments ) +{ + ss << " int k = gid0;\n"; + for (size_t i = 0; i < vSubArguments.size(); i++) + { + CheckSubArgumentIsNan(ss, vSubArguments, i); + } +} + +void CheckVariables::UnrollDoubleVector( outputstream& ss, + const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR, + int nCurWindowSize ) +{ + int unrollSize = 16; + if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) + { + ss << " loop = (" << nCurWindowSize << " - gid0)/"; + ss << unrollSize << ";\n"; + } + else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << " loop = (" << nCurWindowSize << " + gid0)/"; + ss << unrollSize << ";\n"; + + } + else + { + ss << " loop = " << nCurWindowSize << "/" << unrollSize << ";\n"; + } + + ss << " for ( int j = 0;j< loop; j++)\n"; + ss << " {\n"; + ss << " int i = "; + if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) + { + ss << "gid0 + j * " << unrollSize << ";\n"; + } + else + { + ss << "j * " << unrollSize << ";\n"; + } + + if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << " int doubleIndex = i+gid0;\n"; + } + else + { + ss << " int doubleIndex = i;\n"; + } + + for (int j = 0; j < unrollSize; j++) + { + ss << unrollstr.str(); + ss << "i++;\n"; + ss << "doubleIndex++;\n"; + } + ss << " }\n"; + ss << " for (int i = "; + if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) + { + ss << "gid0 + loop *" << unrollSize << "; i < "; + ss << nCurWindowSize << "; i++)\n"; + } + else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << "0 + loop *" << unrollSize << "; i < gid0+"; + ss << nCurWindowSize << "; i++)\n"; + } + else + { + ss << "0 + loop *" << unrollSize << "; i < "; + ss << nCurWindowSize << "; i++)\n"; + } + ss << " {\n"; + if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) + { + ss << " int doubleIndex = i+gid0;\n"; + } + else + { + ss << " int doubleIndex = i;\n"; + } + ss << unrollstr.str(); + ss << " }\n"; +} + +void Reduction::GenSlidingWindowFunction( outputstream& ss, + const std::string& sSymName, SubArguments& vSubArguments ) +{ + GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); + ss << "{\n"; + ss << "double tmp = " << GetBottom() << ";\n"; + ss << "int gid0 = get_global_id(0);\n"; + if (isAverage() || isMinOrMax()) + ss << "int nCount = 0;\n"; + ss << "double tmpBottom;\n"; + unsigned i = vSubArguments.size(); + while (i--) + { + if (NumericRange* NR = dynamic_cast<NumericRange*>(vSubArguments[i].get())) + { + bool needBody; + NR->GenReductionLoopHeader(ss, needBody); + if (!needBody) + continue; + } + else if (NumericRangeStringsToZero* NRS = dynamic_cast<NumericRangeStringsToZero*>(vSubArguments[i].get())) + { + bool needBody; + NRS->GenReductionLoopHeader(ss, needBody); + if (!needBody) + continue; + } + else if (ParallelNumericRange* PNR = dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get())) + { + //did not handle yet + bool bNeedBody = false; + PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody); + if (!bNeedBody) + continue; + } + else if (StringRange* SR = dynamic_cast<StringRange*>(vSubArguments[i].get())) + { + //did not handle yet + bool needBody; + SR->GenReductionLoopHeader(ss, needBody); + if (!needBody) + continue; + } + else + { + FormulaToken* pCur = vSubArguments[i]->GetFormulaToken(); + if( pCur == nullptr || pCur->GetType() == formula::svDoubleVectorRef ) + { + throw Unhandled(__FILE__, __LINE__); + } + ss << "{\n"; + } + if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode()) + { + bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments); + + ss << " tmpBottom = " << GetBottom() << ";\n"; + + if (!bNanHandled) + { + ss << " if (isnan("; + ss << vSubArguments[i]->GenSlidingWindowDeclRef(); + ss << "))\n"; + if (ZeroReturnZero()) + ss << " return 0;\n"; + else + { + ss << " tmp = "; + ss << Gen2("tmpBottom", "tmp") << ";\n"; + } + ss << " else\n"; + } + ss << " tmp = "; + ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp"); + ss << ";\n"; + } + else + { + ss << " tmp = "; + ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp"); + ss << ";\n"; + } + ss << "}\n"; + } + if (isAverage()) + ss << + "if (nCount==0)\n" + " return CreateDoubleError(DivisionByZero);\n"; + else if (isMinOrMax()) + ss << + "if (nCount==0)\n" + " return 0;\n"; + ss << "return tmp"; + if (isAverage()) + ss << "/(double)nCount"; + ss << ";\n}"; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/opbase.hxx b/sc/source/core/opencl/opbase.hxx new file mode 100644 index 0000000000..04ebab1ee7 --- /dev/null +++ b/sc/source/core/opencl/opbase.hxx @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <clew/clew.h> +#include <formula/token.hxx> +#include <formula/types.hxx> +#include <formula/vectortoken.hxx> +#include <opencl/OpenCLZone.hxx> +#include <sal/log.hxx> +#include <memory> +#include <set> +#include <vector> +#include "utils.hxx" + +struct ScCalcConfig; + +namespace sc::opencl { + +// FIXME: The idea that somebody would bother to (now and then? once a year? once a month?) manually +// edit a source file and change the value of some #defined constant and run some ill-defined +// "correctness test" is of course ludicrous. Either things are checked in normal unit tests, in +// every 'make check', or not at all. The below comments are ridiculous. + +#define REDUCE_THRESHOLD 201 // set to 4 for correctness testing. priority 1 +#define UNROLLING_FACTOR 16 // set to 4 for correctness testing (if no reduce) + + +class FormulaTreeNode; + +/// Exceptions + +/// Failed in parsing +class UnhandledToken +{ +public: + UnhandledToken( const char* m, std::string fn, int ln ); + + std::string mMessage; + std::string mFile; + int mLineNumber; +}; + +/// Failed in marshaling +class OpenCLError +{ +public: + OpenCLError( std::string function, cl_int error, std::string file, int line ); + + std::string mFunction; + cl_int mError; + std::string mFile; + int mLineNumber; +}; + +/// Inconsistent state +class Unhandled +{ +public: + Unhandled( std::string fn, int ln ); + + std::string mFile; + int mLineNumber; +}; + +class InvalidParameterCount +{ +public: + InvalidParameterCount( int parameterCount, std::string file, int ln ); + + int mParameterCount; + std::string mFile; + int const mLineNumber; +}; + +// Helper macros to be used in code emitting OpenCL code for Calc functions. +// Require the vSubArguments parameter. +#define CHECK_PARAMETER_COUNT(min, max) \ + do { \ + const int count = vSubArguments.size(); \ + if( count < ( min ) || count > ( max )) \ + throw InvalidParameterCount( count, __FILE__, __LINE__ ); \ + } while( false ) +#define CHECK_PARAMETER_COUNT_MIN(min) \ + do { \ + const int count = vSubArguments.size(); \ + if( count < ( min )) \ + throw InvalidParameterCount( count, __FILE__, __LINE__ ); \ + } while( false ) +#define CHECK_PARAMETER_DOUBLEVECTORREF(arg) \ + do { \ + formula::FormulaToken *token = vSubArguments[arg]->GetFormulaToken(); \ + if (token == nullptr || token->GetType() != formula::svDoubleVectorRef) \ + throw Unhandled(__FILE__, __LINE__); \ + } while( false ) + +typedef std::shared_ptr<FormulaTreeNode> FormulaTreeNodeRef; + +class FormulaTreeNode +{ +public: + explicit FormulaTreeNode( const formula::FormulaToken* ft ) : mpCurrentFormula(ft) + { + Children.reserve(8); + } + std::vector<FormulaTreeNodeRef> Children; + formula::FormulaToken* GetFormulaToken() const + { + return const_cast<formula::FormulaToken*>(mpCurrentFormula.get()); + } + +private: + formula::FormulaConstTokenRef mpCurrentFormula; +}; + +/// (Partially) abstract base class for an operand +class DynamicKernelArgument +{ +public: + /// delete copy constructor + DynamicKernelArgument( const DynamicKernelArgument& ) = delete; + + /// delete copy-assignment operator + const DynamicKernelArgument& operator=( const DynamicKernelArgument& ) = delete; + + DynamicKernelArgument( const ScCalcConfig& config, std::string s, FormulaTreeNodeRef ft ); + virtual ~DynamicKernelArgument() {} + + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const = 0; + + /// When declared as input to a sliding window function + virtual void GenSlidingWindowDecl( outputstream& ss ) const = 0; + + /// When referenced in a sliding window function + virtual std::string GenSlidingWindowDeclRef( bool = false ) const = 0; + + /// Create buffer and pass the buffer to a given kernel + virtual size_t Marshal( cl_kernel, int, int, cl_program ) = 0; + + virtual size_t GetWindowSize() const = 0; + + /// When Mix, it will be called + virtual std::string GenDoubleSlidingWindowDeclRef( bool = false ) const; + + /// When Mix, it will be called + virtual std::string GenStringSlidingWindowDeclRef( bool = false ) const; + + /// Will generate value saying whether the value is a string. + virtual std::string GenIsString( bool = false ) const { return "false"; } + + /// Generate use/references to the argument + virtual void GenDeclRef( outputstream& ss ) const; + + virtual void GenSlidingWindowFunction( outputstream& ); + formula::FormulaToken* GetFormulaToken() const; + virtual std::string DumpOpName() const; + virtual void DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const; + const std::string& GetName() const; + virtual bool NeedParallelReduction() const; + /// If there's actually no argument, i.e. it expands to no code. + virtual bool IsEmpty() const { return false; } + + static void ClearStringIds(); + +protected: + const ScCalcConfig& mCalcConfig; + std::string mSymName; + FormulaTreeNodeRef mFormulaTree; + static int GetStringId( const rtl_uString* string ); +}; + +typedef std::shared_ptr<DynamicKernelArgument> DynamicKernelArgumentRef; + +/// Holds an input (read-only) argument reference to a SingleVectorRef. +/// or a DoubleVectorRef for non-sliding-window argument of complex functions +/// like SumOfProduct +/// In most of the cases the argument is introduced +/// by a Push operation in the given RPN. +class VectorRef : public DynamicKernelArgument +{ +public: + VectorRef( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int index = 0 ); + virtual ~VectorRef() override; + + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override; + /// When declared as input to a sliding window function + virtual void GenSlidingWindowDecl( outputstream& ss ) const override; + + /// When referenced in a sliding window function + virtual std::string GenSlidingWindowDeclRef( bool = false ) const override; + + /// Create buffer and pass the buffer to a given kernel + virtual size_t Marshal( cl_kernel, int, int, cl_program ) override; + + virtual void GenSlidingWindowFunction( outputstream& ) override; + virtual size_t GetWindowSize() const override; + virtual std::string DumpOpName() const override; + virtual void DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const override; + const std::string& GetName() const; + cl_mem GetCLBuffer() const; + virtual bool NeedParallelReduction() const override; + +protected: + // Used by marshaling + cl_mem mpClmem; + // index in multiple double vector refs that have multiple ranges + const int mnIndex; + // Makes Marshall convert strings to 0 values. + bool forceStringsToZero; + // Used for storing when the data needs to be modified before sending to OpenCL. + std::vector< double > dataBuffer; +}; + +// Sets VectorRef::forceStringsToZero. +class VectorRefStringsToZero : public VectorRef +{ +public: + VectorRefStringsToZero( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int index = 0 ); +}; + +/// A vector of strings +class DynamicKernelStringArgument : public VectorRef +{ +public: + DynamicKernelStringArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft, int index = 0 ) : + VectorRef(config, s, ft, index) { } + + virtual void GenSlidingWindowFunction( outputstream& ) override { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + ss << "__global double *" << mSymName; + } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + DynamicKernelStringArgument::GenDecl(ss); + } + virtual std::string GenIsString( bool = false ) const override; + virtual size_t Marshal( cl_kernel, int, int, cl_program ) override; +}; + +/// Arguments that are actually compile-time constants +class DynamicKernelConstantArgument : public DynamicKernelArgument +{ +public: + DynamicKernelConstantArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft ) : + DynamicKernelArgument(config, s, ft) { } + /// Generate declaration + virtual void GenDecl( outputstream& ss ) const override + { + ss << "double " << mSymName; + } + virtual void GenDeclRef( outputstream& ss ) const override + { + ss << mSymName; + } + virtual void GenSlidingWindowDecl( outputstream& ss ) const override + { + GenDecl(ss); + } + virtual std::string GenSlidingWindowDeclRef( bool = false ) const override + { + if (GetFormulaToken()->GetType() != formula::svDouble) + throw Unhandled(__FILE__, __LINE__); + return mSymName; + } + virtual size_t GetWindowSize() const override + { + return 1; + } + virtual double GetDouble() const + { + formula::FormulaToken* Tok = GetFormulaToken(); + if (Tok->GetType() != formula::svDouble) + throw Unhandled(__FILE__, __LINE__); + return Tok->GetDouble(); + } + /// Create buffer and pass the buffer to a given kernel + virtual size_t Marshal( cl_kernel k, int argno, int, cl_program ) override + { + OpenCLZone zone; + double tmp = GetDouble(); + // Pass the scalar result back to the rest of the formula kernel + SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": double: " << preciseFloat( tmp )); + cl_int err = clSetKernelArg(k, argno, sizeof(double), static_cast<void*>(&tmp)); + if (CL_SUCCESS != err) + throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); + return 1; + } +}; + +// Constant 0 argument when a string is forced to zero. +class DynamicKernelStringToZeroArgument : public DynamicKernelConstantArgument +{ +public: + DynamicKernelStringToZeroArgument( const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft ) : + DynamicKernelConstantArgument(config, s, ft) { } + virtual std::string GenSlidingWindowDeclRef( bool = false ) const override + { + return mSymName; + } + virtual double GetDouble() const override { return 0; } +}; + + +/// Abstract class for code generation +class OpBase +{ +public: + // FIXME: What exactly is this? It seems to be a starting value for some calculations + // (1 for OpMul, MAXFLOAT for OpMin), but it's often used pointlessly and sometimes + // even incorrectly (default value for when the cell is empty). + virtual std::string GetBottom() { return "";}; + virtual std::string Gen2( const std::string&/*lhs*/, + const std::string&/*rhs*/ ) const { return "";} + static std::string Gen( std::vector<std::string>& /*argVector*/ ) { return "";}; + virtual std::string BinFuncName() const { return "";}; + virtual void BinInlineFun( std::set<std::string>&, + std::set<std::string>& ) { } + virtual bool takeString() const = 0; + virtual bool takeNumeric() const = 0; + // Whether DoubleRef containing more than one column is handled properly. + virtual bool canHandleMultiVector() const { return false; } + //Continue process 'Zero' or Not(like OpMul, not continue process when meet + // 'Zero' + virtual bool ZeroReturnZero() { return false;} + // For use with COUNTA() etc, input strings will be converted to 0 in data. + virtual bool forceStringsToZero() const { return false; } + virtual ~OpBase() { } +}; + +class SlidingFunctionBase : public OpBase +{ +public: + typedef std::vector<DynamicKernelArgumentRef> SubArguments; + virtual void GenSlidingWindowFunction( outputstream&, + const std::string&, SubArguments& ) = 0; +protected: + // This enum controls how the generated code will handle empty cells in ranges. + enum EmptyArgType + { + EmptyIsZero, // empty cells become 0.0 + EmptyIsNan, // empty cells become NAN, use isnan() to check in code + SkipEmpty // empty cells will be skipped + }; + // This enum controls whether the generated code will also include variable + // <name>_is_string that will be set depending on the value type. + enum GenerateArgTypeType + { + DoNotGenerateArgType, + GenerateArgType + }; + void GenerateFunctionDeclaration( const std::string& sSymName, + SubArguments& vSubArguments, outputstream& ss ); + // Generate code for "double <name> = <value>;" from vSubArguments, svDoubleVectorRef is not supported. + void GenerateArg( const char* name, int arg, SubArguments& vSubArguments, outputstream& ss, + EmptyArgType empty = EmptyIsZero, GenerateArgTypeType generateType = DoNotGenerateArgType ); + // overload, variable will be named "arg<arg>" + void GenerateArg( int arg, SubArguments& vSubArguments, outputstream& ss, + EmptyArgType empty = EmptyIsZero, GenerateArgTypeType generateType = DoNotGenerateArgType ); + // generate code for "double <name> = <value>;" from vSubArguments, if it exists, + // otherwise set to <def> + void GenerateArgWithDefault( const char* name, int arg, double def, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty = EmptyIsZero ); + // Generate code that will handle all arguments firstArg-lastArg (zero-based, inclusive), + // including range arguments (svDoubleVectorRef) and each value will be processed by 'code', + // value will be named "arg". + static void GenerateRangeArgs( int firstArg, int lastArg, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code ); + // overload, handle all arguments + static void GenerateRangeArgs( SubArguments& vSubArguments, outputstream& ss, + EmptyArgType empty, const char* code ); + // overload, handle the given argument + static void GenerateRangeArg( int arg, SubArguments& vSubArguments, outputstream& ss, + EmptyArgType empty, const char* code ); + // Overload. + // Both arguments must be svDoubleRef of the same size. + // If 'firstElementDiff' is set, the loop start will be offset by '+ firstElementDiff'. + void GenerateRangeArg( int arg1, int arg2, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff = nullptr ); + // Generate code that will handle the given two arguments in one loop where n-th element of arg1 and arg2 + // will be handled at the same time, named 'arg1' and 'arg2'. + // Both arguments must be svDoubleRef of the same size. + // If 'firstElementDiff' is set, the loop start will be offset by '+ firstElementDiff'. + static void GenerateRangeArgPair( int arg1, int arg2, SubArguments& vSubArguments, + outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff = nullptr ); + // Generate code for "double <name> = range[<element>]" from vSubArguments. + // The argument must be svDoubleRef. + static void GenerateRangeArgElement( const char* name, int arg, const char* element, + SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty ); + static void GenerateDoubleVectorLoopHeader( outputstream& ss, + const formula::DoubleVectorRefToken* pDVR, const char* firstElementDiff ); +}; + +class Normal : public SlidingFunctionBase +{ +public: + virtual void GenSlidingWindowFunction( outputstream& ss, + const std::string& sSymName, SubArguments& vSubArguments ) override; + virtual bool takeString() const override { return false; } + virtual bool takeNumeric() const override { return true; } +}; + +class CheckVariables : public Normal +{ +public: + static void GenTmpVariables( outputstream& ss, const SubArguments& vSubArguments ); + static void CheckSubArgumentIsNan( outputstream& ss, + SubArguments& vSubArguments, int argumentNum ); + static void CheckAllSubArgumentIsNan( outputstream& ss, + SubArguments& vSubArguments ); + // only check isnan + static void CheckSubArgumentIsNan2( outputstream& ss, + SubArguments& vSubArguments, int argumentNum, const std::string& p ); + static void UnrollDoubleVector( outputstream& ss, + const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR, + int nCurWindowSize ); +}; + +class OpAverage; +class OpCount; + +/// Handling a Double Vector that is used as a sliding window input +/// to either a sliding window average or sum-of-products +/// Generate a sequential loop for reductions +template<class Base> +class DynamicKernelSlidingArgument : public Base +{ +public: + DynamicKernelSlidingArgument(const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft, + std::shared_ptr<SlidingFunctionBase> CodeGen, int index); + // Should only be called by SumIfs. Yikes! + virtual bool NeedParallelReduction() const; + virtual void GenSlidingWindowFunction( outputstream& ) { } + + std::string GenSlidingWindowDeclRef( bool nested = false ) const; + /// Controls how the elements in the DoubleVectorRef are traversed + size_t GenReductionLoopHeader( outputstream& ss, bool& needBody ); + + size_t GetArrayLength() const { return mpDVR->GetArrayLength(); } + + size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); } + + bool GetStartFixed() const { return bIsStartFixed; } + + bool GetEndFixed() const { return bIsEndFixed; } + +protected: + bool bIsStartFixed, bIsEndFixed; + const formula::DoubleVectorRefToken* mpDVR; + // from parent nodes + std::shared_ptr<SlidingFunctionBase> mpCodeGen; +}; + +/// Handling a Double Vector that is used as a sliding window input +/// Performs parallel reduction based on given operator +template<class Base> +class ParallelReductionVectorRef : public Base +{ +public: + ParallelReductionVectorRef(const ScCalcConfig& config, const std::string& s, + const FormulaTreeNodeRef& ft, + std::shared_ptr<SlidingFunctionBase> CodeGen, int index); + ~ParallelReductionVectorRef(); + + /// Emit the definition for the auxiliary reduction kernel + virtual void GenSlidingWindowFunction( outputstream& ss ); + virtual std::string GenSlidingWindowDeclRef( bool ) const; + /// Controls how the elements in the DoubleVectorRef are traversed + size_t GenReductionLoopHeader( outputstream& ss, int nResultSize, bool& needBody ); + virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program mpProgram ); + size_t GetArrayLength() const { return mpDVR->GetArrayLength(); } + size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); } + bool GetStartFixed() const { return bIsStartFixed; } + bool GetEndFixed() const { return bIsEndFixed; } + +protected: + bool bIsStartFixed, bIsEndFixed; + const formula::DoubleVectorRefToken* mpDVR; + // from parent nodes + std::shared_ptr<SlidingFunctionBase> mpCodeGen; + // controls whether to invoke the reduction kernel during marshaling or not + cl_mem mpClmem2; +}; + +class Reduction : public SlidingFunctionBase +{ + int const mnResultSize; +public: + explicit Reduction(int nResultSize) : mnResultSize(nResultSize) {} + + typedef DynamicKernelSlidingArgument<VectorRef> NumericRange; + typedef DynamicKernelSlidingArgument<VectorRefStringsToZero> NumericRangeStringsToZero; + typedef DynamicKernelSlidingArgument<DynamicKernelStringArgument> StringRange; + typedef ParallelReductionVectorRef<VectorRef> ParallelNumericRange; + + virtual bool HandleNaNArgument( outputstream&, unsigned, SubArguments& ) const + { + return false; + } + + virtual void GenSlidingWindowFunction( outputstream& ss, + const std::string& sSymName, SubArguments& vSubArguments ) override; + virtual bool isAverage() const { return false; } + virtual bool isMinOrMax() const { return false; } + virtual bool takeString() const override { return false; } + virtual bool takeNumeric() const override { return true; } +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/utils.cxx b/sc/source/core/opencl/utils.cxx new file mode 100644 index 0000000000..0d43d8c3ed --- /dev/null +++ b/sc/source/core/opencl/utils.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "utils.hxx" + +#include <cassert> +#include <cmath> +#include <cfloat> +#include <limits> +#include <sstream> + +namespace sc +{ +namespace opencl +{ +namespace +{ +#ifdef SAL_LOG_INFO +class outputstream_num_put : public std::num_put<char> +{ +protected: + virtual iter_type do_put(iter_type s, std::ios_base&, char_type, double v) const override + { + std::string str = preciseFloat(v); + return std::copy(str.begin(), str.end(), s); + } + virtual iter_type do_put(iter_type, std::ios_base&, char_type, long double) const override + { + abort(); // we do not use these + } + using std::num_put<char>::do_put; +}; +#endif +} // namespace + +outputstream::outputstream() +{ + precision(DECIMAL_DIG); + setf(std::ios::showpoint); +#ifdef SAL_LOG_INFO + // Calling precision() makes the output have trailing insignificant zeroes, which + // makes reading the source annoying. So override this stream's floating output + // handling to force usage of our preciseFloat(), which has a saner output. + imbue(std::locale(std::locale("C"), new outputstream_num_put)); +#endif +} + +#undef stringstream +std::string preciseFloat(double f) +{ + std::stringstream stream; + stream.precision(std::numeric_limits<double>::digits10 + 1); + stream.setf(std::ios::showpoint); + stream << f; + std::string str = stream.str(); + size_t end = str.find('e'); + if (end == std::string::npos) + end = str.size(); + for (size_t pos = end - 1; pos > 0; --pos) + { + if (str[pos] != '0') + { + if (str[pos] == '.') + { + ++pos; + if (pos == end) // 10. without trailing 0 + { + return str + '0'; + } + } + ++pos; + assert(pos <= end); + str.resize(std::copy(str.begin() + end, str.end(), str.begin() + pos) - str.begin()); + return str; + } + } + abort(); +} +} +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/utils.hxx b/sc/source/core/opencl/utils.hxx new file mode 100644 index 0000000000..a0c8ebfd72 --- /dev/null +++ b/sc/source/core/opencl/utils.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <sstream> + +namespace sc::opencl +{ +// The way ostream handles floating point output is pretty broken for our usecase. +// The default precision (6) is low, leading to possible precision loss of constant +// float arguments in the generated code. Moreover numbers without a fractional +// part will be printed as e.g. '2', making them integers in the generated code +// (causing problems e.g. with floor() overloads being ambiguous). The std::showpoint +// manipulator forces a decimal point, but then all numbers will be printed +// at the maximum precision even with insignificant trailing 0's, making the numbers +// a pain to read. +// And these flags need to be set on every std::stringstream instance we use, +// which may be easy to omit. +// So as a solution to this: +// - provide our own wrapper class +// - prohibit direct usage of std::stringstream + +class outputstream : public std::stringstream +{ +private: + typedef std::stringstream base; + +public: + outputstream(); +}; + +// Returns a string containing the string representation of the given floating pointer number. +// Unlike printf/iostream, this tries to be as precise and representative as possible +// (it always includes a decimal point, and it uses the highest precision necessary/possible). +std::string preciseFloat(double f); +std::string preciseFloat(long double f) = delete; // we do not use these + +#define stringstream do_not_use_std_stringstream +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |