Actual source code: partition.c

  2: #include <private/matimpl.h>               /*I "petscmat.h" I*/

  4: /* Logging support */
  5: PetscClassId  MAT_PARTITIONING_CLASSID;

  7: /*
  8:    Simplest partitioning, keeps the current partitioning.
  9: */
 12: static PetscErrorCode MatPartitioningApply_Current(MatPartitioning part,IS *partitioning)
 13: {
 15:   PetscInt       m;
 16:   PetscMPIInt    rank,size;

 19:   MPI_Comm_size(((PetscObject)part)->comm,&size);
 20:   if (part->n != size) {
 21:     SETERRQ(((PetscObject)part)->comm,PETSC_ERR_SUP,"This is the DEFAULT NO-OP partitioner, it currently only supports one domain per processor\nuse -matpartitioning_type parmetis or chaco or scotch for more than one subdomain per processor");
 22:   }
 23:   MPI_Comm_rank(((PetscObject)part)->comm,&rank);

 25:   MatGetLocalSize(part->adj,&m,PETSC_NULL);
 26:   ISCreateStride(((PetscObject)part)->comm,m,rank,0,partitioning);
 27:   return(0);
 28: }

 32: static PetscErrorCode MatPartitioningApply_Square(MatPartitioning part,IS *partitioning)
 33: {
 35:   PetscInt       cell,n,N,p,rstart,rend,*color;
 36:   PetscMPIInt    size;

 39:   MPI_Comm_size(((PetscObject)part)->comm,&size);
 40:   if (part->n != size) SETERRQ(((PetscObject)part)->comm,PETSC_ERR_SUP,"Currently only supports one domain per processor");
 41:   p = (PetscInt)sqrt((double)part->n);
 42:   if (p*p != part->n) SETERRQ(((PetscObject)part)->comm,PETSC_ERR_SUP,"Square partitioning requires \"perfect square\" number of domains");

 44:   MatGetSize(part->adj,&N,PETSC_NULL);
 45:   n = (PetscInt)sqrt((double)N);
 46:   if (n*n != N) SETERRQ(((PetscObject)part)->comm,PETSC_ERR_SUP,"Square partitioning requires square domain");
 47:   if (n%p != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Square partitioning requires p to divide n");
 48:   MatGetOwnershipRange(part->adj,&rstart,&rend);
 49:   PetscMalloc((rend-rstart)*sizeof(PetscInt),&color);
 50:   /* for (int cell=rstart; cell<rend; cell++) { color[cell-rstart] = ((cell%n) < (n/2)) + 2 * ((cell/n) < (n/2)); } */
 51:   for (cell=rstart; cell<rend; cell++) {
 52:     color[cell-rstart] = ((cell%n) / (n/p)) + p * ((cell/n) / (n/p));
 53:   }
 54:   ISCreateGeneral(((PetscObject)part)->comm,rend-rstart,color,PETSC_OWN_POINTER,partitioning);
 55:   return(0);
 56: }

 61: PetscErrorCode  MatPartitioningCreate_Current(MatPartitioning part)
 62: {
 64:   part->ops->apply   = MatPartitioningApply_Current;
 65:   part->ops->view    = 0;
 66:   part->ops->destroy = 0;
 67:   return(0);
 68: }

 74: PetscErrorCode  MatPartitioningCreate_Square(MatPartitioning part)
 75: {
 77:   part->ops->apply   = MatPartitioningApply_Square;
 78:   part->ops->view    = 0;
 79:   part->ops->destroy = 0;
 80:   return(0);
 81: }

 84: /* ===========================================================================================*/

 86: PetscFList MatPartitioningList = 0;
 87: PetscBool  MatPartitioningRegisterAllCalled = PETSC_FALSE;


 92: PetscErrorCode  MatPartitioningRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatPartitioning))
 93: {
 95:   char fullname[PETSC_MAX_PATH_LEN];

 98:   PetscFListConcat(path,name,fullname);
 99:   PetscFListAdd(&MatPartitioningList,sname,fullname,(void (*)(void))function);
100:   return(0);
101: }

105: /*@C
106:    MatPartitioningRegisterDestroy - Frees the list of partitioning routines.

108:   Not Collective

110:   Level: developer

112: .keywords: matrix, register, destroy

114: .seealso: MatPartitioningRegisterDynamic(), MatPartitioningRegisterAll()
115: @*/
116: PetscErrorCode  MatPartitioningRegisterDestroy(void)
117: {

121:   MatPartitioningRegisterAllCalled = PETSC_FALSE;
122:   PetscFListDestroy(&MatPartitioningList);
123:   return(0);
124: }

128: /*@C
129:    MatPartitioningGetType - Gets the Partitioning method type and name (as a string) 
130:         from the partitioning context.

132:    Not collective

134:    Input Parameter:
135: .  partitioning - the partitioning context

137:    Output Parameter:
138: .  type - partitioner type

140:    Level: intermediate

142:    Not Collective

144: .keywords: Partitioning, get, method, name, type
145: @*/
146: PetscErrorCode  MatPartitioningGetType(MatPartitioning partitioning,const MatPartitioningType *type)
147: {
151:   *type = ((PetscObject)partitioning)->type_name;
152:   return(0);
153: }

157: /*@C
158:    MatPartitioningSetNParts - Set how many partitions need to be created;
159:         by default this is one per processor. Certain partitioning schemes may
160:         in fact only support that option.

162:    Not collective

164:    Input Parameter:
165: .  partitioning - the partitioning context
166: .  n - the number of partitions

168:    Level: intermediate

170:    Not Collective

172: .keywords: Partitioning, set

174: .seealso: MatPartitioningCreate(), MatPartitioningApply()
175: @*/
176: PetscErrorCode  MatPartitioningSetNParts(MatPartitioning part,PetscInt n)
177: {
179:   part->n = n;
180:   return(0);
181: }

185: /*@
186:    MatPartitioningApply - Gets a partitioning for a matrix.

188:    Collective on Mat

190:    Input Parameters:
191: .  matp - the matrix partitioning object

193:    Output Parameters:
194: .   partitioning - the partitioning. For each local node this tells the processor
195:                    number that that node is assigned to.

197:    Options Database Keys:
198:    To specify the partitioning through the options database, use one of
199:    the following 
200: $    -mat_partitioning_type parmetis, -mat_partitioning current
201:    To see the partitioning result
202: $    -mat_partitioning_view

204:    Level: beginner

206:    The user can define additional partitionings; see MatPartitioningRegisterDynamic().

208: .keywords: matrix, get, partitioning

210: .seealso:  MatPartitioningRegisterDynamic(), MatPartitioningCreate(),
211:            MatPartitioningDestroy(), MatPartitioningSetAdjacency(), ISPartitioningToNumbering(),
212:            ISPartitioningCount()
213: @*/
214: PetscErrorCode  MatPartitioningApply(MatPartitioning matp,IS *partitioning)
215: {
217:   PetscBool      flag = PETSC_FALSE;

222:   if (!matp->adj->assembled) SETERRQ(((PetscObject)matp)->comm,PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
223:   if (matp->adj->factortype) SETERRQ(((PetscObject)matp)->comm,PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
224:   if (!matp->ops->apply) SETERRQ(((PetscObject)matp)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must set type with MatPartitioningSetFromOptions() or MatPartitioningSetType()");
225:   PetscLogEventBegin(MAT_Partitioning,matp,0,0,0);
226:   (*matp->ops->apply)(matp,partitioning);
227:   PetscLogEventEnd(MAT_Partitioning,matp,0,0,0);

229:   PetscOptionsGetBool(PETSC_NULL,"-mat_partitioning_view",&flag,PETSC_NULL);
230:   if (flag) {
231:     PetscViewer viewer;
232:     PetscViewerASCIIGetStdout(((PetscObject)matp)->comm,&viewer);
233:     MatPartitioningView(matp,viewer);
234:     ISView(*partitioning,viewer);
235:   }
236:   return(0);
237: }
238: 
241: /*@
242:    MatPartitioningSetAdjacency - Sets the adjacency graph (matrix) of the thing to be
243:       partitioned.

245:    Collective on MatPartitioning and Mat

247:    Input Parameters:
248: +  part - the partitioning context
249: -  adj - the adjacency matrix

251:    Level: beginner

253: .keywords: Partitioning, adjacency

255: .seealso: MatPartitioningCreate()
256: @*/
257: PetscErrorCode  MatPartitioningSetAdjacency(MatPartitioning part,Mat adj)
258: {
262:   part->adj = adj;
263:   return(0);
264: }

268: /*@
269:    MatPartitioningDestroy - Destroys the partitioning context.

271:    Collective on Partitioning

273:    Input Parameters:
274: .  part - the partitioning context

276:    Level: beginner

278: .keywords: Partitioning, destroy, context

280: .seealso: MatPartitioningCreate()
281: @*/
282: PetscErrorCode  MatPartitioningDestroy(MatPartitioning *part)
283: {

287:   if (!*part) return(0);
289:   if (--((PetscObject)(*part))->refct > 0) {*part = 0; return(0);}

291:   if ((*part)->ops->destroy) {
292:     (*(*part)->ops->destroy)((*part));
293:   }
294:   PetscFree((*part)->vertex_weights);
295:   PetscFree((*part)->part_weights);
296:   PetscHeaderDestroy(part);
297:   return(0);
298: }

302: /*@C
303:    MatPartitioningSetVertexWeights - Sets the weights for vertices for a partitioning.

305:    Logically Collective on Partitioning

307:    Input Parameters:
308: +  part - the partitioning context
309: -  weights - the weights, on each process this array must have the same size as the number of local rows

311:    Level: beginner

313:    Notes:
314:       The array weights is freed by PETSc so the user should not free the array. In C/C++
315:    the array must be obtained with a call to PetscMalloc(), not malloc().

317: .keywords: Partitioning, destroy, context

319: .seealso: MatPartitioningCreate(), MatPartitioningSetType(), MatPartitioningSetPartitionWeights()
320: @*/
321: PetscErrorCode  MatPartitioningSetVertexWeights(MatPartitioning part,const PetscInt weights[])
322: {


328:   PetscFree(part->vertex_weights);
329:   part->vertex_weights = (PetscInt*)weights;
330:   return(0);
331: }

335: /*@C
336:    MatPartitioningSetPartitionWeights - Sets the weights for each partition.

338:    Logically Collective on Partitioning

340:    Input Parameters:
341: +  part - the partitioning context
342: -  weights - An array of size nparts that is used to specify the fraction of
343:              vertex weight that should be distributed to each sub-domain for
344:              the balance constraint. If all of the sub-domains are to be of
345:              the same size, then each of the nparts elements should be set
346:              to a value of 1/nparts. Note that the sum of all of the weights
347:              should be one.

349:    Level: beginner

351:    Notes:
352:       The array weights is freed by PETSc so the user should not free the array. In C/C++
353:    the array must be obtained with a call to PetscMalloc(), not malloc().

355: .keywords: Partitioning, destroy, context

357: .seealso: MatPartitioningCreate(), MatPartitioningSetType(), MatPartitioningSetVertexWeights()
358: @*/
359: PetscErrorCode  MatPartitioningSetPartitionWeights(MatPartitioning part,const PetscReal weights[])
360: {


366:   PetscFree(part->part_weights);
367:   part->part_weights = (PetscReal*)weights;
368:   return(0);
369: }

373: /*@
374:    MatPartitioningCreate - Creates a partitioning context.

376:    Collective on MPI_Comm

378:    Input Parameter:
379: .   comm - MPI communicator 

381:    Output Parameter:
382: .  newp - location to put the context

384:    Level: beginner

386: .keywords: Partitioning, create, context

388: .seealso: MatPartitioningSetType(), MatPartitioningApply(), MatPartitioningDestroy(),
389:           MatPartitioningSetAdjacency()

391: @*/
392: PetscErrorCode  MatPartitioningCreate(MPI_Comm comm,MatPartitioning *newp)
393: {
394:   MatPartitioning part;
395:   PetscErrorCode  ierr;
396:   PetscMPIInt     size;

399:   *newp          = 0;

401: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
402:   MatInitializePackage(PETSC_NULL);
403: #endif
404:   PetscHeaderCreate(part,_p_MatPartitioning,struct _MatPartitioningOps,MAT_PARTITIONING_CLASSID,-1,"MatPartitioning","Matrix/graph partitioning","MatOrderings",comm,MatPartitioningDestroy,
405:                     MatPartitioningView);
406:   part->vertex_weights = PETSC_NULL;
407:   part->part_weights   = PETSC_NULL;
408:   MPI_Comm_size(comm,&size);
409:   part->n = (PetscInt)size;

411:   *newp = part;
412:   return(0);
413: }

417: /*@C 
418:    MatPartitioningView - Prints the partitioning data structure.

420:    Collective on MatPartitioning

422:    Input Parameters:
423: .  part - the partitioning context
424: .  viewer - optional visualization context

426:    Level: intermediate

428:    Note:
429:    The available visualization contexts include
430: +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
431: -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
432:          output where only the first processor opens
433:          the file.  All other processors send their 
434:          data to the first processor to print. 

436:    The user can open alternative visualization contexts with
437: .     PetscViewerASCIIOpen() - output to a specified file

439: .keywords: Partitioning, view

441: .seealso: PetscViewerASCIIOpen()
442: @*/
443: PetscErrorCode  MatPartitioningView(MatPartitioning part,PetscViewer viewer)
444: {
445:   PetscErrorCode            ierr;
446:   PetscBool                 iascii;

450:   if (!viewer) {
451:     PetscViewerASCIIGetStdout(((PetscObject)part)->comm,&viewer);
452:   }

456:   PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
457:   if (iascii) {
458:     PetscObjectPrintClassNamePrefixType((PetscObject)part,viewer,"MatPartitioning Object");
459:     if (part->vertex_weights) {
460:       PetscViewerASCIIPrintf(viewer,"  Using vertex weights\n");
461:     }
462:   } else {
463:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for this MatParitioning",((PetscObject)viewer)->type_name);
464:   }

466:   if (part->ops->view) {
467:     PetscViewerASCIIPushTab(viewer);
468:     (*part->ops->view)(part,viewer);
469:     PetscViewerASCIIPopTab(viewer);
470:   }

472:   return(0);
473: }

477: /*@C
478:    MatPartitioningSetType - Sets the type of partitioner to use

480:    Collective on MatPartitioning

482:    Input Parameter:
483: .  part - the partitioning context.
484: .  type - a known method

486:    Options Database Command:
487: $  -mat_partitioning_type  <type>
488: $      Use -help for a list of available methods
489: $      (for instance, parmetis)

491:    Level: intermediate

493: .keywords: partitioning, set, method, type

495: .seealso: MatPartitioningCreate(), MatPartitioningApply(), MatPartitioningType

497: @*/
498: PetscErrorCode  MatPartitioningSetType(MatPartitioning part,const MatPartitioningType type)
499: {
500:   PetscErrorCode ierr,(*r)(MatPartitioning);
501:   PetscBool  match;


507:   PetscTypeCompare((PetscObject)part,type,&match);
508:   if (match) return(0);

510:   if (part->setupcalled) {
511:      (*part->ops->destroy)(part);
512:     part->data        = 0;
513:     part->setupcalled = 0;
514:   }

516:    PetscFListFind(MatPartitioningList,((PetscObject)part)->comm,type,PETSC_TRUE,(void (**)(void)) &r);

518:   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown partitioning type %s",type);

520:   part->ops->destroy      = (PetscErrorCode (*)(MatPartitioning)) 0;
521:   part->ops->view         = (PetscErrorCode (*)(MatPartitioning,PetscViewer)) 0;
522:   (*r)(part);

524:   PetscFree(((PetscObject)part)->type_name);
525:   PetscStrallocpy(type,&((PetscObject)part)->type_name);
526:   return(0);
527: }

531: /*@
532:    MatPartitioningSetFromOptions - Sets various partitioning options from the 
533:         options database.

535:    Collective on MatPartitioning

537:    Input Parameter:
538: .  part - the partitioning context.

540:    Options Database Command:
541: $  -mat_partitioning_type  <type>
542: $      Use -help for a list of available methods
543: $      (for instance, parmetis)

545:    Level: beginner

547: .keywords: partitioning, set, method, type
548: @*/
549: PetscErrorCode  MatPartitioningSetFromOptions(MatPartitioning part)
550: {
552:   PetscBool  flag;
553:   char       type[256];
554:   const char *def;

557:   PetscObjectOptionsBegin((PetscObject)part);
558:     if (!((PetscObject)part)->type_name) {
559: #if defined(PETSC_HAVE_PARMETIS)
560:       def = MATPARTITIONINGPARMETIS;
561: #else
562:       def = MATPARTITIONINGCURRENT;
563: #endif
564:     } else {
565:       def = ((PetscObject)part)->type_name;
566:     }
567:     PetscOptionsList("-mat_partitioning_type","Type of partitioner","MatPartitioningSetType",MatPartitioningList,def,type,256,&flag);
568:     if (flag) {
569:       MatPartitioningSetType(part,type);
570:     }
571:     /*
572:       Set the type if it was never set.
573:     */
574:     if (!((PetscObject)part)->type_name) {
575:       MatPartitioningSetType(part,def);
576:     }

578:     if (part->ops->setfromoptions) {
579:       (*part->ops->setfromoptions)(part);
580:     }
581:   PetscOptionsEnd();
582:   return(0);
583: }