static boost::tuple< boost::shared_ptr<Matrix>, boost::shared_ptr<Matrix> > transfer_operators(const Matrix &A, params &prm) { typedef typename backend::value_type<Matrix>::type V; const size_t n = rows(A); TIC("aggregates"); Aggregates aggr(A, prm.aggr, prm.nullspace.cols); TOC("aggregates"); TIC("interpolation"); boost::shared_ptr<Matrix> P = tentative_prolongation<Matrix>( n, aggr.count, aggr.id, prm.nullspace, prm.aggr.block_size ); TOC("interpolation"); boost::shared_ptr<Matrix> R = boost::make_shared<Matrix>(); *R = transpose(*P); if (prm.nullspace.cols > 0) prm.aggr.block_size = prm.nullspace.cols; return boost::make_tuple(P, R); }
std::tuple< std::shared_ptr< distributed_matrix<Backend> >, std::shared_ptr< distributed_matrix<Backend> > > transfer_operators(const distributed_matrix<Backend> &A) { pmis<Backend> aggr(A, prm.aggr); return std::make_tuple(aggr.p_tent, transpose(*aggr.p_tent)); }
pointwise_aggregates(const Matrix &A, const params &prm) : count(0) { if (prm.block_size == 1) { plain_aggregates aggr(A, prm); count = aggr.count; strong_connection.swap(aggr.strong_connection); id.swap(aggr.id); } else { strong_connection.resize( nonzeros(A) ); id.resize( rows(A) ); Matrix Ap = pointwise_matrix(A, prm.block_size); plain_aggregates pw_aggr(Ap, prm); count = pw_aggr.count * prm.block_size; #pragma omp parallel { std::vector<ptrdiff_t> marker(Ap.nrows, -1); #ifdef _OPENMP int nt = omp_get_num_threads(); int tid = omp_get_thread_num(); size_t chunk_size = (Ap.nrows + nt - 1) / nt; size_t chunk_start = tid * chunk_size; size_t chunk_end = std::min(Ap.nrows, chunk_start + chunk_size); #else size_t chunk_start = 0; size_t chunk_end = Ap.nrows; #endif for(size_t ip = chunk_start, ia = ip * prm.block_size; ip < chunk_end; ++ip) { ptrdiff_t row_beg = Ap.ptr[ip]; ptrdiff_t row_end = row_beg; for(unsigned k = 0; k < prm.block_size; ++k, ++ia) { id[ia] = prm.block_size * pw_aggr.id[ip] + k; for(ptrdiff_t ja = A.ptr[ia], ea = A.ptr[ia+1]; ja < ea; ++ja) { ptrdiff_t cp = A.col[ja] / prm.block_size; if (marker[cp] < row_beg) { marker[cp] = row_end; strong_connection[ja] = pw_aggr.strong_connection[row_end]; ++row_end; } else { strong_connection[ja] = pw_aggr.strong_connection[ marker[cp] ]; } } } } } } }
int main() { FILE *neigh; FILE *train; FILE *test; FILE *result; int user, movie, rating, time; long double pred; long double mae; int n; int user_pos; int cur_user; long double mae_list[500]; int mae_i=0; test = fopen("new_testing.dat", "r"); neigh = fopen("new_neighbours.dat", "r"); train = fopen("new_training.dat", "r"); result = fopen("result.dat", "w"); while(!feof(test)) { fscanf(test, "%d::%d::%d::%d\n", &user, &movie, &rating, &time); mae = 0.0; n = 0; cur_user = user; printf("\nFor user %d", cur_user); while(user==cur_user) { pred = aggr(user, movie, neigh, train); fprintf(result, "%d::%d::%llf\n", user, movie, pred); mae += fabsl(pred-rating); n++; user_pos=ftell(test); if(feof(test)) break; fscanf(test, "%d::%d::%d::%d\n", &user, &movie, &rating, &time); } mae = mae/((long double)(n)); mae_list[mae_i++] = mae; if(feof(test)) break; fseek(test, user_pos, SEEK_SET); } mae = 0.0; for(n=0; n<mae_i; n++) mae += mae_list[n]; mae = mae/mae_i; fprintf(result, "MAE:%llf\n", mae); fclose(test); fclose(neigh); fclose(train); fclose(result); return 0; }
std::tuple< std::shared_ptr<Matrix>, std::shared_ptr<Matrix> > transfer_operators(const Matrix &A) { typedef typename backend::value_type<Matrix>::type Val; typedef ptrdiff_t Idx; AMGCL_TIC("aggregates"); Aggregates aggr(A, prm.aggr, prm.nullspace.cols); prm.aggr.eps_strong *= 0.5; AMGCL_TOC("aggregates"); AMGCL_TIC("interpolation"); auto P_tent = tentative_prolongation<Matrix>( rows(A), aggr.count, aggr.id, prm.nullspace, prm.aggr.block_size ); // Filter the system matrix backend::crs<Val> Af; Af.set_size(rows(A), cols(A)); Af.ptr[0] = 0; std::vector<Val> dia(Af.nrows); #pragma omp parallel for for(Idx i = 0; i < static_cast<Idx>(Af.nrows); ++i) { Idx row_begin = A.ptr[i]; Idx row_end = A.ptr[i+1]; Idx row_width = row_end - row_begin; Val D = math::zero<Val>(); for(Idx j = row_begin; j < row_end; ++j) { Idx c = A.col[j]; Val v = A.val[j]; if (c == i) D += v; else if (!aggr.strong_connection[j]) { D += v; --row_width; } } dia[i] = D; Af.ptr[i+1] = row_width; } Af.set_nonzeros(Af.scan_row_sizes()); #pragma omp parallel for for(Idx i = 0; i < static_cast<Idx>(Af.nrows); ++i) { Idx row_begin = A.ptr[i]; Idx row_end = A.ptr[i+1]; Idx row_head = Af.ptr[i]; for(Idx j = row_begin; j < row_end; ++j) { Idx c = A.col[j]; if (c == i) { Af.col[row_head] = i; Af.val[row_head] = dia[i]; ++row_head; } else if (aggr.strong_connection[j]) { Af.col[row_head] = c; Af.val[row_head] = A.val[j]; ++row_head; } } } std::vector<Val> omega; auto P = interpolation(Af, dia, *P_tent, omega); auto R = restriction (Af, dia, *P_tent, omega); AMGCL_TOC("interpolation"); if (prm.nullspace.cols > 0) prm.aggr.block_size = prm.nullspace.cols; return std::make_tuple(P, R); }
void *aggr_combiner (iterator_t *itr) { return aggr(itr); }
static boost::tuple< boost::shared_ptr<Matrix>, boost::shared_ptr<Matrix> > transfer_operators(const Matrix &A, params &prm) { typedef typename backend::value_type<Matrix>::type value_type; typedef typename math::scalar_of<value_type>::type scalar_type; const size_t n = rows(A); BOOST_AUTO(Aptr, A.ptr_data()); BOOST_AUTO(Acol, A.col_data()); BOOST_AUTO(Aval, A.val_data()); TIC("aggregates"); Aggregates aggr(A, prm.aggr, prm.nullspace.cols); prm.aggr.eps_strong *= 0.5; TOC("aggregates"); TIC("interpolation"); boost::shared_ptr<Matrix> P_tent = tentative_prolongation<Matrix>( n, aggr.count, aggr.id, prm.nullspace, prm.aggr.block_size ); boost::shared_ptr<Matrix> P = boost::make_shared<Matrix>(); P->nrows = rows(*P_tent); P->ncols = cols(*P_tent); P->ptr.resize(n + 1, 0); #pragma omp parallel { std::vector<ptrdiff_t> marker(P->ncols, -1); #ifdef _OPENMP int nt = omp_get_num_threads(); int tid = omp_get_thread_num(); ptrdiff_t chunk_size = (n + nt - 1) / nt; ptrdiff_t chunk_start = tid * chunk_size; ptrdiff_t chunk_end = std::min<ptrdiff_t>(n, chunk_start + chunk_size); #else ptrdiff_t chunk_start = 0; ptrdiff_t chunk_end = n; #endif // Count number of entries in P. for(ptrdiff_t i = chunk_start; i < chunk_end; ++i) { for(ptrdiff_t ja = Aptr[i], ea = Aptr[i+1]; ja < ea; ++ja) { ptrdiff_t ca = Acol[ja]; // Skip weak off-diagonal connections. if (ca != i && !aggr.strong_connection[ja]) continue; for(ptrdiff_t jp = P_tent->ptr[ca], ep = P_tent->ptr[ca+1]; jp < ep; ++jp) { ptrdiff_t cp = P_tent->col[jp]; if (marker[cp] != i) { marker[cp] = i; ++( P->ptr[i + 1] ); } } } } boost::fill(marker, -1); #pragma omp barrier #pragma omp single { boost::partial_sum(P->ptr, P->ptr.begin()); P->col.resize(P->ptr.back()); P->val.resize(P->ptr.back()); } // Fill the interpolation matrix. for(ptrdiff_t i = chunk_start; i < chunk_end; ++i) { // Diagonal of the filtered matrix is the original matrix // diagonal minus its weak connections. value_type dia = math::zero<value_type>(); for(ptrdiff_t j = Aptr[i], e = Aptr[i+1]; j < e; ++j) { if (Acol[j] == i) dia += Aval[j]; else if (!aggr.strong_connection[j]) dia -= Aval[j]; } dia = math::inverse(dia); ptrdiff_t row_beg = P->ptr[i]; ptrdiff_t row_end = row_beg; for(ptrdiff_t ja = Aptr[i], ea = Aptr[i + 1]; ja < ea; ++ja) { ptrdiff_t ca = Acol[ja]; // Skip weak off-diagonal connections. if (ca != i && !aggr.strong_connection[ja]) continue; value_type va = (ca == i) ? static_cast<value_type>(static_cast<scalar_type>(1 - prm.relax) * math::identity<value_type>()) : static_cast<value_type>(static_cast<scalar_type>(-prm.relax) * dia * Aval[ja]); for(ptrdiff_t jp = P_tent->ptr[ca], ep = P_tent->ptr[ca+1]; jp < ep; ++jp) { ptrdiff_t cp = P_tent->col[jp]; value_type vp = P_tent->val[jp]; if (marker[cp] < row_beg) { marker[cp] = row_end; P->col[row_end] = cp; P->val[row_end] = va * vp; ++row_end; } else { P->val[ marker[cp] ] += va * vp; } } } } } TOC("interpolation"); boost::shared_ptr<Matrix> R = boost::make_shared<Matrix>(); *R = transpose(*P); if (prm.nullspace.cols > 0) prm.aggr.block_size = prm.nullspace.cols; return boost::make_tuple(P, R); }
static boost::tuple< boost::shared_ptr<Matrix>, boost::shared_ptr<Matrix> > transfer_operators(const Matrix &A, params &prm) { typedef typename backend::value_type<Matrix>::type Val; const size_t n = rows(A); TIC("aggregates"); Aggregates aggr(A, prm.aggr); prm.aggr.eps_strong *= 0.5; TOC("aggregates"); TIC("interpolation"); boost::shared_ptr<Matrix> P = boost::make_shared<Matrix>(); P->nrows = n; P->ncols = aggr.count; P->ptr.resize(n + 1, 0); #pragma omp parallel { std::vector<ptrdiff_t> marker(aggr.count, -1); #ifdef _OPENMP int nt = omp_get_num_threads(); int tid = omp_get_thread_num(); size_t chunk_size = (n + nt - 1) / nt; size_t chunk_start = tid * chunk_size; size_t chunk_end = std::min(n, chunk_start + chunk_size); #else size_t chunk_start = 0; size_t chunk_end = n; #endif // Count number of entries in P. for(size_t i = chunk_start; i < chunk_end; ++i) { for(ptrdiff_t j = A.ptr[i], e = A.ptr[i+1]; j < e; ++j) { size_t c = static_cast<size_t>(A.col[j]); // Skip weak off-diagonal connections. if (c != i && !aggr.strong_connection[j]) continue; ptrdiff_t g = aggr.id[c]; if (g >= 0 && static_cast<size_t>(marker[g]) != i) { marker[g] = static_cast<ptrdiff_t>(i); ++( P->ptr[i + 1] ); } } } boost::fill(marker, -1); #pragma omp barrier #pragma omp single { boost::partial_sum(P->ptr, P->ptr.begin()); P->col.resize(P->ptr.back()); P->val.resize(P->ptr.back()); } // Fill the interpolation matrix. for(size_t i = chunk_start; i < chunk_end; ++i) { // Diagonal of the filtered matrix is the original matrix // diagonal minus its weak connections. Val dia = 0; for(ptrdiff_t j = A.ptr[i], e = A.ptr[i+1]; j < e; ++j) { if (static_cast<size_t>(A.col[j]) == i) dia += A.val[j]; else if (!aggr.strong_connection[j]) dia -= A.val[j]; } dia = 1 / dia; ptrdiff_t row_beg = P->ptr[i]; ptrdiff_t row_end = row_beg; for(ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) { size_t c = static_cast<size_t>(A.col[j]); // Skip weak couplings, ... if (c != i && !aggr.strong_connection[j]) continue; // ... and the ones not in any aggregate. ptrdiff_t g = aggr.id[c]; if (g < 0) continue; Val v = (c == i) ? 1 - prm.relax : -prm.relax * dia * A.val[j]; if (marker[g] < row_beg) { marker[g] = row_end; P->col[row_end] = g; P->val[row_end] = v; ++row_end; } else { P->val[ marker[g] ] += v; } } } } TOC("interpolation"); boost::shared_ptr<Matrix> R = boost::make_shared<Matrix>(); *R = transpose(*P); return boost::make_tuple(P, R); }
pointwise_aggregates(const Matrix &A, const params &prm, unsigned min_aggregate) : count(0) { typedef typename backend::value_type<Matrix>::type value_type; typedef typename math::scalar_of<value_type>::type scalar_type; if (prm.block_size == 1) { plain_aggregates aggr(A, prm); remove_small_aggregates(A.nrows, 1, min_aggregate, aggr); count = aggr.count; strong_connection.swap(aggr.strong_connection); id.swap(aggr.id); } else { strong_connection.resize( nonzeros(A) ); id.resize( rows(A) ); auto ap = backend::pointwise_matrix(A, prm.block_size); backend::crs<scalar_type> &Ap = *ap; plain_aggregates pw_aggr(Ap, prm); remove_small_aggregates( Ap.nrows, prm.block_size, min_aggregate, pw_aggr); count = pw_aggr.count * prm.block_size; #pragma omp parallel { std::vector<ptrdiff_t> j(prm.block_size); std::vector<ptrdiff_t> e(prm.block_size); #pragma omp for for(ptrdiff_t ip = 0; ip < static_cast<ptrdiff_t>(Ap.nrows); ++ip) { ptrdiff_t ia = ip * prm.block_size; for(unsigned k = 0; k < prm.block_size; ++k, ++ia) { id[ia] = prm.block_size * pw_aggr.id[ip] + k; j[k] = A.ptr[ia]; e[k] = A.ptr[ia+1]; } for(ptrdiff_t jp = Ap.ptr[ip], ep = Ap.ptr[ip+1]; jp < ep; ++jp) { ptrdiff_t cp = Ap.col[jp]; bool sp = (cp == ip) || pw_aggr.strong_connection[jp]; ptrdiff_t col_end = (cp + 1) * prm.block_size; for(unsigned k = 0; k < prm.block_size; ++k) { ptrdiff_t beg = j[k]; ptrdiff_t end = e[k]; while(beg < end && A.col[beg] < col_end) { strong_connection[beg] = sp && A.col[beg] != (ia + k); ++beg; } j[k] = beg; } } } } } }