magma_int_t magma_sresidual( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector x, float *res ){ // some useful variables float zero = MAGMA_S_ZERO, one = MAGMA_S_ONE, mone = MAGMA_S_NEG_ONE; magma_int_t dofs = A.num_rows; magma_s_vector r; magma_s_vinit( &r, Magma_DEV, A.num_rows, zero ); magma_s_spmv( one, A, x, zero, r ); // r = A x magma_saxpy(dofs, mone, b.val, 1, r.val, 1); // r = r - b *res = magma_snrm2(dofs, r.val, 1); // res = ||r|| // /magma_snrm2(dofs, b.val, 1); /||b|| //printf( "relative residual: %e\n", *res ); magma_s_vfree(&r); return MAGMA_SUCCESS; }
magma_int_t magma_spastixsetup( magma_s_sparse_matrix A, magma_s_vector b, magma_s_preconditioner *precond ){ #if defined(HAVE_PASTIX) #if defined(PRECISION_d) pastix_data_t *pastix_data = NULL; /* Pointer to a storage structure needed by pastix */ pastix_int_t ncol; /* Size of the matrix */ pastix_int_t *colptr = NULL; /* Indexes of first element of each column in row and values */ pastix_int_t *rows = NULL; /* Row of each element of the matrix */ pastix_float_t *values = NULL; /* Value of each element of the matrix */ pastix_float_t *rhs = NULL; /* right hand side */ pastix_int_t *iparm = NULL; /* integer parameters for pastix */ float *dparm = NULL; /* floating parameters for pastix */ pastix_int_t *perm = NULL; /* Permutation tabular */ pastix_int_t *invp = NULL; /* Reverse permutation tabular */ pastix_int_t mat_type; magma_s_sparse_matrix A_h1, B; magma_s_vector diag, c_t, b_h; magma_s_vinit( &c_t, Magma_CPU, A.num_rows, MAGMA_S_ZERO ); magma_s_vinit( &diag, Magma_CPU, A.num_rows, MAGMA_S_ZERO ); magma_s_vtransfer( b, &b_h, A.memory_location, Magma_CPU); if( A.storage_type != Magma_CSR ){ magma_s_mtransfer( A, &A_h1, A.memory_location, Magma_CPU); magma_s_mconvert( A_h1, &B, A_h1.storage_type, Magma_CSR); } else{ magma_s_mtransfer( A, &B, A.memory_location, Magma_CPU); } rhs = (pastix_float_t*) b_h.val; ncol = B.num_rows; colptr = B.row; rows = B.col; values = (pastix_float_t*) B.val; mat_type = API_SYM_NO; iparm = (pastix_int_t*)malloc(IPARM_SIZE*sizeof(pastix_int_t)); dparm = (pastix_float_t*)malloc(DPARM_SIZE*sizeof(pastix_float_t)); /*******************************************/ /* Initialize parameters to default values */ /*******************************************/ iparm[IPARM_MODIFY_PARAMETER] = API_NO; pastix(&pastix_data, MPI_COMM_WORLD, ncol, colptr, rows, values, perm, invp, rhs, 1, iparm, dparm); iparm[IPARM_THREAD_NBR] = 16; iparm[IPARM_SYM] = mat_type; iparm[IPARM_FACTORIZATION] = API_FACT_LU; iparm[IPARM_VERBOSE] = API_VERBOSE_YES; iparm[IPARM_ORDERING] = API_ORDER_SCOTCH; iparm[IPARM_INCOMPLETE] = API_NO; iparm[IPARM_RHS_MAKING] = API_RHS_B; //iparm[IPARM_AMALGAMATION] = 5; iparm[IPARM_LEVEL_OF_FILL] = 0; /* if (incomplete == 1) { dparm[DPARM_EPSILON_REFINEMENT] = 1e-7; } */ /* * Matrix needs : * - to be in fortran numbering * - to have only the lower triangular part in symmetric case * - to have a graph with a symmetric structure in unsymmetric case * If those criteria are not matched, the csc will be reallocated and changed. */ iparm[IPARM_MATRIX_VERIFICATION] = API_YES; perm = (pastix_int_t*)malloc(ncol*sizeof(pastix_int_t)); invp = (pastix_int_t*)malloc(ncol*sizeof(pastix_int_t)); /*******************************************/ /* Step 1 - Ordering / Scotch */ /* Perform it only when the pattern of */ /* matrix change. */ /* eg: mesh refinement */ /* In many cases users can simply go from */ /* API_TASK_ORDERING to API_TASK_ANALYSE */ /* in one call. */ /*******************************************/ /*******************************************/ /* Step 2 - Symbolic factorization */ /* Perform it only when the pattern of */ /* matrix change. */ /*******************************************/ /*******************************************/ /* Step 3 - Mapping and Compute scheduling */ /* Perform it only when the pattern of */ /* matrix change. */ /*******************************************/ /*******************************************/ /* Step 4 - Numerical Factorisation */ /* Perform it each time the values of the */ /* matrix changed. */ /*******************************************/ iparm[IPARM_START_TASK] = API_TASK_ORDERING; iparm[IPARM_END_TASK] = API_TASK_NUMFACT; pastix(&pastix_data, MPI_COMM_WORLD, ncol, colptr, rows, values, perm, invp, NULL, 1, iparm, dparm); precond->int_array_1 = (magma_int_t*) perm; precond->int_array_2 = (magma_int_t*) invp; precond->M.val = (float*) values; precond->M.col = (magma_int_t*) colptr; precond->M.row = (magma_int_t*) rows; precond->M.num_rows = A.num_rows; precond->M.num_cols = A.num_cols; precond->M.memory_location = Magma_CPU; precond->pastix_data = pastix_data; precond->iparm = iparm; precond->dparm = dparm; if( A.storage_type != Magma_CSR){ magma_s_mfree( &A_h1 ); } magma_s_vfree( &b_h); magma_s_mfree( &B ); #else printf( "error: only real supported yet.\n"); #endif #else printf( "error: pastix not available.\n"); #endif return MAGMA_SUCCESS; }
magma_int_t magma_sbicgstab( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector *x, magma_s_solver_par *solver_par ){ // prepare solver feedback solver_par->solver = Magma_BICGSTAB; solver_par->numiter = 0; solver_par->info = 0; // some useful variables float c_zero = MAGMA_S_ZERO, c_one = MAGMA_S_ONE, c_mone = MAGMA_S_NEG_ONE; magma_int_t dofs = A.num_rows; // workspace magma_s_vector r,rr,p,v,s,t; magma_s_vinit( &r, Magma_DEV, dofs, c_zero ); magma_s_vinit( &rr, Magma_DEV, dofs, c_zero ); magma_s_vinit( &p, Magma_DEV, dofs, c_zero ); magma_s_vinit( &v, Magma_DEV, dofs, c_zero ); magma_s_vinit( &s, Magma_DEV, dofs, c_zero ); magma_s_vinit( &t, Magma_DEV, dofs, c_zero ); // solver variables float alpha, beta, omega, rho_old, rho_new; float nom, betanom, nom0, r0, den, res; // solver setup magma_sscal( dofs, c_zero, x->val, 1) ; // x = 0 magma_scopy( dofs, b.val, 1, r.val, 1 ); // r = b magma_scopy( dofs, b.val, 1, rr.val, 1 ); // rr = b nom0 = betanom = magma_snrm2( dofs, r.val, 1 ); // nom = || r || nom = nom0*nom0; rho_old = omega = alpha = MAGMA_S_MAKE( 1.0, 0. ); solver_par->init_res = nom0; magma_s_spmv( c_one, A, r, c_zero, v ); // z = A r den = MAGMA_S_REAL( magma_sdot(dofs, v.val, 1, r.val, 1) ); // den = z' * r if ( (r0 = nom * solver_par->epsilon) < ATOLERANCE ) r0 = ATOLERANCE; if ( nom < r0 ) return MAGMA_SUCCESS; // check positive definite if (den <= 0.0) { printf("Operator A is not postive definite. (Ar,r) = %f\n", den); return -100; } //Chronometry real_Double_t tempo1, tempo2; magma_device_sync(); tempo1=magma_wtime(); if( solver_par->verbose > 0 ){ solver_par->res_vec[0] = nom0; solver_par->timing[0] = 0.0; } // start iteration for( solver_par->numiter= 1; solver_par->numiter<solver_par->maxiter; solver_par->numiter++ ){ rho_new = magma_sdot( dofs, rr.val, 1, r.val, 1 ); // rho=<rr,r> beta = rho_new/rho_old * alpha/omega; // beta=rho/rho_old *alpha/omega magma_sscal( dofs, beta, p.val, 1 ); // p = beta*p magma_saxpy( dofs, c_mone * omega * beta, v.val, 1 , p.val, 1 ); // p = p-omega*beta*v magma_saxpy( dofs, c_one, r.val, 1, p.val, 1 ); // p = p+r magma_s_spmv( c_one, A, p, c_zero, v ); // v = Ap alpha = rho_new / magma_sdot( dofs, rr.val, 1, v.val, 1 ); magma_scopy( dofs, r.val, 1 , s.val, 1 ); // s=r magma_saxpy( dofs, c_mone * alpha, v.val, 1 , s.val, 1 ); // s=s-alpha*v magma_s_spmv( c_one, A, s, c_zero, t ); // t=As omega = magma_sdot( dofs, t.val, 1, s.val, 1 ) // omega = <s,t>/<t,t> / magma_sdot( dofs, t.val, 1, t.val, 1 ); magma_saxpy( dofs, alpha, p.val, 1 , x->val, 1 ); // x=x+alpha*p magma_saxpy( dofs, omega, s.val, 1 , x->val, 1 ); // x=x+omega*s magma_scopy( dofs, s.val, 1 , r.val, 1 ); // r=s magma_saxpy( dofs, c_mone * omega, t.val, 1 , r.val, 1 ); // r=r-omega*t res = betanom = magma_snrm2( dofs, r.val, 1 ); nom = betanom*betanom; rho_old = rho_new; // rho_old=rho if( solver_par->verbose > 0 ){ magma_device_sync(); tempo2=magma_wtime(); if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) res; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } if ( res/nom0 < solver_par->epsilon ) { break; } } magma_device_sync(); tempo2=magma_wtime(); solver_par->runtime = (real_Double_t) tempo2-tempo1; float residual; magma_sresidual( A, b, *x, &residual ); solver_par->iter_res = res; solver_par->final_res = residual; if( solver_par->numiter < solver_par->maxiter){ solver_par->info = 0; }else if( solver_par->init_res > solver_par->final_res ){ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -2; } else{ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -1; } magma_s_vfree(&r); magma_s_vfree(&rr); magma_s_vfree(&p); magma_s_vfree(&v); magma_s_vfree(&s); magma_s_vfree(&t); return MAGMA_SUCCESS; } /* magma_sbicgstab */
magma_int_t magma_spgmres( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector *x, magma_s_solver_par *solver_par, magma_s_preconditioner *precond_par ){ // prepare solver feedback solver_par->solver = Magma_PGMRES; solver_par->numiter = 0; solver_par->info = 0; // local variables float c_zero = MAGMA_S_ZERO, c_one = MAGMA_S_ONE, c_mone = MAGMA_S_NEG_ONE; magma_int_t dofs = A.num_rows; magma_int_t i, j, k, m = 0; magma_int_t restart = min( dofs-1, solver_par->restart ); magma_int_t ldh = restart+1; float nom, rNorm, RNorm, nom0, betanom, r0 = 0.; // CPU workspace //magma_setdevice(0); float *H, *HH, *y, *h1; magma_smalloc_pinned( &H, (ldh+1)*ldh ); magma_smalloc_pinned( &y, ldh ); magma_smalloc_pinned( &HH, ldh*ldh ); magma_smalloc_pinned( &h1, ldh ); // GPU workspace magma_s_vector r, q, q_t, z, z_t, t; magma_s_vinit( &t, Magma_DEV, dofs, c_zero ); magma_s_vinit( &r, Magma_DEV, dofs, c_zero ); magma_s_vinit( &q, Magma_DEV, dofs*(ldh+1), c_zero ); magma_s_vinit( &z, Magma_DEV, dofs*(ldh+1), c_zero ); magma_s_vinit( &z_t, Magma_DEV, dofs, c_zero ); q_t.memory_location = Magma_DEV; q_t.val = NULL; q_t.num_rows = q_t.nnz = dofs; float *dy, *dH = NULL; if (MAGMA_SUCCESS != magma_smalloc( &dy, ldh )) return MAGMA_ERR_DEVICE_ALLOC; if (MAGMA_SUCCESS != magma_smalloc( &dH, (ldh+1)*ldh )) return MAGMA_ERR_DEVICE_ALLOC; // GPU stream magma_queue_t stream[2]; magma_event_t event[1]; magma_queue_create( &stream[0] ); magma_queue_create( &stream[1] ); magma_event_create( &event[0] ); magmablasSetKernelStream(stream[0]); magma_sscal( dofs, c_zero, x->val, 1 ); // x = 0 magma_scopy( dofs, b.val, 1, r.val, 1 ); // r = b nom0 = betanom = magma_snrm2( dofs, r.val, 1 ); // nom0= || r|| nom = nom0 * nom0; solver_par->init_res = nom0; H(1,0) = MAGMA_S_MAKE( nom0, 0. ); magma_ssetvector(1, &H(1,0), 1, &dH(1,0), 1); if ( (r0 = nom0 * RTOLERANCE ) < ATOLERANCE ) r0 = solver_par->epsilon; if ( nom < r0 ) return MAGMA_SUCCESS; //Chronometry real_Double_t tempo1, tempo2; magma_device_sync(); tempo1=magma_wtime(); if( solver_par->verbose > 0 ){ solver_par->res_vec[0] = nom0; solver_par->timing[0] = 0.0; } // start iteration for( solver_par->numiter= 1; solver_par->numiter<solver_par->maxiter; solver_par->numiter++ ){ for(k=1; k<=restart; k++) { magma_scopy(dofs, r.val, 1, q(k-1), 1); // q[0] = 1.0/||r|| magma_sscal(dofs, 1./H(k,k-1), q(k-1), 1); // (to be fused) q_t.val = q(k-1); magmablasSetKernelStream(stream[0]); // preconditioner // z[k] = M^(-1) q(k) magma_s_applyprecond_left( A, q_t, &t, precond_par ); magma_s_applyprecond_right( A, t, &z_t, precond_par ); magma_scopy(dofs, z_t.val, 1, z(k-1), 1); // r = A q[k] magma_s_spmv( c_one, A, z_t, c_zero, r ); // if (solver_par->ortho == Magma_MGS ) { // modified Gram-Schmidt for (i=1; i<=k; i++) { H(i,k) =magma_sdot(dofs, q(i-1), 1, r.val, 1); // H(i,k) = q[i] . r magma_saxpy(dofs,-H(i,k), q(i-1), 1, r.val, 1); // r = r - H(i,k) q[i] } H(k+1,k) = MAGMA_S_MAKE( magma_snrm2(dofs, r.val, 1), 0. ); // H(k+1,k) = ||r|| /*}else if (solver_par->ortho == Magma_FUSED_CGS ) { // fusing sgemv with snrm2 in classical Gram-Schmidt magmablasSetKernelStream(stream[0]); magma_scopy(dofs, r.val, 1, q(k), 1); // dH(1:k+1,k) = q[0:k] . r magmablas_sgemv(MagmaTrans, dofs, k+1, c_one, q(0), dofs, r.val, 1, c_zero, &dH(1,k), 1); // r = r - q[0:k-1] dH(1:k,k) magmablas_sgemv(MagmaNoTrans, dofs, k, c_mone, q(0), dofs, &dH(1,k), 1, c_one, r.val, 1); // 1) dH(k+1,k) = sqrt( dH(k+1,k) - dH(1:k,k) ) magma_scopyscale( dofs, k, r.val, q(k), &dH(1,k) ); // 2) q[k] = q[k] / dH(k+1,k) magma_event_record( event[0], stream[0] ); magma_queue_wait_event( stream[1], event[0] ); magma_sgetvector_async(k+1, &dH(1,k), 1, &H(1,k), 1, stream[1]); // asynch copy dH(1:(k+1),k) to H(1:(k+1),k) } else { // classical Gram-Schmidt (default) // > explicitly calling magmabls magmablasSetKernelStream(stream[0]); magmablas_sgemv(MagmaTrans, dofs, k, c_one, q(0), dofs, r.val, 1, c_zero, &dH(1,k), 1); // dH(1:k,k) = q[0:k-1] . r #ifndef SNRM2SCALE // start copying dH(1:k,k) to H(1:k,k) magma_event_record( event[0], stream[0] ); magma_queue_wait_event( stream[1], event[0] ); magma_sgetvector_async(k, &dH(1,k), 1, &H(1,k), 1, stream[1]); #endif // r = r - q[0:k-1] dH(1:k,k) magmablas_sgemv(MagmaNoTrans, dofs, k, c_mone, q(0), dofs, &dH(1,k), 1, c_one, r.val, 1); #ifdef SNRM2SCALE magma_scopy(dofs, r.val, 1, q(k), 1); // q[k] = r / H(k,k-1) magma_snrm2scale(dofs, q(k), dofs, &dH(k+1,k) ); // dH(k+1,k) = sqrt(r . r) and r = r / dH(k+1,k) magma_event_record( event[0], stream[0] ); // start sending dH(1:k,k) to H(1:k,k) magma_queue_wait_event( stream[1], event[0] ); // can we keep H(k+1,k) on GPU and combine? magma_sgetvector_async(k+1, &dH(1,k), 1, &H(1,k), 1, stream[1]); #else H(k+1,k) = MAGMA_S_MAKE( magma_snrm2(dofs, r.val, 1), 0. ); // H(k+1,k) = sqrt(r . r) if( k<solver_par->restart ){ magmablasSetKernelStream(stream[0]); magma_scopy(dofs, r.val, 1, q(k), 1); // q[k] = 1.0/H[k][k-1] r magma_sscal(dofs, 1./H(k+1,k), q(k), 1); // (to be fused) } #endif }*/ /* Minimization of || b-Ax || in H_k */ for (i=1; i<=k; i++) { HH(k,i) = magma_cblas_sdot( i+1, &H(1,k), 1, &H(1,i), 1 ); } h1[k] = H(1,k)*H(1,0); if (k != 1){ for (i=1; i<k; i++) { HH(k,i) = HH(k,i)/HH(i,i);// for (m=i+1; m<=k; m++){ HH(k,m) -= HH(k,i) * HH(m,i) * HH(i,i); } h1[k] -= h1[i] * HH(k,i); } } y[k] = h1[k]/HH(k,k); if (k != 1) for (i=k-1; i>=1; i--) { y[i] = h1[i]/HH(i,i); for (j=i+1; j<=k; j++) y[i] -= y[j] * HH(j,i); } m = k; rNorm = fabs(MAGMA_S_REAL(H(k+1,k))); }/* Minimization done */ // compute solution approximation magma_ssetmatrix(m, 1, y+1, m, dy, m ); magma_sgemv(MagmaNoTrans, dofs, m, c_one, z(0), dofs, dy, 1, c_one, x->val, 1); // compute residual magma_s_spmv( c_mone, A, *x, c_zero, r ); // r = - A * x magma_saxpy(dofs, c_one, b.val, 1, r.val, 1); // r = r + b H(1,0) = MAGMA_S_MAKE( magma_snrm2(dofs, r.val, 1), 0. ); // RNorm = H[1][0] = || r || RNorm = MAGMA_S_REAL( H(1,0) ); betanom = fabs(RNorm); if( solver_par->verbose > 0 ){ magma_device_sync(); tempo2=magma_wtime(); if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } if ( betanom < r0 ) { break; } } magma_device_sync(); tempo2=magma_wtime(); solver_par->runtime = (real_Double_t) tempo2-tempo1; float residual; magma_sresidual( A, b, *x, &residual ); solver_par->iter_res = betanom; solver_par->final_res = residual; if( solver_par->numiter < solver_par->maxiter){ solver_par->info = 0; }else if( solver_par->init_res > solver_par->final_res ){ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -2; } else{ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -1; } // free pinned memory magma_free_pinned( H ); magma_free_pinned( y ); magma_free_pinned( HH ); magma_free_pinned( h1 ); // free GPU memory magma_free(dy); if (dH != NULL ) magma_free(dH); magma_s_vfree(&t); magma_s_vfree(&r); magma_s_vfree(&q); magma_s_vfree(&z); magma_s_vfree(&z_t); // free GPU streams and events magma_queue_destroy( stream[0] ); magma_queue_destroy( stream[1] ); magma_event_destroy( event[0] ); magmablasSetKernelStream(NULL); return MAGMA_SUCCESS; } /* magma_spgmres */
extern "C" magma_int_t magma_scg_merge( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector *x, magma_s_solver_par *solver_par, magma_queue_t queue ) { // set queue for old dense routines magma_queue_t orig_queue; magmablasGetKernelStream( &orig_queue ); // prepare solver feedback solver_par->solver = Magma_CGMERGE; solver_par->numiter = 0; solver_par->info = MAGMA_SUCCESS; // some useful variables float c_zero = MAGMA_S_ZERO, c_one = MAGMA_S_ONE; magma_int_t dofs = A.num_rows; // GPU stream magma_queue_t stream[2]; magma_event_t event[1]; magma_queue_create( &stream[0] ); magma_queue_create( &stream[1] ); magma_event_create( &event[0] ); // GPU workspace magma_s_vector r, d, z; magma_s_vinit( &r, Magma_DEV, dofs, c_zero, queue ); magma_s_vinit( &d, Magma_DEV, dofs, c_zero, queue ); magma_s_vinit( &z, Magma_DEV, dofs, c_zero, queue ); float *d1, *d2, *skp; d1 = NULL; d2 = NULL; skp = NULL; magma_int_t stat_dev = 0, stat_cpu = 0; stat_dev += magma_smalloc( &d1, dofs*(1) ); stat_dev += magma_smalloc( &d2, dofs*(1) ); // array for the parameters stat_dev += magma_smalloc( &skp, 6 ); // skp = [alpha|beta|gamma|rho|tmp1|tmp2] if( stat_dev != 0 ){ magma_free( d1 ); magma_free( d2 ); magma_free( skp ); printf("error: memory allocation.\n"); return MAGMA_ERR_DEVICE_ALLOC; } // solver variables float alpha, beta, gamma, rho, tmp1, *skp_h; float nom, nom0, r0, betanom, den; // solver setup magma_sscal( dofs, c_zero, x->dval, 1) ; // x = 0 magma_scopy( dofs, b.dval, 1, r.dval, 1 ); // r = b magma_scopy( dofs, b.dval, 1, d.dval, 1 ); // d = b nom0 = betanom = magma_snrm2( dofs, r.dval, 1 ); nom = nom0 * nom0; // nom = r' * r magma_s_spmv( c_one, A, d, c_zero, z, queue ); // z = A d den = MAGMA_S_REAL( magma_sdot(dofs, d.dval, 1, z.dval, 1) ); // den = d'* z solver_par->init_res = nom0; // array on host for the parameters stat_cpu += magma_smalloc_cpu( &skp_h, 6 ); if( stat_cpu != 0 ){ magma_free( d1 ); magma_free( d2 ); magma_free( skp ); magma_free_cpu( skp_h ); printf("error: memory allocation.\n"); return MAGMA_ERR_HOST_ALLOC; } alpha = rho = gamma = tmp1 = c_one; beta = magma_sdot(dofs, r.dval, 1, r.dval, 1); skp_h[0]=alpha; skp_h[1]=beta; skp_h[2]=gamma; skp_h[3]=rho; skp_h[4]=tmp1; skp_h[5]=MAGMA_S_MAKE(nom, 0.0); magma_ssetvector( 6, skp_h, 1, skp, 1 ); if ( (r0 = nom * solver_par->epsilon) < ATOLERANCE ) r0 = ATOLERANCE; if ( nom < r0 ) { magmablasSetKernelStream( orig_queue ); return MAGMA_SUCCESS; } // check positive definite if (den <= 0.0) { printf("Operator A is not postive definite. (Ar,r) = %f\n", den); magmablasSetKernelStream( orig_queue ); return MAGMA_NONSPD; solver_par->info = MAGMA_NONSPD;; } //Chronometry real_Double_t tempo1, tempo2; tempo1 = magma_sync_wtime( queue ); if ( solver_par->verbose > 0 ) { solver_par->res_vec[0] = (real_Double_t) nom0; solver_par->timing[0] = 0.0; } // start iteration for( solver_par->numiter= 1; solver_par->numiter<solver_par->maxiter; solver_par->numiter++ ) { magmablasSetKernelStream(stream[0]); // computes SpMV and dot product magma_scgmerge_spmv1( A, d1, d2, d.dval, z.dval, skp, queue ); // updates x, r, computes scalars and updates d magma_scgmerge_xrbeta( dofs, d1, d2, x->dval, r.dval, d.dval, z.dval, skp, queue ); // check stopping criterion (asynchronous copy) magma_sgetvector_async( 1 , skp+1, 1, skp_h+1, 1, stream[1] ); betanom = sqrt(MAGMA_S_REAL(skp_h[1])); if ( solver_par->verbose > 0 ) { tempo2 = magma_sync_wtime( queue ); if ( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } if ( betanom < r0 ) { break; } } tempo2 = magma_sync_wtime( queue ); solver_par->runtime = (real_Double_t) tempo2-tempo1; float residual; magma_sresidual( A, b, *x, &residual, queue ); solver_par->iter_res = betanom; solver_par->final_res = residual; if ( solver_par->numiter < solver_par->maxiter) { solver_par->info = MAGMA_SUCCESS; } else if ( solver_par->init_res > solver_par->final_res ) { if ( solver_par->verbose > 0 ) { if ( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = MAGMA_SLOW_CONVERGENCE; } else { if ( solver_par->verbose > 0 ) { if ( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = MAGMA_DIVERGENCE; } magma_s_vfree(&r, queue ); magma_s_vfree(&z, queue ); magma_s_vfree(&d, queue ); magma_free( d1 ); magma_free( d2 ); magma_free( skp ); magma_free_cpu( skp_h ); magmablasSetKernelStream( orig_queue ); return MAGMA_SUCCESS; } /* magma_scg_merge */
magma_int_t magma_sbicgstab_merge( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector *x, magma_s_solver_par *solver_par ){ // prepare solver feedback solver_par->solver = Magma_BICGSTABMERGE; solver_par->numiter = 0; solver_par->info = 0; // some useful variables float c_zero = MAGMA_S_ZERO, c_one = MAGMA_S_ONE; magma_int_t dofs = A.num_rows; // GPU stream magma_queue_t stream[2]; magma_event_t event[1]; magma_queue_create( &stream[0] ); magma_queue_create( &stream[1] ); magma_event_create( &event[0] ); // workspace magma_s_vector q, r,rr,p,v,s,t; float *d1, *d2, *skp; magma_smalloc( &d1, dofs*(2) ); magma_smalloc( &d2, dofs*(2) ); // array for the parameters magma_smalloc( &skp, 8 ); // skp = [alpha|beta|omega|rho_old|rho|nom|tmp1|tmp2] magma_s_vinit( &q, Magma_DEV, dofs*6, c_zero ); // q = rr|r|p|v|s|t rr.memory_location = Magma_DEV; rr.val = NULL; rr.num_rows = rr.nnz = dofs; r.memory_location = Magma_DEV; r.val = NULL; r.num_rows = r.nnz = dofs; p.memory_location = Magma_DEV; p.val = NULL; p.num_rows = p.nnz = dofs; v.memory_location = Magma_DEV; v.val = NULL; v.num_rows = v.nnz = dofs; s.memory_location = Magma_DEV; s.val = NULL; s.num_rows = s.nnz = dofs; t.memory_location = Magma_DEV; t.val = NULL; t.num_rows = t.nnz = dofs; rr.val = q(0); r.val = q(1); p.val = q(2); v.val = q(3); s.val = q(4); t.val = q(5); // solver variables float alpha, beta, omega, rho_old, rho_new, *skp_h; float nom, nom0, betanom, r0, den; // solver setup magma_sscal( dofs, c_zero, x->val, 1) ; // x = 0 magma_scopy( dofs, b.val, 1, q(0), 1 ); // rr = b magma_scopy( dofs, b.val, 1, q(1), 1 ); // r = b rho_new = magma_sdot( dofs, r.val, 1, r.val, 1 ); // rho=<rr,r> nom = MAGMA_S_REAL(magma_sdot( dofs, r.val, 1, r.val, 1 )); nom0 = betanom = sqrt(nom); // nom = || r || rho_old = omega = alpha = MAGMA_S_MAKE( 1.0, 0. ); beta = rho_new; solver_par->init_res = nom0; // array on host for the parameters magma_smalloc_cpu( &skp_h, 8 ); skp_h[0]=alpha; skp_h[1]=beta; skp_h[2]=omega; skp_h[3]=rho_old; skp_h[4]=rho_new; skp_h[5]=MAGMA_S_MAKE(nom, 0.0); magma_ssetvector( 8, skp_h, 1, skp, 1 ); magma_s_spmv( c_one, A, r, c_zero, v ); // z = A r den = MAGMA_S_REAL( magma_sdot(dofs, v.val, 1, r.val, 1) );// den = z dot r if ( (r0 = nom * solver_par->epsilon) < ATOLERANCE ) r0 = ATOLERANCE; if ( nom < r0 ) return MAGMA_SUCCESS; // check positive definite if (den <= 0.0) { printf("Operator A is not postive definite. (Ar,r) = %f\n", den); return -100; } //Chronometry real_Double_t tempo1, tempo2; magma_device_sync(); tempo1=magma_wtime(); if( solver_par->verbose > 0 ){ solver_par->res_vec[0] = nom0; solver_par->timing[0] = 0.0; } // start iteration for( solver_par->numiter= 1; solver_par->numiter<solver_par->maxiter; solver_par->numiter++ ){ magmablasSetKernelStream(stream[0]); // computes p=r+beta*(p-omega*v) magma_sbicgmerge1( dofs, skp, v.val, r.val, p.val ); magma_s_spmv( c_one, A, p, c_zero, v ); // v = Ap magma_smdotc( dofs, 1, q.val, v.val, d1, d2, skp ); magma_sbicgmerge4( 1, skp ); magma_sbicgmerge2( dofs, skp, r.val, v.val, s.val ); // s=r-alpha*v magma_s_spmv( c_one, A, s, c_zero, t ); // t=As magma_smdotc( dofs, 2, q.val+4*dofs, t.val, d1, d2, skp+6 ); magma_sbicgmerge4( 2, skp ); magma_sbicgmerge3( dofs, skp, p.val, s.val, // x=x+alpha*p+omega*s t.val, x->val, r.val ); // r=s-omega*t magma_smdotc( dofs, 2, q.val, r.val, d1, d2, skp+4); magma_sbicgmerge4( 3, skp ); // check stopping criterion (asynchronous copy) magma_sgetvector_async( 1 , skp+5, 1, skp_h+5, 1, stream[1] ); betanom = sqrt(MAGMA_S_REAL(skp_h[5])); if( solver_par->verbose > 0 ){ magma_device_sync(); tempo2=magma_wtime(); if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } if ( betanom < r0 ) { break; } } magma_device_sync(); tempo2=magma_wtime(); solver_par->runtime = (real_Double_t) tempo2-tempo1; float residual; magma_sresidual( A, b, *x, &residual ); solver_par->iter_res = betanom; solver_par->final_res = residual; if( solver_par->numiter < solver_par->maxiter){ solver_par->info = 0; }else if( solver_par->init_res > solver_par->final_res ){ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -2; } else{ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -1; } magma_s_vfree(&q); // frees all vectors magma_free(d1); magma_free(d2); magma_free( skp ); magma_free_cpu( skp_h ); return MAGMA_SUCCESS; } /* sbicgstab_merge */
/* //////////////////////////////////////////////////////////////////////////// -- running magma_scg magma_scg_merge */ int main( int argc, char** argv) { TESTING_INIT(); magma_s_solver_par solver_par; solver_par.epsilon = 10e-16; solver_par.maxiter = 1000; solver_par.verbose = 0; solver_par.num_eigenvalues = 0; magma_s_preconditioner precond_par; precond_par.solver = Magma_JACOBI; precond_par.levels = 0; precond_par.sweeps = 10; int precond = 0; int format = 0; int version = 0; int scale = 0; magma_scale_t scaling = Magma_NOSCALE; magma_s_sparse_matrix A, B, B_d; magma_s_vector x, b; B.blocksize = 8; B.alignment = 8; float one = MAGMA_S_MAKE(1.0, 0.0); float zero = MAGMA_S_MAKE(0.0, 0.0); B.storage_type = Magma_CSR; int i; for( i = 1; i < argc; ++i ) { if ( strcmp("--format", argv[i]) == 0 ) { format = atoi( argv[++i] ); switch( format ) { case 0: B.storage_type = Magma_CSR; break; case 1: B.storage_type = Magma_ELL; break; case 2: B.storage_type = Magma_ELLRT; break; case 3: B.storage_type = Magma_SELLP; break; } }else if ( strcmp("--mscale", argv[i]) == 0 ) { scale = atoi( argv[++i] ); switch( scale ) { case 0: scaling = Magma_NOSCALE; break; case 1: scaling = Magma_UNITDIAG; break; case 2: scaling = Magma_UNITROW; break; } }else if ( strcmp("--precond", argv[i]) == 0 ) { precond = atoi( argv[++i] ); switch( precond ) { case 0: precond_par.solver = Magma_JACOBI; break; case 1: precond_par.solver = Magma_ICC; break; case 2: precond_par.solver = Magma_AICC; break; } }else if ( strcmp("--version", argv[i]) == 0 ) { version = atoi( argv[++i] ); }else if ( strcmp("--blocksize", argv[i]) == 0 ) { B.blocksize = atoi( argv[++i] ); }else if ( strcmp("--alignment", argv[i]) == 0 ) { B.alignment = atoi( argv[++i] ); }else if ( strcmp("--verbose", argv[i]) == 0 ) { solver_par.verbose = atoi( argv[++i] ); } else if ( strcmp("--maxiter", argv[i]) == 0 ) { solver_par.maxiter = atoi( argv[++i] ); } else if ( strcmp("--tol", argv[i]) == 0 ) { sscanf( argv[++i], "%f", &solver_par.epsilon ); } else if ( strcmp("--levels", argv[i]) == 0 ) { precond_par.levels = atoi( argv[++i] ); }else if ( strcmp("--sweeps", argv[i]) == 0 ) { precond_par.sweeps = atoi( argv[++i] ); } else break; } printf( "\n# usage: ./run_spcg" " [ --format %d (0=CSR, 1=ELL 2=ELLRT, 3=SELLP)" " [ --blocksize %d --alignment %d ]" " --mscale %d (0=no, 1=unitdiag, 2=unitrownrm)" " --verbose %d (0=summary, k=details every k iterations)" " --maxiter %d --tol %.2e" " --precond %d (0=Jacobi, 1=IC, 2=AIC [ --levels %d --sweeps %d]) ]" " matrices \n\n", format, (int)B.blocksize, (int)B.alignment, scale, (int)solver_par.verbose, (int)solver_par.maxiter, solver_par.epsilon, precond, (int) precond_par.levels, (int) precond_par.sweeps ); magma_ssolverinfo_init( &solver_par, &precond_par ); while( i < argc ){ magma_s_csr_mtx( &A, argv[i] ); printf( "\n# matrix info: %d-by-%d with %d nonzeros\n\n", (int) A.num_rows,(int) A.num_cols,(int) A.nnz ); // scale matrix magma_smscale( &A, scaling ); magma_s_mconvert( A, &B, Magma_CSR, B.storage_type ); magma_s_mtransfer( B, &B_d, Magma_CPU, Magma_DEV ); // vectors and initial guess magma_s_vinit( &b, Magma_DEV, A.num_cols, one ); magma_s_vinit( &x, Magma_DEV, A.num_cols, one ); magma_s_spmv( one, B_d, x, zero, b ); // b = A x magma_s_vfree(&x); magma_s_vinit( &x, Magma_DEV, A.num_cols, zero ); magma_s_precondsetup( B_d, b, &precond_par ); magma_spcg( B_d, b, &x, &solver_par, &precond_par ); magma_ssolverinfo( &solver_par, &precond_par ); magma_s_mfree(&B_d); magma_s_mfree(&B); magma_s_mfree(&A); magma_s_vfree(&x); magma_s_vfree(&b); i++; } magma_ssolverinfo_free( &solver_par, &precond_par ); TESTING_FINALIZE(); return 0; }
extern "C" magma_int_t magma_scg( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector *x, magma_s_solver_par *solver_par, magma_queue_t queue ) { // set queue for old dense routines magma_queue_t orig_queue; magmablasGetKernelStream( &orig_queue ); // prepare solver feedback solver_par->solver = Magma_CG; solver_par->numiter = 0; solver_par->info = MAGMA_SUCCESS; // local variables float c_zero = MAGMA_S_ZERO, c_one = MAGMA_S_ONE; magma_int_t dofs = A.num_rows; // GPU workspace magma_s_vector r, p, q; magma_s_vinit( &r, Magma_DEV, dofs, c_zero, queue ); magma_s_vinit( &p, Magma_DEV, dofs, c_zero, queue ); magma_s_vinit( &q, Magma_DEV, dofs, c_zero, queue ); // solver variables float alpha, beta; float nom, nom0, r0, betanom, betanomsq, den; // solver setup magma_sscal( dofs, c_zero, x->dval, 1) ; // x = 0 magma_scopy( dofs, b.dval, 1, r.dval, 1 ); // r = b magma_scopy( dofs, b.dval, 1, p.dval, 1 ); // p = b nom0 = betanom = magma_snrm2( dofs, r.dval, 1 ); nom = nom0 * nom0; // nom = r' * r magma_s_spmv( c_one, A, p, c_zero, q, queue ); // q = A p den = MAGMA_S_REAL( magma_sdot(dofs, p.dval, 1, q.dval, 1) );// den = p dot q solver_par->init_res = nom0; if ( (r0 = nom * solver_par->epsilon) < ATOLERANCE ) r0 = ATOLERANCE; if ( nom < r0 ) { magmablasSetKernelStream( orig_queue ); return MAGMA_SUCCESS; } // check positive definite if (den <= 0.0) { printf("Operator A is not postive definite. (Ar,r) = %f\n", den); magmablasSetKernelStream( orig_queue ); return MAGMA_NONSPD; solver_par->info = MAGMA_NONSPD; } //Chronometry real_Double_t tempo1, tempo2; tempo1 = magma_sync_wtime( queue ); if ( solver_par->verbose > 0 ) { solver_par->res_vec[0] = (real_Double_t)nom0; solver_par->timing[0] = 0.0; } // start iteration for( solver_par->numiter= 1; solver_par->numiter<solver_par->maxiter; solver_par->numiter++ ) { alpha = MAGMA_S_MAKE(nom/den, 0.); magma_saxpy(dofs, alpha, p.dval, 1, x->dval, 1); // x = x + alpha p magma_saxpy(dofs, -alpha, q.dval, 1, r.dval, 1); // r = r - alpha q betanom = magma_snrm2(dofs, r.dval, 1); // betanom = || r || betanomsq = betanom * betanom; // betanoms = r' * r if ( solver_par->verbose > 0 ) { tempo2 = magma_sync_wtime( queue ); if ( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } if ( betanom < r0 ) { break; } beta = MAGMA_S_MAKE(betanomsq/nom, 0.); // beta = betanoms/nom magma_sscal(dofs, beta, p.dval, 1); // p = beta*p magma_saxpy(dofs, c_one, r.dval, 1, p.dval, 1); // p = p + r magma_s_spmv( c_one, A, p, c_zero, q, queue ); // q = A p den = MAGMA_S_REAL(magma_sdot(dofs, p.dval, 1, q.dval, 1)); // den = p dot q nom = betanomsq; } tempo2 = magma_sync_wtime( queue ); solver_par->runtime = (real_Double_t) tempo2-tempo1; float residual; magma_sresidual( A, b, *x, &residual, queue ); solver_par->final_res = residual; if ( solver_par->numiter < solver_par->maxiter) { solver_par->info = MAGMA_SUCCESS; } else if ( solver_par->init_res > solver_par->final_res ) { if ( solver_par->verbose > 0 ) { if ( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = MAGMA_SLOW_CONVERGENCE; } else { if ( solver_par->verbose > 0 ) { if ( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) betanom; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = MAGMA_DIVERGENCE; } magma_s_vfree(&r, queue ); magma_s_vfree(&p, queue ); magma_s_vfree(&q, queue ); magmablasSetKernelStream( orig_queue ); return MAGMA_SUCCESS; } /* magma_scg */
magma_int_t magma_spcg( magma_s_sparse_matrix A, magma_s_vector b, magma_s_vector *x, magma_s_solver_par *solver_par, magma_s_preconditioner *precond_par ){ // prepare solver feedback solver_par->solver = Magma_PCG; solver_par->numiter = 0; solver_par->info = 0; // local variables float c_zero = MAGMA_S_ZERO, c_one = MAGMA_S_ONE; magma_int_t dofs = A.num_rows; // GPU workspace magma_s_vector r, rt, p, q, h; magma_s_vinit( &r, Magma_DEV, dofs, c_zero ); magma_s_vinit( &rt, Magma_DEV, dofs, c_zero ); magma_s_vinit( &p, Magma_DEV, dofs, c_zero ); magma_s_vinit( &q, Magma_DEV, dofs, c_zero ); magma_s_vinit( &h, Magma_DEV, dofs, c_zero ); // solver variables float alpha, beta; float nom, nom0, r0, gammaold, gammanew, den, res; // solver setup magma_sscal( dofs, c_zero, x->val, 1) ; // x = 0 magma_scopy( dofs, b.val, 1, r.val, 1 ); // r = b // preconditioner magma_s_applyprecond_left( A, r, &rt, precond_par ); magma_s_applyprecond_right( A, rt, &h, precond_par ); magma_scopy( dofs, h.val, 1, p.val, 1 ); // p = h nom = MAGMA_S_REAL( magma_sdot(dofs, r.val, 1, h.val, 1) ); nom0 = magma_snrm2( dofs, r.val, 1 ); magma_s_spmv( c_one, A, p, c_zero, q ); // q = A p den = MAGMA_S_REAL( magma_sdot(dofs, p.val, 1, q.val, 1) );// den = p dot q solver_par->init_res = nom0; if ( (r0 = nom * solver_par->epsilon) < ATOLERANCE ) r0 = ATOLERANCE; if ( nom < r0 ) return MAGMA_SUCCESS; // check positive definite if (den <= 0.0) { printf("Operator A is not postive definite. (Ar,r) = %f\n", den); return -100; } //Chronometry real_Double_t tempo1, tempo2; magma_device_sync(); tempo1=magma_wtime(); if( solver_par->verbose > 0 ){ solver_par->res_vec[0] = (real_Double_t)nom0; solver_par->timing[0] = 0.0; } // start iteration for( solver_par->numiter= 1; solver_par->numiter<solver_par->maxiter; solver_par->numiter++ ){ // preconditioner magma_s_applyprecond_left( A, r, &rt, precond_par ); magma_s_applyprecond_right( A, rt, &h, precond_par ); gammanew = MAGMA_S_REAL( magma_sdot(dofs, r.val, 1, h.val, 1) ); // gn = < r,h> if( solver_par->numiter==1 ){ magma_scopy( dofs, h.val, 1, p.val, 1 ); // p = h }else{ beta = MAGMA_S_MAKE(gammanew/gammaold, 0.); // beta = gn/go magma_sscal(dofs, beta, p.val, 1); // p = beta*p magma_saxpy(dofs, c_one, h.val, 1, p.val, 1); // p = p + h } magma_s_spmv( c_one, A, p, c_zero, q ); // q = A p den = MAGMA_S_REAL(magma_sdot(dofs, p.val, 1, q.val, 1)); // den = p dot q alpha = MAGMA_S_MAKE(gammanew/den, 0.); magma_saxpy(dofs, alpha, p.val, 1, x->val, 1); // x = x + alpha p magma_saxpy(dofs, -alpha, q.val, 1, r.val, 1); // r = r - alpha q gammaold = gammanew; res = magma_snrm2( dofs, r.val, 1 ); if( solver_par->verbose > 0 ){ magma_device_sync(); tempo2=magma_wtime(); if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) res; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } if ( res/nom0 < solver_par->epsilon ) { break; } } magma_device_sync(); tempo2=magma_wtime(); solver_par->runtime = (real_Double_t) tempo2-tempo1; float residual; magma_sresidual( A, b, *x, &residual ); solver_par->iter_res = res; solver_par->final_res = residual; if( solver_par->numiter < solver_par->maxiter){ solver_par->info = 0; }else if( solver_par->init_res > solver_par->final_res ){ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) res; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -2; } else{ if( solver_par->verbose > 0 ){ if( (solver_par->numiter)%solver_par->verbose==0 ) { solver_par->res_vec[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) res; solver_par->timing[(solver_par->numiter)/solver_par->verbose] = (real_Double_t) tempo2-tempo1; } } solver_par->info = -1; } magma_s_vfree(&r); magma_s_vfree(&rt); magma_s_vfree(&p); magma_s_vfree(&q); magma_s_vfree(&h); return MAGMA_SUCCESS; } /* magma_scg */