sc/source/core/opencl/op_statistical.cxx | 345 ++++++++++++------------------- sc/source/core/opencl/op_statistical.hxx | 125 ++++++----- 2 files changed, 203 insertions(+), 267 deletions(-)
New commits: commit ebc0db7acee7a470c4e41cddbb97274343899ce0 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Sep 20 18:08:35 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Wed Sep 21 10:23:49 2022 +0200 fix and simplify opencl functions that calculate difference from mean ocVar, ocStDev etc. Besides the copy&paste reductions, these also need to use fsub_approx() otherwise they can fail with large numbers. Change-Id: Ic96caaa0d5711d811a27b0e2034db357a71b9fa1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140255 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/core/opencl/op_statistical.cxx b/sc/source/core/opencl/op_statistical.cxx index 1fbc80e2e00e..6441f8343daa 100644 --- a/sc/source/core/opencl/op_statistical.cxx +++ b/sc/source/core/opencl/op_statistical.cxx @@ -15,59 +15,9 @@ using namespace formula; -namespace sc::opencl { -void OpVar::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 fSum = 0.0;\n"; - ss << " double fMean = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double fCount = 0.0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " fCount += 1.0;\n" - ); - ss << " fMean = fSum / fCount;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg - fMean) * (arg - fMean);\n" - ); - ss << " if (fCount <= 1.0)\n"; - ss << " return CreateDoubleError(DivisionByZero);\n"; - ss << " else\n"; - ss << " return vSum / (fCount - 1.0);\n"; - ss << "}\n"; -} +#include "op_math_helpers.hxx" -void OpVarP::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 fSum = 0.0;\n"; - ss << " double fMean = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double fCount = 0.0;\n"; - ss << " double arg = 0.0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " fCount += 1.0;\n" - ); - ss << " fMean = fSum / fCount;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg - fMean) * (arg - fMean);\n" - ); - ss << " if (fCount == 0.0)\n"; - ss << " return CreateDoubleError(DivisionByZero);\n"; - ss << " else\n"; - ss << " return vSum / fCount;\n"; - ss << "}\n"; -} +namespace sc::opencl { void OpZTest::BinInlineFun(std::set<std::string>& decls, std::set<std::string>& funs) @@ -371,77 +321,6 @@ void OpWeibull::GenSlidingWindowFunction(outputstream &ss, ss << "}\n"; } -void OpSkew::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 fSum = 0.0;\n"; - ss << " double fMean = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double fCount = 0.0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " fCount += 1.0;\n" - ); - ss << " if(fCount <= 2.0)\n"; - ss << " return CreateDoubleError(DivisionByZero);\n"; - ss << " else\n"; - ss << " fMean = fSum / fCount;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg - fMean) * (arg - fMean);\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 = (arg - fMean) / fStdDev;\n" - " xcube = xcube + dx * dx * dx;\n" - ); - ss << " return ((xcube * fCount) / (fCount - 1.0))"; - ss << " / (fCount - 2.0);\n"; - ss << "}\n"; -} - -void OpSkewp::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"; - ss << " double fSum = 0.0;\n"; - ss << " double fMean = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double fCount = 0.0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " fCount += 1.0;\n" - ); - ss << " if(fCount <= 2.0)\n"; - ss << " return CreateDoubleError(DivisionByZero);\n"; - ss << " else\n"; - ss << " fMean = fSum / fCount;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg - fMean) * (arg - fMean);\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 = (arg - fMean) / fStdDev;\n" - " xcube = xcube + dx * dx * dx;\n" - ); - ss << " return xcube / fCount;\n"; - ss << "}\n"; -} - void OpTInv::BinInlineFun(std::set<std::string>& decls, std::set<std::string>& funs) { @@ -492,58 +371,6 @@ void OpTInv::GenSlidingWindowFunction(outputstream &ss, ss << "}\n"; } -void OpStDev::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 fSum = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double fMean = 0.0;\n"; - ss << " double fCount = 0.0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " fCount += 1.0;\n" - ); - ss << " fMean = fSum / fCount;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg - fMean) * (arg - fMean);\n" - ); - 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) -{ - CHECK_PARAMETER_COUNT( 1, 30 ); - GenerateFunctionDeclaration( sSymName, vSubArguments, ss ); - ss << "{\n"; - ss << " int gid0 = get_global_id(0);\n"; - ss << " double fSum = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double fMean = 0.0;\n"; - ss << " double fCount = 0.0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " fCount += 1.0;\n" - ); - ss << " fMean = fSum / fCount;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg - fMean) * (arg - fMean);\n" - ); - ss << " if (fCount <= 1.0)\n"; - ss << " return CreateDoubleError(DivisionByZero);\n"; - ss << " else\n"; - ss << " return sqrt(vSum / fCount);\n"; - ss << "}\n"; -} - void OpFisher::GenSlidingWindowFunction( outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) { @@ -1163,41 +990,6 @@ void OpMedian::GenSlidingWindowFunction( ss <<" return tmp;\n"; ss << "}\n"; } -void OpKurt:: 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 fSum = 0.0;\n"; - ss << " double vSum = 0.0;\n"; - ss << " double totallength=0;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " fSum += arg;\n" - " totallength +=1;\n" - ); - ss << " if( totallength < 4 )\n"; - ss << " return CreateDoubleError(DivisionByZero);\n"; - ss << " double fMean = fSum / totallength;\n"; - GenerateRangeArgs( vSubArguments, ss, SkipEmpty, - " vSum += (arg-fMean)*(arg-fMean);\n" - ); - ss << " double fStdDev = sqrt(vSum / (totallength - 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 = (totallength - 2.0) * (totallength - 3.0);\n"; - ss<< " double k_l = totallength * (totallength + 1.0) /"; - ss<< "((totallength - 1.0) * k_d);\n"; - ss<< " double k_t = 3.0 * (totallength - 1.0) * "; - ss<< "(totallength - 1.0) / k_d;\n"; - ss<< " return xpower4 * k_l - k_t;\n"; - ss << "}"; -} void OpLogInv::BinInlineFun(std::set<std::string>& decls, std::set<std::string>& funs) @@ -2394,6 +2186,139 @@ void OpRsq::GenSlidingWindowFunction( ); } +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); diff --git a/sc/source/core/opencl/op_statistical.hxx b/sc/source/core/opencl/op_statistical.hxx index e235231ee121..64ca0c1cdf7c 100644 --- a/sc/source/core/opencl/op_statistical.hxx +++ b/sc/source/core/opencl/op_statistical.hxx @@ -28,22 +28,6 @@ public: const std::string &sSymName, SubArguments &vSubArguments) override; virtual std::string BinFuncName() const override { return "ExponDist"; } }; -class OpVar: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "Var"; } - virtual bool canHandleMultiVector() const override { return true; } -}; -class OpVarP: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "VarP"; } - virtual bool canHandleMultiVector() const override { return true; } -}; class OpZTest: public Normal { public: @@ -52,39 +36,6 @@ public: virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>&) override; virtual std::string BinFuncName() const override { return "ZTest"; } }; -class OpStDevP: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "StDevP"; } - virtual bool canHandleMultiVector() const override { return true; } -}; - -class OpStDev: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "StDev"; } - virtual bool canHandleMultiVector() const override { return true; } -}; -class OpSkew: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "Skew"; } - virtual bool canHandleMultiVector() const override { return true; } -}; -class OpSkewp: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "Skewp"; } - virtual bool canHandleMultiVector() const override { return true; } -}; class OpWeibull: public Normal { public: @@ -230,14 +181,6 @@ class OpPhi:public Normal{ const std::string &sSymName, SubArguments &vSubArguments) override; virtual std::string BinFuncName() const override { return "OpPhi"; } }; -class OpKurt: public Normal -{ -public: - virtual void GenSlidingWindowFunction(outputstream &ss, - const std::string &sSymName, SubArguments &vSubArguments) override; - virtual std::string BinFuncName() const override { return "Kurt"; } - virtual bool canHandleMultiVector() const override { return true; } -}; class OpPermut:public Normal{ public: @@ -503,6 +446,74 @@ public: 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: