92std::vector<std::tuple<IT,IT,IT,NT>>
ExchangeData1(std::vector<std::vector<std::tuple<IT,IT,IT,NT>>> & tempTuples, MPI_Comm World)
96 MPI_Datatype MPI_tuple;
97 MPI_Type_contiguous(
sizeof(std::tuple<IT,IT,IT,NT>), MPI_CHAR, &MPI_tuple);
98 MPI_Type_commit(&MPI_tuple);
101 MPI_Comm_size(World, &
nprocs);
103 int * sendcnt =
new int[
nprocs];
104 int * recvcnt =
new int[
nprocs];
105 int * sdispls =
new int[
nprocs]();
106 int * rdispls =
new int[
nprocs]();
112 sendcnt[i] = tempTuples[i].size();
113 totsend += tempTuples[i].size();
116 MPI_Alltoall(sendcnt, 1, MPI_INT, recvcnt, 1, MPI_INT, World);
118 std::partial_sum(sendcnt, sendcnt+
nprocs-1, sdispls+1);
119 std::partial_sum(recvcnt, recvcnt+
nprocs-1, rdispls+1);
120 IT totrecv = std::accumulate(recvcnt,recvcnt+
nprocs,
static_cast<IT>(0));
122 std::vector< std::tuple<IT,IT,IT,NT> > sendTuples(totsend);
123 for(
int i=0; i<
nprocs; ++i)
125 copy(tempTuples[i].begin(), tempTuples[i].end(), sendTuples.data()+sdispls[i]);
126 std::vector< std::tuple<IT,IT,IT,NT> >().swap(tempTuples[i]);
128 std::vector< std::tuple<IT,IT,IT,NT> > recvTuples(totrecv);
129 MPI_Alltoallv(sendTuples.data(), sendcnt, sdispls, MPI_tuple, recvTuples.data(), recvcnt, rdispls, MPI_tuple, World);
130 DeleteAll(sendcnt, recvcnt, sdispls, rdispls);
131 MPI_Type_free(&MPI_tuple);
413std::vector< std::tuple<IT,IT,NT> >
Phase1(
const AWPM_param<IT>& param,
Dcsc<IT, NT>* dcsc,
const std::vector<IT>& colptr,
const std::vector<IT>& RepMateR2C,
const std::vector<IT>& RepMateC2R,
const std::vector<NT>& RepMateWR2C,
const std::vector<NT>& RepMateWC2R )
418 double tstart = MPI_Wtime();
421 MPI_Comm World = param.
commGrid->GetWorld();
426 std::vector<int> sendcnt(param.
nprocs,0);
433 std::vector<int> tsendcnt(param.
nprocs,0);
437 for(
int k=0; k<param.
lncol; ++k)
439 IT mj = RepMateC2R[k];
442 for(
IT cp = colptr[k]; cp < colptr[k+1]; ++cp)
444 IT li = dcsc->
ir[cp];
446 IT mi = RepMateR2C[li];
450 int rrank = param.
m_perproc != 0 ? std::min(
static_cast<int>(mj / param.
m_perproc), param.
pr-1) : (param.
pr-1);
451 int crank = param.
n_perproc != 0 ? std::min(
static_cast<int>(mi / param.
n_perproc), param.
pc-1) : (param.
pc-1);
452 int owner = param.
commGrid->GetRank(rrank , crank);
457 for(
int i=0; i<param.
nprocs; i++)
459 __sync_fetch_and_add(sendcnt.data()+i, tsendcnt[i]);
466 IT totsend = std::accumulate(sendcnt.data(), sendcnt.data()+param.
nprocs,
static_cast<IT>(0));
467 std::vector<int> sdispls (param.
nprocs, 0);
468 std::partial_sum(sendcnt.data(), sendcnt.data()+param.
nprocs-1, sdispls.data()+1);
470 std::vector< std::tuple<IT,IT,NT> > sendTuples(totsend);
471 std::vector<int> transferCount(param.
nprocs,0);
480 std::vector<int> tsendcnt(param.
nprocs,0);
481 std::vector<std::tuple<IT,IT, NT>> tsendTuples (param.
nprocs*THREAD_BUF_LEN);
485 for(
int k=0; k<param.
lncol; ++k)
487 IT mj = RepMateC2R[k];
491 for(
IT cp = colptr[k]; cp < colptr[k+1]; ++cp)
493 IT li = dcsc->
ir[cp];
495 IT mi = RepMateR2C[li];
498 double w = dcsc->
numx[cp]- RepMateWR2C[li] - RepMateWC2R[lj];
499 int rrank = param.
m_perproc != 0 ? std::min(
static_cast<int>(mj / param.
m_perproc), param.
pr-1) : (param.
pr-1);
500 int crank = param.
n_perproc != 0 ? std::min(
static_cast<int>(mi / param.
n_perproc), param.
pc-1) : (param.
pc-1);
501 int owner = param.
commGrid->GetRank(rrank , crank);
503 if (tsendcnt[owner] < THREAD_BUF_LEN)
505 tsendTuples[THREAD_BUF_LEN * owner + tsendcnt[owner]] = std::make_tuple(mi, mj, w);
510 int tt = __sync_fetch_and_add(transferCount.data()+owner, THREAD_BUF_LEN);
511 copy( tsendTuples.data()+THREAD_BUF_LEN * owner, tsendTuples.data()+THREAD_BUF_LEN * (owner+1) , sendTuples.data() + sdispls[owner]+ tt);
513 tsendTuples[THREAD_BUF_LEN * owner] = std::make_tuple(mi, mj, w);
519 for(
int owner=0; owner < param.
nprocs; owner++)
521 if (tsendcnt[owner] >0)
523 int tt = __sync_fetch_and_add(transferCount.data()+owner, tsendcnt[owner]);
524 copy( tsendTuples.data()+THREAD_BUF_LEN * owner, tsendTuples.data()+THREAD_BUF_LEN * owner + tsendcnt[owner], sendTuples.data() + sdispls[owner]+ tt);
529 double t1Comp = MPI_Wtime() - tstart;
530 tstart = MPI_Wtime();
534 std::vector<int> recvcnt (param.
nprocs);
535 std::vector<int> rdispls (param.
nprocs, 0);
537 MPI_Alltoall(sendcnt.data(), 1, MPI_INT, recvcnt.data(), 1, MPI_INT, World);
538 std::partial_sum(recvcnt.data(), recvcnt.data()+param.
nprocs-1, rdispls.data()+1);
539 IT totrecv = std::accumulate(recvcnt.data(), recvcnt.data()+param.
nprocs,
static_cast<IT>(0));
542 MPI_Datatype MPI_tuple;
543 MPI_Type_contiguous(
sizeof(std::tuple<IT,IT,NT>), MPI_CHAR, &MPI_tuple);
544 MPI_Type_commit(&MPI_tuple);
546 std::vector< std::tuple<IT,IT,NT> > recvTuples1(totrecv);
547 MPI_Alltoallv(sendTuples.data(), sendcnt.data(), sdispls.data(), MPI_tuple, recvTuples1.data(), recvcnt.data(), rdispls.data(), MPI_tuple, World);
548 MPI_Type_free(&MPI_tuple);
549 double t1Comm = MPI_Wtime() - tstart;
558std::vector< std::tuple<IT,IT,IT,NT> >
Phase2(
const AWPM_param<IT>& param, std::vector<std::tuple<IT,IT,NT>>& recvTuples,
Dcsc<IT, NT>* dcsc,
const std::vector<IT>& colptr,
const std::vector<IT>& RepMateR2C,
const std::vector<IT>& RepMateC2R,
const std::vector<NT>& RepMateWR2C,
const std::vector<NT>& RepMateWC2R )
561 MPI_Comm World = param.
commGrid->GetWorld();
563 double tstart = MPI_Wtime();
566 __gnu_parallel::sort(recvTuples.begin(), recvTuples.end());
567 std::vector<std::vector<std::tuple<IT,IT, IT, NT>>> tempTuples1 (param.
nprocs);
569 std::vector<int> sendcnt(param.
nprocs,0);
578 nBins = omp_get_num_threads() * 4;
583#pragma omp parallel for
585 for(
int i=0; i<nBins; i++)
587 int perBin = recvTuples.size()/nBins;
588 int startBinIndex = perBin * i;
589 int endBinIndex = perBin * (i+1);
590 if(i==nBins-1) endBinIndex = recvTuples.size();
593 std::vector<int> tsendcnt(param.
nprocs,0);
594 for(
int k=startBinIndex; k<endBinIndex;)
597 IT mi = std::get<0>(recvTuples[k]);
599 IT i = RepMateC2R[lcol];
601 IT idx2 = colptr[lcol];
603 for(; std::get<0>(recvTuples[idx1]) == mi && idx2 < colptr[lcol+1];)
606 IT mj = std::get<1>(recvTuples[idx1]) ;
608 IT j = RepMateR2C[lrow];
609 IT lrowMat = dcsc->
ir[idx2];
612 NT weight = std::get<2>(recvTuples[idx1]);
613 NT cw = weight + RepMateWR2C[lrow];
616 int rrank = (param.
m_perproc != 0) ? std::min(
static_cast<int>(mj / param.
m_perproc), param.
pr-1) : (param.
pr-1);
617 int crank = (param.
n_perproc != 0) ? std::min(
static_cast<int>(j / param.
n_perproc), param.
pc-1) : (param.
pc-1);
618 int owner = param.
commGrid->GetRank(rrank , crank);
624 else if(lrowMat > lrow)
630 for(;std::get<0>(recvTuples[idx1]) == mi ; idx1++);
634 for(
int i=0; i<param.
nprocs; i++)
636 __sync_fetch_and_add(sendcnt.data()+i, tsendcnt[i]);
643 IT totsend = std::accumulate(sendcnt.data(), sendcnt.data()+param.
nprocs,
static_cast<IT>(0));
644 std::vector<int> sdispls (param.
nprocs, 0);
645 std::partial_sum(sendcnt.data(), sendcnt.data()+param.
nprocs-1, sdispls.data()+1);
647 std::vector< std::tuple<IT,IT,IT,NT> > sendTuples(totsend);
648 std::vector<int> transferCount(param.
nprocs,0);
654#pragma omp parallel for
656 for(
int i=0; i<nBins; i++)
658 int perBin = recvTuples.size()/nBins;
659 int startBinIndex = perBin * i;
660 int endBinIndex = perBin * (i+1);
661 if(i==nBins-1) endBinIndex = recvTuples.size();
664 std::vector<int> tsendcnt(param.
nprocs,0);
665 std::vector<std::tuple<IT,IT, IT, NT>> tsendTuples (param.
nprocs*THREAD_BUF_LEN);
666 for(
int k=startBinIndex; k<endBinIndex;)
668 IT mi = std::get<0>(recvTuples[k]);
670 IT i = RepMateC2R[lcol];
672 IT idx2 = colptr[lcol];
674 for(; std::get<0>(recvTuples[idx1]) == mi && idx2 < colptr[lcol+1];)
677 IT mj = std::get<1>(recvTuples[idx1]) ;
679 IT j = RepMateR2C[lrow];
680 IT lrowMat = dcsc->
ir[idx2];
683 NT weight = std::get<2>(recvTuples[idx1]);
684 NT cw = weight + RepMateWR2C[lrow];
687 int rrank = (param.
m_perproc != 0) ? std::min(
static_cast<int>(mj / param.
m_perproc), param.
pr-1) : (param.
pr-1);
688 int crank = (param.
n_perproc != 0) ? std::min(
static_cast<int>(j / param.
n_perproc), param.
pc-1) : (param.
pc-1);
689 int owner = param.
commGrid->GetRank(rrank , crank);
691 if (tsendcnt[owner] < THREAD_BUF_LEN)
693 tsendTuples[THREAD_BUF_LEN * owner + tsendcnt[owner]] = std::make_tuple(mj, mi, i, cw);
698 int tt = __sync_fetch_and_add(transferCount.data()+owner, THREAD_BUF_LEN);
699 std::copy( tsendTuples.data()+THREAD_BUF_LEN * owner, tsendTuples.data()+THREAD_BUF_LEN * (owner+1) , sendTuples.data() + sdispls[owner]+ tt);
701 tsendTuples[THREAD_BUF_LEN * owner] = std::make_tuple(mj, mi, i, cw);
709 else if(lrowMat > lrow)
715 for(;std::get<0>(recvTuples[idx1]) == mi ; idx1++);
719 for(
int owner=0; owner < param.
nprocs; owner++)
721 if (tsendcnt[owner] >0)
723 int tt = __sync_fetch_and_add(transferCount.data()+owner, tsendcnt[owner]);
724 std::copy( tsendTuples.data()+THREAD_BUF_LEN * owner, tsendTuples.data()+THREAD_BUF_LEN * owner + tsendcnt[owner], sendTuples.data() + sdispls[owner]+ tt);
731 double t2Comp = MPI_Wtime() - tstart;
732 tstart = MPI_Wtime();
734 std::vector<int> recvcnt (param.
nprocs);
735 std::vector<int> rdispls (param.
nprocs, 0);
737 MPI_Alltoall(sendcnt.data(), 1, MPI_INT, recvcnt.data(), 1, MPI_INT, World);
738 std::partial_sum(recvcnt.data(), recvcnt.data()+param.
nprocs-1, rdispls.data()+1);
739 IT totrecv = std::accumulate(recvcnt.data(), recvcnt.data()+param.
nprocs,
static_cast<IT>(0));
742 MPI_Datatype MPI_tuple;
743 MPI_Type_contiguous(
sizeof(std::tuple<IT,IT,IT,NT>), MPI_CHAR, &MPI_tuple);
744 MPI_Type_commit(&MPI_tuple);
746 std::vector< std::tuple<IT,IT,IT,NT> > recvTuples1(totrecv);
747 MPI_Alltoallv(sendTuples.data(), sendcnt.data(), sdispls.data(), MPI_tuple, recvTuples1.data(), recvcnt.data(), rdispls.data(), MPI_tuple, World);
748 MPI_Type_free(&MPI_tuple);
749 double t2Comm = MPI_Wtime() - tstart;
797 auto commGrid =
A.getcommgrid();
798 int myrank=commGrid->GetRank();
799 MPI_Comm World = commGrid->GetWorld();
800 MPI_Comm ColWorld = commGrid->GetColWorld();
801 MPI_Comm RowWorld = commGrid->GetRowWorld();
802 int nprocs = commGrid->GetSize();
803 int pr = commGrid->GetGridRows();
804 int pc = commGrid->GetGridCols();
805 int rowrank = commGrid->GetRankInProcRow();
806 int colrank = commGrid->GetRankInProcCol();
807 int diagneigh = commGrid->GetComplementRank();
812 IT nrows =
A.getnrow();
813 IT ncols =
A.getncol();
815 IT m_perproc = nrows / pr;
816 IT n_perproc = ncols / pc;
817 DER* spSeq =
A.seqptr();
819 IT lnrow = spSeq->getnrow();
820 IT lncol = spSeq->getncol();
821 IT localRowStart = colrank * m_perproc;
822 IT localColStart = rowrank * n_perproc;
839 double tPhase1 = 0, tPhase2 = 0, tPhase3 = 0, tPhase4 = 0, tPhase5 = 0, tUpdate = 0;
849 MPI_Sendrecv(&xsize, 1, MPI_INT, diagneigh,
TRX, &trxsize, 1, MPI_INT, diagneigh,
TRX, World, &status);
850 std::vector<IT> trxnums(trxsize);
851 MPI_Sendrecv(mateCol2Row.
GetLocArr(), xsize,
MPIType<IT>(), diagneigh,
TRX, trxnums.data(), trxsize,
MPIType<IT>(), diagneigh,
TRX, World, &status);
854 std::vector<int> colsize(pc);
855 colsize[colrank] = trxsize;
856 MPI_Allgather(MPI_IN_PLACE, 1, MPI_INT, colsize.data(), 1, MPI_INT, ColWorld);
857 std::vector<int> dpls(pc,0);
858 std::partial_sum(colsize.data(), colsize.data()+pc-1, dpls.data()+1);
859 int accsize = std::accumulate(colsize.data(), colsize.data()+pc, 0);
860 std::vector<IT> RepMateC2R(accsize);
861 MPI_Allgatherv(trxnums.data(), trxsize,
MPIType<IT>(), RepMateC2R.data(), colsize.data(), dpls.data(),
MPIType<IT>(), ColWorld);
874 std::vector<int> rowsize(pr);
875 rowsize[rowrank] = xsize;
876 MPI_Allgather(MPI_IN_PLACE, 1, MPI_INT, rowsize.data(), 1, MPI_INT, RowWorld);
877 std::vector<int> rdpls(pr,0);
878 std::partial_sum(rowsize.data(), rowsize.data()+pr-1, rdpls.data()+1);
879 accsize = std::accumulate(rowsize.data(), rowsize.data()+pr, 0);
880 std::vector<IT> RepMateR2C(accsize);
887 std::vector<IT> colptr (lncol+1,-1);
888 for(
auto colit = spSeq->begcol(); colit != spSeq->endcol(); ++colit)
890 IT lj = colit.colid();
892 colptr[lj] = colit.colptr();
894 colptr[lncol] = spSeq->getnnz();
895 for(
IT k=lncol-1; k>=0; k--)
899 colptr[k] = colptr[k+1];
908 std::vector<NT> RepMateWR2C(lnrow);
909 std::vector<NT> RepMateWC2R(lncol);
916 NT weightPrev = weightCur - 999999999999;
917 while(weightCur > weightPrev && iterations++ < 10)
922 if(myrank==0) std::cout <<
"Iteration " << iterations <<
". matching weight: sum = "<< weightCur <<
" min = " << minw << std::endl;
926 double tstart = MPI_Wtime();
927 std::vector<std::tuple<IT,IT,NT>> recvTuples =
Phase1(param, dcsc, colptr, RepMateR2C, RepMateC2R, RepMateWR2C, RepMateWC2R );
928 tPhase1 += (MPI_Wtime() - tstart);
929 tstart = MPI_Wtime();
931 std::vector<std::tuple<IT,IT,IT,NT>> recvTuples1 =
Phase2(param, recvTuples, dcsc, colptr, RepMateR2C, RepMateC2R, RepMateWR2C, RepMateWC2R );
932 std::vector< std::tuple<IT,IT,NT> >().swap(recvTuples);
933 tPhase2 += (MPI_Wtime() - tstart);
934 tstart = MPI_Wtime();
937 std::vector<std::tuple<IT,IT,IT,NT>> bestTuplesPhase3 (lncol);
939#pragma omp parallel for
941 for(
int k=0; k<lncol; ++k)
943 bestTuplesPhase3[k] = std::make_tuple(-1,-1,-1,0);
946 for(
int k=0; k<recvTuples1.size(); ++k)
948 IT mj = std::get<0>(recvTuples1[k]) ;
949 IT mi = std::get<1>(recvTuples1[k]) ;
950 IT i = std::get<2>(recvTuples1[k]) ;
951 NT weight = std::get<3>(recvTuples1[k]);
952 IT j = RepMateR2C[mj - localRowStart];
953 IT lj = j - localColStart;
956 if( (std::get<0>(bestTuplesPhase3[lj]) == -1) || (weight > std::get<3>(bestTuplesPhase3[lj])) )
958 bestTuplesPhase3[lj] = std::make_tuple(i,mi,mj,weight);
962 std::vector<std::vector<std::tuple<IT,IT, IT, NT>>> tempTuples1 (
nprocs);
963 for(
int k=0; k<lncol; ++k)
965 if( std::get<0>(bestTuplesPhase3[k]) != -1)
969 IT i = std::get<0>(bestTuplesPhase3[k]) ;
970 IT mi = std::get<1>(bestTuplesPhase3[k]) ;
971 IT mj = std::get<2>(bestTuplesPhase3[k]) ;
972 IT j = RepMateR2C[mj - localRowStart];
973 NT weight = std::get<3>(bestTuplesPhase3[k]);
976 tempTuples1[owner].push_back(std::make_tuple(i, j, mj, weight));
982 tPhase3 += (MPI_Wtime() - tstart);
983 tstart = MPI_Wtime();
985 std::vector<std::tuple<IT,IT,IT,IT, NT>> bestTuplesPhase4 (lncol);
991#pragma omp parallel for
993 for(
int k=0; k<lncol; ++k)
995 bestTuplesPhase4[k] = std::make_tuple(-1,-1,-1,-1,0);
998 for(
int k=0; k<recvTuples1.size(); ++k)
1000 IT i = std::get<0>(recvTuples1[k]) ;
1001 IT j = std::get<1>(recvTuples1[k]) ;
1002 IT mj = std::get<2>(recvTuples1[k]) ;
1003 IT mi = RepMateR2C[i-localRowStart];
1004 NT weight = std::get<3>(recvTuples1[k]);
1005 IT lmi = mi - localColStart;
1010 if( ((std::get<0>(bestTuplesPhase4[lmi]) == -1) || (weight > std::get<4>(bestTuplesPhase4[lmi]))) && std::get<0>(bestTuplesPhase3[lmi])==-1 )
1012 bestTuplesPhase4[lmi] = std::make_tuple(i,j,mi,mj,weight);
1018 std::vector<std::vector<std::tuple<IT,IT,IT, IT>>> winnerTuples (
nprocs);
1021 for(
int k=0; k<lncol; ++k)
1023 if( std::get<0>(bestTuplesPhase4[k]) != -1)
1027 IT i = std::get<0>(bestTuplesPhase4[k]) ;
1028 IT j = std::get<1>(bestTuplesPhase4[k]) ;
1029 IT mi = std::get<2>(bestTuplesPhase4[k]) ;
1030 IT mj = std::get<3>(bestTuplesPhase4[k]) ;
1034 winnerTuples[owner].push_back(std::make_tuple(i, j, mi, mj));
1039 winnerTuples[owner].push_back(std::make_tuple(mj, mi, j, i));
1042 std::vector<std::tuple<IT,IT,IT,IT>> recvWinnerTuples =
ExchangeData1(winnerTuples, World);
1043 tPhase4 += (MPI_Wtime() - tstart);
1044 tstart = MPI_Wtime();
1047 std::vector<std::tuple<IT,IT>> rowBcastTuples(recvWinnerTuples.size());
1048 std::vector<std::tuple<IT,IT>> colBcastTuples(recvWinnerTuples.size());
1050#pragma omp parallel for
1052 for(
int k=0; k<recvWinnerTuples.size(); ++k)
1054 IT i = std::get<0>(recvWinnerTuples[k]) ;
1055 IT j = std::get<1>(recvWinnerTuples[k]) ;
1056 IT mi = std::get<2>(recvWinnerTuples[k]) ;
1057 IT mj = std::get<3>(recvWinnerTuples[k]);
1059 colBcastTuples[k] = std::make_tuple(j,i);
1060 rowBcastTuples[k] = std::make_tuple(mj,mi);
1063 std::vector<std::tuple<IT,IT>> updatedR2C =
MateBcast(rowBcastTuples, RowWorld);
1064 std::vector<std::tuple<IT,IT>> updatedC2R =
MateBcast(colBcastTuples, ColWorld);
1066 tPhase5 += (MPI_Wtime() - tstart);
1067 tstart = MPI_Wtime();
1071#pragma omp parallel for
1073 for(
int k=0; k<updatedR2C.size(); k++)
1075 IT row = std::get<0>(updatedR2C[k]);
1076 IT mate = std::get<1>(updatedR2C[k]);
1077 RepMateR2C[row-localRowStart] = mate;
1081#pragma omp parallel for
1083 for(
int k=0; k<updatedC2R.size(); k++)
1085 IT col = std::get<0>(updatedC2R[k]);
1086 IT mate = std::get<1>(updatedC2R[k]);
1087 RepMateC2R[col-localColStart] = mate;
1093 weightPrev = weightCur;
1096 tUpdate += (MPI_Wtime() - tstart);
1106 std::cout <<
"------------- overal timing (HWPM) -------------" << std::endl;
1108 std::cout <<
"Phase1: "<< tPhase1 <<
"\nPhase2: " << tPhase2 <<
"\nPhase3: " << tPhase3 <<
"\nPhase4: " << tPhase4 <<
"\nPhase5: " << tPhase5 <<
"\nUpdate: " << tUpdate << std::endl;
1109 std::cout <<
"-------------------------------------------------" << std::endl;
1113 UpdateMatching(mateRow2Col, mateCol2Row, RepMateR2C, RepMateC2R);