Epetra_OskiMultiVector::Epetra_OskiMultiVector(const Epetra_MultiVector& Source) : Epetra_MultiVector(Source), Epetra_View_(&Source), Copy_Created_(false) { double* A; double** Aptr; int LDA; int* LDAptr; LDAptr = new int[1]; Aptr = new double*[1]; if(Source.ConstantStride() || (Source.NumVectors() == 1)) { if(Source.ExtractView(Aptr, LDAptr)) std::cerr << "Extract view failed\n"; else Oski_View_ = oski_CreateMultiVecView(*Aptr, Source.MyLength(), Source.NumVectors(), LAYOUT_COLMAJ, *LDAptr); } else { Copy_Created_ = true; LDA = Source.MyLength(); A = new double[LDA*Source.NumVectors()]; if(Source.ExtractCopy(A, LDA)) std::cerr << "Extract copy failed\n"; else Oski_View_ = oski_CreateMultiVecView(A, Source.MyLength(), Source.NumVectors(), LAYOUT_COLMAJ, LDA); } delete [] LDAptr; delete [] Aptr; }
//========================================================================= // NOTE: This method should be removed and replaced with calls to Epetra_Util_ExtractHbData() int Epetra_LinearProblemRedistor::ExtractHbData(int & M, int & N, int & nz, int * & ptr, int * & ind, double * & val, int & Nrhs, double * & rhs, int & ldrhs, double * & lhs, int & ldlhs) const { Epetra_CrsMatrix * RedistMatrix = dynamic_cast<Epetra_CrsMatrix *>(RedistProblem_->GetMatrix()); if (RedistMatrix==0) EPETRA_CHK_ERR(-1); // This matrix is zero or not an Epetra_CrsMatrix if (!RedistMatrix->IndicesAreContiguous()) { // Data must be contiguous for this to work EPETRA_CHK_ERR(-2); } M = RedistMatrix->NumMyRows(); N = RedistMatrix->NumMyCols(); nz = RedistMatrix->NumMyNonzeros(); val = (*RedistMatrix)[0]; // Dangerous, but cheap and effective way to access first element in const Epetra_CrsGraph & RedistGraph = RedistMatrix->Graph(); ind = RedistGraph[0]; // list of values and indices Epetra_MultiVector * LHS = RedistProblem_->GetLHS(); Epetra_MultiVector * RHS = RedistProblem_->GetRHS(); Nrhs = RHS->NumVectors(); if (Nrhs>1) { if (!RHS->ConstantStride()) {EPETRA_CHK_ERR(-3)}; // Must have strided vectors if (!LHS->ConstantStride()) {EPETRA_CHK_ERR(-4)}; // Must have strided vectors } ldrhs = RHS->Stride(); rhs = (*RHS)[0]; // Dangerous but effective (again) ldlhs = LHS->Stride(); lhs = (*LHS)[0]; // Finally build ptr vector if (ptr_==0) { ptr_ = new int[M+1]; ptr_[0] = 0; for (int i=0; i<M; i++) ptr_[i+1] = ptr_[i] + RedistGraph.NumMyIndices(i); } ptr = ptr_; return(0); }
int BuildMatrixTests (Epetra_MultiVector & C, const char TransA, const char TransB, const double alpha, Epetra_MultiVector& A, Epetra_MultiVector& B, const double beta, Epetra_MultiVector& C_GEMM ) { // For given values of TransA, TransB, alpha and beta, a (possibly // zero) filled Epetra_MultiVector C, and allocated // Epetra_MultiVectors A, B and C_GEMM this routine will generate values for // Epetra_MultiVectors A, B and C_GEMM such that, if A, B and (this) are // used with GEMM in this class, the results should match the results // generated by this routine. // Test for Strided multivectors (required for GEMM ops) if (!A.ConstantStride() || !B.ConstantStride() || !C_GEMM.ConstantStride() || !C.ConstantStride()) return(-1); // Error int i, j; double fi, fj; // Used for casting loop variables to floats // Get a view of the MultiVectors double *Ap = 0; double *Bp = 0; double *Cp = 0; double *C_GEMMp = 0; int A_nrows = A.MyLength(); int A_ncols = A.NumVectors(); int B_nrows = B.MyLength(); int B_ncols = B.NumVectors(); int C_nrows = C.MyLength(); int C_ncols = C.NumVectors(); int A_Stride = 0; int B_Stride = 0; int C_Stride = 0; int C_GEMM_Stride = 0; A.ExtractView(&Ap, &A_Stride); B.ExtractView(&Bp, &B_Stride); C.ExtractView(&Cp, &C_Stride); C_GEMM.ExtractView(&C_GEMMp, &C_GEMM_Stride); // Define some useful constants int opA_ncols = (TransA=='N') ? A.NumVectors() : A.MyLength(); int opB_nrows = (TransB=='N') ? B.MyLength() : B.NumVectors(); int C_global_inner_dim = (TransA=='N') ? A.NumVectors() : A.GlobalLength(); bool A_is_local = (!A.DistributedGlobal()); bool B_is_local = (!B.DistributedGlobal()); bool C_is_local = (!C.DistributedGlobal()); int A_IndexBase = A.Map().IndexBase(); int B_IndexBase = B.Map().IndexBase(); // Build two new maps that we can use for defining global equation indices below Epetra_Map * A_Map = new Epetra_Map(-1, A_nrows, A_IndexBase, A.Map().Comm()); Epetra_Map * B_Map = new Epetra_Map(-1, B_nrows, B_IndexBase, B.Map().Comm()); int* A_MyGlobalElements = new int[A_nrows]; A_Map->MyGlobalElements(A_MyGlobalElements); int* B_MyGlobalElements = new int[B_nrows]; B_Map->MyGlobalElements(B_MyGlobalElements); // Check for compatible dimensions if (C.MyLength() != C_nrows || opA_ncols != opB_nrows || C.NumVectors() != C_ncols || C.MyLength() != C_GEMM.MyLength() || C.NumVectors() != C_GEMM.NumVectors() ) { delete A_Map; delete B_Map; delete [] A_MyGlobalElements; delete [] B_MyGlobalElements; return(-2); // Return error } bool Case1 = ( A_is_local && B_is_local && C_is_local); // Case 1 above bool Case2 = (!A_is_local && !B_is_local && C_is_local && TransA=='T' );// Case 2 bool Case3 = (!A_is_local && B_is_local && !C_is_local && TransA=='N');// Case 3 // Test for meaningful cases if (!(Case1 || Case2 || Case3)) { delete A_Map; delete B_Map; delete [] A_MyGlobalElements; delete [] B_MyGlobalElements; return(-3); // Meaningless case } /* Fill A, B and C with values as follows: If A_is_local is false: A(i,j) = A_MyGlobalElements[i]*j, i=1,...,numLocalEquations, j=1,...,NumVectors else A(i,j) = i*j, i=1,...,numLocalEquations, j=1,...,NumVectors If B_is_local is false: B(i,j) = 1/(A_MyGlobalElements[i]*j), i=1,...,numLocalEquations, j=1,...,NumVectors else B(i,j) = 1/(i*j), i=1,...,numLocalEquations, j=1,...,NumVectors In addition, scale each entry by GlobalLength for A and 1/GlobalLength for B--keeps the magnitude of entries in check C_GEMM will depend on A_is_local and B_is_local. Three cases: 1) A_is_local true and B_is_local true: C_GEMM will be local replicated and equal to A*B = i*NumVectors/j 2) A_is_local false and B_is_local false C_GEMM will be local replicated = A(trans)*B(i,j) = i*numGlobalEquations/j 3) A_is_local false B_is_local true C_GEMM will distributed global and equals A*B = A_MyGlobalElements[i]*NumVectors/j */ // Define a scalar to keep magnitude of entries reasonable double sf = C_global_inner_dim; double sfinv = 1.0/sf; // Define A depending on A_is_local if (A_is_local) { for (j = 0; j <A_ncols ; j++) for (i = 0; i<A_nrows; i++) { fi = i+1; // Get float version of i and j, offset by 1. fj = j+1; Ap[i + A_Stride*j] = (fi*sfinv)*fj; } } else { for (j = 0; j <A_ncols ; j++) for (i = 0; i<A_nrows; i++) { fi = A_MyGlobalElements[i]+1; // Get float version of i and j, offset by 1. fj = j+1; Ap[i + A_Stride*j] = (fi*sfinv)*fj; } } // Define B depending on TransB and B_is_local if (B_is_local) { for (j = 0; j <B_ncols ; j++) for (i = 0; i<B_nrows; i++) { fi = i+1; // Get float version of i and j, offset by 1. fj = j+1; Bp[i + B_Stride*j] = 1.0/((fi*sfinv)*fj); } } else { for (j = 0; j <B_ncols ; j++) for (i = 0; i<B_nrows; i++) { fi = B_MyGlobalElements[i]+1; // Get float version of i and j, offset by 1. fj = j+1; Bp[i + B_Stride*j] = 1.0/((fi*sfinv)*fj); } } // Define C_GEMM depending on A_is_local and B_is_local. C_GEMM is also a // function of alpha, beta, TransA, TransB: // C_GEMM = alpha*A(TransA)*B(TransB) + beta*C_GEMM if (Case1) { for (j = 0; j <C_ncols ; j++) for (i = 0; i<C_nrows; i++) { // Get float version of i and j, offset by 1. fi = (i+1)*C_global_inner_dim; fj = j+1; C_GEMMp[i + C_GEMM_Stride*j] = alpha * (fi/fj) + beta * Cp[i + C_Stride*j]; } } else if (Case2) { for (j = 0; j <C_ncols ; j++) for (i = 0; i<C_nrows; i++) { // Get float version of i and j, offset by 1. fi = (i+1)*C_global_inner_dim; fj = j+1; C_GEMMp[i + C_GEMM_Stride*j] = alpha * (fi/fj) + beta * Cp[i + C_Stride*j]; } } else { for (j = 0; j <C_ncols ; j++) for (i = 0; i<C_nrows; i++) { // Get float version of i and j. fi = (A_MyGlobalElements[i]+1)*C_global_inner_dim; fj = j+1; C_GEMMp[i + C_GEMM_Stride*j] = alpha * (fi/fj) + beta * Cp[i + C_Stride*j]; } } delete A_Map; delete B_Map; delete [] A_MyGlobalElements; delete [] B_MyGlobalElements; return(0); }