COMBINATORIAL_BLAS 1.6
 
Loading...
Searching...
No Matches
ApproxWeightPerfectMatching.cpp
Go to the documentation of this file.
1
2#ifdef THREADED
3#ifndef _OPENMP
4#define _OPENMP
5#endif
6
7#include <omp.h>
8int cblas_splits = 1;
9#endif
10
11#include "../CombBLAS.h"
12#include <mpi.h>
13#include <sys/time.h>
14#include <iostream>
15#include <functional>
16#include <algorithm>
17#include <vector>
18#include <string>
19#include <sstream>
20#include <limits>
21
22
23#include "BPMaximalMatching.h"
24#include "BPMaximumMatching.h"
26
27using namespace std;
28using namespace combblas;
29
30// algorithmic options
32int init;
34bool fewexp;
37string ofname;
38
39
40typedef SpParMat < int64_t, bool, SpDCCols<int64_t,bool> > Par_DCSC_Bool;
41typedef SpParMat < int64_t, int64_t, SpDCCols<int64_t, int64_t> > Par_DCSC_int64_t;
42typedef SpParMat < int64_t, double, SpDCCols<int64_t, double> > Par_DCSC_Double;
43typedef SpParMat < int64_t, double, SpCCols<int64_t, double> > Par_CSC_Double;
44typedef SpParMat < int64_t, bool, SpCCols<int64_t,bool> > Par_CSC_Bool;
45
47{
48 int myrank;
49 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
50 if(myrank == 0)
51 {
52 cout << "\n-------------- usage --------------\n";
53 cout << "Usage: ./awpm -input <filename>\n";
54 cout << "Optional parameters: -randPerm: randomly permute the matrix for load balance (default: no random permutation)\n";
55 cout << " -optsum: Optimize the sum of diagonal (default: Optimize the product of diagonal)\n";
56 cout << " -noWeightedCard: do not use weighted cardinality matching (default: use weighted cardinality matching)\n";
57 cout << " -output <output file>: output file name (if not provided: inputfile.awpm.txt)\n";
58 cout << " \n-------------- examples ----------\n";
59 cout << "Example: mpirun -np 4 ./awpm -input cage12.mtx \n" << endl;
60 cout << "(output matching is saved to cage12.mtx.awpm.txt)\n" << endl;
61 }
62}
63
64
65
66
67
68
69
70int main(int argc, char* argv[])
71{
72
73 // ------------ initialize MPI ---------------
74 int provided;
75 MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided);
76 if (provided < MPI_THREAD_SERIALIZED)
77 {
78 printf("ERROR: The MPI library does not have MPI_THREAD_SERIALIZED support\n");
79 MPI_Abort(MPI_COMM_WORLD, 1);
80 }
81 int nprocs, myrank;
82 MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
83 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
84 if(argc < 3)
85 {
86 ShowUsage();
87 MPI_Finalize();
88 return -1;
89 }
90
91 init = DMD;
92 randMaximal = false;
93 prune = false;
94 randMM = true;
95 moreSplit = false;
96 fewexp=false;
97 saveMatching = true;
98 ofname = "";
99 randPerm = false;
100 bool optimizeProd = true; // by default optimize sum_log_abs(aii) (after equil)
101
102 bool weightedCard = true;
103 string ifilename = "";
104 string ofname = "";
105 for(int i = 1; i<argc; i++)
106 {
107 if (string(argv[i]) == string("-input")) ifilename = argv[i+1];
108 if (string(argv[i]) == string("-output")) ofname = argv[i+1];
109 if (string(argv[i]) == string("-optsum")) optimizeProd = false;
110 if (string(argv[i]) == string("-noWeightedCard")) weightedCard = false;
111 if (string(argv[i]) == string("-randPerm")) randPerm = true;
112 }
113 if(ofname=="") ofname = ifilename + ".awpm.txt";
114
115
116
117
118 // ------------ Process input arguments and build matrix ---------------
119 {
120 Par_DCSC_Double * AWeighted;
121 ostringstream tinfo;
122 tinfo << fixed;
123 cout << fixed;
124 double t01, t02;
125 if(ifilename!="")
126 {
127 AWeighted = new Par_DCSC_Double();
128 t01 = MPI_Wtime();
129 AWeighted->ParallelReadMM(ifilename, true, maximum<double>()); // one-based matrix market file
130 t02 = MPI_Wtime();
131
132 if(AWeighted->getnrow() != AWeighted->getncol())
133 {
134 SpParHelper::Print("Rectangular matrix: Can not compute a perfect matching.\n");
135 MPI_Finalize();
136 return -1;
137 }
138
139 tinfo.str("");
140 tinfo << "Reading input matrix in" << t02-t01 << " seconds" << endl;
141 SpParHelper::Print(tinfo.str());
142
143 SpParHelper::Print("Pruning explicit zero entries....\n");
144 AWeighted->Prune([](double val){return fabs(val)==0;}, true);
145
146 AWeighted->PrintInfo();
147 }
148 else
149 {
150 ShowUsage();
151 MPI_Finalize();
152 return -1;
153 }
154
155
156
157 // ***** careful: if you permute the matrix, you have the permute the matching vectors as well!!
158 // randomly permute for load balance
159
160 FullyDistVec<int64_t, int64_t> randp( AWeighted->getcommgrid());
161 if(randPerm)
162 {
163 if(AWeighted->getnrow() == AWeighted->getncol())
164 {
165 randp.iota(AWeighted->getnrow(), 0);
166 randp.RandPerm();
167 (*AWeighted)(randp,randp,true);
168 SpParHelper::Print("Matrix is randomly permuted for load balance.\n");
169 }
170 else
171 {
172 SpParHelper::Print("Rectangular matrix: Can not apply symmetric permutation.\n");
173 }
174 }
175
176
177 Par_DCSC_Bool A = *AWeighted; //just to compute degree
178 // Reduce is not multithreaded, so I am doing it here
179 FullyDistVec<int64_t, int64_t> degCol(A.getcommgrid());
180 A.Reduce(degCol, Column, plus<int64_t>(), static_cast<int64_t>(0));
181
182
183 // transform weights
184 if(optimizeProd)
185 TransformWeight(*AWeighted, true);
186 else
187 TransformWeight(*AWeighted, false);
188 // convert to CSC for SpMSpV calls
189 Par_CSC_Double AWeightedCSC(*AWeighted);
190 Par_CSC_Bool ABoolCSC(*AWeighted);
191
192
193 // Compute the initial trace
194 int64_t diagnnz;
195 double origWeight = Trace(*AWeighted, diagnnz);
196 bool isOriginalPerfect = diagnnz==A.getnrow();
197
198
199
200
201
202 FullyDistVec<int64_t, int64_t> mateRow2Col ( A.getcommgrid(), A.getnrow(), (int64_t) -1);
203 FullyDistVec<int64_t, int64_t> mateCol2Row ( A.getcommgrid(), A.getncol(), (int64_t) -1);
204
205
206
207
208 init = DMD; randMaximal = false; randMM = false; prune = true;
209
210 // Maximal
211 double ts = MPI_Wtime();
212 if(weightedCard)
213 WeightedGreedy(AWeightedCSC, mateRow2Col, mateCol2Row, degCol);
214 else
215 WeightedGreedy(ABoolCSC, mateRow2Col, mateCol2Row, degCol);
216 double tmcl = MPI_Wtime() - ts;
217
218 double mclWeight = MatchingWeight( *AWeighted, mateRow2Col, mateCol2Row);
219 SpParHelper::Print("After Greedy sanity check\n");
220 bool isPerfectMCL = CheckMatching(mateRow2Col,mateCol2Row);
221
222 if(isOriginalPerfect && mclWeight<=origWeight) // keep original
223 {
224 SpParHelper::Print("Maximal is not better that the natural ordering. Hence, keeping the natural ordering.\n");
225 mateRow2Col.iota(A.getnrow(), 0);
226 mateCol2Row.iota(A.getncol(), 0);
227 mclWeight = origWeight;
228 isPerfectMCL = true;
229 }
230
231
232 // MCM
233 double tmcm = 0;
234 double mcmWeight = mclWeight;
235 if(!isPerfectMCL) // run MCM only if we don't have a perfect matching
236 {
237 ts = MPI_Wtime();
238 if(weightedCard)
239 maximumMatching(AWeightedCSC, mateRow2Col, mateCol2Row, true, false, true);
240 else
241 maximumMatching(AWeightedCSC, mateRow2Col, mateCol2Row, true, false, false);
242 tmcm = MPI_Wtime() - ts;
243 mcmWeight = MatchingWeight( *AWeighted, mateRow2Col, mateCol2Row) ;
244 SpParHelper::Print("After MCM sanity check\n");
245 CheckMatching(mateRow2Col,mateCol2Row);
246 }
247
248
249 // AWPM
250 ts = MPI_Wtime();
251 TwoThirdApprox(*AWeighted, mateRow2Col, mateCol2Row);
252 double tawpm = MPI_Wtime() - ts;
253
254 double awpmWeight = MatchingWeight( *AWeighted, mateRow2Col, mateCol2Row) ;
255 SpParHelper::Print("After AWPM sanity check\n");
256 CheckMatching(mateRow2Col,mateCol2Row);
257 if(isOriginalPerfect && awpmWeight<origWeight) // keep original
258 {
259 SpParHelper::Print("AWPM is not better that the natural ordering. Hence, keeping the natural ordering.\n");
260 mateRow2Col.iota(A.getnrow(), 0);
261 mateCol2Row.iota(A.getncol(), 0);
262 awpmWeight = origWeight;
263 }
264
265
266 int nthreads = 1;
267#ifdef THREADED
268#pragma omp parallel
269 {
270 nthreads = omp_get_num_threads();
271 }
272#endif
273
274 tinfo.str("");
275 tinfo << "Weight: [ Original Greedy MCM AWPM] " << origWeight << " " << mclWeight << " "<< mcmWeight << " " << awpmWeight << endl;
276 tinfo << "Time: [Processes Threads Cores Greedy MCM AWPM Total] " << nprocs << " " << nthreads << " " << nprocs * nthreads << " " << tTotalMaximal << " "<< tTotalMaximum << " " << tawpm << " "<< tTotalMaximal + tTotalMaximum + tawpm << endl;
277 SpParHelper::Print(tinfo.str());
278
279 //revert random permutation if applied before
280 if(randPerm==true && randp.TotalLength() >0)
281 {
282 // inverse permutation
283 FullyDistVec<int64_t, int64_t>invRandp = randp.sort();
284 mateRow2Col = mateRow2Col(invRandp);
285 }
286 if(saveMatching && ofname!="")
287 {
288 mateRow2Col.ParallelWrite(ofname,false,false);
289 }
290
291
292 }
293 MPI_Finalize();
294 return 0;
295}
296
297
int main(int argc, char *argv[])
SpParMat< int64_t, bool, SpDCCols< int64_t, bool > > Par_DCSC_Bool
SpParMat< int64_t, double, SpCCols< int64_t, double > > Par_CSC_Double
SpParMat< int64_t, bool, SpCCols< int64_t, bool > > Par_CSC_Bool
SpParMat< int64_t, double, SpDCCols< int64_t, double > > Par_DCSC_Double
SpParMat< int64_t, int64_t, SpDCCols< int64_t, int64_t > > Par_DCSC_int64_t
#define DMD
int cblas_splits
Definition DirOptBFS.cpp:72
void maximumMatching(PSpMat_s32p64 &Aeff, FullyDistVec< int64_t, int64_t > &mateRow2Col, FullyDistVec< int64_t, int64_t > &mateCol2Row)
void ParallelWrite(const std::string &filename, bool onebased, HANDLER handler, bool includeindices=true)
void iota(IT globalsize, NT first)
FullyDistVec< IT, IT > sort()
static void Print(const std::string &s)
SpParMat< IT, NT, DER > Prune(_UnaryOperation __unary_op, bool inPlace=true)
Definition SpParMat.h:175
void PrintInfo() const
IT getncol() const
Definition SpParMat.cpp:694
void ParallelReadMM(const std::string &filename, bool onebased, _BinaryOperation BinOp)
std::shared_ptr< CommGrid > getcommgrid() const
Definition SpParMat.h:275
IT getnrow() const
Definition SpParMat.cpp:685
long int64_t
Definition compat.h:21
@ Column
Definition SpDefs.h:114
bool CheckMatching(FullyDistVec< IT, IT > &mateRow2Col, FullyDistVec< IT, IT > &mateCol2Row)
Definition Utility.h:113
NT MatchingWeight(std::vector< NT > &RepMateWC2R, MPI_Comm RowWorld, NT &minw)
void TransformWeight(SpParMat< IT, NT, DER > &A, bool applylog)
NT Trace(SpParMat< IT, NT, DER > &A, IT &rettrnnz=0)
void TwoThirdApprox(SpParMat< IT, NT, DER > &A, FullyDistVec< IT, IT > &mateRow2Col, FullyDistVec< IT, IT > &mateCol2Row)
void WeightedGreedy(Par_MAT_Double &A, FullyDistVec< IT, IT > &mateRow2Col, FullyDistVec< IT, IT > &mateCol2Row, FullyDistVec< IT, IT > &degCol)
double A
Compute the maximum of two values.
Definition Operations.h:155