int Zoltan_Color_Test( ZZ *zz, /* Zoltan structure */ int *num_gid_entries, /* # of entries for a global id */ int *num_lid_entries, /* # of entries for a local id */ int num_obj, /* Input: number of objects */ ZOLTAN_ID_PTR global_ids, /* Input: global ids of the vertices */ /* The application must allocate enough space */ ZOLTAN_ID_PTR local_ids, /* Input: local ids of the vertices */ /* The application must allocate enough space */ int *color_exp /* Input: Colors assigned to local vertices */ ) { static char *yo = "color_test_fn"; int nvtx = num_obj; /* number of vertices */ int i, j; int ierr = ZOLTAN_OK; int ferr = ZOLTAN_OK; /* final error signal */ char coloring_problem; /* Input: which coloring to perform; currently only supports D1, D2 coloring and variants */ char coloring_problemStr[MAX_PARAM_STRING_LEN]; /* string version coloring problem name */ int ss=100; char comm_pattern='S', coloring_order='I', coloring_method='F'; int comm[2],gcomm[2]; int *color=NULL; int *adjproc=NULL, *xadj=NULL; ZOLTAN_GNO_TYPE gvtx; /* number of global vertices */ ZOLTAN_GNO_TYPE *vtxdist=NULL, *adjncy=NULL; ZG graph; ZOLTAN_GNO_TYPE *requested_GNOs = NULL; /* Return GNOs of the requested GIDs. */ int *loc_partialD2 = NULL; /* local binary array showing which vertices to be colored */ int *partialD2 = NULL; /* global binary array showing which vertices to be colored */ struct Zoltan_DD_Struct *dd_color; /* DDirectory for colors */ ZOLTAN_GNO_TYPE *local_GNOs = NULL; ZOLTAN_GNO_TYPE *global_GNOs = NULL; memset (&graph, 0, sizeof(ZG)); /* PARAMETER SETTINGS */ Zoltan_Bind_Param(Color_params, "COLORING_PROBLEM", (void *) &coloring_problemStr); Zoltan_Bind_Param(Color_params, "SUPERSTEP_SIZE", (void *) &ss); Zoltan_Bind_Param(Color_params, "COMM_PATTERN", (void *) &comm_pattern); Zoltan_Bind_Param(Color_params, "VERTEX_VISIT_ORDER", (void *) &coloring_order); Zoltan_Bind_Param(Color_params, "COLORING_METHOD", (void *) &coloring_method); strncpy(coloring_problemStr, "distance-1", MAX_PARAM_STRING_LEN); Zoltan_Assign_Param_Vals(zz->Params, Color_params, zz->Debug_Level, zz->Proc, zz->Debug_Proc); /* Check validity of parameters - they should be consistent with Zoltan_Color */ if (!strcasecmp(coloring_problemStr, "distance-1")) coloring_problem = '1'; else if (!strcasecmp(coloring_problemStr, "distance-2")) coloring_problem = '2'; else if (!strcasecmp(coloring_problemStr, "partial-distance-2") || !strcasecmp(coloring_problemStr, "bipartite")) coloring_problem = 'P'; else { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Unknown coloring requested. Using Distance-1 coloring."); coloring_problem = '1'; } if (ss == 0) { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Invalid superstep size. Using default value 100."); ss = 100; } if (comm_pattern != 'S' && comm_pattern != 'A') { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Invalid communication pattern. Using synchronous communication (S)."); comm_pattern = 'S'; } if (comm_pattern == 'A' && (coloring_problem == '2' || coloring_problem == 'P')) { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Asynchronous communication pattern is not implemented for distance-2 coloring and its variants. Using synchronous communication (S)."); comm_pattern = 'S'; } if (coloring_order != 'I' && coloring_order != 'B' && coloring_order != 'U' && coloring_order != 'L' && coloring_order != 'N' && coloring_order != 'S') { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Invalid coloring order. Using internal first coloring order (I)."); coloring_order = 'I'; } if (coloring_order == 'U' && (coloring_problem == '2' || coloring_problem == 'P')) { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Interleaved coloring order is not implemented for distance-2 coloring and its variants. Using internal first coloring order (I)."); coloring_order = 'I'; } if (coloring_method !='F') { ZOLTAN_PRINT_WARN(zz->Proc, yo, "Invalid coloring method. Using first fit method (F)."); coloring_method = 'F'; } /* Compute Max number of array entries per ID over all processors. This is a sanity-maintaining step; we don't want different processors to have different values for these numbers. */ comm[0] = zz->Num_GID; comm[1] = zz->Num_LID; MPI_Allreduce(comm, gcomm, 2, MPI_INT, MPI_MAX, zz->Communicator); zz->Num_GID = *num_gid_entries = gcomm[0]; zz->Num_LID = *num_lid_entries = gcomm[1]; /* Return if this processor is not in the Zoltan structure's communicator. */ if (ZOLTAN_PROC_NOT_IN_COMMUNICATOR(zz)) return ZOLTAN_OK; /* BUILD THE GRAPH */ /* Check that the user has allocated space for the return args. */ if (!color_exp) ZOLTAN_COLOR_ERROR(ZOLTAN_FATAL, "Color argument is NULL. Please give colors of local vertices."); requested_GNOs = (ZOLTAN_GNO_TYPE *) ZOLTAN_MALLOC(num_obj * sizeof(ZOLTAN_GNO_TYPE)); Zoltan_ZG_Build (zz, &graph, 0, 1, num_obj, global_ids, requested_GNOs); Zoltan_ZG_Export (zz, &graph, &gvtx, &nvtx, NULL, NULL, &vtxdist, &xadj, &adjncy, &adjproc, NULL, NULL); if (gvtx > (ZOLTAN_GNO_TYPE)INT_MAX){ if (zz->Proc == 0){ fprintf(stderr, "Zoltan_Color_Test assumes number of vertices (%ld) is less than INT_MAX\n",gvtx); } ierr = ZOLTAN_FATAL; goto End; } KDDKDDKDD(zz->Proc, "COLORTEST DD"); /* Exchange global color information */ if (vtxdist[zz->Num_Proc] && !(color = (int *) ZOLTAN_CALLOC(vtxdist[zz->Num_Proc], sizeof(int)))) MEMORY_ERROR; if (nvtx && !(local_GNOs = (ZOLTAN_GNO_TYPE *) ZOLTAN_MALLOC(nvtx * sizeof(ZOLTAN_GNO_TYPE)))) MEMORY_ERROR; for (i=0; i<nvtx; ++i) local_GNOs[i] = i+vtxdist[zz->Proc]; if (vtxdist[zz->Num_Proc] && !(global_GNOs = (ZOLTAN_GNO_TYPE *) ZOLTAN_MALLOC(vtxdist[zz->Num_Proc] * sizeof(ZOLTAN_GNO_TYPE)))) MEMORY_ERROR; for (i=0; i<vtxdist[zz->Num_Proc]; ++i) global_GNOs[i] = i; ierr = Zoltan_DD_Create (&dd_color, zz->Communicator, sizeof(ZOLTAN_GNO_TYPE)/sizeof(ZOLTAN_ID_TYPE), 0, 0, num_obj, 0); if (ierr != ZOLTAN_OK) ZOLTAN_COLOR_ERROR(ierr, "Cannot construct DDirectory."); /* Put req obs with 1 but first inialize the rest with 0 */ ierr = Zoltan_DD_Update (dd_color, (ZOLTAN_ID_PTR)local_GNOs, NULL, NULL, color, nvtx); if (ierr != ZOLTAN_OK) ZOLTAN_COLOR_ERROR(ierr, "Cannot update DDirectory."); ierr = Zoltan_DD_Update (dd_color, (ZOLTAN_ID_PTR)requested_GNOs, NULL, NULL, color_exp, num_obj); if (ierr != ZOLTAN_OK) ZOLTAN_COLOR_ERROR(ierr, "Cannot update DDirectory."); /* Get requested colors from the DDirectory. */ ierr = Zoltan_DD_Find (dd_color, (ZOLTAN_ID_PTR)global_GNOs, NULL, NULL, color, vtxdist[zz->Num_Proc], NULL); if (ierr != ZOLTAN_OK) ZOLTAN_COLOR_ERROR(ierr, "Cannot find object in DDirectory."); /* Free DDirectory */ Zoltan_DD_Destroy(&dd_color); ZOLTAN_FREE(&local_GNOs); ZOLTAN_FREE(&global_GNOs); KDDKDDKDD(zz->Proc, "COLORTEST CHECK"); if (coloring_problem == 'P' || coloring_problem == '2') { if (vtxdist[zz->Num_Proc] && !(partialD2 = (int *) ZOLTAN_CALLOC(vtxdist[zz->Num_Proc], sizeof(int)))) MEMORY_ERROR; if (vtxdist[zz->Num_Proc] && !(loc_partialD2 = (int *) ZOLTAN_CALLOC(vtxdist[zz->Num_Proc], sizeof(int)))) MEMORY_ERROR; if (coloring_problem == 'P') { for (i=0; i<num_obj; ++i) { int gno=requested_GNOs[i]; loc_partialD2[gno] = 1; } MPI_Allreduce(loc_partialD2, partialD2, vtxdist[zz->Num_Proc], MPI_INT, MPI_LOR, zz->Communicator); } else { for (i=0; i<vtxdist[zz->Num_Proc]; ++i) partialD2[i] = 1; } } /* Check if there is an error in coloring */ if (coloring_problem == '1') { for (i=0; i<nvtx; i++) { int gno = i + (int)vtxdist[zz->Proc]; if (color[gno] <= 0) { /* object i is not colored properly */ ierr = ZOLTAN_FATAL; printf("Error in coloring! u:%d, cu:%d\n", gno, color[gno]); break; } for (j = xadj[i]; j < xadj[i+1]; ++j) { int v = (int)adjncy[j]; if (color[gno] == color[v]) { /* neighbors have the same color */ ierr = ZOLTAN_FATAL; printf("Error in coloring! u:%d, v:%d, cu:%d, cv:%d\n", gno, v, color[gno], color[v]); break; } } if (ierr == ZOLTAN_FATAL) break; } } else if (coloring_problem == '2' || coloring_problem == 'P') { for (i=0; i<nvtx; i++) { int gno = i + (int)vtxdist[zz->Proc]; if (partialD2[gno] && color[gno] <= 0) { /* object i is not colored properly */ ierr = ZOLTAN_FATAL; printf("Error in coloring! u:%d, cu:%d\n", gno, color[gno]); break; } for (j = xadj[i]; j < xadj[i+1]; ++j) { int v = (int)adjncy[j], k; if (partialD2[v] && color[v] <= 0) { ierr = ZOLTAN_FATAL; printf("Error in coloring! d1-neigh: u:%d, v:%d, cu:%d, cv:%d pu:%d pv:%d\n", gno, v, color[gno], color[v], partialD2[gno], partialD2[v]); break; } if (partialD2[gno] && partialD2[v] && color[gno] == color[v]) { /* d-1 neighbors have the same color */ ierr = ZOLTAN_FATAL; printf("Error in coloring! d1-neigh: u:%d, v:%d, cu:%d, cv:%d pu:%d pv:%d\n", gno, v, color[gno], color[v], partialD2[gno], partialD2[v]); break; } for (k = j+1; k < xadj[i+1]; ++k) { int w = (int)adjncy[k]; if (partialD2[v] && partialD2[w] && color[v] == color[w]) { /* d-2 neighbors have the same color */ ierr = ZOLTAN_FATAL; printf("Error in coloring! d2-neigh: v:%d, w:%d, cv:%d, cw:%d pv:%d pw:%d\n", v, w, color[v], color[w], partialD2[v], partialD2[w]); break; } } } if (ierr == ZOLTAN_FATAL) break; } } else ZOLTAN_COLOR_ERROR(ZOLTAN_WARN, "Zoltan_Color_Test is only implemented for distance-1 and distance-2 coloring. Unknown coloring, skipping verification."); End: KDDKDDKDD(zz->Proc, "COLORTEST DONE"); if (ierr==ZOLTAN_FATAL) ierr = 2; MPI_Allreduce(&ierr, &ferr, 1, MPI_INT, MPI_MAX, zz->Communicator); if (ferr == 2) ierr = ZOLTAN_FATAL; else ierr = ZOLTAN_OK; Zoltan_ZG_Free (&graph); ZOLTAN_FREE(&adjproc); ZOLTAN_FREE(&color); ZOLTAN_FREE(&requested_GNOs); ZOLTAN_FREE(&partialD2); ZOLTAN_FREE(&loc_partialD2); return ierr; }
int Zoltan_Preprocess_Graph( ZZ *zz, /* Zoltan structure */ ZOLTAN_ID_PTR *global_ids, ZOLTAN_ID_PTR *local_ids, ZOLTAN_Third_Graph *gr, /* Graph for third part libs */ ZOLTAN_Third_Geom *geo, ZOLTAN_Third_Part *prt, ZOLTAN_Third_Vsize *vsp ) { static char *yo = "Zoltan_Preprocess_Graph"; int ierr; float *float_vwgt=NULL, *float_ewgts=NULL; char msg[256]; ZG *graph = &(gr->graph); int local; char add_obj_weight[MAX_PARAM_STRING_LEN+1]; ZOLTAN_TRACE_ENTER(zz, yo); /* Initialize all local pointers to NULL. This is necessary * because we free all non-NULL pointers upon errors. */ gr->vtxdist = gr->xadj = gr->adjncy = NULL; gr->vwgt = gr->ewgts = NULL; float_vwgt = float_ewgts = NULL; if (gr->obj_wgt_dim >= 0) { /* Check weight dimensions */ if (zz->Obj_Weight_Dim<0){ sprintf(msg, "Object weight dimension is %d, " "but should be >= 0. Using Obj_Weight_Dim = 0.", zz->Obj_Weight_Dim); ZOLTAN_PRINT_WARN(zz->Proc, yo, msg); gr->obj_wgt_dim = 0; } else { gr->obj_wgt_dim = zz->Obj_Weight_Dim; } } else gr->obj_wgt_dim = 0; if (gr->edge_wgt_dim >= 0) { if (zz->Edge_Weight_Dim<0){ sprintf(msg, "Edge weight dimension is %d, " "but should be >= 0. Using Edge_Weight_Dim = 0.", zz->Edge_Weight_Dim); ZOLTAN_PRINT_WARN(zz->Proc, yo, msg); gr->edge_wgt_dim = 0; } else if (zz->Edge_Weight_Dim>1){ ZOLTAN_PRINT_WARN(zz->Proc, yo, "This method does not support " "multidimensional edge weights. Using Edge_Weight_Dim = 1."); gr->edge_wgt_dim = 1; } else { gr->edge_wgt_dim = zz->Edge_Weight_Dim; } } else gr->edge_wgt_dim = 0; /* Default graph type is GLOBAL. */ /* Get parameter options shared by ParMetis and Jostle */ gr->check_graph = 1; /* default */ gr->scatter = 1; /* default */ gr->final_output = 0; strcpy(add_obj_weight, "NONE"); /* default */ Zoltan_Bind_Param(Graph_params, "CHECK_GRAPH", (void *) &gr->check_graph); Zoltan_Bind_Param(Graph_params, "SCATTER_GRAPH", (void *) &gr->scatter); Zoltan_Bind_Param(Graph_params, "FINAL_OUTPUT", (void *) &gr->final_output); Zoltan_Bind_Param(Graph_params, "ADD_OBJ_WEIGHT", (void *) add_obj_weight); Zoltan_Assign_Param_Vals(zz->Params, Graph_params, zz->Debug_Level, zz->Proc, zz->Debug_Proc); /* If reorder is true, we already have the id lists. Ignore weights. */ if ((*global_ids == NULL) || (!gr->id_known)){ int *input_part = NULL; ierr = Zoltan_Get_Obj_List(zz, &gr->num_obj, global_ids, local_ids, gr->obj_wgt_dim, &float_vwgt, &input_part); CHECK_IERR; if (prt) { prt->input_part = input_part; } else if (input_part) { /* Ordering, dont need part */ ZOLTAN_FREE(&input_part); } if (ierr){ /* Return error */ ZOLTAN_PARMETIS_ERROR(ierr, "Get_Obj_List returned error."); } } /* Build Graph for third party library data structures, or just get vtxdist. */ if (gr->get_data) { local = IS_LOCAL_GRAPH(gr->graph_type); ZOLTAN_FREE(&float_vwgt); ierr = Zoltan_ZG_Build (zz, graph, local); /* Normal graph */ CHECK_IERR; ierr = Zoltan_ZG_Export (zz, graph, &gr->num_obj, &gr->num_obj, &gr->obj_wgt_dim, &gr->edge_wgt_dim, &gr->vtxdist, &gr->xadj, &gr->adjncy, &gr->adjproc, &float_vwgt, &float_ewgts, NULL); /* TODO: support graph redistribution */ /* if (prt) */ /* ierr = Zoltan_ZG_Vertex_Info(zz, &graph, global_ids, &prt->input_part); */ /* else */ /* ierr = Zoltan_ZG_Vertex_Info(zz, &graph, global_ids, NULL); */ /* /\* Just to try *\/ */ /* if (prt) { */ /* prt->input_part = (int *)ZOLTAN_CALLOC(gr->num_obj, sizeof(int)); */ /* } */ if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){ ZOLTAN_PARMETIS_ERROR(ierr, "Zoltan_Build_Graph returned error."); } } else{ /* Only geometry */ int i; /* No graph but still needs vtxdist*/ gr->vtxdist = (int*) ZOLTAN_MALLOC ((zz->Num_Proc+1)*sizeof(int)); if (gr->vtxdist == NULL) ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory."); gr->vtxdist[0] = 0; MPI_Allgather(&gr->num_obj, 1, MPI_INT, gr->vtxdist+1, 1, MPI_INT, zz->Communicator); for (i=1 ; i <= zz->Num_Proc ; ++i) { gr->vtxdist[i] += gr->vtxdist[i-1]; } } if (prt) { prt->part_sizes = prt->input_part_sizes; /* ParMETIS needs prt->part to be allocated, even when num_obj=0. */ /* See Zoltan bug 4299. */ prt->part = (indextype *)ZOLTAN_MALLOC((gr->num_obj+1) * sizeof(indextype)); if (!prt->part) { /* Not enough memory */ ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory."); } if (gr->num_obj >0) { memcpy (prt->part, prt->input_part, (gr->num_obj) * sizeof(indextype)); } else { prt->input_part = NULL; } } /* Convert from float. */ /* Get vertex weights if needed */ if (gr->obj_wgt_dim){ ierr = Zoltan_Preprocess_Scale_Weights (gr, float_vwgt, &gr->vwgt, gr->num_obj, gr->obj_wgt_dim, 1, zz, "vertex", gr->vtxdist[zz->Proc]); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){ /* Return error code */ ZOLTAN_PARMETIS_ERROR(ierr, "Error in scaling of weights."); } ZOLTAN_FREE(&float_vwgt); } if (strcasecmp(add_obj_weight, "NONE")){ if (Zoltan_Preprocess_Add_Weight(zz, gr, prt, add_obj_weight) != ZOLTAN_OK) ZOLTAN_PARMETIS_ERROR(ierr, "Error in adding vertex weights."); } /* Get edge weights if needed */ if (gr->get_data) gr->num_edges = gr->xadj[gr->num_obj]; else { gr->num_edges = 0; gr->edge_wgt_dim = 0; } if (gr->edge_wgt_dim){ ierr = Zoltan_Preprocess_Scale_Weights (gr, float_ewgts, &gr->ewgts, gr->num_edges, gr->edge_wgt_dim, 1, zz, "edge", 0); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){ /* Return error code */ ZOLTAN_PARMETIS_ERROR(ierr, "Error in scaling of weights."); } if (!gr->final_output) { ZOLTAN_FREE(&float_ewgts); } else gr->float_ewgts = float_ewgts; } else { ZOLTAN_FREE(&float_ewgts); } if (geo){ ierr = Zoltan_Preprocess_Extract_Geom (zz, global_ids, local_ids, gr, geo); if (ierr) { ZOLTAN_PARMETIS_ERROR(ZOLTAN_FATAL, "Error returned from Zoltan_Preprocess_Extract_Geom"); } } if (vsp) { ierr = Zoltan_Preprocess_Extract_Vsize (zz, global_ids, local_ids, gr, vsp); if (ierr) { ZOLTAN_PARMETIS_ERROR(ZOLTAN_FATAL, "Error returned from Zoltan_Preprocess_Extract_Vsize"); } } /* Scatter graph? * If data distribution is highly imbalanced, it is better to * redistribute the graph data structure before calling ParMetis. * After partitioning, the results must be mapped back. */ if (gr->scatter < gr->scatter_min) gr->scatter = gr->scatter_min; if (gr->scatter>0) { ierr = Zoltan_Preprocess_Scatter_Graph (zz, gr, prt, geo, vsp); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PARMETIS_ERROR(ZOLTAN_FATAL, "Error returned from Zoltan_Preprocess_Scatter_Graph"); } } /* Verify that graph is correct */ if (gr->get_data){ int flag; if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL) flag = 2; /* Maximum output level */ else flag = 1; /* Medium output level */ ierr = Zoltan_Verify_Graph(zz->Communicator, gr->vtxdist, gr->xadj, gr->adjncy, gr->vwgt, gr->ewgts, gr->obj_wgt_dim, gr->edge_wgt_dim, gr->graph_type, gr->check_graph, flag); } End: ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }