/* This function may work on any distribution of the bipartite graph */ int Zoltan_ZG_Register(ZZ* zz, ZG* graph, int* properties) { static char *yo = "Zoltan_ZG_Register"; int ierr = ZOLTAN_OK; int *props; struct Zoltan_DD_Struct *dd; int size; ZOLTAN_ID_PTR GID; ZOLTAN_TRACE_ENTER(zz, yo); size = graph->mtx.mtx.nY; dd = graph->mtx.mtx.ddY; if (graph->bipartite) { /* Need to construct another properties array with only the fixed elements ! */ int vertlno; if (graph->fixObj) { dd = graph->mtx.mtx.ddX; } props = (int*)ZOLTAN_MALLOC(sizeof(int)*size); if (graph->mtx.mtx.nY && props == NULL) MEMORY_ERROR; GID = ZOLTAN_MALLOC_GID_ARRAY(zz, size); if (size && GID == NULL) MEMORY_ERROR; for (size = 0, vertlno = 0 ; vertlno < graph->mtx.mtx.nY ; ++vertlno) { if (graph->fixed_vertices[vertlno]) { props[size] = properties[vertlno]; ZOLTAN_SET_GID(zz, GID+ size*zz->Num_GID, graph->mtx.mtx.yGID+vertlno*zz->Num_GID); size ++; } } } else { props = properties; GID = graph->mtx.mtx.yGID; if (graph->mtx.mtx.ddY == NULL) { ierr = Zoltan_DD_Create (&graph->mtx.mtx.ddY, zz->Communicator, 1, zz->Num_GID, 1, graph->mtx.mtx.globalY/zz->Num_Proc, 0); CHECK_IERR; /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(graph->mtx.mtx.ddY, graph->mtx.mtx.globalX/zz->Num_Proc); } dd = graph->mtx.mtx.ddY; } /* Make our new numbering public */ ierr = Zoltan_DD_Update (dd, GID, NULL, NULL, props, size); CHECK_IERR; End: if (graph->bipartite) { ZOLTAN_FREE(&props); ZOLTAN_FREE(&GID); } ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }
/* Performs a permutation of the matrix, perm_y A perm_y^t. * TODO: at this time we only do symmetric permutations (don't know xGNO !). */ int Zoltan_Matrix_Permute(ZZ* zz, Zoltan_matrix *m, int* perm_y) { static char *yo = "Zoltan_Matrix_Permute"; int ierr = ZOLTAN_OK; int *pinGNO = NULL; ZOLTAN_ID_PTR yGID=NULL; float *ywgt=NULL; struct Zoltan_DD_Struct *dd; ZOLTAN_TRACE_ENTER(zz, yo); /* First apply y permutation */ if (m->completed) { /* We directly know the good arrays */ yGID = m->yGID; ywgt = m->ywgt; if (m->ddY == NULL || m->ddY != m->ddX) { /* We have to create again the DD */ /* We have to define ddY : yGNO, yGID, ywgt */ ierr = Zoltan_DD_Create (&m->ddY, zz->Communicator, 1, zz->Num_GID, m->ywgtdim*sizeof(float)/sizeof(int), m->globalY/zz->Num_Proc, 0); /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(m->ddY, m->globalY/zz->Num_Proc); } } else { /* We have to get these fields */ /* Update data directories */ yGID = ZOLTAN_MALLOC_GID_ARRAY(zz, m->nY); ywgt = (float*) ZOLTAN_MALLOC(m->nY * sizeof(float) * m->ywgtdim); if (m->nY && (yGID == NULL || (m->ywgtdim && ywgt == NULL))) MEMORY_ERROR; /* Get Informations about Y */ Zoltan_DD_Find (m->ddY, (ZOLTAN_ID_PTR)m->yGNO, yGID, (ZOLTAN_ID_PTR)ywgt, NULL, m->nY, NULL); } memcpy (m->yGNO, perm_y, m->nY*sizeof(int)); /* Get Informations about Y */ Zoltan_DD_Update (m->ddY, (ZOLTAN_ID_PTR)m->yGNO, yGID, (ZOLTAN_ID_PTR)ywgt, NULL, m->nY); ZOLTAN_FREE (&yGID); ZOLTAN_FREE (&ywgt); /* We have to define dd : old_yGNO, new_yGNO */ ierr = Zoltan_DD_Create (&dd, zz->Communicator, 1, 1, 0, m->globalY/zz->Num_Proc, 0); /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(dd, m->globalY/zz->Num_Proc); Zoltan_DD_Update (dd, (ZOLTAN_ID_PTR)m->yGNO, (ZOLTAN_ID_PTR)perm_y, NULL, NULL, m->nY); pinGNO = (int*)ZOLTAN_MALLOC(m->nPins*sizeof(int)); if (m->nPins && pinGNO == NULL) MEMORY_ERROR; Zoltan_DD_Find (dd, (ZOLTAN_ID_PTR)m->pinGNO, (ZOLTAN_ID_PTR)pinGNO, NULL, NULL, m->nY, NULL); ZOLTAN_FREE(&m->pinGNO); m->pinGNO = pinGNO; pinGNO = NULL; End: ZOLTAN_FREE (&pinGNO); ZOLTAN_FREE (&yGID); ZOLTAN_FREE (&ywgt); ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }
int Zoltan_Matrix_Build (ZZ* zz, Zoltan_matrix_options *opt, Zoltan_matrix* matrix) { static char *yo = "Zoltan_Matrix_Build"; int ierr = ZOLTAN_OK; int nX; int *xGNO = NULL; ZOLTAN_ID_PTR xLID=NULL; ZOLTAN_ID_PTR xGID=NULL; ZOLTAN_ID_PTR yGID=NULL; ZOLTAN_ID_PTR pinID=NULL; float *xwgt = NULL; int * Input_Parts=NULL; struct Zoltan_DD_Struct *dd = NULL; int *proclist = NULL; int *xpid = NULL; int i; ZOLTAN_TRACE_ENTER(zz, yo); memset (matrix, 0, sizeof(Zoltan_matrix)); /* Set all fields to 0 */ memcpy (&matrix->opts, opt, sizeof(Zoltan_matrix_options)); /**************************************************/ /* Obtain vertex information from the application */ /**************************************************/ ierr = Zoltan_Get_Obj_List(zz, &nX, &xGID, &xLID, zz->Obj_Weight_Dim, &xwgt, &Input_Parts); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error getting object data"); goto End; } ZOLTAN_FREE(&Input_Parts); ZOLTAN_FREE(&xwgt); /*******************************************************************/ /* Assign vertex consecutive numbers (gnos) */ /*******************************************************************/ if (matrix->opts.speed == MATRIX_FULL_DD) { /* Zoltan computes a translation */ if (nX) { xGNO = (int*) ZOLTAN_MALLOC(nX*sizeof(int)); if (xGNO == NULL) MEMORY_ERROR; } ierr = Zoltan_PHG_GIDs_to_global_numbers(zz, xGNO, nX, matrix->opts.randomize, &matrix->globalX); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error assigning global numbers to vertices"); goto End; } ierr = Zoltan_DD_Create (&dd, zz->Communicator, zz->Num_GID, 1, 0, nX, 0); CHECK_IERR; /* Make our new numbering public */ Zoltan_DD_Update (dd, xGID, (ZOLTAN_ID_PTR) xGNO, NULL, NULL, nX); } else { /* We don't want to use the DD */ xGNO = (int *) xGID; MPI_Allreduce(&nX, &matrix->globalX, 1, MPI_INT, MPI_SUM, zz->Communicator); } /* I store : xGNO, xGID, xpid, */ ierr = Zoltan_DD_Create (&matrix->ddX, zz->Communicator, 1, zz->Num_GID, 1, matrix->globalX/zz->Num_Proc, 0); CHECK_IERR; /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(matrix->ddX, matrix->globalX/zz->Num_Proc); /* Associate all the data with our xGNO */ xpid = (int*)ZOLTAN_MALLOC(nX*sizeof(int)); if (nX >0 && xpid == NULL) MEMORY_ERROR; for (i = 0 ; i < nX ; ++i) xpid[i] = zz->Proc; Zoltan_DD_Update (matrix->ddX, (ZOLTAN_ID_PTR)xGNO, xGID, (ZOLTAN_ID_PTR) xpid, NULL, nX); ZOLTAN_FREE(&xpid); if (matrix->opts.pinwgt) matrix->pinwgtdim = zz->Edge_Weight_Dim; else matrix->pinwgtdim = 0; ierr = matrix_get_edges(zz, matrix, &yGID, &pinID, nX, &xGID, &xLID, &xGNO, &xwgt); CHECK_IERR; matrix->nY_ori = matrix->nY; if ((ierr != ZOLTAN_OK) && (ierr != ZOLTAN_WARN)){ goto End; } if (matrix->opts.enforceSquare && matrix->redist) { /* Convert yGID to yGNO using the same translation as x */ /* Needed for graph : rowID = colID */ /* y and x may have different distributions */ matrix->yGNO = (int*)ZOLTAN_MALLOC(matrix->nY * sizeof(int)); if (matrix->nY && matrix->yGNO == NULL) MEMORY_ERROR; ierr = Zoltan_DD_Find (dd, yGID, (ZOLTAN_ID_PTR)(matrix->yGNO), NULL, NULL, matrix->nY, NULL); if (ierr != ZOLTAN_OK) { ZOLTAN_PRINT_ERROR(zz->Proc,yo,"Hyperedge GIDs don't match.\n"); ierr = ZOLTAN_FATAL; goto End; } } if (matrix->opts.local) { /* keep only local edges */ proclist = (int*) ZOLTAN_MALLOC(matrix->nPins*sizeof(int)); if (matrix->nPins && proclist == NULL) MEMORY_ERROR; } else proclist = NULL; /* Convert pinID to pinGNO using the same translation as x */ if (matrix->opts.speed == MATRIX_FULL_DD) { matrix->pinGNO = (int*)ZOLTAN_MALLOC(matrix->nPins* sizeof(int)); if ((matrix->nPins > 0) && (matrix->pinGNO == NULL)) MEMORY_ERROR; ierr = Zoltan_DD_Find (dd, pinID, (ZOLTAN_ID_PTR)(matrix->pinGNO), NULL, NULL, matrix->nPins, proclist); if (ierr != ZOLTAN_OK) { ZOLTAN_PRINT_ERROR(zz->Proc,yo,"Undefined GID found.\n"); ierr = ZOLTAN_FATAL; goto End; } ZOLTAN_FREE(&pinID); Zoltan_DD_Destroy(&dd); dd = NULL; } else { matrix->pinGNO = (int *) pinID; pinID = NULL; } /* if (matrix->opts.local) { /\* keep only local edges *\/ */ /* int *nnz_list; /\* nnz offset to delete *\/ */ /* int nnz; /\* number of nnz to delete *\/ */ /* int i; */ /* nnz_list = (int*) ZOLTAN_MALLOC(matrix->nPins*sizeof(int)); */ /* if (matrix->nPins && nnz_list == NULL) MEMORY_ERROR; */ /* for (i = 0, nnz=0 ; i < matrix->nPins ; ++i) { */ /* if (proclist[i] == zz->Proc) continue; */ /* nnz_list[nnz++] = i; */ /* } */ /* ZOLTAN_FREE(&proclist); */ /* Zoltan_Matrix_Delete_nnz(zz, matrix, nnz, nnz_list); */ /* } */ if (!matrix->opts.enforceSquare) { /* Hyperedges name translation is different from the one of vertices */ matrix->yGNO = (int*)ZOLTAN_CALLOC(matrix->nY, sizeof(int)); if (matrix->nY && matrix->yGNO == NULL) MEMORY_ERROR; /* int nGlobalEdges = 0; */ ierr = Zoltan_PHG_GIDs_to_global_numbers(zz, matrix->yGNO, matrix->nY, matrix->opts.randomize, &matrix->globalY); CHECK_IERR; /* /\**************************************************************************************** */ /* * If it is desired to remove dense edges, divide the list of edges into */ /* * two lists. The ZHG structure will contain the removed edges (if final_output is true), */ /* * and the kept edges will be returned. */ /* ****************************************************************************************\/ */ /* totalNumEdges = zhg->globalHedges; */ /* ierr = remove_dense_edges_matrix(zz, zhg, edgeSizeThreshold, final_output, */ /* &nLocalEdges, &nGlobalEdges, &nPins, */ /* &edgeGNO, &edgeSize, &edgeWeight, &pinGNO, &pinProcs); */ /* if (nGlobalEdges < totalNumEdges){ */ /* /\* re-assign edge global numbers if any edges were removed *\/ */ /* ierr = Zoltan_PHG_GIDs_to_global_numbers(zz, edgeGNO, nLocalEdges, */ /* randomizeInitDist, &totalNumEdges); */ /* if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { */ /* ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error reassigning global numbers to edges"); */ /* goto End; */ /* } */ /* } */ /* We have to define ddY : yGNO, yGID, ywgt */ ierr = Zoltan_DD_Create (&matrix->ddY, zz->Communicator, 1, zz->Num_GID, 0, matrix->globalY/zz->Num_Proc, 0); /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(matrix->ddY, matrix->globalY/zz->Num_Proc); /* Associate all the data with our yGNO */ Zoltan_DD_Update (matrix->ddY, (ZOLTAN_ID_PTR)matrix->yGNO, yGID, NULL, NULL, matrix->nY); } End: ZOLTAN_FREE(&xpid); ZOLTAN_FREE(&xLID); ZOLTAN_FREE(&xGNO); ZOLTAN_FREE(&xGID); ZOLTAN_FREE(&xwgt); ZOLTAN_FREE(&Input_Parts); ZOLTAN_FREE(&proclist); if (dd != NULL) Zoltan_DD_Destroy(&dd); /* Already stored in the DD */ ZOLTAN_FREE(&yGID); ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }
int Zoltan_Matrix_Build (ZZ* zz, Zoltan_matrix_options *opt, Zoltan_matrix* matrix, int request_GNOs, /* Input: Flag indicating calling code needs translation of extra GIDs to GNOs; partial 2D coloring needs this feature. */ int num_requested, /* Input: Local # of GIDs needing translation to GNOs. */ ZOLTAN_ID_PTR requested_GIDs, /* Input: Calling code requests the GNOs for these GIDs */ ZOLTAN_GNO_TYPE *requested_GNOs /* Output: Return GNOs of the requested GIDs. */ ) { static char *yo = "Zoltan_Matrix_Build"; int ierr = ZOLTAN_OK; int nX; ZOLTAN_GNO_TYPE tmp; ZOLTAN_GNO_TYPE *xGNO = NULL; ZOLTAN_ID_PTR xLID=NULL; ZOLTAN_ID_PTR xGID=NULL; ZOLTAN_ID_PTR yGID=NULL; ZOLTAN_ID_PTR pinID=NULL; float *xwgt = NULL; int * Input_Parts=NULL; struct Zoltan_DD_Struct *dd = NULL; int *proclist = NULL; int *xpid = NULL; int i; int gno_size_for_dd; MPI_Datatype zoltan_gno_mpi_type; int use_full_dd = (opt->speed == MATRIX_FULL_DD); int fast_build_base = opt->fast_build_base; matrix->opts.speed = opt->speed; matrix->opts.fast_build_base = opt->fast_build_base; ZOLTAN_TRACE_ENTER(zz, yo); if (num_requested && (!requested_GIDs || !requested_GNOs)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error in requested input; needed arrays are NULL.\n"); } /* ZOLTAN_GNO_TYPE is >= ZOLTAN_ID_TYPE */ gno_size_for_dd = sizeof(ZOLTAN_GNO_TYPE) / sizeof(ZOLTAN_ID_TYPE); zoltan_gno_mpi_type = Zoltan_mpi_gno_type(); memset (matrix, 0, sizeof(Zoltan_matrix)); /* Set all fields to 0 */ memcpy (&matrix->opts, opt, sizeof(Zoltan_matrix_options)); /**************************************************/ /* Obtain vertex information from the application */ /**************************************************/ ierr = Zoltan_Get_Obj_List(zz, &nX, &xGID, &xLID, zz->Obj_Weight_Dim, &xwgt, &Input_Parts); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error getting object data"); goto End; } ZOLTAN_FREE(&Input_Parts); ZOLTAN_FREE(&xwgt); /*******************************************************************/ /* Assign vertex consecutive numbers (gnos) */ /*******************************************************************/ if (use_full_dd) { /* Zoltan computes a translation */ /* Have to use Data Directory if request_GNOs is true. */ if (nX) { xGNO = (ZOLTAN_GNO_TYPE*) ZOLTAN_MALLOC(nX*sizeof(ZOLTAN_GNO_TYPE)); if (xGNO == NULL) MEMORY_ERROR; } ierr = Zoltan_PHG_GIDs_to_global_numbers(zz, xGNO, nX, matrix->opts.randomize, &matrix->globalX); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error assigning global numbers to vertices"); goto End; } ierr = Zoltan_DD_Create (&dd, zz->Communicator, zz->Num_GID, gno_size_for_dd, 0, nX, 0); CHECK_IERR; /* Make our new numbering public */ Zoltan_DD_Update (dd, xGID, (ZOLTAN_ID_PTR) xGNO, NULL, NULL, nX); if (request_GNOs) { Zoltan_DD_Find(dd, requested_GIDs, (ZOLTAN_ID_PTR) requested_GNOs, NULL, NULL, num_requested, NULL); } } else { /* We don't want to use the DD */ /* * KDDKDD 2/10/11 This code cannot work when NUM_GID_ENTRIES>1. * KDDKDD 2/10/11 The assumption is that, if a user sets the * KDDKDD 2/10/11 appropriate parameter to enable this code, the user * KDDKDD 2/10/11 knows that his GIDs are compatible with integers. */ if (sizeof(ZOLTAN_GNO_TYPE) != sizeof(ZOLTAN_ID_TYPE)){ xGNO = (ZOLTAN_GNO_TYPE*) ZOLTAN_MALLOC(nX*sizeof(ZOLTAN_GNO_TYPE)); if (nX && xGNO == NULL) MEMORY_ERROR; for (i=0; i < nX; i++) xGNO[i] = (ZOLTAN_GNO_TYPE)xGID[i] - fast_build_base; } else { xGNO = (ZOLTAN_GNO_TYPE *)xGID; if (fast_build_base) for (i = 0; i < nX; i++) xGNO[i] -= fast_build_base; } for (i = 0; i < num_requested; i++) requested_GNOs[i] = (ZOLTAN_GNO_TYPE)requested_GIDs[i] - fast_build_base; tmp = (ZOLTAN_GNO_TYPE)nX; MPI_Allreduce(&tmp, &matrix->globalX, 1, zoltan_gno_mpi_type, MPI_SUM, zz->Communicator); } /* I store : xGNO, xGID, xpid, */ ierr = Zoltan_DD_Create (&matrix->ddX, zz->Communicator, gno_size_for_dd, zz->Num_GID, sizeof(int), matrix->globalX/zz->Num_Proc, 0); CHECK_IERR; /* Hope a linear assignment will help a little */ if (matrix->globalX/zz->Num_Proc) Zoltan_DD_Set_Neighbor_Hash_Fn1(matrix->ddX, matrix->globalX/zz->Num_Proc); /* Associate all the data with our xGNO */ xpid = (int*)ZOLTAN_MALLOC(nX*sizeof(int)); if (nX >0 && xpid == NULL) MEMORY_ERROR; for (i = 0 ; i < nX ; ++i) xpid[i] = zz->Proc; Zoltan_DD_Update (matrix->ddX, (ZOLTAN_ID_PTR)xGNO, xGID, (char *)xpid, NULL, nX); ZOLTAN_FREE(&xpid); if (matrix->opts.pinwgt) matrix->pinwgtdim = zz->Edge_Weight_Dim; else matrix->pinwgtdim = 0; ierr = matrix_get_edges(zz, matrix, &yGID, &pinID, nX, &xGID, &xLID, &xGNO, &xwgt, use_full_dd); CHECK_IERR; matrix->nY_ori = matrix->nY; if ((ierr != ZOLTAN_OK) && (ierr != ZOLTAN_WARN)){ goto End; } if (matrix->opts.enforceSquare && matrix->redist) { /* Convert yGID to yGNO using the same translation as x */ /* Needed for graph : rowID = colID */ /* y and x may have different distributions */ matrix->yGNO = (ZOLTAN_GNO_TYPE*)ZOLTAN_MALLOC(matrix->nY * sizeof(ZOLTAN_GNO_TYPE)); if (matrix->nY && matrix->yGNO == NULL) { ZOLTAN_FREE(&pinID); MEMORY_ERROR; } ierr = Zoltan_DD_Find (dd, yGID, (ZOLTAN_ID_PTR)(matrix->yGNO), NULL, NULL, matrix->nY, NULL); if (ierr != ZOLTAN_OK) { ZOLTAN_PRINT_ERROR(zz->Proc,yo,"Hyperedge GIDs don't match.\n"); ierr = ZOLTAN_FATAL; ZOLTAN_FREE(&pinID); goto End; } } if (matrix->opts.local) { /* keep only local edges */ proclist = (int*) ZOLTAN_MALLOC(matrix->nPins*sizeof(int)); if (matrix->nPins && proclist == NULL) { ZOLTAN_FREE(&pinID); MEMORY_ERROR; } } else proclist = NULL; /* Convert pinID to pinGNO using the same translation as x */ if (use_full_dd) { matrix->pinGNO = (ZOLTAN_GNO_TYPE*)ZOLTAN_MALLOC(matrix->nPins* sizeof(ZOLTAN_GNO_TYPE)); if ((matrix->nPins > 0) && (matrix->pinGNO == NULL)) { ZOLTAN_FREE(&pinID); MEMORY_ERROR; } ierr = Zoltan_DD_Find (dd, pinID, (ZOLTAN_ID_PTR)(matrix->pinGNO), NULL, NULL, matrix->nPins, proclist); if (ierr != ZOLTAN_OK) { ZOLTAN_PRINT_ERROR(zz->Proc,yo,"Undefined GID found.\n"); ierr = ZOLTAN_FATAL; goto End; } ZOLTAN_FREE(&pinID); Zoltan_DD_Destroy(&dd); dd = NULL; } else { if (sizeof(ZOLTAN_GNO_TYPE) != sizeof(ZOLTAN_ID_TYPE)){ matrix->pinGNO = (ZOLTAN_GNO_TYPE *)ZOLTAN_MALLOC(matrix->nPins * sizeof(ZOLTAN_GNO_TYPE)); if (matrix->nPins && !matrix->pinGNO){ ZOLTAN_FREE(&pinID); MEMORY_ERROR; } for (i=0; i < matrix->nPins; i++) matrix->pinGNO[i] = (ZOLTAN_GNO_TYPE)pinID[i] - fast_build_base; ZOLTAN_FREE(&pinID); } else{ matrix->pinGNO = (ZOLTAN_GNO_TYPE *) pinID; if (fast_build_base) for (i=0; i < matrix->nPins; i++) matrix->pinGNO[i] -= fast_build_base; pinID = NULL; } } /* if (matrix->opts.local) { /\* keep only local edges *\/ */ /* int *nnz_list; /\* nnz offset to delete *\/ */ /* int nnz; /\* number of nnz to delete *\/ */ /* int i; */ /* nnz_list = (int*) ZOLTAN_MALLOC(matrix->nPins*sizeof(int)); */ /* if (matrix->nPins && nnz_list == NULL) MEMORY_ERROR; */ /* for (i = 0, nnz=0 ; i < matrix->nPins ; ++i) { */ /* if (proclist[i] == zz->Proc) continue; */ /* nnz_list[nnz++] = i; */ /* } */ /* ZOLTAN_FREE(&proclist); */ /* Zoltan_Matrix_Delete_nnz(zz, matrix, nnz, nnz_list); */ /* } */ if (!matrix->opts.enforceSquare) { /* Hyperedges name translation is different from the one of vertices */ matrix->yGNO = (ZOLTAN_GNO_TYPE*)ZOLTAN_CALLOC(matrix->nY, sizeof(ZOLTAN_GNO_TYPE)); if (matrix->nY && matrix->yGNO == NULL) MEMORY_ERROR; /* int nGlobalEdges = 0; */ ierr = Zoltan_PHG_GIDs_to_global_numbers(zz, matrix->yGNO, matrix->nY, matrix->opts.randomize, &matrix->globalY); CHECK_IERR; /* /\**************************************************************************************** */ /* * If it is desired to remove dense edges, divide the list of edges into */ /* * two lists. The ZHG structure will contain the removed edges (if final_output is true), */ /* * and the kept edges will be returned. */ /* ****************************************************************************************\/ */ /* totalNumEdges = zhg->globalHedges; */ /* ierr = remove_dense_edges_matrix(zz, zhg, edgeSizeThreshold, final_output, */ /* &nLocalEdges, &nGlobalEdges, &nPins, */ /* &edgeGNO, &edgeSize, &edgeWeight, &pinGNO, &pinProcs); */ /* if (nGlobalEdges < totalNumEdges){ */ /* /\* re-assign edge global numbers if any edges were removed *\/ */ /* ierr = Zoltan_PHG_GIDs_to_global_numbers(zz, edgeGNO, nLocalEdges, */ /* randomizeInitDist, &totalNumEdges); */ /* if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { */ /* ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error reassigning global numbers to edges"); */ /* goto End; */ /* } */ /* } */ /* We have to define ddY : yGNO, yGID, ywgt */ ierr = Zoltan_DD_Create (&matrix->ddY, zz->Communicator, gno_size_for_dd, zz->Num_GID, 0, matrix->globalY/zz->Num_Proc, 0); /* Hope a linear assignment will help a little */ if (matrix->globalY/zz->Num_Proc) Zoltan_DD_Set_Neighbor_Hash_Fn1(matrix->ddY, matrix->globalY/zz->Num_Proc); /* Associate all the data with our yGNO */ Zoltan_DD_Update (matrix->ddY, (ZOLTAN_ID_PTR)matrix->yGNO, yGID, NULL, NULL, matrix->nY); } End: ZOLTAN_FREE(&xpid); ZOLTAN_FREE(&xLID); ZOLTAN_FREE(&xGNO); ZOLTAN_FREE(&xGID); ZOLTAN_FREE(&xwgt); ZOLTAN_FREE(&Input_Parts); ZOLTAN_FREE(&proclist); if (dd != NULL) Zoltan_DD_Destroy(&dd); /* Already stored in the DD */ ZOLTAN_FREE(&yGID); ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }
int Zoltan_Order( ZZ *zz, /* Zoltan structure */ int num_gid_entries, /* # of entries for a global id */ int num_obj, /* Number of objects to order */ ZOLTAN_ID_PTR gids, /* List of global ids (local to this proc) */ /* The application must allocate enough space */ int *rank, /* rank[i] is the rank of gids[i] */ int *iperm /* iperm[rank[i]]=i, only for sequential ordering */ ) { /* * Main user-call for ordering. * Input: * zz, a Zoltan structure with appropriate function pointers set. * gids, a list of global ids or enough space to store such a list * lids, a list of local ids or enough space to store such a list * Output: * num_gid_entries * num_lid_entries * gids, a list of global ids (filled in if empty on entry) * lids, a list of local ids (filled in if empty on entry) * rank, rank[i] is the global rank of gids[i] * Return values: * Zoltan error code. */ char *yo = "Zoltan_Order"; int ierr; double start_time, end_time; double order_time[2] = {0.0,0.0}; char msg[256]; int comm[2],gcomm[2]; ZOLTAN_ORDER_FN *Order_fn; struct Zoltan_Order_Options opt; int * vtxdist = NULL; ZOLTAN_ID_PTR local_gids=NULL, lids=NULL; int local_num_obj; int *local_rank = NULL, *local_iperm=NULL; struct Zoltan_DD_Struct *dd = NULL; ZOLTAN_TRACE_ENTER(zz, yo); if (zz->Proc == zz->Debug_Proc && zz->Debug_Level >= ZOLTAN_DEBUG_PARAMS) Zoltan_Print_Key_Params(zz); start_time = Zoltan_Time(zz->Timer); /* * 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 = gcomm[0]; if (num_gid_entries != zz->Num_GID) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "num_gid_entries doesn't have the good value"); return (ZOLTAN_FATAL); } zz->Order.nbr_objects = num_obj; zz->Order.rank = rank; zz->Order.iperm = iperm; zz->Order.gids = gids; zz->Order.lids = lids; zz->Order.start = NULL; zz->Order.ancestor = NULL; zz->Order.leaves = NULL; zz->Order.nbr_leaves = 0; zz->Order.nbr_blocks = 0; /* * Return if this processor is not in the Zoltan structure's * communicator. */ if (ZOLTAN_PROC_NOT_IN_COMMUNICATOR(zz)) { ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_OK); } /* * Get ordering options from parameter list. */ /* Set default parameter values */ strncpy(opt.method, "PARMETIS", MAX_PARAM_STRING_LEN); #ifdef HAVE_MPI strncpy(opt.order_type, "DIST", MAX_PARAM_STRING_LEN); #else strncpy(opt.order_type, "SERIAL", MAX_PARAM_STRING_LEN); #endif /* HAVE_MPI */ opt.use_order_info = 0; opt.start_index = 0; opt.reorder = 0; Zoltan_Bind_Param(Order_params, "ORDER_METHOD", (void *) opt.method); Zoltan_Bind_Param(Order_params, "ORDER_TYPE", (void *) opt.order_type); Zoltan_Bind_Param(Order_params, "ORDER_START_INDEX", (void *) &opt.start_index); Zoltan_Bind_Param(Order_params, "REORDER", (void *) &opt.reorder); Zoltan_Bind_Param(Order_params, "USE_ORDER_INFO", (void *) &opt.use_order_info); Zoltan_Assign_Param_Vals(zz->Params, Order_params, zz->Debug_Level, zz->Proc, zz->Debug_Proc); zz->Order.start_index = opt.start_index; /* * Check that the user has allocated space for the return args. */ if (!(gids && rank)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Input argument is NULL. Please allocate all required arrays before calling this routine."); ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_FATAL); } /* * Find the selected method. */ if (!strcmp(opt.method, "NONE")) { if (zz->Proc == zz->Debug_Proc && zz->Debug_Level >= ZOLTAN_DEBUG_PARAMS) ZOLTAN_PRINT_WARN(zz->Proc, yo, "Ordering method selected == NONE; no ordering performed\n"); ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_WARN); } #ifdef ZOLTAN_PARMETIS else if (!strcmp(opt.method, "NODEND")) { Order_fn = Zoltan_ParMetis_Order; } else if (!strcmp(opt.method, "METIS")) { Order_fn = Zoltan_ParMetis_Order; /* Set ORDER_METHOD to NODEND and ORDER_TYPE to LOCAL */ strcpy(opt.method, "NODEND"); strcpy(opt.order_type, "LOCAL"); } else if (!strcmp(opt.method, "PARMETIS")) { Order_fn = Zoltan_ParMetis_Order; /* Set ORDER_METHOD to NODEND and ORDER_TYPE to LOCAL */ strcpy(opt.method, "NODEND"); strcpy(opt.order_type, "GLOBAL"); } #endif /* ZOLTAN_PARMETIS */ #ifdef ZOLTAN_SCOTCH else if (!strcmp(opt.method, "SCOTCH")) { Order_fn = Zoltan_Scotch_Order; /* Set ORDER_METHOD to NODEND and ORDER_TYPE to LOCAL */ strcpy(opt.method, "NODEND"); /* strcpy(opt.order_type, "GLOBAL"); */ } #endif /* ZOLTAN_SCOTCH */ else { fprintf(stderr, "%s\n", opt.method); ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Unknown ordering method"); ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_FATAL); } if (!strcmp(opt.order_type, "GLOBAL")) strcpy (opt.order_type, "DIST"); if (!strcmp(opt.order_type, "LOCAL")) strcpy (opt.order_type, "SERIAL"); strcpy(zz->Order.order_type, opt.order_type); /* * Construct the heterogenous machine description. */ ierr = Zoltan_Build_Machine_Desc(zz); if (ierr == ZOLTAN_FATAL) { ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); } ZOLTAN_TRACE_DETAIL(zz, yo, "Done machine description"); /* * Call the actual ordering function. * Compute gid according to the local graph. */ if (zz->Get_Num_Obj != NULL) { local_num_obj = zz->Get_Num_Obj(zz->Get_Num_Obj_Data, &ierr); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Get_Num_Obj."); return (ierr); } } else { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Must register ZOLTAN_NUM_OBJ_FN."); return (ZOLTAN_FATAL); } local_gids = ZOLTAN_MALLOC_GID_ARRAY(zz, local_num_obj); local_rank = (int*) ZOLTAN_MALLOC(local_num_obj*sizeof(int)); local_iperm = (int*) ZOLTAN_MALLOC(local_num_obj*sizeof(int)); lids = ZOLTAN_MALLOC_LID_ARRAY(zz, local_num_obj); ierr = (*Order_fn)(zz, local_num_obj, local_gids, lids, local_rank, local_iperm, &opt); ZOLTAN_FREE(&lids); if (ierr) { sprintf(msg, "Ordering routine returned error code %d.", ierr); if (ierr == ZOLTAN_WARN) { ZOLTAN_PRINT_WARN(zz->Proc, yo, msg); } else { ZOLTAN_PRINT_ERROR(zz->Proc, yo, msg); Zoltan_Multifree(__FILE__, __LINE__, 3, &local_gids, &local_rank, &local_iperm); ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); } } ZOLTAN_TRACE_DETAIL(zz, yo, "Done ordering"); /* Compute inverse permutation if necessary */ if ((!(opt.return_args & RETURN_RANK) && (rank != NULL)) || (!(opt.return_args & RETURN_IPERM) && (iperm != NULL))) { ierr = Zoltan_Get_Distribution(zz, &vtxdist); if (ierr) { /* Error */ ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Zoltan_Get_Distribution.\n"); return (ierr); } if (!(opt.return_args & RETURN_RANK) && (rank != NULL)) { /* Compute rank from iperm */ ZOLTAN_TRACE_DETAIL(zz, yo, "Inverting permutation"); Zoltan_Inverse_Perm(zz, local_iperm, local_rank, vtxdist, opt.order_type, opt.start_index); } else if (!(opt.return_args & RETURN_IPERM) && (iperm != NULL)) { /* Compute iperm from rank */ ZOLTAN_TRACE_DETAIL(zz, yo, "Inverting permutation"); Zoltan_Inverse_Perm(zz, local_rank, local_iperm, vtxdist, opt.order_type, opt.start_index); } ZOLTAN_FREE(&vtxdist); } ZOLTAN_TRACE_DETAIL(zz, yo, "Done Invert Permutation"); /* TODO: Use directly the "graph" structure to avoid to duplicate things. */ /* I store : GNO, rank, iperm */ ierr = Zoltan_DD_Create (&dd, zz->Communicator, zz->Num_GID, (local_rank==NULL)?0:1, (local_iperm==NULL)?0:1, local_num_obj, 0); /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(dd, local_num_obj); /* Associate all the data with our xGNO */ Zoltan_DD_Update (dd, local_gids, (ZOLTAN_ID_PTR)local_rank, (ZOLTAN_ID_PTR) local_iperm, NULL, local_num_obj); ZOLTAN_FREE(&local_gids); ZOLTAN_FREE(&local_rank); ZOLTAN_FREE(&local_iperm); Zoltan_DD_Find (dd, gids, (ZOLTAN_ID_PTR)rank, (ZOLTAN_ID_PTR)iperm, NULL, num_obj, NULL); Zoltan_DD_Destroy(&dd); ZOLTAN_TRACE_DETAIL(zz, yo, "Done Registering results"); end_time = Zoltan_Time(zz->Timer); order_time[0] = end_time - start_time; if (zz->Debug_Level >= ZOLTAN_DEBUG_LIST) { int i; Zoltan_Print_Sync_Start(zz->Communicator, TRUE); printf("ZOLTAN: rank for ordering on Proc %d\n", zz->Proc); for (i = 0; i < num_obj; i++) { printf("GID = "); ZOLTAN_PRINT_GID(zz, &(gids[i*(num_gid_entries)])); printf(", rank = %3d\n", rank[i]); } printf("\n"); Zoltan_Print_Sync_End(zz->Communicator, TRUE); } /* Print timing info */ if (zz->Debug_Level >= ZOLTAN_DEBUG_ZTIME) { if (zz->Proc == zz->Debug_Proc) { printf("ZOLTAN Times: \n"); } Zoltan_Print_Stats (zz->Communicator, zz->Debug_Proc, order_time[0], "ZOLTAN Balance: "); } ZOLTAN_TRACE_EXIT(zz, yo); if (ierr) return (ierr); else return (ZOLTAN_OK); }
int Zoltan_Order ( struct Zoltan_Struct *zz, int num_gid_entries, int num_obj, ZOLTAN_ID_PTR gids, ZOLTAN_ID_PTR permuted_global_ids ) { /* * Main user-call for ordering. * Input: * zz, a Zoltan structure with appropriate function pointers set. * gids, a list of global ids. * num_gid_entries * Output: * permuted_global_ids * Return values: * Zoltan error code. */ char *yo = "Zoltan_Order"; int ierr; double start_time, end_time; double order_time[2] = {0.0,0.0}; char msg[256]; int comm[2],gcomm[2]; ZOLTAN_ORDER_FN *Order_fn; struct Zoltan_Order_Options opt; ZOLTAN_ID_PTR local_gids=NULL, lids=NULL; int local_num_obj; int *local_rank = NULL; struct Zoltan_DD_Struct *dd = NULL; ZOLTAN_TRACE_ENTER(zz, yo); if (zz->Proc == zz->Debug_Proc && zz->Debug_Level >= ZOLTAN_DEBUG_PARAMS) Zoltan_Print_Key_Params(zz); start_time = Zoltan_Time(zz->Timer); /* * 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 = gcomm[0]; if (num_gid_entries != zz->Num_GID) { char msg[253]; sprintf(msg, "num_gid_entries=%d is not equal to parameter setting " "NUM_GID_ENTRIES=%d\n", num_gid_entries, zz->Num_GID); ZOLTAN_PRINT_ERROR(zz->Proc, yo, msg); return (ZOLTAN_FATAL); } zz->Order.nbr_objects = num_obj; zz->Order.start = NULL; zz->Order.ancestor = NULL; zz->Order.leaves = NULL; zz->Order.nbr_leaves = 0; zz->Order.nbr_blocks = 0; /* * Return if this processor is not in the Zoltan structure's * communicator. */ if (ZOLTAN_PROC_NOT_IN_COMMUNICATOR(zz)) { ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_OK); } /* * Get ordering options from parameter list. */ /* Set default parameter values */ #ifdef HAVE_MPI strncpy(opt.method, "PARMETIS", MAX_PARAM_STRING_LEN); strcpy(zz->Order.order_type, "GLOBAL"); #else strncpy(opt.method, "METIS", MAX_PARAM_STRING_LEN); strcpy(zz->Order.order_type, "LOCAL"); #endif /* HAVE_MPI */ opt.use_order_info = 0; opt.start_index = 0; Zoltan_Bind_Param(Order_params, "ORDER_METHOD", (void *) opt.method); Zoltan_Bind_Param(Order_params, "USE_ORDER_INFO", (void *) &opt.use_order_info); Zoltan_Assign_Param_Vals(zz->Params, Order_params, zz->Debug_Level, zz->Proc, zz->Debug_Proc); /* * Check that the user has allocated space for the return args. */ if (num_obj && !(gids && permuted_global_ids)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Input argument is NULL. Please allocate all required arrays before calling this routine."); ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_FATAL); } /* * Find the selected method. */ if (!strcmp(opt.method, "NONE")) { if (zz->Proc == zz->Debug_Proc && zz->Debug_Level >= ZOLTAN_DEBUG_PARAMS) ZOLTAN_PRINT_WARN(zz->Proc, yo, "Ordering method selected == NONE; no ordering performed\n"); ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_WARN); } else if (!strcmp(opt.method, "LOCAL_HSFC")) { Order_fn = Zoltan_LocalHSFC_Order; strcpy(zz->Order.order_type, "LOCAL"); /*MMW, not sure about this*/ } #ifdef ZOLTAN_PARMETIS else if (!strcmp(opt.method, "METIS")) { Order_fn = Zoltan_ParMetis_Order; strcpy(zz->Order.order_type, "LOCAL"); } else if (!strcmp(opt.method, "PARMETIS")) { Order_fn = Zoltan_ParMetis_Order; strcpy(zz->Order.order_type, "GLOBAL"); } #endif /* ZOLTAN_PARMETIS */ #ifdef ZOLTAN_SCOTCH else if (!strcmp(opt.method, "SCOTCH")) { Order_fn = Zoltan_Scotch_Order; strcpy(zz->Order.order_type, "LOCAL"); } else if (!strcmp(opt.method, "PTSCOTCH")) { Order_fn = Zoltan_Scotch_Order; strcpy(zz->Order.order_type, "GLOBAL"); } #endif /* ZOLTAN_SCOTCH */ #ifdef ZOLTAN_HUND else if (!strcasecmp(opt.method, "HUND")) { ierr = Zoltan_HUND(zz, num_gid_entries, num_obj, gids, permuted_global_ids, NULL); goto End; } #endif /* ZOLTAN_HUND */ else { fprintf(stderr, "%s\n", opt.method); ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Unknown ordering method"); ZOLTAN_TRACE_EXIT(zz, yo); return (ZOLTAN_FATAL); } /* TODO : Ask why useful ! */ /* * Construct the heterogenous machine description. */ ierr = Zoltan_Build_Machine_Desc(zz); if (ierr == ZOLTAN_FATAL) { ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); } ZOLTAN_TRACE_DETAIL(zz, yo, "Done machine description"); /************************************ * Check for required query function ************************************/ if (zz->Get_Num_Obj != NULL) { local_num_obj = zz->Get_Num_Obj(zz->Get_Num_Obj_Data, &ierr); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Get_Num_Obj."); return (ierr); } } else { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Must register ZOLTAN_NUM_OBJ_FN."); return (ZOLTAN_FATAL); } /* TODO allocate all this stuff with the graph */ local_gids = ZOLTAN_MALLOC_GID_ARRAY(zz, local_num_obj); local_rank = (int*) ZOLTAN_MALLOC(local_num_obj*sizeof(int)); lids = ZOLTAN_MALLOC_LID_ARRAY(zz, local_num_obj); /* * Call the actual ordering function. * Compute gid according to the local graph. */ ierr = (*Order_fn)(zz, local_num_obj, local_gids, lids, local_rank, NULL, &opt); ZOLTAN_FREE(&lids); if (ierr) { sprintf(msg, "Ordering routine returned error code %d.", ierr); if (ierr == ZOLTAN_WARN) { ZOLTAN_PRINT_WARN(zz->Proc, yo, msg); } else { ZOLTAN_PRINT_ERROR(zz->Proc, yo, msg); Zoltan_Multifree(__FILE__, __LINE__, 2, &local_gids, &local_rank); ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); } } ZOLTAN_TRACE_DETAIL(zz, yo, "Done ordering"); /* TODO: Use directly the "graph" structure to avoid to duplicate things. */ /* TODO: At this time, I consider rank == permuted_global_ids */ /* I store : GNO, rank, permuted GID */ /* MMW: perhaps don't ever use graph here since we need to support geometric orderings, otherwise need if/else */ ierr = Zoltan_DD_Create (&dd, zz->Communicator, zz->Num_GID, (local_rank==NULL)?0:1, 0, local_num_obj, 0); /* Hope a linear assignment will help a little */ if (local_num_obj) Zoltan_DD_Set_Neighbor_Hash_Fn1(dd, local_num_obj); /* Associate all the data with our xGNO */ Zoltan_DD_Update (dd, local_gids, (ZOLTAN_ID_PTR)local_rank, NULL, NULL, local_num_obj); ZOLTAN_FREE(&local_gids); ZOLTAN_FREE(&local_rank); Zoltan_DD_Find (dd, gids, (ZOLTAN_ID_PTR)permuted_global_ids, NULL, NULL, num_obj, NULL); Zoltan_DD_Destroy(&dd); ZOLTAN_TRACE_DETAIL(zz, yo, "Done Registering results"); end_time = Zoltan_Time(zz->Timer); order_time[0] = end_time - start_time; if (zz->Debug_Level >= ZOLTAN_DEBUG_LIST) { int i; Zoltan_Print_Sync_Start(zz->Communicator, TRUE); printf("ZOLTAN: rank for ordering on Proc %d\n", zz->Proc); for (i = 0; i < num_obj; i++) { printf("GID = "); ZOLTAN_PRINT_GID(zz, &(gids[i*(num_gid_entries)])); printf(", rank = %3d\n", permuted_global_ids[i]); } printf("\n"); Zoltan_Print_Sync_End(zz->Communicator, TRUE); } /* Print timing info */ if (zz->Debug_Level >= ZOLTAN_DEBUG_ZTIME) { if (zz->Proc == zz->Debug_Proc) { printf("ZOLTAN Times: \n"); } Zoltan_Print_Stats (zz->Communicator, zz->Debug_Proc, order_time[0], "ZOLTAN Balance: "); } #ifdef ZOLTAN_HUND End: #endif /*ZOLTAN_HUND*/ ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }
int Zoltan_Matrix_Sym(ZZ* zz, Zoltan_matrix *matrix, int bipartite) { static char *yo = "Zoltan_Matrix_Sym"; int ierr = ZOLTAN_OK; Zoltan_Arc *tr_tab = NULL; int i, j, cnt; ZOLTAN_ID_PTR yGID = NULL; int *ypid=NULL; float *pinwgt=NULL; int * ybipart = NULL; ZOLTAN_TRACE_ENTER(zz, yo); if (bipartite || !matrix->opts.enforceSquare) { matrix->bipartite = 1; matrix->redist = 1; } if (matrix->ywgtdim != zz->Obj_Weight_Dim) FATAL_ERROR("Cannot form bipartite graph: vertex and edge weights are not consistant"); matrix->opts.symmetrize = 1; /* Update the data directories */ tr_tab = (Zoltan_Arc*) ZOLTAN_MALLOC(sizeof(Zoltan_Arc)*(matrix->nPins*2+matrix->nY)); if (matrix->nPins && tr_tab == NULL) MEMORY_ERROR; pinwgt = (float*)ZOLTAN_MALLOC((matrix->nPins*2+matrix->nY)*matrix->pinwgtdim*sizeof(float)); for (i = 0 ; i < 2 ; ++i) /* Copy pin weights */ memcpy(pinwgt + i*matrix->nPins*matrix->pinwgtdim*sizeof(float), matrix->pinwgt, matrix->nPins*matrix->pinwgtdim*sizeof(float)); for (i=0, cnt = 0 ; i < matrix->nY ; ++i) { for (j = matrix->ystart[i] ; j < matrix->yend[i] ; ++j) { tr_tab[cnt].GNO[0] = matrix->yGNO[i] + bipartite*matrix->globalX; /* Normal arc */ tr_tab[cnt].GNO[1] = matrix->pinGNO[j]; memcpy(pinwgt + cnt*matrix->pinwgtdim, matrix->pinwgt+j*matrix->pinwgtdim, matrix->pinwgtdim*sizeof(float)); cnt ++; tr_tab[cnt].GNO[0] = matrix->pinGNO[j]; /* Symmetric arc */ tr_tab[cnt].GNO[1] = matrix->yGNO[i] + bipartite*matrix->globalX; /* new ordering */ memcpy(pinwgt + cnt*matrix->pinwgtdim, matrix->pinwgt+j*matrix->pinwgtdim, matrix->pinwgtdim*sizeof(float)); cnt ++; } if (matrix->ystart[i] == matrix->yend[i]) { /* Singleton */ tr_tab[cnt].GNO[0] = matrix->yGNO[i] + bipartite*matrix->globalX; /* Normal arc */ tr_tab[cnt].GNO[1] = -1; cnt ++; } } ZOLTAN_FREE(&matrix->pinwgt); Zoltan_Matrix_Remove_DupArcs(zz, cnt, tr_tab, pinwgt, matrix); ZOLTAN_FREE(&tr_tab); ZOLTAN_FREE(&pinwgt); if (bipartite) { int endX; int * yGNO = NULL; /* Update data directories */ yGID = ZOLTAN_MALLOC_GID_ARRAY(zz, matrix->nY); ypid = (int*) ZOLTAN_MALLOC(matrix->nY*sizeof(int)); ybipart = (int*) ZOLTAN_MALLOC(matrix->nY*sizeof(int)); for (endX = 0 ; endX < matrix->nY ; ++endX) { if (matrix->yGNO[endX] >= matrix->globalX) break; ybipart[endX] = 0; } /* Get Informations about X */ Zoltan_DD_Find (matrix->ddX, (ZOLTAN_ID_PTR)matrix->yGNO, yGID, (ZOLTAN_ID_PTR)ypid, NULL, endX, NULL); yGNO = (int*)ZOLTAN_MALLOC(endX*sizeof(int)); for (i = endX ; i < matrix->nY ; ++i) { yGNO[i-endX] = matrix->yGNO[i] - matrix->globalX; /* TODO: add a something to have the correct ypid */ ybipart[endX] = 1; } /* Get Informations about Y */ Zoltan_DD_Find (matrix->ddY, (ZOLTAN_ID_PTR)yGNO, yGID + endX*zz->Num_GID, NULL, NULL, matrix->nY-endX, NULL); if (matrix->ddY != matrix->ddX) Zoltan_DD_Destroy (&matrix->ddY); Zoltan_DD_Destroy (&matrix->ddX); matrix->globalX += matrix->globalY; matrix->globalY = matrix->globalX; /* I store : xGNO, xGID, xpid, bipart */ ierr = Zoltan_DD_Create (&matrix->ddX, zz->Communicator, 1, zz->Num_GID, 1, matrix->globalX/zz->Num_Proc, 0); matrix->ddY = matrix->ddX; /* Hope a linear assignment will help a little */ Zoltan_DD_Set_Neighbor_Hash_Fn1(matrix->ddX, matrix->globalX/zz->Num_Proc); /* Associate all the data with our xyGNO */ Zoltan_DD_Update (matrix->ddX, (ZOLTAN_ID_PTR)matrix->yGNO, yGID, (ZOLTAN_ID_PTR)ypid, ybipart, matrix->nY); } End: ZOLTAN_FREE(&ybipart); ZOLTAN_FREE(&ypid); ZOLTAN_FREE(&pinwgt); ZOLTAN_FREE(&yGID); ZOLTAN_FREE(&tr_tab); ZOLTAN_TRACE_EXIT(zz, yo); return (ierr); }