diff --git a/CMakeLists.txt b/CMakeLists.txt index 229159995ed3b317425bb0bd1daacbe8b248a8a3..09e8e427da5875ddb5f35a7c3121f9547c155f40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,17 @@ endif(LAPACKE_FOUND) option(DEBUG_MODE "Set to On to compile with debug info" OFF) option(BUILD_SHARED_LIBS "Build shared libraries" OFF) +option(BUILD_WARNINGS "Build with warning options" ON) + if(DEBUG_MODE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -W -Wall -fdiagnostics-color=always") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") +endif() + +if(BUILD_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always -Wall -W") endif() if(BUILD_SHARED_LIBS) @@ -70,7 +78,7 @@ if(BUILD_SHARED_LIBS) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") + #Ajout d'un repertoire src add_subdirectory(src) diff --git a/src/Block.hpp b/src/Block.hpp index 95fe7c91cc33664b167ac3076c64f88659bf67a4..bde5d4a2d3d1cf626c2acf2ac00d469cc3966dda 100644 --- a/src/Block.hpp +++ b/src/Block.hpp @@ -107,16 +107,17 @@ public: /** * @brief Copy input Block datas inside */ - void CopyBlock(Block<Scalar,Primary>& in){ + void CopyBlock(Block<Scalar,Primary>& in, int nbColToCopy,int start=0){ //Check - if(in.getSizeBlock() != SizeBlock){ - std::cout<<"SizeBlock different between input block and current block\n"; - exit(0); - } if(in.getLeadingDim() != ldb){ std::cout<<"Leading Dim different between input block and current block\n"; exit(0); } + if(nbColToCopy != SizeBlock){ + std::cout<<"SizeBlock different between input clo to copy" + <<" and current block\n"; + exit(0); + } for(int i=0 ; i<SizeBlock ; ++i){ memcpy(getPtr(i),in.getPtr(i),sizeof(Scalar)*ldb); } @@ -133,39 +134,29 @@ public: * @brief Compute SVD of current block, and write down U inside * output, and Singular Values inside sigma. */ - void DecompositionSVD(Block<Scalar,Primary>& output, Block<Scalar,Primary> sigma){ + void DecompositionSVD(Block<Scalar,Primary>& output, Block<Primary>& sigma){ //What I need: - //jobu : A --> all the U part is computed - //jobvt : N --> no part of V^{H} is computed - - } - - - //Methods for Pj - - /** - * @brief get the number of vectors used - */ - int getUsedVects()const{ - return nbVectUsed; - } - - void OrthoBlock(Block<Scalar,Primary>& input,Scalar * toWrite, int ldToWrite){ - Fill the coeff - call_Tgemm<>(getUsedVects(),input.getSizeBlock(),getLeadingDim(), - getPtr(),getLeadingDim(), - input.getPtr(),input.getLeadingDim(), - toWrite,ldToWrite,Scalar(1),Scalar(0)); - //Read again the coeffs in order to modify input - //Input = (-1) * Pj * toWrite + Wj; - call_gemm<Scalar>(getLeadingDim(),input.getSizeBlock(),getUsedVects(), - getPtr(i),getLeadingDim(), - toWrite, ldToWrite, - Wj.getPtr(),Wj.getLeadingDim(), - Scalar(-1), Scalar(1)); + char jobu = 'S'; //jobu : S --> Only first size_block vectors computed + char jobvt = 'N'; //jobvt : N --> no part of V^{H} is computed + Scalar* Vt; //Won't be used + int ldVt = 1; //Won't be used + //Needed in case Lapack did not converge + Primary * superb = new Primary[output.getSizeBlock()-1]; + int res = callLapack_gesvd<>(jobu,jobvt,getLeadingDim(),getSizeBlock(), + getPtr(),getLeadingDim(), + sigma.getPtr(), + output.getPtr(),output.getLeadingDim(), + Vt,ldVt, superb); + if(res!=0){ + std::cout<<"Problem ... in SVD, did not converge\n"; + if(res>0){ + for(int i=0 ; i<res; ++i) std::cout<<superb[i]<<"\t"; + std::cout<<"\n"; + } + } + delete [] superb; } - }; diff --git a/src/BlockArnoldiIb.hpp b/src/BlockArnoldiIb.hpp index 9a715fa5d8e40b9b496d7f0c232f3829278317c8..779b5be1be57982c5b502ec1cf95f260e98bcb17 100644 --- a/src/BlockArnoldiIb.hpp +++ b/src/BlockArnoldiIb.hpp @@ -15,7 +15,7 @@ int BlockArnoldiIb(Matrix& A,Block<Scalar,Primary>& B, Block<Scalar,Primary>& X0 //store norms std::vector<Primary> normB; for(int i=0 ; i< SizeBlock ; ++i){ - normB.push_back(B.template getNorm<Primary>(i)); + normB.push_back(B.getNorm(i)); } //Compute epsilon_R (step 1) Primary epsilon_R = normB.front(); @@ -68,8 +68,12 @@ int BlockArnoldiIb(Matrix& A,Block<Scalar,Primary>& B, Block<Scalar,Primary>& X0 base.ComputeMGSOrtho(Wj,toWrite,L.getLeadingDim()); std::cout<<"Ortho against V done"<<std::endl; - //Same against Pj - Pj.OrthoBlock(Wj,); + //Orthogonalisation de Wj par rapport à Pj + //Stockage des coeffs de l'ortho dans la partie en haut à droite de H|_j + //QR de Wj --> Wj~ et Dj + //Reconstitution de la matrice F ? ou bien tout sera fait in place + // + } } diff --git a/src/BlockGMRes.hpp b/src/BlockGMRes.hpp index 4eacf028bb703334694aad1b45959157db00d38c..48a3f64f8a7f96bfd2374f73d540aaed9a2f9f33 100644 --- a/src/BlockGMRes.hpp +++ b/src/BlockGMRes.hpp @@ -188,7 +188,7 @@ int BlockGMRes(Matrix& A, Block<Scalar,Primary>& B, Block<Scalar,Primary>& X0, } } } - Sol.CopyBlock(X0); + Sol.CopyBlock(X0,X0.getSizeBlock()); return globalStep; } diff --git a/src/BlockWP.hpp b/src/BlockWP.hpp new file mode 100644 index 0000000000000000000000000000000000000000..318a420dac9d51074686aae2888a164ec68352a2 --- /dev/null +++ b/src/BlockWP.hpp @@ -0,0 +1,104 @@ +#ifndef BLOCKWP_HPP +#define BLOCKWP_HPP + +#include "Block.hpp" + +/** + * @brief This class represent a block of datas containing P and W + * concatenated. + * Thus a cursor to know where P ends and W starts is needed. + */ +template<typename Scalar,typename Primary> +class BlockWP : public Block<Scalar,Primary>{ + int cursor; + using Parent=Block<Scalar,Primary>; +public: + + BlockWP(int sizeBlock, int sizeVector) : Parent(sizeBlock,sizeVector),cursor(0){ + } + + ~BlockWP(){ + } + + Scalar * getW(){ + return Parent::getPtr(cursor); + } + + Scalar * getP(){ + return Parent::getPtr(); + } + + int getSizeP() const { + return cursor; + } + int getSizeW() const { + return Parent::getSizeBlock()-cursor; + } + + /** + * @brief Compute C = P^{H} * W and then W = W-C*P + * + */ + void OrthoWP(Scalar * toWrite, int ldToWrite){ + if(cursor>0){ + //Generate coeef inside C + call_Tgemm<>(getSizeP(),getSizeW(),Parent::getLeadingDim(), + getP(),Parent::getLeadingDim(), + getW(),Parent::getLeadingDim(), + toWrite,ldToWrite,Scalar(1),Scalar(0)); + //Modify W part relatively to C and P + //Wj=(-1) * Pj * toWrite + Wj; + call_gemm<>(Parent::getLeadingDim(),getSizeW(),getSizeP(), + getP(),Parent::getLeadingDim(), + toWrite,ldToWrite, + getW(),Parent::getLeadingDim(), + Scalar(-1),Scalar(1)); + } + } + + /** + * @brief Compute QR facto of W part. W will be overwritten by + * Q. R part generated will go inside input toWrite ptr + */ + void QRofW(Scalar * toWriteR, int ldR){ + } + + /** + * @brief Compute Product between [P,W] and input block and write + * result inside toWrite (will be used for updating V) + * + */ + void ComputeProduct(Block<Scalar,Primary>& input, + Scalar toWrite,int ldToWrite){ + call_gemm<>(Parent::getLeadingDim(),input.getSizeBlock(),Parent::getSizeBlock(), + Parent::getPtr(),Parent::getLeadingDim(), + input.getPtr(),input.getLeadingDim(), + toWrite,ldToWrite, + Scalar(1),Scalar(0)); + } + + /** + * @brief Compute the product between [P,W] and input block and + * write the result in place of P. (obviously used to update P) + */ + void ComputeProduct(Block<Scalar,Primary>& input){ + //Create temporary blck to store result, + Block<Scalar,Primary> temp(input.getSizeBlock(),Parent::getLeadingDim()); + + call_gemm<>(Parent::getLeadingDim(),input.getSizeBlock(),Parent::getSizeBlock(), + Parent::getPtr(),Parent::getLeadingDim(), + input.getPtr(),input.getLeadingDim(), + temp.getPtr(),temp.getLeadingDim(), + Scalar(1),Scalar(0)); + //temp will be copied back inside P part, and cursor will be + //updated + memcpy(getP(),temp.getPtr(), + sizeof(Scalar)*temp.getSizeBlock()*temp.getLeadingDim()); + cursor = temp.getSizeBlock(); + //Not necessary, should be erased but still... + memset(getW(),0,getSizeW()*Parent::getLeadingDim()*sizeof(Scalar)); + } +}; + + +#endif //BLOCKWP_HPP diff --git a/src/HessExtended.hpp b/src/HessExtended.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7b6d25dea785a4c6127c9524198bcf9277c9109 --- /dev/null +++ b/src/HessExtended.hpp @@ -0,0 +1,121 @@ +#ifndef HESSEXTENDED_HPP +#define HESSEXTENDED_HPP + +#include "Block.hpp" +#include "LapackInterface.hpp" + +/** + * This class will store what correspond to the Hessenberg in + * classical Ib-BGMRes. + * + */ +template<typename Scalar> +class HessExtended{ + //Relative to global parameters + int p; //Size of first block + + //Relative to total size + int nbTotalCol; + int ldHess; + + //Relative to current state for columns + int nbBlckColUsed; + //Number of vector in each block col + // [p,p,p-1,p-2,p-2,...] + std::vector<int> nbVectInBlck; + //Will be used to get the starting of block col; + // [0,p,2p ,3p-1,4p-3,...] + std::vector<int> sumNbVectInBlck; + + //Relative to current state of line + int nbLineUsed;//Correspond to the Ortho coeff', i.e. without Hj + //on the last row. + + //Datas: + Scalar * data; + +public: + HessExtended(int inP,int inRestart) : p(inP), + nbTotalCol(p*restart), + ldHess(p*(restart+1)), + nbBlckColUsed(0), + nbLineUsed(0),data(nullptr){ + data = new Scalar[nbTotalLine*nbTotalCol]; + memset(data,0,sizeof(Scalar)*nbTotalLine*nbTotalCol); + } + + ~HessExtended(){ + delete [] data; + } + + int getLeadingDim() const { + return ldHess; + } + + /** + * @brief return the ptr to the start of new blockcol, and augment + * the cursors + */ + Scalar * getNewStartingCol(int inSizeBlock){ + int ref = sumNbVectInBlck.back(); + nbVectInBlck.push_back(inSizeBlock); + sumNbVectInBlck.push_back(ref.inSizeBlock); + return &data[ref*ldHess]; + } + + /** + * @brief Remove the last part (containing H), and filling it with + * W^{H}*H + * + * @param Wj + */ + template<typename Primary> + void UpdateBottomLine(Block<Scalar,Primary>& W){ + //Update nbLine !! + } + + /** + * @brief Compute Product : + * |Lj| + * |Hj| x |Y| + */ + template<typename Primary> + void ComputeResidual(Block<Scalar,Primary>& input, + Block<Scalar,Primary>& gamma, + Block<Scalar,Primary>& outputY, + Block<Scalar,Primary>& outputResidual){ + //Maybe Gamma need to be augmented + } + + + + /** + * Following member function are relative to the |Hj block at the + * bottom. + */ + + /** + * @brief Get the ptr to write/read G + * + */ + Scalar * getPtrToG(){ + } + + /** + * @brief Get the ptr to write/read C coeffs + * + */ + Scalar * getPtrToC(){ + } + + /** + * @brief Get the ptr to write/read D triang part + * + */ + Scalar * getPtrToD(){ + } + +}; + + +#endif //HESSEXTENDED_HPP diff --git a/src/LapackInterface.hpp b/src/LapackInterface.hpp index b8443889cb5c6d5694984cad73eae1e231ebae00..afc2dbfc96b3ff3ee99c2e6a919e0fadb6141008 100644 --- a/src/LapackInterface.hpp +++ b/src/LapackInterface.hpp @@ -89,7 +89,8 @@ void call_gemm(int , int , int , //nb lines in mat, nbcol in b, Primary * , int , //Second one Primary * , int , //Res Primary , Primary){ //Factor : first:alpha, second:beta - std::cout<<"Support for complex double, complex float, float and double only (gemm)\n"; + std::cout<<"Support for complex double, complex float," + <<"float and double only (gemm)\n"; exit(0); } template<> //float @@ -314,15 +315,40 @@ int callLapack_orgqr(int m, int p, * * Ref : https://software.intel.com/en-us/node/521150 */ -template<typename Scalar> -int callLapack_gesvd(int ,int , - Scalar *, int, - Scalar *, int){ - std::cout<<"Only complx float and compl double supported\n"; +template<typename Scalar,typename Primary> +int callLapack_gesvd(char,char, //Jobu and jobvt + int ,int , //nb line and nb col + Scalar *, int, //input matrix and leading dim associated + Primary*, //output sigma + Scalar *, int, //output U and leading dim associated + Scalar *,int, //output V^{H} and leading dim associated + Primary *){ //array fill in case of no convergence + std::cout<<"Only complx float and complx double supported\n"; exit(0); return 0; } - +template<> //specialization on std::complex<double> +int callLapack_gesvd(char jobu,char jobvt, + int m ,int n, + std::complex<double> * A, int ldA, + double* sigma, + std::complex<double> * U, int ldU, + std::complex<double> * V, int ldV, + double * sup){ + return LAPACKE_zgesvd(LAPACK_COL_MAJOR,jobu,jobvt,m,n,A,ldA,sigma, + U,ldU,V,ldV,sup); +} +template<> //specialization on std::complex<float> +int callLapack_gesvd(char jobu,char jobvt, + int m ,int n, + std::complex<float> * A, int ldA, + float* sigma, + std::complex<float> * U, int ldU, + std::complex<float> * V, int ldV, + float * sup){ + return LAPACKE_cgesvd(LAPACK_COL_MAJOR,jobu,jobvt,m,n,A,ldA,sigma, + U,ldU,V,ldV,sup); +} #endif //LapackInterface.hpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 491ae0269c77bad11f8e3bb8cfa24a13ef3bda3f..cb6239803cdfeb3b7dc9fd090ac1e448a24f3596 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 2.8) set(GMRES_TEST_SRC testBlockClass.cpp testBlockGMRes.cpp + testBlockSvd.cpp + testBlockWP.cpp ) #set(LIBS_FOR_TESTS ibgmresdr) diff --git a/test/testBlockGMRes.cpp b/test/testBlockGMRes.cpp index a94d812bf8d4207b2d4a3bb144791613a39abfb6..0f4b0bb729e4f82262bdd2dbe8f2cde5bc10ae93 100644 --- a/test/testBlockGMRes.cpp +++ b/test/testBlockGMRes.cpp @@ -151,7 +151,7 @@ int main(int ac, char ** av){ Block<Scalar> MatxSolMinusB(SizeBlock,dim); //X_Diff : X_Exact - Sol_computed Block<Scalar> X_Diff(SizeBlock,dim); - MatxSolMinusB.CopyBlock(MatxSol); + MatxSolMinusB.CopyBlock(MatxSol,MatxSolMinusB.getSizeBlock()); for(int idxRHS=0 ; idxRHS<SizeBlock ; ++idxRHS){ for(int j=0 ; j<dim; ++j){ MatxSolMinusB.getPtr(idxRHS)[j] -= RHS.getPtr(idxRHS)[j]; diff --git a/test/testBlockSvd.cpp b/test/testBlockSvd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f0d6bd39ef050e9bcc0d67f98f9d4b546d195b0 --- /dev/null +++ b/test/testBlockSvd.cpp @@ -0,0 +1,40 @@ +#include "../src/Block.hpp" +#include <vector> +#include <random> + +int main(int ac, char ** av){ + std::vector<std::string > args(av,av+ac); + for(auto ag : args) + std::cout << ag << "\n"; + + using Primary=double; + using Scalar=std::complex<Primary>; + + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<> dis(0, 2); + + int SizeBlock = 5; + int sizeVect = 25; + + Block<Scalar,Primary> B(SizeBlock,sizeVect); + //Fill the block + for(int i=0; i<SizeBlock ; ++i){ + for(int j=0 ; j<sizeVect ; ++j){ + B.getPtr()[ i* B.getLeadingDim() + j] = dis(gen); + } + } + + //Store Sigma + Block<Primary> Sigma(1,SizeBlock); + + //Store U + Block<Scalar,Primary> U(SizeBlock,sizeVect); + + B.DecompositionSVD(U,Sigma); + + Sigma.displayBlock("Singular values"); + + return 0; +} diff --git a/test/testBlockWP.cpp b/test/testBlockWP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0a89732592ae0d6eadd54e54c93f6eeacf43674 --- /dev/null +++ b/test/testBlockWP.cpp @@ -0,0 +1,35 @@ +#include "BlockWP.hpp" +#include <complex> +#include <random> + +/** + * This exec is used to test the features of BlockWP class. + */ +int main(int ac ,char ** av){ + + std::vector<std::string > args(av,av+ac); + for(auto ag : args) + std::cout << ag << "\n"; + + int SizeBlock = 5; + int Dim = 25; + + using Primary=double; + using Scalar=std::complex<Primary>; + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<> dis(0, 2); + + BlockWP<Scalar,Primary> WP(SizeBlock,Dim); + + //Fill it + for(int i=0; i<SizeBlock ; ++i){ + for(int j=0 ; j<Dim ; ++j){ + WP.getPtr()[ i* WP.getLeadingDim() + j] = dis(gen); + } + } + + + return 0; +}