COMBINATORIAL_BLAS 1.6
 
Loading...
Searching...
No Matches
MCL.cpp
Go to the documentation of this file.
1/****************************************************************/
2/* Parallel Combinatorial BLAS Library (for Graph Computations) */
3/* version 1.6 -------------------------------------------------*/
4/* date: 6/15/2017 ---------------------------------------------*/
5/* authors: Ariful Azad, Aydin Buluc --------------------------*/
6/****************************************************************/
7/*
8 Copyright (c) 2010-2017, The Regents of the University of California
9
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
16
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 THE SOFTWARE.
27 */
28
29
30#include <mpi.h>
31
32// These macros should be defined before stdint.h is included
33#ifndef __STDC_CONSTANT_MACROS
34#define __STDC_CONSTANT_MACROS
35#endif
36#ifndef __STDC_LIMIT_MACROS
37#define __STDC_LIMIT_MACROS
38#endif
39#include <stdint.h>
40
41#include <sys/time.h>
42#include <iostream>
43#include <fstream>
44#include <string>
45#include <sstream> // Required for stringstreams
46#include <ctime>
47#include <cmath>
48#include "CombBLAS/CombBLAS.h"
49#include "CC.h"
50#include "WriteMCLClusters.h"
51
52using namespace std;
53using namespace combblas;
54
55#define EPS 0.0001
56
63double cblas_allgathertime; // for compilation (TODO: fix this dependency)
65double tIO;
66
67
68
69class Dist
70{
71 public:
75};
76
77
78
79typedef struct
80{
81 //Input/Output file
82 string ifilename;
84 int base; // only usefule for matrix market files
85
86 string ofilename;
87
88 //Preprocessing
91
92 //inflation
93 double inflation;
94
95 //pruning
96 double prunelimit;
100 int kselectVersion; // 0: adapt based on k, 1: kselect1, 2: kselect2
101
102 //HipMCL optimization
105 bool isDoublePrecision; // true: double, false: float
106 bool is64bInt; // true: int64_t, false: int32_t (currently for both local and global indexing)
107
108 //debugging
109 bool show;
110
111
113
114
116{
117 //Input/Output file
118 param.ifilename = "";
119 param.isInputMM = false;
120 param.ofilename = "";
121 param.base = 1;
122
123 //Preprocessing
124 // mcl removes isolated vertices by default,
125 // we don't do this because it will create different ordering of vertices!
126 param.remove_isolated = false;
127 param.randpermute = 0;
128
129 //inflation
130 param.inflation = 0.0;
131
132 //pruning
133 param.prunelimit = 1.0/10000.0;
134 param.select = 1100;
135 param.recover_num = 1400;
136 param.recover_pct = .9; // we allow both 90 or .9 as input. Internally, we keep it 0.9
137 param.kselectVersion = 1;
138
139 //HipMCL optimization
140 param.phases = 1;
141 param.perProcessMem = 0;
142 param.isDoublePrecision = true;
143 param.is64bInt = true;
144
145 //debugging
146 param.show = false;
147}
148
150{
152 runinfo << "\n======================================" << endl;
153 runinfo << "Running HipMCL with the parameters: " << endl;
154 runinfo << "======================================" << endl;
155 runinfo << "Input/Output file" << endl;
156 runinfo << " input filename: " << param.ifilename << endl;
157 runinfo << " input file type: " ;
158 if(param.isInputMM)
159 {
160 runinfo << " Matrix Market" << endl;
161 runinfo << " Base of the input matrix: " << param.base << endl;
162 }
163 else runinfo << " Labeled Triples format" << endl;
164 runinfo << " Output filename: " << param.ofilename << endl;
165
166
167 runinfo << "Preprocessing" << endl;
168 runinfo << " Remove isolated vertices? : ";
169 if (param.remove_isolated) runinfo << "yes";
170 else runinfo << "no" << endl;
171
172 runinfo << " Randomly permute vertices? : ";
173 if (param.randpermute) runinfo << "yes";
174 else runinfo << "no" << endl;
175
176 runinfo << "Inflation: " << param.inflation << endl;
177
178 runinfo << "Pruning" << endl;
179 runinfo << " Prunelimit: " << param.prunelimit << endl;
180 runinfo << " Recover number: " << param.recover_num << endl;
181 runinfo << " Recover percent: " << ceil(param.recover_pct*100) << endl;
182 runinfo << " Selection number: " << param.select << endl;
183 // do not expose selection option at this moment
184 //runinfo << "Selection algorithm: ";
185 //if(kselectVersion==1) runinfo << "tournament select" << endl;
186 //else if(kselectVersion==2) runinfo << "quickselect" << endl;
187 //else runinfo << "adaptive based on k" << endl;
188
189
190
191 runinfo << "HipMCL optimization" << endl;
192 runinfo << " Number of phases: " << param.phases << endl;
193 runinfo << " Memory avilable per process: ";
194 if(param.perProcessMem>0) runinfo << param.perProcessMem << "GB" << endl;
195 else runinfo << "not provided" << endl;
196 if(param.isDoublePrecision) runinfo << "Using double precision floating point" << endl;
197 else runinfo << "Using single precision floating point" << endl;
198 if(param.is64bInt ) runinfo << "Using 64 bit indexing" << endl;
199 else runinfo << "Using 32 bit indexing" << endl;
200
201 runinfo << "Debugging" << endl;
202 runinfo << " Show matrices after major steps? : ";
203 if (param.show) runinfo << "yes";
204 else runinfo << "no" << endl;
205 runinfo << "======================================" << endl;
207}
208
210{
211 for (int i = 1; i < argc; i++)
212 {
213 if (strcmp(argv[i],"-M")==0){
214 param.ifilename = string(argv[i+1]);
215 }
216 else if (strcmp(argv[i],"--matrix-market")==0){
217 param.isInputMM = true;
218 }
219 else if (strcmp(argv[i],"-o")==0){
220 param.ofilename = string(argv[i+1]);
221 }
222 else if (strcmp(argv[i],"--show")==0){
223 param.show = true;
224 }
225 else if (strcmp(argv[i],"--remove-isolated")==0){
226 param.remove_isolated = true;
227 }
228 else if (strcmp(argv[i],"--tournament-select")==0){
229 param.kselectVersion = 1;
230 }
231 else if (strcmp(argv[i],"--quick-select")==0){
232 param.kselectVersion = 2;
233
234 }
235 else if (strcmp(argv[i],"-I")==0){
236 param.inflation = atof(argv[i + 1]);
237
238 } else if (strcmp(argv[i],"-p")==0) {
239 param.prunelimit = atof(argv[i + 1]);
240
241 } else if (strcmp(argv[i],"-S")==0) {
242 param.select = atoi(argv[i + 1]);
243
244 } else if (strcmp(argv[i],"-R")==0) {
245 param.recover_num = atoi(argv[i + 1]);
246
247 } else if (strcmp(argv[i],"-pct")==0)
248 {
249 param.recover_pct = atof(argv[i + 1]);
250 if(param.recover_pct>1) param.recover_pct/=100.00;
251 } else if (strcmp(argv[i],"-base")==0) {
252 param.base = atoi(argv[i + 1]);
253 }
254 else if (strcmp(argv[i],"-rand")==0) {
255 param.randpermute = atoi(argv[i + 1]);
256 }
257 else if (strcmp(argv[i],"-phases")==0) {
258 param.phases = atoi(argv[i + 1]);
259 }
260 else if (strcmp(argv[i],"-per-process-mem")==0) {
261 param.perProcessMem = atoi(argv[i + 1]);
262 }
263 else if (strcmp(argv[i],"--single-precision")==0) {
264 param.isDoublePrecision = false;
265 }
266 else if (strcmp(argv[i],"--32bit-index")==0) {
267 param.is64bInt = false;
268 }
269 }
270
271 if(param.ofilename=="") // construct output file name if it is not provided
272 {
273 param.ofilename = param.ifilename + ".hipmcl";
274 }
275
276}
277
278
280{
282
283 runinfo << "Usage: ./hipmcl -M <input filename> -I <inlfation> (required)" << endl;
284
285 runinfo << "======================================" << endl;
286 runinfo << " Detail parameter options " << endl;
287 runinfo << "======================================" << endl;
288
289
290
291 runinfo << "Input/Output file" << endl;
292 runinfo << " -M <input file name (labeled triples format)> (mandatory)" << endl;
293 runinfo << " --matrix-market : if provided, the input file is in the matrix market format (default: the file is in labeled triples format)" << endl;
294 runinfo << " -base <index of the first vertex in the matrix market file, 0|1> (default: 1) " << endl;
295 runinfo << " -o <output filename> (default: input_file_name.hipmcl )" << endl;
296
297 runinfo << "Inflation" << endl;
298 runinfo << "-I <inflation> (mandatory)\n";
299
300 runinfo << "Preprocessing" << endl;
301 runinfo << " -rand <randomly permute vertices> (default:0)\n";
302 runinfo << " --remove-isolated : if provided, remove isolated vertices (default: don't remove isolated vertices)\n";
303
304
305 runinfo << "Pruning" << endl;
306 runinfo << " -p <cutoff> (default: 1/10000)\n";
307 runinfo << " -R <recovery number> (default: 1400)\n";
308 runinfo << " -pct <recovery pct> (default: 90)\n";
309 runinfo << " -S <selection number> (default: 1100)\n";
310
311
312 runinfo << "HipMCL optimization" << endl;
313 runinfo << " -phases <number of phases> (default:1)\n";
314 runinfo << " -per-process-mem <memory (GB) available per process> (default:0, number of phases is not estimated)\n";
315 runinfo << " --single-precision (if not provided, use double precision floating point numbers)\n" << endl;
316 runinfo << " --32bit-index (if not provided, use 64 bit indexing for vertex ids)\n" << endl;
317
318 runinfo << "Debugging" << endl;
319 runinfo << " --show: show information about matrices after major steps (default: do not show matrices)" << endl;
320
321
322
323 runinfo << "======================================" << endl;
324 runinfo << " Few examples " << endl;
325 runinfo << "======================================" << endl;
326 runinfo << "Example with with a graph in labeled triples format on a laptop with 8GB memory and 8 cores:\nexport OMP_NUM_THREADS=8\nbin/hipmcl -M data/sevenvertexgraph.txt -I 2 -per-process-mem 8" << endl;
327 runinfo << "Same as above with 4 processes and 2 theaded per process cores:\nexport OMP_NUM_THREADS=2\nmpirun -np 4 bin/hipmcl -M data/sevenvertexgraph.txt -I 2 -per-process-mem 2" << endl;
328 runinfo << "Example with a graph in matrix market format:\nbin/hipmcl -M data/sevenvertex.mtx --matrix-market -base 1 -I 2 -per-process-mem 8" << endl;
329
330 runinfo << "Example on the NERSC/Edison system with 16 nodes and 24 threads per node: \nsrun -N 16 -n 16 -c 24 bin/hipmcl -M data/hep-th.mtx --matrix-market -base 1 -per-process-mem 64 -o hep-th.hipmcl" << endl;
332}
333
334
335// base: base of items
336// clusters are always numbered 0-based
337template <typename IT, typename NT, typename DER>
339{
340 IT nCC;
341 // A is a directed graph
342 // symmetricize A
343
345 AT.Transpose();
346 A += AT;
348 return cclabels;
349}
350
351
352template <typename IT, typename NT, typename DER>
354{
355 FullyDistVec<IT, NT> colsums = A.Reduce(Column, plus<NT>(), 0.0);
356 colsums.Apply(safemultinv<NT>());
357 A.DimApply(Column, colsums, multiplies<NT>()); // scale each "Column" with the given vector
358}
359
360template <typename IT, typename NT, typename DER>
362{
363 // sums of squares of columns
365 // Matrix entries are non-negative, so max() can use zero as identity
367 colmaxs -= colssqs;
368
369 // multiplu by number of nonzeros in each column
370 FullyDistVec<IT, NT> nnzPerColumn = A.Reduce(Column, plus<NT>(), 0.0, [](NT val){return 1.0;});
371 colmaxs.EWiseApply(nnzPerColumn, multiplies<NT>());
372
373 return colmaxs.Reduce(maximum<NT>(), 0.0);
374}
375
376template <typename IT, typename NT, typename DER>
378{
379 A.Apply(bind2nd(exponentiate(), power));
380}
381
382// default adjustloop setting
383// 1. Remove loops
384// 2. set loops to max of all arc weights
385template <typename IT, typename NT, typename DER>
387{
388
389 A.RemoveLoops();
391 A.Apply([](NT val){return val==numeric_limits<NT>::min() ? 1.0 : val;}); // for isolated vertices
392 A.AddLoops(colmaxs);
394 outs << "Adjusting loops" << endl;
396}
397
398template <typename IT, typename NT, typename DER>
400{
402 FullyDistVec<IT, NT> ColSums = A.Reduce(Column, plus<NT>(), 0.0);
404 IT numIsolated = A.getnrow() - nonisov.TotalLength();
405 outs << "Number of isolated vertices: " << numIsolated << endl;
407
408 A(nonisov, nonisov, true);
409 SpParHelper::Print("Removed isolated vertices.\n");
410 if(param.show)
411 {
412 A.PrintInfo();
413 }
414
415}
416
417//TODO: handle reordered cluster ids
418template <typename IT, typename NT, typename DER>
420{
421 // randomly permute for load balance
422 if(A.getnrow() == A.getncol())
423 {
424 FullyDistVec<IT, IT> p( A.getcommgrid());
425 p.iota(A.getnrow(), 0);
426 p.RandPerm();
427 (A)(p,p,true);// in-place permute to save memory
428 SpParHelper::Print("Applied symmetric permutation.\n");
429 }
430 else
431 {
432 SpParHelper::Print("Rectangular matrix: Can not apply symmetric permutation.\n");
433 }
434}
435
436template <typename IT, typename NT, typename DER>
438{
439 if(param.remove_isolated)
441
442 if(param.randpermute)
444
445 // Adjust self loops
446 AdjustLoops(A);
447
448 // Make stochastic
450 SpParHelper::Print("Made stochastic\n");
451
452 if(param.show)
453 {
454 A.PrintInfo();
455 }
456
457
458 // chaos doesn't make sense for non-stochastic matrices
459 // it is in the range {0,1} for stochastic matrices
460 NT chaos = 1;
461 int it=1;
462 double tInflate = 0;
463 double tExpand = 0;
465 // while there is an epsilon improvement
466 while( chaos > EPS)
467 {
468 double t1 = MPI_Wtime();
469 //A.Square<PTFF>() ; // expand
470 A = MemEfficientSpGEMM<PTFF, NT, DER>(A, A, param.phases, param.prunelimit, (IT)param.select, (IT)param.recover_num, param.recover_pct, param.kselectVersion, param.perProcessMem);
471
473 tExpand += (MPI_Wtime() - t1);
474
475 if(param.show)
476 {
477 SpParHelper::Print("After expansion\n");
478 A.PrintInfo();
479 }
480 chaos = Chaos(A);
481
482 double tInflate1 = MPI_Wtime();
483 Inflate(A, param.inflation);
486
487 if(param.show)
488 {
489 SpParHelper::Print("After inflation\n");
490 A.PrintInfo();
491 }
492
493
494
495 double newbalance = A.LoadImbalance();
496 double t3=MPI_Wtime();
497 stringstream s;
498 s << "Iteration# " << setw(3) << it << " : " << " chaos: " << setprecision(3) << chaos << " load-balance: "<< newbalance << " Time: " << (t3-t1) << endl;
499 SpParHelper::Print(s.str());
500 it++;
501
502
503
504 }
505
506
507 double tcc1 = MPI_Wtime();
508 // bool does not work because A.AddLoops(1) can not create a fullydist vector with Bool?
509 // write a promote train for float
512 double tcc = MPI_Wtime() - tcc1;
513
514
515#ifdef TIMING
516 int myrank;
518 if(myrank==0)
519 {
520 cout << "================detailed timing==================" << endl;
521
523 cout << " Abcast= " << mcl_Abcasttime << endl;
524 cout << " Bbcast= " << mcl_Bbcasttime << endl;
525 cout << " localspgemm= " << mcl_localspgemmtime << endl;
526 cout << " multiwaymergetime= "<< mcl_multiwaymergetime << endl;
527 cout << "Prune: " << mcl_kselecttime + mcl_prunecolumntime << endl;
528 cout << " kselect= " << mcl_kselecttime << endl;
529 cout << " prunecolumn= " << mcl_prunecolumntime << endl;
530 cout << "Inflation " << tInflate << endl;
531 cout << "Component: " << tcc << endl;
532 cout << "File I/O: " << tIO << endl;
533 cout << "=================================================" << endl;
534 }
535
536#endif
537
538 return cclabels;
539
540
541}
542
543template <typename IT, typename NT, typename DER>
545{
547 AT.Transpose();
548 if(!(AT == A))
549 {
550 SpParHelper::Print("Symmatricizing an unsymmetric input matrix.\n");
551 A += AT;
552 }
553}
554
555template <typename GIT, typename LIT, typename NT>
557{
560
561 // read file
562
563 SpParHelper::Print("Reading input file......\n");
564
565 double tIO1 = MPI_Wtime();
566 if(param.isInputMM)
567 A.ParallelReadMM(param.ifilename, param.base, maximum<NT>()); // if base=0, then it is implicitly converted to Boolean false
568 else // default labeled triples format
569 vtxLabels = A.ReadGeneralizedTuples(param.ifilename, maximum<NT>());
570
571 tIO = MPI_Wtime() - tIO1;
573 outs << " : took " << tIO << " seconds" << endl;
575 // Symmetricize the matrix only if needed
577
578 double balance = A.LoadImbalance();
579
580 outs.str("");
581 outs.clear();
582 if(!param.is64bInt) // don't compute nnz because it may overflow
583 {
584 GIT nnz = A.getnnz();
585 GIT nv = A.getnrow();
586 outs << "Number of vertices: " << nv << " number of edges: "<< nnz << endl;
587 }
588 outs << "Load balance: " << balance << endl;
590
591 if(param.show)
592 {
593 A.PrintInfo();
594 }
595
596
597
598#ifdef TIMING
599 mcl_Abcasttime = 0;
600 mcl_Bbcasttime = 0;
603 mcl_kselecttime = 0;
605#endif
606
607
608
609 double tstart = MPI_Wtime();
610
611 // Run HipMCL
613 //culstLabels.ParallelWrite(param.ofilename, param.base); // clusters are always numbered 0-based
614
615 if(param.isInputMM)
616 WriteMCLClusters(param.ofilename, culstLabels, param.base);
617 else
619
620
621
622 GIT nclusters = culstLabels.Reduce(maximum<GIT>(), (GIT) 0 ) ;
623 nclusters ++; // because of zero based indexing for clusters
624
625 double tend = MPI_Wtime();
627 s2 << "Number of clusters: " << nclusters << endl;
628 s2 << "Total time: " << (tend-tstart) << endl;
629 s2 << "=================================================\n" << endl ;
630 SpParHelper::Print(s2.str());
631
632}
633
634
635int main(int argc, char* argv[])
636{
637 int provided;
640 {
641 printf("ERROR: The MPI library does not have MPI_THREAD_SERIALIZED support\n");
643 }
644
645 int nthreads = 1;
646#ifdef THREADED
647#pragma omp parallel
648 {
649 nthreads = omp_get_num_threads();
650 }
651#endif
652
653 int nprocs, myrank;
656
658
659 // initialize parameters to default values
661
662 // Populate parameters from command line options
664
665 // check if mandatory arguments are provided
666 if(param.ifilename=="" || param.inflation == 0.0)
667 {
668 SpParHelper::Print("Required options are missing.\n");
669 ShowOptions();
670 MPI_Finalize();
671 return -1;
672 }
673
674
675 if(myrank == 0)
676 {
677 cout << "\nProcess Grid used (pr x pc x threads): " << sqrt(nprocs) << " x " << sqrt(nprocs) << " x " << nthreads << endl;
678 }
679
680
681 // show parameters used to run HipMCL
683
684 if(param.perProcessMem==0)
685 {
686 if(myrank == 0)
687 {
688 cout << "******** Number of phases will not be estimated as -per-process-mem option is supplied. It is highly recommended that you provide -per-process-mem option for large-scale runs. *********** " << endl;
689 }
690 }
691
692 {
693 if(param.isDoublePrecision)
694 if(param.is64bInt) // default case
696 else
698 else if(param.is64bInt)
700 else
701 MainBody<int32_t, int32_t, float>(param); // memory effecient case
702 }
703
704
705
706 // make sure the destructors for all objects are called before MPI::Finalize()
707 MPI_Finalize();
708 return 0;
709}
double mcl_localspgemmtime
Definition MCL.cpp:59
double mcl_multiwaymergetime
Definition MCL.cpp:60
double mcl_prunecolumntime
Definition MCL.cpp:62
int main(int argc, char *argv[])
Definition MCL.cpp:635
double mcl_Bbcasttime
Definition MCL.cpp:58
void ShowParam(HipMCLParam &param)
Definition MCL.cpp:149
void RandPermute(SpParMat< IT, NT, DER > &A, HipMCLParam &param)
Definition MCL.cpp:419
void MakeColStochastic(SpParMat< IT, NT, DER > &A)
Definition MCL.cpp:353
void ProcessParam(int argc, char *argv[], HipMCLParam &param)
Definition MCL.cpp:209
double mcl_kselecttime
Definition MCL.cpp:61
void InitParam(HipMCLParam &param)
Definition MCL.cpp:115
FullyDistVec< IT, IT > HipMCL(SpParMat< IT, NT, DER > &A, HipMCLParam &param)
Definition MCL.cpp:437
double cblas_allgathertime
Definition MCL.cpp:63
void AdjustLoops(SpParMat< IT, NT, DER > &A)
Definition MCL.cpp:386
int64_t mcl_memory
Definition MCL.cpp:64
#define EPS
Definition MCL.cpp:55
void RemoveIsolated(SpParMat< IT, NT, DER > &A, HipMCLParam &param)
Definition MCL.cpp:399
void Inflate(SpParMat< IT, NT, DER > &A, double power)
Definition MCL.cpp:377
double mcl_Abcasttime
Definition MCL.cpp:57
NT Chaos(SpParMat< IT, NT, DER > &A)
Definition MCL.cpp:361
void MainBody(HipMCLParam &param)
Definition MCL.cpp:556
double tIO
Definition MCL.cpp:65
void ShowOptions()
Definition MCL.cpp:279
FullyDistVec< IT, IT > Interpret(SpParMat< IT, NT, DER > &A)
Definition MCL.cpp:338
FullyDistVec< int64_t, double > MPI_DenseVec
Definition MCL.cpp:74
SpDCCols< int64_t, double > DCCols
Definition MCL.cpp:72
SpParMat< int64_t, double, DCCols > MPI_DCCols
Definition MCL.cpp:73
static void Print(const std::string &s)
@ Column
Definition SpDefs.h:114
void WriteMCLClusters(std::string ofName, FullyDistVec< IT, IT > clustIdForVtx, FullyDistVec< IT, std::array< char, MAXVERTNAME > > vtxLabels)
void Symmetricize(PARMAT &A)
Definition ReadMatDist.h:29
FullyDistVec< IT, IT > CC(SpParMat< IT, NT, DER > &A, IT &nCC)
Definition CC.h:276
double A
string ifilename
Definition MCL.cpp:82
bool is64bInt
Definition MCL.cpp:106
bool show
Definition MCL.cpp:109
int randpermute
Definition MCL.cpp:89
int64_t select
Definition MCL.cpp:97
int phases
Definition MCL.cpp:103
string ofilename
Definition MCL.cpp:86
double recover_pct
Definition MCL.cpp:99
bool remove_isolated
Definition MCL.cpp:90
bool isInputMM
Definition MCL.cpp:83
int base
Definition MCL.cpp:84
int64_t recover_num
Definition MCL.cpp:98
int perProcessMem
Definition MCL.cpp:104
bool isDoublePrecision
Definition MCL.cpp:105
int kselectVersion
Definition MCL.cpp:100
double inflation
Definition MCL.cpp:93
double prunelimit
Definition MCL.cpp:96