From 2b1e9d5e6a7c31dd6b94aa53a50aa64641c85b39 Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Tue, 23 Aug 2022 11:33:45 +0200 Subject: [PATCH] Integration of newton solver coming from numerical recipes to solve --- .../Bases/InterpKernelException.hxx | 1 + src/INTERP_KERNEL/CMakeLists.txt | 4 + src/INTERP_KERNEL/InterpKernelDenseMatrix.hxx | 53 +++++ src/INTERP_KERNEL/InterpKernelDenseMatrix.txx | 141 +++++++++++ .../InterpKernelRootsMultiDim.hxx | 218 ++++++++++++++++++ .../LinearAlgebra/InterpKernelDenseMatrix.cxx | 22 ++ .../LinearAlgebra/InterpKernelLUDecomp.cxx | 142 ++++++++++++ .../LinearAlgebra/InterpKernelLUDecomp.hxx | 43 ++++ .../LinearAlgebra/InterpKernelQRDecomp.cxx | 170 ++++++++++++++ .../LinearAlgebra/InterpKernelQRDecomp.hxx | 44 ++++ 10 files changed, 838 insertions(+) create mode 100644 src/INTERP_KERNEL/InterpKernelDenseMatrix.hxx create mode 100644 src/INTERP_KERNEL/InterpKernelDenseMatrix.txx create mode 100644 src/INTERP_KERNEL/InterpKernelRootsMultiDim.hxx create mode 100644 src/INTERP_KERNEL/LinearAlgebra/InterpKernelDenseMatrix.cxx create mode 100644 src/INTERP_KERNEL/LinearAlgebra/InterpKernelLUDecomp.cxx create mode 100644 src/INTERP_KERNEL/LinearAlgebra/InterpKernelLUDecomp.hxx create mode 100644 src/INTERP_KERNEL/LinearAlgebra/InterpKernelQRDecomp.cxx create mode 100644 src/INTERP_KERNEL/LinearAlgebra/InterpKernelQRDecomp.hxx diff --git a/src/INTERP_KERNEL/Bases/InterpKernelException.hxx b/src/INTERP_KERNEL/Bases/InterpKernelException.hxx index 7703b7b46..f4f05bd62 100644 --- a/src/INTERP_KERNEL/Bases/InterpKernelException.hxx +++ b/src/INTERP_KERNEL/Bases/InterpKernelException.hxx @@ -25,6 +25,7 @@ #include #include +#include namespace INTERP_KERNEL { diff --git a/src/INTERP_KERNEL/CMakeLists.txt b/src/INTERP_KERNEL/CMakeLists.txt index 5de054ed0..bc07afc1c 100644 --- a/src/INTERP_KERNEL/CMakeLists.txt +++ b/src/INTERP_KERNEL/CMakeLists.txt @@ -62,6 +62,9 @@ SET(interpkernel_SOURCES ExprEval/InterpKernelValue.cxx ExprEval/InterpKernelAsmX86.cxx GaussPoints/InterpKernelGaussCoords.cxx + LinearAlgebra/InterpKernelDenseMatrix.cxx + LinearAlgebra/InterpKernelLUDecomp.cxx + LinearAlgebra/InterpKernelQRDecomp.cxx ) INCLUDE_DIRECTORIES( @@ -70,6 +73,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/Geometric2D ${CMAKE_CURRENT_SOURCE_DIR}/ExprEval ${CMAKE_CURRENT_SOURCE_DIR}/GaussPoints + ${CMAKE_CURRENT_SOURCE_DIR}/LinearAlgebra ) IF (NOT DEFINED MSVC) diff --git a/src/INTERP_KERNEL/InterpKernelDenseMatrix.hxx b/src/INTERP_KERNEL/InterpKernelDenseMatrix.hxx new file mode 100644 index 000000000..38e4a6128 --- /dev/null +++ b/src/INTERP_KERNEL/InterpKernelDenseMatrix.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#pragma once + +#include "INTERPKERNELDefines.hxx" +#include "MCIdType.hxx" + +namespace INTERP_KERNEL +{ + template + class INTERPKERNEL_EXPORT DenseMatrixT + { + private: + mcIdType nn; + mcIdType mm; + T **v; + public: + DenseMatrixT(); + DenseMatrixT(mcIdType n, mcIdType m); + DenseMatrixT(mcIdType n, mcIdType m, const T &a); + DenseMatrixT(mcIdType n, mcIdType m, const T *a); + DenseMatrixT(const DenseMatrixT &rhs); + DenseMatrixT & operator=(const DenseMatrixT &rhs); + using value_type = T; + //! subscripting: pointer to row i + T* operator[](const mcIdType i) { return v[i]; } + const T* operator[](const mcIdType i) const { return v[i]; } + mcIdType nrows() const { return nn; } + mcIdType ncols() const { return mm; } + void resize(mcIdType newn, mcIdType newm); + void assign(mcIdType newn, mcIdType newm, const T &a); + ~DenseMatrixT(); + }; + + using DenseMatrix = DenseMatrixT; +} diff --git a/src/INTERP_KERNEL/InterpKernelDenseMatrix.txx b/src/INTERP_KERNEL/InterpKernelDenseMatrix.txx new file mode 100644 index 000000000..9705f4fdb --- /dev/null +++ b/src/INTERP_KERNEL/InterpKernelDenseMatrix.txx @@ -0,0 +1,141 @@ +// Copyright (C) 2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#pragma once + +#include "InterpKernelDenseMatrix.hxx" + +namespace INTERP_KERNEL +{ + template + DenseMatrixT::DenseMatrixT() : nn(0), mm(0), v(nullptr) {} + + template + DenseMatrixT::DenseMatrixT(mcIdType n, mcIdType m) : nn(n), mm(m), v(n>0 ? new T*[n] : nullptr) + { + mcIdType i,nel=m*n; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1;i + DenseMatrixT::DenseMatrixT(mcIdType n, mcIdType m, const T &a) : nn(n), mm(m), v(n>0 ? new T*[n] : nullptr) + { + mcIdType i,j,nel=m*n; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1; i< n; i++) v[i] = v[i-1] + m; + for (i=0; i< n; i++) for (j=0; j + DenseMatrixT::DenseMatrixT(mcIdType n, mcIdType m, const T *a) : nn(n), mm(m), v(n>0 ? new T*[n] : nullptr) + { + mcIdType i,j,nel=m*n; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1; i< n; i++) v[i] = v[i-1] + m; + for (i=0; i< n; i++) for (j=0; j + DenseMatrixT::DenseMatrixT(const DenseMatrixT &rhs) : nn(rhs.nn), mm(rhs.mm), v(nn>0 ? new T*[nn] : nullptr) + { + mcIdType i,j,nel=mm*nn; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1; i< nn; i++) v[i] = v[i-1] + mm; + for (i=0; i< nn; i++) for (j=0; j + DenseMatrixT & DenseMatrixT::operator=(const DenseMatrixT &rhs) + { + if (this != &rhs) { + mcIdType i,j,nel; + if (nn != rhs.nn || mm != rhs.mm) { + if ( v ) { + delete[] (v[0]); + delete[] (v); + } + nn=rhs.nn; + mm=rhs.mm; + v = nn>0 ? new T*[nn] : nullptr; + nel = mm*nn; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1; i< nn; i++) v[i] = v[i-1] + mm; + } + for (i=0; i< nn; i++) for (j=0; j + void DenseMatrixT::resize(mcIdType newn, mcIdType newm) + { + mcIdType i,nel; + if (newn != nn || newm != mm) + { + if ( v ) + { + delete[] (v[0]); + delete[] (v); + } + nn = newn; + mm = newm; + v = nn>0 ? new T*[nn] : nullptr; + nel = mm*nn; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1; i< nn; i++) v[i] = v[i-1] + mm; + } + } + + template + void DenseMatrixT::assign(mcIdType newn, mcIdType newm, const T& a) + { + mcIdType i,j,nel; + if (newn != nn || newm != mm) + { + if ( v ) + { + delete[] (v[0]); + delete[] (v); + } + nn = newn; + mm = newm; + v = nn>0 ? new T*[nn] : nullptr; + nel = mm*nn; + if (v) v[0] = nel>0 ? new T[nel] : nullptr; + for (i=1; i< nn; i++) v[i] = v[i-1] + mm; + } + for (i=0; i< nn; i++) for (j=0; j + DenseMatrixT::~DenseMatrixT() + { + if ( v ) + { + delete[] (v[0]); + delete[] (v); + } + } +} diff --git a/src/INTERP_KERNEL/InterpKernelRootsMultiDim.hxx b/src/INTERP_KERNEL/InterpKernelRootsMultiDim.hxx new file mode 100644 index 000000000..3fba59fdb --- /dev/null +++ b/src/INTERP_KERNEL/InterpKernelRootsMultiDim.hxx @@ -0,0 +1,218 @@ +// Copyright (C) 2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// Implementation coming from Numerical Recipes in C of 1994 (version 2.04) p 384 +// Root finding and non linear sets of equation using line searches and backtracking + +#include "InterpKernelDenseMatrix.hxx" +#include "InterpKernelLUDecomp.hxx" +#include "InterpKernelQRDecomp.hxx" +#include "InterpKernelException.hxx" +#include "MCIdType.hxx" + +#include +#include +#include + +template +inline T sqr(const T a) { return a*a; } + +namespace INTERP_KERNEL +{ + template + void LineSearches(const std::vector& xold, const double fold, const std::vector& g, std::vector &p, + std::vector &x, double &f, const double stpmax, bool &check, T &func) + { + const double ALF=1.0e-4, TOLX=std::numeric_limits::epsilon(); + double a,alam,alam2=0.0,alamin,b,disc,f2=0.0; + double rhs1,rhs2,slope=0.0,sum=0.0,temp,test,tmplam; + mcIdType i,n=xold.size(); + check=false; + for (i=0;i stpmax) + for (i=0;i= 0.0) THROW_IK_EXCEPTION("Roundoff problem in LineSearches."); + test=0.0; + for (i=0;i test) test=temp; + } + alamin=TOLX/test; + alam=1.0; + for (;;) + { + for (i=0;i0.5*alam) + tmplam=0.5*alam; + } + } + alam2=alam; + f2 = f; + alam=std::max(tmplam,0.1*alam); + } + } + template + class JacobianCalculator + { + private: + const double EPS; + T &func; + public: + JacobianCalculator(T &funcc) : EPS(1.0e-8),func(funcc) {} + INTERP_KERNEL::DenseMatrix operator() (const std::vector& x, const std::vector& fvec) + { + mcIdType n=x.size(); + INTERP_KERNEL::DenseMatrix df(n,n); + std::vector xh=x; + for (mcIdType j=0;j f=func(xh); + xh[j]=temp; + for (mcIdType i=0;i + class FMin + { + private: + std::vector fvec; + T &func; + mcIdType n; + public: + FMin(T &funcc) : func(funcc){} + double operator() (const std::vector& x) + { + n=x.size(); + double sum=0; + fvec=func(x); + for (mcIdType i=0;i& getVector() { return fvec; } + }; + + template + void SolveWithNewton(std::vector &x, bool &check, T &vecfunc) + { + const mcIdType MAXITS=200; + const double TOLF=1.0e-8,TOLMIN=1.0e-12,STPMX=100.0; + const double TOLX=std::numeric_limits::epsilon(); + mcIdType i,j,its,n=x.size(); + double den,f,fold,stpmax,sum,temp,test; + std::vector g(n),p(n),xold(n); + INTERP_KERNEL::DenseMatrix fjac(n,n); + FMin fmin(vecfunc); + JacobianCalculator fdjac(vecfunc); + std::vector &fvec=fmin.getVector(); + f=fmin(x); + test=0.0; + for (i=0;i test) test=std::abs(fvec[i]); + if (test < 0.01*TOLF) + { + check=false; + return; + } + sum=0.0; + for (i=0;i test) test=std::abs(fvec[i]); + if (test < TOLF) + { + check=false; + return; + } + if (check) + { + test=0.0; + den=std::max(f,0.5*n); + for (i=0;i test) test=temp; + } + check=(test < TOLMIN); + return; + } + test=0.0; + for (i=0;i test) test=temp; + } + if (test < TOLX) + return; + } + THROW_IK_EXCEPTION("MAXITS exceeded in newt"); + } +} diff --git a/src/INTERP_KERNEL/LinearAlgebra/InterpKernelDenseMatrix.cxx b/src/INTERP_KERNEL/LinearAlgebra/InterpKernelDenseMatrix.cxx new file mode 100644 index 000000000..141b3b935 --- /dev/null +++ b/src/INTERP_KERNEL/LinearAlgebra/InterpKernelDenseMatrix.cxx @@ -0,0 +1,22 @@ +// Copyright (C) 2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "InterpKernelDenseMatrix.txx" + +template class INTERPKERNEL_EXPORT INTERP_KERNEL::DenseMatrixT; diff --git a/src/INTERP_KERNEL/LinearAlgebra/InterpKernelLUDecomp.cxx b/src/INTERP_KERNEL/LinearAlgebra/InterpKernelLUDecomp.cxx new file mode 100644 index 000000000..3416e5ad2 --- /dev/null +++ b/src/INTERP_KERNEL/LinearAlgebra/InterpKernelLUDecomp.cxx @@ -0,0 +1,142 @@ +// Copyright (C) 2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// Implementation coming from Numerical Recipes in C of 1994 (version 2.04) + +#include "InterpKernelLUDecomp.hxx" +#include "InterpKernelException.hxx" + +#include + +using namespace INTERP_KERNEL; + +LUDecomp::LUDecomp(const INTERP_KERNEL::DenseMatrix& a) : n(a.nrows()), lu(a), aref(a), indx(n) +{ + const double TINY=1.0e-40; + mcIdType i,imax,j,k; + double big,temp; + std::vector vv(n); + d=1.0; + for (i=0;i big) big=temp; + if (big == 0.0) THROW_IK_EXCEPTION("Singular matrix in LUDecomp"); + vv[i]=1.0/big; + } + for (k=0;k big) + { + big=temp; + imax=i; + } + } + if (k != imax) { + for (j=0;j& b, std::vector &x) +{ + mcIdType i,ii=0,ip,j; + double sum; + if (b.size() != ToSizeT(n) || x.size() != ToSizeT(n)) + THROW_IK_EXCEPTION("LUDecomp::solve bad sizes"); + for (i=0;i=0;i--) { + sum=x[i]; + for (j=i+1;j xx(n); + for (j=0;j& b, std::vector &x) +{ + mcIdType i,j; + std::vector r(n); + for (i=0;i + +namespace INTERP_KERNEL +{ + class LUDecomp + { + private: + mcIdType n; + INTERP_KERNEL::DenseMatrix lu; + std::vector indx; + double d; + const INTERP_KERNEL::DenseMatrix& aref; + public: + LUDecomp (const INTERP_KERNEL::DenseMatrix& a); + void solve(const std::vector& b, std::vector &x); + void solve(const INTERP_KERNEL::DenseMatrix& b, INTERP_KERNEL::DenseMatrix &x); + void inverse(INTERP_KERNEL::DenseMatrix &ainv); + double det(); + void mprove(const std::vector& b, std::vector &x); + }; +} diff --git a/src/INTERP_KERNEL/LinearAlgebra/InterpKernelQRDecomp.cxx b/src/INTERP_KERNEL/LinearAlgebra/InterpKernelQRDecomp.cxx new file mode 100644 index 000000000..78afd9829 --- /dev/null +++ b/src/INTERP_KERNEL/LinearAlgebra/InterpKernelQRDecomp.cxx @@ -0,0 +1,170 @@ +// Copyright (C) 2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// Implementation coming from Numerical Recipes in C of 1994 (version 2.04) + +#include "InterpKernelQRDecomp.hxx" +#include "InterpKernelException.hxx" + +#include + +using namespace INTERP_KERNEL; + +template +inline T sqr(const T a) { return a*a; } + +template +inline T sign(const T &a, const T &b) { return b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a); } + +QRDecomp::QRDecomp(const INTERP_KERNEL::DenseMatrix& a): n(a.nrows()), qt(n,n), r(a), sing(false) +{ + mcIdType i,j,k; + std::vector c(n), d(n); + double scale,sigma,sum,tau; + for (k=0;k& b, std::vector &x) +{ + qtmult(b,x); + rsolve(x,x); +} + +void QRDecomp::qtmult(const std::vector& b, std::vector &x) +{ + mcIdType i,j; + double sum; + for (i=0;i& b, std::vector &x) +{ + mcIdType i,j; + double sum; + if (sing) THROW_IK_EXCEPTION("attempting solve in a singular QR"); + for (i=n-1;i>=0;i--) { + sum=b[i]; + for (j=i+1;j& u, const std::vector& v) +{ + mcIdType i,k; + std::vector w(u); + for (k=n-1;k>=0;k--) + if (w[k] != 0.0) break; + if (k < 0) k=0; + for (i=k-1;i>=0;i--) { + rotate(i,w[i],-w[i+1]); + if (w[i] == 0.0) + w[i]=std::abs(w[i+1]); + else if (std::abs(w[i]) > std::abs(w[i+1])) + w[i]=std::abs(w[i])*std::sqrt(1.0+sqr(w[i+1]/w[i])); + else w[i]=std::abs(w[i+1])*std::sqrt(1.0+sqr(w[i]/w[i+1])); + } + for (i=0;i= 0.0 ? 1.0 : -1.0); + } + else if (std::abs(a) > std::abs(b)) + { + fact=b/a; + c=sign(1.0/std::sqrt(1.0+(fact*fact)),a); + s=fact*c; + } + else + { + fact=a/b; + s=sign(1.0/std::sqrt(1.0+(fact*fact)),b); + c=fact*s; + } + for (j=i;j + +namespace INTERP_KERNEL +{ + struct QRDecomp + { + private: + mcIdType n; + INTERP_KERNEL::DenseMatrix qt; + INTERP_KERNEL::DenseMatrix r; + bool sing; + public: + QRDecomp(const INTERP_KERNEL::DenseMatrix& a); + void solve(const std::vector& b, std::vector &x); + void qtmult(const std::vector& b, std::vector &x); + void rsolve(const std::vector& b, std::vector &x); + void update(const std::vector& u, const std::vector& v); + void rotate(const mcIdType i, const double a, const double b); + }; +} -- 2.39.2