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
45
47{
48 int 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;
77 {
78 printf("ERROR: The MPI library does not have MPI_THREAD_SERIALIZED support\n");
80 }
81 int nprocs, myrank;
84 if(argc < 3)
85 {
86 ShowUsage();
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 {
122 tinfo << fixed;
123 cout << fixed;
124 double t01, t02;
125 if(ifilename!="")
126 {
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;
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
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
180 A.Reduce(degCol, Column, plus<int64_t>(), static_cast<int64_t>(0));
181
182
183 // transform weights
184 if(optimizeProd)
186 else
187 TransformWeight(*AWeighted, false);
188 // convert to CSC for SpMSpV calls
191
192
193 // Compute the initial trace
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)
214 else
216 double tmcl = MPI_Wtime() - ts;
217
219 SpParHelper::Print("After Greedy sanity check\n");
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);
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)
240 else
242 tmcm = MPI_Wtime() - ts;
244 SpParHelper::Print("After MCM sanity check\n");
246 }
247
248
249 // AWPM
250 ts = MPI_Wtime();
252 double tawpm = MPI_Wtime() - ts;
253
255 SpParHelper::Print("After AWPM sanity check\n");
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);
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;
278
279 //revert random permutation if applied before
280 if(randPerm==true && randp.TotalLength() >0)
281 {
282 // inverse permutation
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
static void Print(const std::string &s)
@ 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 maximumMatching(SpParMat< IT, NT, DER > &A, FullyDistVec< IT, IT > &mateRow2Col, FullyDistVec< IT, IT > &mateCol2Row, bool prune=true, bool randMM=false, bool maximizeWeight=false)
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