From d4254bc45858e4d2e9542e5ddf55bd64a98abb25 Mon Sep 17 00:00:00 2001 From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be> Date: Wed, 7 Sep 2005 14:36:46 +0000 Subject: [PATCH] Added mesh partitioning (added metis) use it now with -partition N for N partitions only works with tets and triangles output should be added (useless for now) --- Common/CommandLine.cpp | 13 +- Common/Context.h | 2 +- Common/DefaultOptions.h | 2 + Common/Options.cpp | 13 +- Common/Options.h | 1 + Graphics/Geom.cpp | 14 +- Mesh/BDS.cpp | 196 +- Mesh/BDS.h | 91 +- Mesh/Create.cpp | 6 +- Mesh/DiscreteSurface.cpp | 292 +- Mesh/Generator.cpp | 5 +- Mesh/Makefile | 5 +- Mesh/Mesh.h | 4 +- Mesh/PartitionMesh.cpp | 195 + Mesh/PartitionMesh.h | 5 + Mesh/Read_Mesh.cpp | 7 +- Metis/Doc/manual.ps | 16447 +++++++++++++++++++++++++++++++++++++ Metis/balance.c | 278 + Metis/bucketsort.c | 43 + Metis/ccgraph.c | 599 ++ Metis/coarsen.c | 83 + Metis/compress.c | 256 + Metis/debug.c | 239 + Metis/defs.h | 161 + Metis/estmem.c | 157 + Metis/fm.c | 194 + Metis/fortran.c | 141 + Metis/frename.c | 312 + Metis/graph.c | 616 ++ Metis/initpart.c | 422 + Metis/kmetis.c | 129 + Metis/kvmetis.c | 130 + Metis/kwayfm.c | 672 ++ Metis/kwayrefine.c | 392 + Metis/kwayvolfm.c | 1778 ++++ Metis/kwayvolrefine.c | 460 ++ Metis/macros.h | 143 + Metis/match.c | 267 + Metis/mbalance.c | 260 + Metis/mbalance2.c | 328 + Metis/mcoarsen.c | 91 + Metis/memory.c | 208 + Metis/mesh.c | 398 + Metis/meshpart.c | 204 + Metis/metis.h | 37 + Metis/mfm.c | 344 + Metis/mfm2.c | 349 + Metis/mincover.c | 259 + Metis/minitpart.c | 355 + Metis/minitpart2.c | 368 + Metis/mkmetis.c | 123 + Metis/mkwayfmh.c | 677 ++ Metis/mkwayrefine.c | 297 + Metis/mmatch.c | 506 ++ Metis/mmd.c | 593 ++ Metis/mpmetis.c | 402 + Metis/mrefine.c | 219 + Metis/mrefine2.c | 55 + Metis/mutil.c | 101 + Metis/myqsort.c | 547 ++ Metis/ometis.c | 764 ++ Metis/parmetis.c | 371 + Metis/pmetis.c | 341 + Metis/pqueue.c | 579 ++ Metis/proto.h | 505 ++ Metis/refine.c | 204 + Metis/rename.h | 418 + Metis/separator.c | 284 + Metis/sfm.c | 1069 +++ Metis/srefine.c | 169 + Metis/stat.c | 287 + Metis/struct.h | 251 + Metis/subdomains.c | 1295 +++ Metis/timing.c | 74 + Metis/util.c | 519 ++ Parser/OpenFile.cpp | 3 +- configure | 54 + configure.in | 32 +- 78 files changed, 38582 insertions(+), 128 deletions(-) create mode 100644 Mesh/PartitionMesh.cpp create mode 100644 Mesh/PartitionMesh.h create mode 100644 Metis/Doc/manual.ps create mode 100644 Metis/balance.c create mode 100644 Metis/bucketsort.c create mode 100644 Metis/ccgraph.c create mode 100644 Metis/coarsen.c create mode 100644 Metis/compress.c create mode 100644 Metis/debug.c create mode 100644 Metis/defs.h create mode 100644 Metis/estmem.c create mode 100644 Metis/fm.c create mode 100644 Metis/fortran.c create mode 100644 Metis/frename.c create mode 100644 Metis/graph.c create mode 100644 Metis/initpart.c create mode 100644 Metis/kmetis.c create mode 100644 Metis/kvmetis.c create mode 100644 Metis/kwayfm.c create mode 100644 Metis/kwayrefine.c create mode 100644 Metis/kwayvolfm.c create mode 100644 Metis/kwayvolrefine.c create mode 100644 Metis/macros.h create mode 100644 Metis/match.c create mode 100644 Metis/mbalance.c create mode 100644 Metis/mbalance2.c create mode 100644 Metis/mcoarsen.c create mode 100644 Metis/memory.c create mode 100644 Metis/mesh.c create mode 100644 Metis/meshpart.c create mode 100644 Metis/metis.h create mode 100644 Metis/mfm.c create mode 100644 Metis/mfm2.c create mode 100644 Metis/mincover.c create mode 100644 Metis/minitpart.c create mode 100644 Metis/minitpart2.c create mode 100644 Metis/mkmetis.c create mode 100644 Metis/mkwayfmh.c create mode 100644 Metis/mkwayrefine.c create mode 100644 Metis/mmatch.c create mode 100644 Metis/mmd.c create mode 100644 Metis/mpmetis.c create mode 100644 Metis/mrefine.c create mode 100644 Metis/mrefine2.c create mode 100644 Metis/mutil.c create mode 100644 Metis/myqsort.c create mode 100644 Metis/ometis.c create mode 100644 Metis/parmetis.c create mode 100644 Metis/pmetis.c create mode 100644 Metis/pqueue.c create mode 100644 Metis/proto.h create mode 100644 Metis/refine.c create mode 100644 Metis/rename.h create mode 100644 Metis/separator.c create mode 100644 Metis/sfm.c create mode 100644 Metis/srefine.c create mode 100644 Metis/stat.c create mode 100644 Metis/struct.h create mode 100644 Metis/subdomains.c create mode 100644 Metis/timing.c create mode 100644 Metis/util.c diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp index 3110ead8e6..2d5137ad01 100644 --- a/Common/CommandLine.cpp +++ b/Common/CommandLine.cpp @@ -1,4 +1,4 @@ -// $Id: CommandLine.cpp,v 1.63 2005-08-22 00:29:11 geuzaine Exp $ +// $Id: CommandLine.cpp,v 1.64 2005-09-07 14:36:44 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -73,6 +73,7 @@ void Print_Usage(char *name){ Msg(DIRECT, " -algo string Select mesh algorithm (iso, tri, aniso, netgen, tetgen)"); Msg(DIRECT, " -smooth int Set number of mesh smoothing steps"); Msg(DIRECT, " -optimize Optimize quality of tetrahedral elements"); + Msg(DIRECT, " -partition int Load a mesh and partition it into $1 parts (METIS is required)"); Msg(DIRECT, " -order int Set mesh order (1, 2)"); Msg(DIRECT, " -scale float Set global scaling factor"); Msg(DIRECT, " -meshscale float Set mesh scaling factor"); @@ -353,6 +354,16 @@ void Get_Options(int argc, char *argv[]) exit(1); } } + else if(!strcmp(argv[i] + 1, "partition")) { + i++; + if(argv[i] != NULL) { + CTX.mesh.nbPartitions = atoi(argv[i++]); + } + else { + fprintf(stderr, ERROR_STR "Missing number\n"); + exit(1); + } + } else if(!strcmp(argv[i] + 1, "smooth")) { i++; if(argv[i] != NULL) diff --git a/Common/Context.h b/Common/Context.h index cc771fa559..d295c34d4c 100644 --- a/Common/Context.h +++ b/Common/Context.h @@ -181,7 +181,7 @@ public : double scaling_factor, lc_factor, rand_factor; int dual, interactive; int light, light_two_side; - int format, nb_smoothing, algo2d, algo3d, order,algo_recombine; + int format, nbPartitions,nb_smoothing, algo2d, algo3d, order,algo_recombine; int point_insertion, speed_max, min_circ_points, constrained_bgmesh; int histogram, initial_only; double normals, tangents, explode; diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index cd9370cfe3..e1bbd3d088 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -954,6 +954,8 @@ StringXNumber MeshOptions_Number[] = { "Global scaling factor applied to the saved mesh" }, { F|O, "Smoothing" , opt_mesh_nb_smoothing , 1. , "Number of smoothing steps applied to the final mesh" }, + { F|O, "Partitioning" , opt_mesh_nb_partitions , 1. , + "Number of partitions applied to the final mesh" }, { F|O, "SmoothNormals" , opt_mesh_smooth_normals , 0. , "Smooth the mesh normals?" }, { F|O, "SpeedMax" , opt_mesh_speed_max , 0. , diff --git a/Common/Options.cpp b/Common/Options.cpp index c5a8397b08..ec9d5a66ea 100644 --- a/Common/Options.cpp +++ b/Common/Options.cpp @@ -1,4 +1,4 @@ -// $Id: Options.cpp,v 1.255 2005-08-24 20:28:42 remacle Exp $ +// $Id: Options.cpp,v 1.256 2005-09-07 14:36:45 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -4396,6 +4396,17 @@ double opt_mesh_nb_smoothing(OPT_ARGS_NUM) return CTX.mesh.nb_smoothing; } +double opt_mesh_nb_partitions(OPT_ARGS_NUM) +{ + if(action & GMSH_SET) + CTX.mesh.nbPartitions = (int)val; + //#if defined(HAVE_FLTK) + // if(WID && (action & GMSH_GUI)) + // WID->mesh_value[0]->value(CTX.mesh.nb_smoothing); + //#endif + return CTX.mesh.nbPartitions; +} + double opt_mesh_algo2d(OPT_ARGS_NUM) { if(action & GMSH_SET){ diff --git a/Common/Options.h b/Common/Options.h index 4496f08d84..b8db3c4166 100644 --- a/Common/Options.h +++ b/Common/Options.h @@ -439,6 +439,7 @@ double opt_mesh_light_two_side(OPT_ARGS_NUM); double opt_mesh_format(OPT_ARGS_NUM); double opt_mesh_msh_file_version(OPT_ARGS_NUM); double opt_mesh_nb_smoothing(OPT_ARGS_NUM); +double opt_mesh_nb_partitions(OPT_ARGS_NUM); double opt_mesh_algo2d(OPT_ARGS_NUM); double opt_mesh_recombine_algo(OPT_ARGS_NUM); double opt_mesh_algo3d(OPT_ARGS_NUM); diff --git a/Graphics/Geom.cpp b/Graphics/Geom.cpp index e116352874..01762f9077 100644 --- a/Graphics/Geom.cpp +++ b/Graphics/Geom.cpp @@ -1,4 +1,4 @@ -// $Id: Geom.cpp,v 1.89 2005-07-04 15:07:40 remacle Exp $ +// $Id: Geom.cpp,v 1.90 2005-09-07 14:36:45 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -150,8 +150,8 @@ void Draw_Curve(void *a, void *b) N = 10 * n; break; } - if(c->Typ == MSH_SEGM_DISCRETE && c->bds) { - BDS_GeomEntity *g = c->bds->get_geom ( c->Num,1); + if(c->Typ == MSH_SEGM_DISCRETE && THEM->bds) { + BDS_GeomEntity *g = THEM->bds->get_geom ( c->Num,1); std::list<BDS_Edge*>::iterator it = g->e.begin(); std::list<BDS_Edge*>::iterator ite = g->e.end(); while (it!=ite){ @@ -349,7 +349,7 @@ void Draw_Polygonal_Surface(Surface * s) if(CTX.geom.light) glEnable(GL_LIGHTING); glEnable(GL_POLYGON_OFFSET_FILL); // always! - BDS_GeomEntity *g = s->bds->get_geom ( s->Num,2); + BDS_GeomEntity *g = THEM->bds->get_geom ( s->Num,2); // if (g->surf) glColor4ubv((GLubyte *) & CTX.color.geom.line); std::list<BDS_Triangle*>::iterator it = g->t.begin(); std::list<BDS_Triangle*>::iterator ite = g->t.end(); @@ -634,7 +634,7 @@ void Draw_Surface(void *a, void *b) glColor4ubv((GLubyte *) & CTX.color.geom.surface); } - if(s->bds){ + if(THEM->bds){ Draw_Polygonal_Surface(s); } else if(s->Typ == MSH_SURF_DISCRETE){ @@ -735,8 +735,8 @@ void HighlightEntity(Vertex * v, Curve * c, Surface * s, int permanent) strcat(Message, "}"); Msg(STATUS1N, Message); } - else if (s->bds){ - BDS_GeomEntity *g = s->bds->get_geom ( s->Num, 2); + else if (THEM->bds){ + BDS_GeomEntity *g = THEM->bds->get_geom ( s->Num, 2); if (g && g->surf) Msg(STATUS1N, "Surface %d (%s)", s->Num,g->surf->nameOf().c_str()); else diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp index 25f2a5b366..e5a0f55747 100644 --- a/Mesh/BDS.cpp +++ b/Mesh/BDS.cpp @@ -402,6 +402,52 @@ BDS_Edge *BDS_Mesh :: find_edge (BDS_Point *p1, BDS_Point *p2, BDS_Triangle *t) return 0; } + +BDS_Triangle *BDS_Mesh::find_triangle (BDS_Edge *e1,BDS_Edge *e2,BDS_Edge *e3) +{ + int i; + for (i=0;i<e1->numfaces();i++) + { + BDS_Triangle *t = e1->faces(i); + BDS_Edge *o1 = t->e1; + BDS_Edge *o2 = t->e2; + BDS_Edge *o3 = t->e3; + if ( (o1 == e1 && o2 == e2 && o3 == e3) || + (o1 == e1 && o2 == e3 && o3 == e2) || + (o1 == e2 && o2 == e1 && o3 == e3) || + (o1 == e2 && o2 == e3 && o3 == e1) || + (o1 == e3 && o2 == e1 && o3 == e2) || + (o1 == e3 && o2 == e2 && o3 == e1) ) return t; + } + for (i=0;i<e2->numfaces();i++) + { + BDS_Triangle *t = e2->faces(i); + BDS_Edge *o1 = t->e1; + BDS_Edge *o2 = t->e2; + BDS_Edge *o3 = t->e3; + if ( (o1 == e1 && o2 == e2 && o3 == e3) || + (o1 == e1 && o2 == e3 && o3 == e2) || + (o1 == e2 && o2 == e1 && o3 == e3) || + (o1 == e2 && o2 == e3 && o3 == e1) || + (o1 == e3 && o2 == e1 && o3 == e2) || + (o1 == e3 && o2 == e2 && o3 == e1) ) return t; + } + for (i=0;i<e3->numfaces();i++) + { + BDS_Triangle *t = e3->faces(i); + BDS_Edge *o1 = t->e1; + BDS_Edge *o2 = t->e2; + BDS_Edge *o3 = t->e3; + if ( (o1 == e1 && o2 == e2 && o3 == e3) || + (o1 == e1 && o2 == e3 && o3 == e2) || + (o1 == e2 && o2 == e1 && o3 == e3) || + (o1 == e2 && o2 == e3 && o3 == e1) || + (o1 == e3 && o2 == e1 && o3 == e2) || + (o1 == e3 && o2 == e2 && o3 == e1) ) return t; + } + return 0; +} + BDS_Edge *BDS_Mesh :: add_edge (int p1, int p2) { BDS_Edge *efound = find_edge (p1,p2); @@ -420,9 +466,15 @@ BDS_Triangle * BDS_Mesh :: add_triangle (int p1, int p2, int p3 ) BDS_Edge *e1=add_edge (p1,p2); BDS_Edge *e2=add_edge (p2,p3); BDS_Edge *e3=add_edge (p3,p1); - // BDS_Edge *e1 = find_edge (p1,p2); - // BDS_Edge *e2 = find_edge (p2,p3); - // BDS_Edge *e3 = find_edge (p3,p1); + return add_triangle(e1,e2,e3); +} + +BDS_Triangle * BDS_Mesh :: add_triangle (BDS_Edge *e1,BDS_Edge *e2,BDS_Edge *e3) +{ + + BDS_Triangle *tfound = find_triangle (e1,e2,e3); + if (tfound)return tfound; + try { BDS_Triangle *t = new BDS_Triangle ( e1, e2, e3 ); triangles.push_back ( t ); @@ -433,6 +485,23 @@ BDS_Triangle * BDS_Mesh :: add_triangle (int p1, int p2, int p3 ) return 0; } } + +BDS_Tet * BDS_Mesh :: add_tet (int p1, int p2, int p3, int p4 ) +{ + BDS_Edge *e1=add_edge (p1,p2); + BDS_Edge *e2=add_edge (p2,p3); + BDS_Edge *e3=add_edge (p3,p1); + BDS_Edge *e4=add_edge (p1,p4); + BDS_Edge *e5=add_edge (p2,p4); + BDS_Edge *e6=add_edge (p3,p4); + BDS_Triangle *t1 = add_triangle (e1,e2,e3); + BDS_Triangle *t2 = add_triangle (e1,e4,e5); + BDS_Triangle *t3 = add_triangle (e2,e6,e5); + BDS_Triangle *t4 = add_triangle (e3,e4,e6); + BDS_Tet *t = new BDS_Tet ( t1, t2, t3, t4 ); + tets.push_back ( t ); + return t; +} void BDS_Mesh :: del_triangle (BDS_Triangle *t) { t->e1->del ( t ); @@ -682,7 +751,7 @@ void BDS_Mesh :: createSearchStructures ( ) printf("creating the ANN search structure\n"); - const double LC_SEARCH = LC *1.e-3; + const double LC_SEARCH = LC *.3e-3; for (std::set<BDS_GeomEntity*,GeomLessThan>::iterator it = geom.begin(); it != geom.end(); @@ -816,29 +885,43 @@ void BDS_Point :: compute_curvature ( ) int compute_curvatures (std::list<BDS_Edge*> &edges) { - std::list<BDS_Edge*>::iterator it = edges.begin(); - std::list<BDS_Edge*>::iterator ite = edges.end(); - while (it != ite) - { - if ((*it)->numfaces() == 2) - { - if ((*it)->faces(0)->g == (*it)->faces(1)->g) - { - BDS_Vector N1=(*it)->faces(0)->N(); - BDS_Vector N2=(*it)->faces(1)->N(); - BDS_Vector C1=(*it)->faces(0)->cog(); - BDS_Vector C2=(*it)->faces(1)->cog(); - BDS_Vector DIFFN = N2-N1; - BDS_Vector DIST = C2-C1; - double crv = 1./sqrt((DIFFN*DIFFN)/(DIST*DIST)); - if ((*it)->p1->radius_of_curvature > crv) - (*it)->p1->radius_of_curvature = crv; - if ((*it)->p2->radius_of_curvature > crv) - (*it)->p2->radius_of_curvature = crv; - } - } - ++it; - } + { + std::list<BDS_Edge*>::iterator it = edges.begin(); + std::list<BDS_Edge*>::iterator ite = edges.end(); + while (it != ite) + { + (*it)->target_length = 1.e22; + (*it)->p1->radius_of_curvature = 1.e22; + (*it)->p2->radius_of_curvature = 1.e22; + ++it; + } + + } + { + std::list<BDS_Edge*>::iterator it = edges.begin(); + std::list<BDS_Edge*>::iterator ite = edges.end(); + while (it != ite) + { + if ((*it)->numfaces() == 2) + { + if ((*it)->faces(0)->g == (*it)->faces(1)->g) + { + BDS_Vector N1=(*it)->faces(0)->N(); + BDS_Vector N2=(*it)->faces(1)->N(); + BDS_Vector C1=(*it)->faces(0)->cog(); + BDS_Vector C2=(*it)->faces(1)->cog(); + BDS_Vector DIFFN = N2-N1; + BDS_Vector DIST = C2-C1; + double crv = 1./sqrt((DIFFN*DIFFN)/(DIST*DIST)); + if ((*it)->p1->radius_of_curvature > crv) + (*it)->p1->radius_of_curvature = crv; + if ((*it)->p2->radius_of_curvature > crv) + (*it)->p2->radius_of_curvature = crv; + } + } + ++it; + } + } } @@ -1685,11 +1768,12 @@ void BDS_Mesh :: cleanup() BDS_Mesh ::~ BDS_Mesh () { - DESTROOOY ( geom.begin(),geom.end()); - DESTROOOY ( points.begin(),points.end()); - cleanup(); - DESTROOOY ( edges.begin(),edges.end()); - DESTROOOY ( triangles.begin(),triangles.end()); + // DESTROOOY ( geom.begin(),geom.end()); + //DESTROOOY ( points.begin(),points.end()); + //cleanup(); + // DESTROOOY ( edges.begin(),edges.end()); + // DESTROOOY ( triangles.begin(),triangles.end()); + // DESTROOOY ( tets.begin(),tets.end()); } bool BDS_Mesh ::split_edge ( BDS_Edge *e, double coord, BDS_Mesh *geom ) @@ -1936,8 +2020,13 @@ bool BDS_Mesh ::collapse_edge ( BDS_Edge *e, BDS_Point *p, const double eps) if (e->numfaces() != 2)return false; if (p->g && p->g->classif_degree == 0)return false; - if (e->g && e->g->classif_degree == 1)return false; - + // not really ok but 'til now this is the best choice not to do collapses on model edges + if (p->g && p->g->classif_degree == 1)return false; + if (e->g && p->g) + { + if(e->g->classif_degree == 2 && p->g != e->g)return false; + } + std::list<BDS_Triangle *> t; BDS_Point *o = e->othervertex (p); @@ -2080,7 +2169,7 @@ bool project_point_on_a_list_of_triangles ( BDS_Point *p , { { double xp,yp,zp; - bool ok = proj_point_triangle ( p->X,p->Y,p->Z,p->N(),*it,xp,yp,zp); + bool ok = proj_point_triangle ( p->X,p->Y,p->Z,(*it)->N(),*it,xp,yp,zp); if (ok) { global_ok = true; @@ -2092,6 +2181,19 @@ bool project_point_on_a_list_of_triangles ( BDS_Point *p , dist2 = d2; } } +// ok = proj_point_triangle ( p->X,p->Y,p->Z,p->N(),*it,xp,yp,zp); +// if (ok) +// { +// global_ok = true; +// double d2 = ((xp-X)*(xp-X)+(yp-Y)*(yp-Y)+(zp-Z)*(zp-Z)); +// if (d2 < dist2 ) +// { +// // printf("one found among %d\n",t.size()); +// XX = xp; YY = yp; ZZ = zp; +// dist2 = d2; +// } +// } + } } ++it; @@ -2209,9 +2311,9 @@ void BDS_Mesh :: compute_metric_edge_lengths (const BDS_Metric & metric) 0.5*(e->p1->Y+e->p2->Y), 0.5*(e->p1->Z+e->p2->Z)); double radius = 1./curvature; - double target = 3.14159 *radius / metric.nb_elements_per_radius_of_curvature; + double target = radius / metric.nb_elements_per_radius_of_curvature; e->target_length = metric.update_target_length (target,e->target_length); - // printf("e1 radius %g target %g length %g mlp %g ml %g\n",radius, target,e->length(),e->length()/target,e->metric_length); + // printf("e1 radius %g target %g length %g mlp %g\n",radius, target,e->length(),e->length()/target); } else { @@ -2264,8 +2366,8 @@ int BDS_Mesh :: adapt_mesh ( double l, bool smooth, BDS_Mesh *geom_mesh) SNAP_SUCCESS = 0; SNAP_FAILURE = 0; - BDS_Metric metric ( l , LC/500 , LC, 3 ); - // printf("METRIC %g %g %g\n",LC,metric._min,metric._max); + BDS_Metric metric ( l , LC/500 , LC, 7 ); + // �pr�intf("METRIC %g %g %g\n",LC,metric._min,metric._max); // add initial set of edges in a list std::list<BDS_Edge*> small_to_long; @@ -2384,7 +2486,7 @@ int BDS_Mesh :: adapt_mesh ( double l, bool smooth, BDS_Mesh *geom_mesh) double qa = (qa1<qa2)?qa1:qa2; double qb = (qb1<qb2)?qb1:qb2; // printf("qa %g qb %g ..\n",qa,qb); - if (qb > qa && d < 0.05 * dd ) + if (qb > qa && d < 0.01 * dd ) { // printf("swop ..\n"); nb_modif++; @@ -2459,5 +2561,19 @@ BDS_Mesh::BDS_Mesh (const BDS_Mesh &other) BDS_Triangle *t = add_triangle(n[0]->iD,n[1]->iD,n[2]->iD); t->g = get_geom ((*it)->g->classif_tag,(*it)->g->classif_degree); t->g->t.push_back(t); + t->status = (*it)->status; + } + + for (std::list<BDS_Tet*>::const_iterator it = other.tets.begin(); + it != other.tets.end(); + ++it) + { + BDS_Point *n[4]; + (*it)->getNodes (n); + BDS_Tet *t = add_tet(n[0]->iD,n[1]->iD,n[2]->iD,n[3]->iD); + t->g = get_geom ((*it)->g->classif_tag,(*it)->g->classif_degree); + // t->g->t.push_back(t); + t->status = (*it)->status; } + } diff --git a/Mesh/BDS.h b/Mesh/BDS.h index f217f688f0..7c8a59c281 100644 --- a/Mesh/BDS.h +++ b/Mesh/BDS.h @@ -14,6 +14,7 @@ #include <math.h> //#include <algorithm> +class BDS_Tet; class BDS_Edge; class BDS_Triangle; class BDS_Mesh; @@ -330,6 +331,7 @@ class BDS_Triangle public: bool deleted; int status; + BDS_Tet *t1,*t2; BDS_Edge *e1,*e2,*e3; BDS_Vector NORMAL; double surface; @@ -337,6 +339,18 @@ public: inline double S() const {return surface;} BDS_GeomEntity *g; + inline BDS_Tet * opposite_tet (BDS_Tet *t) + { + if (t == t1)return t2; + if (t == t2)return t1; + throw; + } + + inline int numtets ( ) const + { + return ( (t1!=0) + (t2 !=0) ); + } + inline BDS_Vector cog() const { BDS_Point *n[3]; @@ -364,8 +378,31 @@ public: n[1] = e1->commonvertex (e2); n[2] = e2->commonvertex (e3); } + + inline void addtet ( BDS_Tet *t) + { + if (!t1) t1 = t; + else if (!t2) t2 = t; + else throw; + } + + inline void del (BDS_Tet *t) + { + if (t == t1) + { + t1 = t2; + t2 = 0; + } + else if (t == t2) + { + t2 = 0; + } + else + throw; + } + BDS_Triangle ( BDS_Edge *A, BDS_Edge *B, BDS_Edge *C) - : deleted (false) , status(0), e1(A),e2(B),e3(C),g(0) + : deleted (false) , status(0), t1(0),t2(0),e1(A),e2(B),e3(C),g(0) { e1->addface(this); e2->addface(this); @@ -374,6 +411,50 @@ public: } }; +class BDS_Tet +{ +public: + bool deleted; + int status; + BDS_Triangle *f1,*f2,*f3,*f4; + double volume; + inline double V() const {return volume;} + BDS_GeomEntity *g; + + inline BDS_Vector cog() const + { + BDS_Point *n[4]; + getNodes (n); + return BDS_Vector ((n[0]->X+n[1]->X+n[2]->X+n[3]->X)/4., + (n[0]->Y+n[1]->Y+n[2]->Y+n[3]->Y)/4., + (n[0]->Z+n[1]->Z+n[2]->Z+n[3]->Z)/4.); + } + + inline void _update () + { + } + + inline void getNodes (BDS_Point *n[4]) const + { + BDS_Point *o[3]; + f1->getNodes (n); + f2->getNodes (o); + if(o[0] != n[0] && o[0] != n[1] &&o[0] != n[2])n[3] = o[0]; + if(o[1] != n[0] && o[1] != n[1] &&o[1] != n[2])n[3] = o[1]; + if(o[2] != n[0] && o[2] != n[1] &&o[2] != n[2])n[3] = o[2]; + } + + BDS_Tet ( BDS_Triangle *A, BDS_Triangle *B, BDS_Triangle *C, BDS_Triangle *D) + : deleted (false) , status(0), f1(A),f2(B),f3(C),f4(D),g(0) + { + f1->addtet(this); + f2->addtet(this); + f3->addtet(this); + f4->addtet(this); + _update(); + } +}; + class BDS_Plane : public BDS_Surface { @@ -399,7 +480,7 @@ public : } virtual double normalCurv ( double x, double y, double z ) const { - return 0.0; + return 1.e-22; } }; @@ -495,15 +576,19 @@ class BDS_Mesh std::set<BDS_Point*,PointLessThan> points; std::list<BDS_Edge*> edges; std::list<BDS_Triangle*> triangles; + std::list<BDS_Tet*> tets; BDS_Point * add_point (int num , double x, double y,double z); BDS_Edge * add_edge (int p1, int p2); void del_point (BDS_Point *p); void del_edge (BDS_Edge *e); - BDS_Triangle *add_triangle (int p1, int p2, int p3); + BDS_Triangle *add_triangle (int p1, int p2, int p3); + BDS_Triangle *add_triangle (BDS_Edge *e1,BDS_Edge *e2,BDS_Edge *e3); + BDS_Tet *add_tet (int p1, int p2, int p3,int p4); void del_triangle (BDS_Triangle *t); void add_geom (int degree, int tag); BDS_Point *find_point (int num); BDS_Edge *find_edge (int p1, int p2); + BDS_Triangle *find_triangle (BDS_Edge *e1,BDS_Edge *e2,BDS_Edge *e3); BDS_Edge *find_edge (BDS_Point *p1, BDS_Point *p2, BDS_Triangle *t)const; BDS_GeomEntity *get_geom (int p1, int p2); bool swap_edge ( BDS_Edge *); diff --git a/Mesh/Create.cpp b/Mesh/Create.cpp index 3ad7e23549..81f5220cf9 100644 --- a/Mesh/Create.cpp +++ b/Mesh/Create.cpp @@ -1,4 +1,4 @@ -// $Id: Create.cpp,v 1.77 2005-07-14 14:28:15 remacle Exp $ +// $Id: Create.cpp,v 1.78 2005-09-07 14:36:45 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -524,7 +524,7 @@ Curve *Create_Curve(int Num, int Typ, int Order, List_T * Liste, {1, 0, 0, 0.0} }; Curve *pC = (Curve *) Malloc(sizeof(Curve)); - pC->bds = 0; + // pC->bds = 0; pC->LinVertexArray = NULL; pC->Color.type = 0; pC->Visible = VIS_GEOM | VIS_MESH; @@ -650,7 +650,7 @@ void Free_Curve(void *a, void *b) Surface *Create_Surface(int Num, int Typ) { Surface *pS = (Surface *) Malloc(sizeof(Surface)); - pS->bds = 0; + // pS->bds = 0; pS->Color.type = 0; pS->Visible = VIS_GEOM | VIS_MESH; pS->Num = Num; diff --git a/Mesh/DiscreteSurface.cpp b/Mesh/DiscreteSurface.cpp index 87b877b378..47d05cc727 100644 --- a/Mesh/DiscreteSurface.cpp +++ b/Mesh/DiscreteSurface.cpp @@ -1,4 +1,4 @@ -// $Id: DiscreteSurface.cpp,v 1.23 2005-08-25 14:56:54 remacle Exp $ +// $Id: DiscreteSurface.cpp,v 1.24 2005-09-07 14:36:45 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -31,73 +31,197 @@ extern Mesh *THEM; extern Context_T CTX; - -void Mesh_To_BDS(Surface *s, BDS_Mesh *m) +extern void Move_SimplexBaseToSimplex(Mesh * M, int dimension); +void Mesh_To_BDS(Mesh *m) { - List_T *vertices = Tree2List ( s->Vertices ) ; + + Msg(STATUS2, "Moving the mesh in the new gmsh structure\n"); + Move_SimplexBaseToSimplex(m, 3); + // create the structure + if (m->bds)delete m->bds; + m->bds = new BDS_Mesh; + PhysicalGroup *p; + + m->bds->Min[0] = m->bds->Min[1] = m->bds->Min[2] = 1.e12; + m->bds->Max[0] = m->bds->Max[1] =m->bds-> Max[2] = -1.e12; + + Msg(STATUS2, "Moving the nodes\n"); + // copy the nodes + List_T *vertices = Tree2List ( m->Vertices ) ; for (int i=0;i<List_Nbr ( vertices ) ;++i) { Vertex *v; List_Read ( vertices, i, &v); - m->add_point (v->Num,v->Pos.X,v->Pos.Y,v->Pos.Z); + if ( v->Pos.X < m->bds->Min [0]) m->bds->Min[0] = v->Pos.X; + if ( v->Pos.Y < m->bds->Min [1]) m->bds->Min[1] = v->Pos.Y; + if ( v->Pos.Z < m->bds->Min [2]) m->bds->Min[2] = v->Pos.Z; + if ( v->Pos.X > m->bds->Max [0]) m->bds->Max[0] = v->Pos.X; + if ( v->Pos.Y > m->bds->Max [1]) m->bds->Max[1] = v->Pos.Y; + if ( v->Pos.Z > m->bds->Max [2]) m->bds->Max[2] = v->Pos.Z; + m->bds->add_point (v->Num,v->Pos.X,v->Pos.Y,v->Pos.Z); } + m->bds->LC = sqrt ((m->bds->Min[0]-m->bds->Max[0])*(m->bds->Min[0]-m->bds->Max[0])+ + (m->bds->Min[1]-m->bds->Max[1])*(m->bds->Min[1]-m->bds->Max[1])+ + (m->bds->Min[2]-m->bds->Max[2])*(m->bds->Min[2]-m->bds->Max[2])); List_Delete (vertices); - List_T *triangles = Tree2List ( s->Simplexes) ; - for (int i=0;i<List_Nbr ( triangles ) ;++i) + + for(int i = 0; i < List_Nbr(m->PhysicalGroups); i++) { + List_Read(m->PhysicalGroups, i, &p); + if(p->Typ == MSH_PHYSICAL_POINT) { + m->bds->add_geom (p->Num,0); + BDS_GeomEntity *g = m->bds->get_geom (p->Num,0); + for(int j = 0; j < List_Nbr(p->Entities); j++) { + int Num; + List_Read(p->Entities, j, &Num); + BDS_Point *ppp = m->bds->find_point (Num); + ppp->g = g; + g->p = ppp; + } + } + } + + Msg(STATUS2, "Moving the curves\n"); + List_T *curves = Tree2List ( m->Curves ) ; + for (int i=0;i<List_Nbr ( curves ) ;++i) { + Curve *c; + List_Read ( curves, i, &c); + m->bds->add_geom ( c->Num, 1); + BDS_GeomEntity *g = m->bds->get_geom (c->Num,1); + List_T *simplices = Tree2List ( c->Simplexes ) ; Simplex *simp; - List_Read ( triangles, i, &simp); - Vertex *v1 = simp->V[0]; - Vertex *v2 = simp->V[1]; - Vertex *v3 = simp->V[2]; - m->add_triangle (v1->Num,v2->Num,v3->Num); + for (int j=0;j<List_Nbr ( simplices) ;++j) + { + List_Read(simplices,j,&simp); + BDS_Edge *edge = m->bds->add_edge (simp->V[0]->Num,simp->V[1]->Num); + edge->g = g; + if (!edge->p1->g)edge->p1->g = g; + if (!edge->p2->g)edge->p2->g = g; + } + List_Delete(simplices); } - List_Delete (triangles); - -} + List_Delete (curves); + Msg(STATUS2, "Moving the surfaces\n"); + List_T *surfaces = Tree2List ( m->Surfaces ) ; + for (int i=0;i<List_Nbr ( surfaces ) ;++i) + { + Surface *s; + List_Read ( surfaces, i, &s); + m->bds->add_geom ( s->Num, 2); + BDS_GeomEntity *g = m->bds->get_geom (s->Num,2); -void BDS_To_Mesh_2(Mesh *m) -{ - Msg(STATUS2, "Moving the surface mesh in the old gmsh structure\n"); - - Tree_Action(m->Vertices, Free_Vertex); - Tree_Delete(m->Vertices); - m->Vertices = Tree_Create(sizeof(Vertex *), compareVertex); + printf("a new surface %d %d is created\n",g->classif_tag,g->classif_degree); - { - std::set<BDS_Point*, PointLessThan>::iterator it = m->bds_mesh->points.begin(); - std::set<BDS_Point*, PointLessThan>::iterator ite = m->bds_mesh->points.end(); - while (it != ite) + List_T *simplices = Tree2List ( s->Simplexes ) ; + Simplex *simp; + for (int j=0;j<List_Nbr ( simplices) ;++j) { - Vertex *vert = Create_Vertex((*it)->iD, (*it)->X,(*it)->Y,(*it)->Z, 1.0, 0.0); - Tree_Add (m->Vertices,&vert); - ++it; + List_Read(simplices,j,&simp); + BDS_Triangle *t = m->bds->add_triangle (simp->V[0]->Num,simp->V[1]->Num,simp->V[2]->Num); + t->g = g; + BDS_Point *n[3]; + t->getNodes (n); + for (int K=0;K<3;K++) + if (!n[K]->g) n[K]->g = g; + if (!t->e1->g)t->e1->g = g; + if (!t->e2->g)t->e2->g = g; + if (!t->e3->g)t->e3->g = g; } + List_Delete(simplices); } - + List_Delete (surfaces); + + Msg(STATUS2, "Moving the %d volumes\n",Tree_Nbr(m->Volumes)); + List_T *volumes = Tree2List ( m->Volumes ) ; + for (int i=0;i<List_Nbr ( volumes ) ;++i) { - std::list<BDS_Edge*>::iterator it = m->bds_mesh->edges.begin(); - std::list<BDS_Edge*>::iterator ite = m->bds_mesh->edges.end(); - while(it!=ite) + Volume *v; + List_Read ( volumes, i, &v); + m->bds->add_geom ( v->Num, 3); + BDS_GeomEntity *g = m->bds->get_geom (v->Num,3); + List_T *simplices = Tree2List ( v->Simplexes ) ; + Simplex *simp; + printf("%d tets\n",List_Nbr ( simplices)); + for (int j=0;j<List_Nbr ( simplices) ;++j) { - BDS_GeomEntity *g = (*it)->g; - if (g && g->classif_degree == 1) - { - Vertex *v1 = FindVertex((*it)->p1->iD, m); - Vertex *v2 = FindVertex((*it)->p2->iD, m); - SimplexBase *simp = Create_SimplexBase(v1,v2,NULL, NULL); - Curve *c = FindCurve (g->classif_tag,m); - if (c) - simp->iEnt = g->classif_tag; - Tree_Insert(c->SimplexesBase, &simp); - } - ++it; + List_Read(simplices,j,&simp); + BDS_Tet *t = m->bds->add_tet (simp->V[0]->Num,simp->V[1]->Num,simp->V[2]->Num,simp->V[3]->Num); + t->g = g; + BDS_Point *n[4]; + t->getNodes (n); + for (int K=0;K<4;K++) + if (!n[K]->g) n[K]->g = g; + if (!t->f1->g) t->f1->g = g; + if (!t->f2->g) t->f2->g = g; + if (!t->f3->g) t->f3->g = g; + if (!t->f4->g) t->f4->g = g; + if (!t->f1->e1->g) t->f1->e1->g = g; + if (!t->f2->e1->g) t->f2->e1->g = g; + if (!t->f3->e1->g) t->f3->e1->g = g; + if (!t->f4->e1->g) t->f4->e1->g = g; + if (!t->f1->e2->g) t->f1->e2->g = g; + if (!t->f2->e2->g) t->f2->e2->g = g; + if (!t->f3->e2->g) t->f3->e2->g = g; + if (!t->f4->e2->g) t->f4->e2->g = g; + if (!t->f1->e3->g) t->f1->e3->g = g; + if (!t->f2->e3->g) t->f2->e3->g = g; + if (!t->f3->e3->g) t->f3->e3->g = g; + if (!t->f4->e3->g) t->f4->e3->g = g; + } + List_Delete(simplices); } - { - std::list<BDS_Triangle*>::iterator it = m->bds_mesh->triangles.begin(); - std::list<BDS_Triangle*>::iterator ite = m->bds_mesh->triangles.end(); - while (it!=ite){ + List_Delete (volumes); + +} +extern int addMeshPartition(int Num, Mesh * M); + +void BDS_To_Mesh_2(Mesh *m) +{ + Msg(STATUS2, "Moving the surface mesh in the old gmsh structure\n"); + + Tree_Action(m->Vertices, Free_Vertex); + Tree_Delete(m->Vertices); + m->Vertices = Tree_Create(sizeof(Vertex *), compareVertex); + + { + std::set<BDS_Point*, PointLessThan>::iterator it = m->bds_mesh->points.begin(); + std::set<BDS_Point*, PointLessThan>::iterator ite = m->bds_mesh->points.end(); + while (it != ite) + { + Vertex *vert = Create_Vertex((*it)->iD, (*it)->X,(*it)->Y,(*it)->Z, 1.0, 0.0); + Tree_Add (m->Vertices,&vert); + ++it; + } + } + + + { + std::list<BDS_Edge*>::iterator it = m->bds_mesh->edges.begin(); + std::list<BDS_Edge*>::iterator ite = m->bds_mesh->edges.end(); + while(it!=ite) + { + BDS_GeomEntity *g = (*it)->g; + if (g && g->classif_degree == 1) + { + Vertex *v1 = FindVertex((*it)->p1->iD, m); + Vertex *v2 = FindVertex((*it)->p2->iD, m); + SimplexBase *simp = Create_SimplexBase(v1,v2,NULL, NULL); + Curve *c = FindCurve (g->classif_tag,m); + if (c) + simp->iEnt = g->classif_tag; + Tree_Insert(c->Simplexes, &simp); + } + ++it; + } + } + { + std::list<BDS_Triangle*>::iterator it = m->bds_mesh->triangles.begin(); + std::list<BDS_Triangle*>::iterator ite = m->bds_mesh->triangles.end(); + while (it!=ite){ + BDS_GeomEntity *g = (*it)->g; + if (g && g->classif_degree == 2) + { BDS_Point *nod[3]; (*it)->getNodes (nod); Vertex *v1 = FindVertex(nod[0]->iD, m); @@ -107,60 +231,100 @@ void BDS_To_Mesh_2(Mesh *m) BDS_GeomEntity *g = (*it)->g; Surface *s = FindSurface (g->classif_tag,m); if(s) + { simp->iEnt = g->classif_tag; + simp->iPart = addMeshPartition((*it)->status, m); + } else - printf("argh\n"); - Tree_Add(s->SimplexesBase, &simp); - ++it; + printf("impossible to find surface %d\n",g->classif_tag); + Tree_Add(s->Simplexes, &simp); + } + ++it; + } + } + { + std::list<BDS_Tet*>::iterator it = m->bds_mesh->tets.begin(); + std::list<BDS_Tet*>::iterator ite = m->bds_mesh->tets.end(); + while (it!=ite){ + BDS_Point *nod[4]; + (*it)->getNodes (nod); + Vertex *v1 = FindVertex(nod[0]->iD, m); + Vertex *v2 = FindVertex(nod[1]->iD, m); + Vertex *v3 = FindVertex(nod[2]->iD, m); + Vertex *v4 = FindVertex(nod[3]->iD, m); + SimplexBase *simp = Create_SimplexBase(v1,v2,v3, v4); + BDS_GeomEntity *g = (*it)->g; + Volume *v = FindVolume (g->classif_tag,m); + if(v) + { + simp->iEnt = g->classif_tag; + simp->iPart = addMeshPartition((*it)->status, m); } + else + printf("argh\n"); + Tree_Add(v->Simplexes, &simp); + ++it; } + } Msg(STATUS2, "Ready"); } + void BDS_To_Mesh(Mesh *m) { Tree_Action(m->Points, Free_Vertex); Tree_Delete(m->Points); + Tree_Action(m->Volumes, Free_Volume); Tree_Action(m->Surfaces, Free_Surface); Tree_Action(m->Curves, Free_Curve); Tree_Delete(m->Surfaces); Tree_Delete(m->Curves); + Tree_Delete(m->Volumes); m->Points = Tree_Create(sizeof(Vertex *), compareVertex); m->Curves = Tree_Create(sizeof(Curve *), compareCurve); m->Surfaces = Tree_Create(sizeof(Surface *), compareSurface); + m->Volumes = Tree_Create(sizeof(Volume *), compareVolume); std::set<BDS_GeomEntity*,GeomLessThan>::iterator it = m->bds->geom.begin(); std::set<BDS_GeomEntity*,GeomLessThan>::iterator ite = m->bds->geom.end(); while (it != ite) { - if ((*it)->classif_degree ==2 ) + if ((*it)->classif_degree ==3 ) + { + Volume *_Vol = 0; + _Vol = FindVolume((*it)->classif_tag, m); + if (!_Vol) + _Vol = Create_Volume((*it)->classif_tag,MSH_VOLUME_DISCRETE); + Tree_Add(m->Volumes, &_Vol); + } + else if ((*it)->classif_degree ==2 ) { Surface *_Surf = 0; _Surf = FindSurface((*it)->classif_tag, m); if (!_Surf) _Surf = Create_Surface((*it)->classif_tag, MSH_SURF_DISCRETE); - _Surf->bds = m->bds; + // _Surf->bds = m->bds; End_Surface(_Surf); - Tree_Add(m->Surfaces, &_Surf); - - - + Tree_Add(m->Surfaces, &_Surf); } else if ((*it)->classif_degree ==1 ) - { + { Curve *_c = 0; _c = FindCurve((*it)->classif_tag, m); if (!_c) _c = Create_Curve((*it)->classif_tag, MSH_SEGM_DISCRETE, 1, NULL, NULL, -1, -1, 0., 1.); - _c->bds = m->bds; + // _c->bds = m->bds; End_Curve(_c); Tree_Add(m->Curves, &_c); } else if ((*it)->classif_degree == 0 ) { - BDS_Point *p = (*it)->p; - Vertex *_v = Create_Vertex(p->iD, p->X,p->Y,p->Z,1,0); - Tree_Add(m->Points, &_v); + BDS_Point *p = (*it)->p; + if (p) + { + Vertex *_v = Create_Vertex(p->iD, p->X,p->Y,p->Z,1,0); + Tree_Add(m->Points, &_v); + } } ++it; } @@ -175,7 +339,7 @@ int MeshDiscreteSurface(Surface *s) { const int NITER = 10; - if(s->bds){ + if(THEM->bds){ Msg(STATUS2, "Discrete Surface Mesh Generator..."); // s->bds is the discrete surface that defines the geometry if(!THEM->bds_mesh){ diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp index 38d062f854..1d803e3a2e 100644 --- a/Mesh/Generator.cpp +++ b/Mesh/Generator.cpp @@ -1,4 +1,4 @@ -// $Id: Generator.cpp,v 1.70 2005-06-10 20:59:15 geuzaine Exp $ +// $Id: Generator.cpp,v 1.71 2005-09-07 14:36:45 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -27,6 +27,7 @@ #include "Context.h" #include "OpenFile.h" #include "Views.h" +#include "PartitionMesh.h" extern Mesh *THEM; extern Context_T CTX; @@ -533,6 +534,8 @@ void mai3d(Mesh * M, int Asked) if(M->status && CTX.mesh.order == 2) Degre2(M->status); + if(M->status > 1 && CTX.mesh.nbPartitions != 1) + PartitionMesh ( M , CTX.mesh.nbPartitions); CTX.threads_lock = 0; CTX.mesh.changed = 1; diff --git a/Mesh/Makefile b/Mesh/Makefile index de5704face..7eb1902c4c 100644 --- a/Mesh/Makefile +++ b/Mesh/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.94 2005-08-22 00:35:06 geuzaine Exp $ +# $Id: Makefile,v 1.95 2005-09-07 14:36:45 remacle Exp $ # # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle # @@ -24,7 +24,7 @@ include ../variables LIB = ../lib/libGmshMesh.a INCLUDE = -I../Numeric -I../NR -I../Common -I../DataStr -I../Geo -I../Mesh\ -I../Graphics -I../Parser -I../Fltk -I../Triangle -I../Tetgen\ - -I../Netgen -I../Netgen/libsrc/include -I../Netgen/libsrc/interface -I../ANN/include + -I../Netgen -I../Netgen/libsrc/include -I../Netgen/libsrc/interface -I../ANN/include -I../Metis CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = 1D_Mesh.cpp \ @@ -67,6 +67,7 @@ SRC = 1D_Mesh.cpp \ Nurbs.cpp \ Interpolation.cpp \ SecondOrder.cpp \ + PartitionMesh.cpp\ Smoothing.cpp \ CrossData.cpp \ Vertex.cpp \ diff --git a/Mesh/Mesh.h b/Mesh/Mesh.h index f369ba33d8..208d016a0f 100644 --- a/Mesh/Mesh.h +++ b/Mesh/Mesh.h @@ -252,7 +252,7 @@ struct _Surf{ CylParam Cyl; Grid_T Grid; // fast search grid ExtrudeParams *Extrude; - BDS_Mesh *bds; + // BDS_Mesh *bds; DrawingColor Color; VertexArray *TriVertexArray; VertexArray *QuadVertexArray; @@ -375,7 +375,7 @@ typedef struct{ CircParam Circle; char functu[256], functv[256], functw[256]; DrawingColor Color; - BDS_Mesh *bds; + // BDS_Mesh *bds; VertexArray *LinVertexArray; }Curve; diff --git a/Mesh/PartitionMesh.cpp b/Mesh/PartitionMesh.cpp new file mode 100644 index 0000000000..d9c509be3b --- /dev/null +++ b/Mesh/PartitionMesh.cpp @@ -0,0 +1,195 @@ +#include "Gmsh.h" +#include "Numeric.h" +#include "Mesh.h" +#include "CAD.h" +#include "Geo.h" +#include "Create.h" +#include "Interpolation.h" +#include "Context.h" +#include "BDS.h" +#include "PartitionMesh.h" +#include "OpenFile.h" +#include "MinMax.h" + +#ifdef HAVE_METIS +extern "C" +{ +#include "metis.h" +} +#endif +extern void Mesh_To_BDS(Mesh *m); +extern void BDS_To_Mesh_2(Mesh *m); +extern void BDS_To_Mesh(Mesh *m); + + +void DeleteMesh(Mesh * M) +{ + List_T *Curves = Tree2List(M->Curves); + for(int i = 0; i < List_Nbr(Curves); i++) { + Curve *c; + List_Read(Curves, i, &c); + Tree_Action(c->Simplexes, Free_SimplexBase); + Tree_Delete(c->Simplexes); + c->Simplexes = Tree_Create(sizeof(SimplexBase *), compareSimplex); + } + List_T *Surfaces = Tree2List(M->Surfaces); + for(int i = 0; i < List_Nbr(Surfaces); i++){ + Surface *s; + List_Read(Surfaces, i, &s); + Tree_Action(s->Simplexes, Free_SimplexBase); + Tree_Delete(s->Simplexes); + s->Simplexes = Tree_Create(sizeof(SimplexBase *), compareSimplex); + } + List_Delete(Surfaces); + + List_T *Volumes = Tree2List(M->Volumes); + for(int i = 0; i < List_Nbr(Volumes); i++){ + Volume *v; + List_Read(Volumes, i, &v); + Tree_Action(v->Simplexes, Free_SimplexBase); + Tree_Delete(v->Simplexes); + v->Simplexes = Tree_Create(sizeof(SimplexBase *), compareSimplex); + } + List_Delete(Volumes); +} + + +void PartitionMesh ( Mesh *M , int NP) +{ + + printf("moving the mesh to BDS\n"); + Mesh_To_BDS (M); + BDS_Mesh *m = M->bds; + printf("partitioning\n"); + PartitionMesh (m,NP); + printf("Moving back to the old data str\n"); + DeleteMesh (M);// BDS_To_Mesh(M); + M->bds_mesh = new BDS_Mesh (*M->bds); + BDS_To_Mesh_2(M); + delete M->bds; + delete M->bds_mesh; + M->bds = 0; + M->bds_mesh = 0; + SetBoundingBox(); +} + +void PartitionMesh ( BDS_Mesh *m , int NP) +{ + +#ifdef HAVE_METIS + // NN = number of nodes of the graph + int dim = (m->tets.size() == 0)?2:3; + int NN = (dim == 2)? m->triangles.size() : m->tets.size() ; + + printf ("%d nodes in the graph\n",NN); + + int *partitionVector = new int[NN]; + int *xadj = new int[NN+2]; + + int totCount = 0; + + std::list<BDS_Triangle*>::iterator it2 = m->triangles.begin(); + std::list<BDS_Tet*>::iterator it3 = m->tets.begin(); + + xadj[0] = 0; + for(int i=0;i<NN;i++) + { + int nbAdj = 0; + if (dim == 2) + { + BDS_Triangle *t = *it2; + t->status = i; + ++it2; + nbAdj = (t->e1->numfaces() + t->e2->numfaces() + t->e3->numfaces() - 3); + totCount += nbAdj; + } + else if (dim == 3) + { + BDS_Tet *t = *it3; + t->status = i; + ++it3; + nbAdj =(t->f1->numtets() + t->f2->numtets() + t->f3->numtets() + t->f4->numtets() - 4); + totCount += nbAdj; + } + xadj[i+1] = xadj[i] + nbAdj; + } + + printf ("Tot Count %d \n",totCount); + + it2 = m->triangles.begin(); + it3 = m->tets.begin(); + + int *adjncy = new int[totCount+1]; + + int count = 0; + + for(int i=0;i<NN;i++) + { + if (dim == 2) + { + BDS_Triangle *t = *it2; + for (int j=0;j<t->e1->numfaces();j++) + { + BDS_Triangle *f = t->e1->faces(j); + if (f != t) adjncy[count++] = f->status; + } + for (int j=0;j<t->e2->numfaces();j++) + { + BDS_Triangle *f = t->e2->faces(j); + if (f != t) adjncy[count++] = f->status; + } + for (int j=0;j<t->e3->numfaces();j++) + { + BDS_Triangle *f = t->e3->faces(j); + if (f != t) adjncy[count++] = f->status; + } + ++it2; + } + else if (dim == 3) + { + BDS_Tet *t = *it3; + BDS_Tet *o = t->f1->opposite_tet (t); + if (o) adjncy[count++] = o->status; + o = t->f2->opposite_tet (t); + if (o) adjncy[count++] = o->status; + o = t->f3->opposite_tet (t); + if (o) adjncy[count++] = o->status; + o = t->f4->opposite_tet (t); + if (o) adjncy[count++] = o->status; + ++it3; + } + } + + int wgtflag = 0; + int numflag = 0; + int options[4]; + options[0] = 0; + int edgecut; + METIS_PartGraphRecursive(&NN,xadj,adjncy,0,0,&wgtflag, + &numflag,&NP,options,&edgecut, + partitionVector); + delete [] xadj; + delete [] adjncy; + + it2 = m->triangles.begin(); + it3 = m->tets.begin(); + + for(int i=0;i<NN;i++) + { + if (dim == 2) + { + BDS_Triangle *t = *it2; + t->status = partitionVector[i]; + ++it2; + } + else if (dim == 3) + { + BDS_Tet *t = *it3; + t->status = partitionVector[i]; + ++it3; + } + } + + delete [] partitionVector; +#endif +} diff --git a/Mesh/PartitionMesh.h b/Mesh/PartitionMesh.h new file mode 100644 index 0000000000..6e22359f88 --- /dev/null +++ b/Mesh/PartitionMesh.h @@ -0,0 +1,5 @@ +#ifndef _PARTITION_MESH_GMSH__ +#define _PARTITION_MESH_GMSH__ +void PartitionMesh ( BDS_Mesh *M , int NP); +void PartitionMesh ( Mesh *M , int NP); +#endif diff --git a/Mesh/Read_Mesh.cpp b/Mesh/Read_Mesh.cpp index 334b3d0f83..e2178c2803 100644 --- a/Mesh/Read_Mesh.cpp +++ b/Mesh/Read_Mesh.cpp @@ -1,4 +1,4 @@ -// $Id: Read_Mesh.cpp,v 1.93 2005-06-20 17:02:46 geuzaine Exp $ +// $Id: Read_Mesh.cpp,v 1.94 2005-09-07 14:36:45 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -28,6 +28,7 @@ #include "MinMax.h" #include "Numeric.h" #include "Context.h" +#include "PartitionMesh.h" extern Context_T CTX; @@ -907,6 +908,7 @@ void Read_Mesh_SMS(Mesh * m, FILE * in) } // Public Read_Mesh routine +extern void Mesh_To_BDS(Mesh *m); void Read_Mesh(Mesh * M, FILE * fp, char *filename, int type) { @@ -928,4 +930,7 @@ void Read_Mesh(Mesh * M, FILE * fp, char *filename, int type) Msg(INFO, "Read mesh file '%s'", filename); Msg(STATUS2N, "Read '%s'", filename); } + if (CTX.mesh.nbPartitions != 1) + PartitionMesh ( M , CTX.mesh.nbPartitions); + // Mesh_To_BDS(M); } diff --git a/Metis/Doc/manual.ps b/Metis/Doc/manual.ps new file mode 100644 index 0000000000..d77abe5658 --- /dev/null +++ b/Metis/Doc/manual.ps @@ -0,0 +1,16447 @@ +%!PS-Adobe-2.0 +%%Creator: dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software +%%Title: manual.dvi +%%Pages: 44 +%%PageOrder: Ascend +%%BoundingBox: 0 0 612 792 +%%DocumentFonts: Helvetica-Bold MTSYN AvantGarde-Demi Helvetica +%%+ Times-Roman Times-Italic Times-Bold Helvetica-Narrow-Bold +%%+ Helvetica-Narrow ZapfDingbats RMTMI Courier Times-BoldItalic +%%+ Helvetica-Narrow-Oblique Courier-Oblique MTEX +%%DocumentPaperSizes: Letter +%%EndComments +%DVIPSCommandLine: dvips -o manual.ps manual +%DVIPSParameters: dpi=600, comments removed +%DVIPSSource: TeX output 1998.09.20:1257 +%%BeginProcSet: tex.pro +<< /Duplex true >> setpagedevice % GK +/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N +/X{S N}B /TR{translate}N /isls false N /vsize 11 72 mul N /hsize 8.5 72 +mul N /landplus90{false}def /@rigin{isls{[0 landplus90{1 -1}{-1 1} +ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale +isls{landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div +hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul +TR[matrix currentmatrix{dup dup round sub abs 0.00001 lt{round}if} +forall round exch round exch]setmatrix}N /@landscape{/isls true N}B +/@manualfeed{statusdict /manualfeed true put}B /@copies{/#copies X}B +/FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{ +/nn 8 dict N nn begin /FontType 3 N /FontMatrix fntrx N /FontBBox FBB N +string /base X array /BitMaps X /BuildChar{CharBuilder}N /Encoding IE N +end dup{/foo setfont}2 array copy cvx N load 0 nn put /ctr 0 N[}B /df{ +/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0] +N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data dup +length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{ +128 ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub +get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data +dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N +/rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup +/base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx +0 ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff +setcachedevice ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff +.1 sub]{ch-image}imagemask restore}B /D{/cc X dup type /stringtype ne{]} +if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{dup dup +length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}B /I{ +cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin +0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul +add .99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore userdict +/eop-hook known{eop-hook}if showpage}N /@start{userdict /start-hook +known{start-hook}if pop /VResolution X /Resolution X 1000 div /DVImag X +/IE 256 array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for +65781.76 div /vsize X 65781.76 div /hsize X}N /p{show}N /RMat[1 0 0 -1 0 +0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X /rulex X V}B /V +{}B /RV statusdict begin /product where{pop product dup length 7 ge{0 7 +getinterval dup(Display)eq exch 0 4 getinterval(NeXT)eq or}{pop false} +ifelse}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale rulex ruley false +RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR rulex ruley scale 1 1 +false RMat{BDot}imagemask grestore}}ifelse B /QV{gsave newpath transform +round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg +rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail +{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M} +B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{ +4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{ +p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p +a}B /bos{/SS save N}B /eos{SS restore}B end +%%EndProcSet +%%BeginProcSet: psfrag.pro +userdict begin +/PSfragLib 90 dict def +/PSfragDict 6 dict def +/PSfrag { PSfragLib begin load exec end } bind def +end +PSfragLib begin +/RO /readonly load def +/CP /currentpoint load def +/CM /currentmatrix load def +/B { bind RO def } bind def +/X { exch def } B +/MD { { X } forall } B +/OE { end exec PSfragLib begin } B +/tstr 8 string def +/islev2 { languagelevel } stopped { false } { 2 ge } ifelse def +[ /tM /srcM /dstM /dM /idM /srcFM /dstFM ] { matrix def } forall +dM defaultmatrix RO idM invertmatrix RO pop +srcFM identmatrix pop +/Hide { gsave { CP } stopped not newpath clip { moveto } if } B +/Unhide { { CP } stopped not grestore { moveto } if } B +/setrepl islev2 {{ /glob currentglobal def true setglobal array astore + globaldict exch /PSfrags exch put glob setglobal }} + {{ array astore /PSfrags X }} ifelse B +/getrepl islev2 {{ globaldict /PSfrags get aload length }} + {{ PSfrags aload length }} ifelse B +/convert { + /src X src length string + /c 0 def src length { + dup c src c get dup 32 lt { pop 32 } if put /c c 1 add def + } repeat +} B +/Begin { + /saver save def + srcFM exch 3 exch put + 0 ne /debugMode X 0 setrepl + dup /S exch dict def { S 3 1 roll exch convert exch put } repeat + srcM CM dup invertmatrix pop + mark { currentdict { end } stopped { pop exit } if } loop + PSfragDict counttomark { begin } repeat pop +} B +/End { + mark { currentdict end dup PSfragDict eq { pop exit } if } loop + counttomark { begin } repeat pop + getrepl saver restore + 7 idiv dup /S exch dict def { + 6 array astore /mtrx X tstr cvs /K X + S K [ S K known { S K get aload pop } if mtrx ] put + } repeat +} B +/Place { + tstr cvs /K X + S K known { + bind /proc X tM CM pop + CP /cY X /cX X + 0 0 transform idtransform neg /aY X neg /aX X + S K get dup length /maxiter X + /iter 1 def { + iter maxiter ne { /saver save def } if + tM setmatrix aX aY translate + [ exch aload pop idtransform ] concat + cX neg cY neg translate cX cY moveto + /proc load OE + iter maxiter ne { saver restore /iter iter 1 add def } if + } forall + /noXY { CP /cY X /cX X } stopped def + tM setmatrix noXY { newpath } { cX cY moveto } ifelse + } { + Hide OE Unhide + } ifelse +} B +/normalize { + 2 index dup mul 2 index dup mul add sqrt div + dup 4 -1 roll exch mul 3 1 roll mul +} B +/replace { + aload pop MD + CP /bY X /lX X gsave initmatrix + str stringwidth abs exch abs add dup 0 eq + { pop } { 360 exch div dup scale } ifelse + lX neg bY neg translate newpath lX bY moveto + str { /ch X ( ) dup 0 ch put false charpath ch Kproc } forall + flattenpath pathbbox [ /uY /uX /lY /lX ] MD + CP grestore moveto + currentfont /FontMatrix get dstFM copy dup + 0 get 0 lt { uX lX /uX X /lX X } if + 3 get 0 lt { uY lY /uY X /lY X } if + /cX uX lX add 0.5 mul def + /cY uY lY add 0.5 mul def + debugMode { gsave 0 setgray 1 setlinewidth + lX lY moveto lX uY lineto uX uY lineto uX lY lineto closepath + lX bY moveto uX bY lineto lX cY moveto uX cY lineto + cX lY moveto cX uY lineto stroke + grestore } if + dstFM dup invertmatrix dstM CM srcM + 2 { dstM concatmatrix } repeat pop + getrepl /temp X + S str convert get { + aload pop [ /rot /scl /loc /K ] MD + /aX cX def /aY cY def + loc { + dup 66 eq { /aY bY def } { % B + dup 98 eq { /aY lY def } { % b + dup 108 eq { /aX lX def } { % l + dup 114 eq { /aX uX def } { % r + dup 116 eq { /aY uY def } % t + if } ifelse } ifelse } ifelse } ifelse pop + } forall + K srcFM rot tM rotate dstM + 2 { tM concatmatrix } repeat aload pop pop pop + 2 { scl normalize 4 2 roll } repeat + aX aY transform + /temp temp 7 add def + } forall + temp setrepl +} B +/Rif { + S 3 index convert known { pop replace } { exch pop OE } ifelse +} B +/XA { bind [ /Kproc /str } B /XC { ] 2 array astore def } B +/xs { pop } XA XC +/xks { /kern load OE } XA /kern XC +/xas { pop ax ay rmoveto } XA /ay /ax XC +/xws { c eq { cx cy rmoveto } if } XA /c /cy /cx XC +/xaws { ax ay rmoveto c eq { cx cy rmoveto } if } + XA /ay /ax /c /cy /cx XC +/raws { xaws { awidthshow } Rif } B +/rws { xws { widthshow } Rif } B +/rks { xks { kshow } Rif } B +/ras { xas { ashow } Rif } B +/rs { xs { show } Rif } B +/rrs { getrepl dup 2 add -1 roll restore setrepl } B +PSfragDict begin +islev2 not { /restore { /rrs PSfrag } B } if +/show { /rs PSfrag } B +/kshow { /rks PSfrag } B +/ashow { /ras PSfrag } B +/widthshow { /rws PSfrag } B +/awidthshow { /raws PSfrag } B +end PSfragDict RO pop +end + +%%EndProcSet +%%BeginFont: Helvetica-Bold +% @@psencodingfile@{ +% author = "S. Rahtz, P. MacKay, Alan Jeffrey, B. Horn, K. Berry", +% version = "0.6", +% date = "22 June 1996", +% filename = "8r.enc", +% email = "kb@@mail.tug.org", +% address = "135 Center Hill Rd. // Plymouth, MA 02360", +% codetable = "ISO/ASCII", +% checksum = "119 662 4424", +% docstring = "Encoding for TrueType or Type 1 fonts to be used with TeX." +% @} +% +% Idea is to have all the characters normally included in Type 1 fonts +% available for typesetting. This is effectively the characters in Adobe +% Standard Encoding + ISO Latin 1 + extra characters from Lucida. +% +% Character code assignments were made as follows: +% +% (1) the Windows ANSI characters are almost all in their Windows ANSI +% positions, because some Windows users cannot easily reencode the +% fonts, and it makes no difference on other systems. The only Windows +% ANSI characters not available are those that make no sense for +% typesetting -- rubout (127 decimal), nobreakspace (160), softhyphen +% (173). quotesingle and grave are moved just because it's such an +% irritation not having them in TeX positions. +% +% (2) Remaining characters are assigned arbitrarily to the lower part +% of the range, avoiding 0, 10 and 13 in case we meet dumb software. +% +% (3) Y&Y Lucida Bright includes some extra text characters; in the +% hopes that other PostScript fonts, perhaps created for public +% consumption, will include them, they are included starting at 0x12. +% +% (4) Remaining positions left undefined are for use in (hopefully) +% upward-compatible revisions, if someday more characters are generally +% available. +% +% (5) hyphen appears twice for compatibility with both ASCII and Windows. +% +/TeXBase1Encoding [ +% 0x00 (encoded characters from Adobe Standard not in Windows 3.1) + /.notdef /dotaccent /fi /fl + /fraction /hungarumlaut /Lslash /lslash + /ogonek /ring /.notdef + /breve /minus /.notdef +% These are the only two remaining unencoded characters, so may as +% well include them. + /Zcaron /zcaron +% 0x10 + /caron /dotlessi +% (unusual TeX characters available in, e.g., Lucida Bright) + /dotlessj /ff /ffi /ffl + /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef + % very contentious; it's so painful not having quoteleft and quoteright + % at 96 and 145 that we move the things normally found there down to here. + /grave /quotesingle +% 0x20 (ASCII begins) + /space /exclam /quotedbl /numbersign + /dollar /percent /ampersand /quoteright + /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash +% 0x30 + /zero /one /two /three /four /five /six /seven + /eight /nine /colon /semicolon /less /equal /greater /question +% 0x40 + /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O +% 0x50 + /P /Q /R /S /T /U /V /W + /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore +% 0x60 + /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o +% 0x70 + /p /q /r /s /t /u /v /w + /x /y /z /braceleft /bar /braceright /asciitilde + /.notdef % rubout; ASCII ends +% 0x80 + /.notdef /.notdef /quotesinglbase /florin + /quotedblbase /ellipsis /dagger /daggerdbl + /circumflex /perthousand /Scaron /guilsinglleft + /OE /.notdef /.notdef /.notdef +% 0x90 + /.notdef /.notdef /.notdef /quotedblleft + /quotedblright /bullet /endash /emdash + /tilde /trademark /scaron /guilsinglright + /oe /.notdef /.notdef /Ydieresis +% 0xA0 + /.notdef % nobreakspace + /exclamdown /cent /sterling + /currency /yen /brokenbar /section + /dieresis /copyright /ordfeminine /guillemotleft + /logicalnot + /hyphen % Y&Y (also at 45); Windows' softhyphen + /registered + /macron +% 0xD0 + /degree /plusminus /twosuperior /threesuperior + /acute /mu /paragraph /periodcentered + /cedilla /onesuperior /ordmasculine /guillemotright + /onequarter /onehalf /threequarters /questiondown +% 0xC0 + /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla + /Egrave /Eacute /Ecircumflex /Edieresis + /Igrave /Iacute /Icircumflex /Idieresis +% 0xD0 + /Eth /Ntilde /Ograve /Oacute + /Ocircumflex /Otilde /Odieresis /multiply + /Oslash /Ugrave /Uacute /Ucircumflex + /Udieresis /Yacute /Thorn /germandbls +% 0xE0 + /agrave /aacute /acircumflex /atilde + /adieresis /aring /ae /ccedilla + /egrave /eacute /ecircumflex /edieresis + /igrave /iacute /icircumflex /idieresis +% 0xF0 + /eth /ntilde /ograve /oacute + /ocircumflex /otilde /odieresis /divide + /oslash /ugrave /uacute /ucircumflex + /udieresis /yacute /thorn /ydieresis +] def +%%EndFont +%%BeginFont: MTSYN + +% MathTime fonts were designed by Michael Spivak. +% Copyright (c) 1996 Publish or Perish, Inc. +% Hinting Copyright (c) 1996 Y&Y, Inc. +% MathTime is a registered trademark of Publish or Perish, Inc. + +11 dict begin +/FontInfo 9 dict dup begin +/version (1.000) readonly def +/Notice (Copyright (c) 1992-1996 Publish or Perish and Y&Y, Inc.) readonly def +/FullName (MTSYN) readonly def +/FamilyName (MathTime) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /MTSYN def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 161 /minus put +dup 162 /periodcentered put +dup 163 /multiply put +dup 164 /asteriskmath put +dup 165 /divide put +dup 166 /diamondmath put +dup 167 /plusminus put +dup 168 /minusplus put +dup 169 /circleplus put +dup 170 /circleminus put +dup 173 /circlemultiply put +dup 174 /circledivide put +dup 175 /circledot put +dup 176 /circlecopyrt put +dup 177 /openbullet put +dup 178 /bullet put +dup 179 /equivasymptotic put +dup 180 /equivalence put +dup 181 /reflexsubset put +dup 182 /reflexsuperset put +dup 183 /lessequal put +dup 184 /greaterequal put +dup 185 /precedesequal put +dup 186 /followsequal put +dup 187 /similar put +dup 188 /approxequal put +dup 189 /propersubset put +dup 190 /propersuperset put +dup 191 /lessmuch put +dup 192 /greatermuch put +dup 193 /precedes put +dup 194 /follows put +dup 195 /arrowleft put +dup 196 /spade put +dup 128 /arrowleft put +dup 0 /minus put +dup 1 /periodcentered put +dup 2 /multiply put +dup 3 /asteriskmath put +dup 4 /divide put +dup 5 /diamondmath put +dup 6 /plusminus put +dup 7 /minusplus put +dup 8 /circleplus put +dup 9 /circleminus put +dup 10 /circlemultiply put +dup 11 /circledivide put +dup 12 /circledot put +dup 13 /circlecopyrt put +dup 14 /openbullet put +dup 15 /bullet put +dup 16 /equivasymptotic put +dup 17 /equivalence put +dup 18 /reflexsubset put +dup 19 /reflexsuperset put +dup 20 /lessequal put +dup 21 /greaterequal put +dup 22 /precedesequal put +dup 23 /followsequal put +dup 24 /similar put +dup 25 /approxequal put +dup 26 /propersubset put +dup 27 /propersuperset put +dup 28 /lessmuch put +dup 29 /greatermuch put +dup 30 /precedes put +dup 31 /follows put +dup 32 /arrowleft put +dup 33 /arrowright put +dup 34 /arrowup put +dup 35 /arrowdown put +dup 36 /arrowboth put +dup 37 /arrownortheast put +dup 38 /arrowsoutheast put +dup 39 /similarequal put +dup 40 /arrowdblleft put +dup 41 /arrowdblright put +dup 42 /arrowdblup put +dup 43 /arrowdbldown put +dup 44 /arrowdblboth put +dup 45 /arrownorthwest put +dup 46 /arrowsouthwest put +dup 47 /proportional put +dup 48 /prime put +dup 49 /infinity put +dup 50 /element put +dup 51 /owner put +dup 52 /triangle put +dup 53 /triangleinv put +dup 54 /negationslash put +dup 55 /mapsto put +dup 56 /universal put +dup 57 /existential put +dup 58 /logicalnot put +dup 59 /emptyset put +dup 60 /Rfractur put +dup 61 /Ifractur put +dup 62 /latticetop put +dup 63 /perpendicular put +dup 64 /aleph put +dup 65 /tie put +dup 66 /openbullet1 put +dup 67 /plus put +dup 68 /equal put +dup 69 /vector put +dup 70 /triangleright put +dup 71 /triangleleft put +dup 72 /equal1 put +dup 73 /semicolon put +dup 74 /grave put +dup 75 /acute put +dup 76 /caron put +dup 77 /breve put +dup 78 /macron put +dup 79 /circumflex put +dup 80 /dotaccent put +dup 81 /tilde put +dup 82 /dieresis put +dup 83 /overbar put +dup 84 /bracketleft put +dup 85 /bracketright put +dup 86 /colon put +dup 87 /exclam put +dup 88 /setminus put +dup 89 /cupproduct put +dup 90 /capproduct put +dup 91 /union put +dup 92 /intersection put +dup 93 /unionmulti put +dup 94 /logicaland put +dup 95 /logicalor put +dup 96 /turnstileleft put +dup 97 /turnstileright put +dup 98 /floorleft put +dup 99 /floorright put +dup 100 /ceilingleft put +dup 101 /ceilingright put +dup 102 /braceleft put +dup 103 /braceright put +dup 104 /angbracketleft put +dup 105 /angbracketright put +dup 106 /bar put +dup 107 /bardbl put +dup 108 /arrowbothv put +dup 109 /arrowdblbothv put +dup 110 /backslash put +dup 111 /wreathproduct put +dup 112 /radical put +dup 113 /coproduct put +dup 114 /nabla put +dup 115 /integral put +dup 116 /unionsq put +dup 117 /intersectionsq put +dup 118 /subsetsqequal put +dup 119 /supersetsqequal put +dup 120 /club1 put +dup 121 /club2 put +dup 122 /spade1 put +dup 123 /spade2 put +dup 124 /club put +dup 125 /diamond put +dup 126 /heart put +dup 127 /spade put +dup 132 /radical1 put +dup 160 /space put +readonly def +/FontBBox{0 -954 1043 900}readonly def +/UniqueID 5087393 def +currentdict end +currentfile eexec +80347982AB3942D930E069A70D0D48311E252234D51741E18DB3A68E8AD1024229E5817A10E796 +A78D2C7F7C1F50961B9A57AA604C9F821DBF5A9295197BC66631678D7D2C7E1F8F2151CE0C29EF +CE46270570F4301C5DAD1B38884732E53DAD05DFC36B020E726CA575F71F04ABF2B49E1F1D6D2A +08A477658CA9A48F1C8CCE14382F0A42201DE56E2821EE2B0E91A818B1B753D810EC2428DAE515 +3B66AF66A6CBCBA4DB2BF926E909644DB41326E327493B2750168D128A100FE56C76B17C16F9CE +939588D19C6E9CDA7CB062196E66E38E537670953934FFC63663C7146A12277D8F7C13B563981D +696E0ABE4478EABEBA753024EBDF3EE17F2613DF08C9228159906A48DDEED6212332EF96023E5C +73EA55AAC6A2B938138EC26B4732C11E8FED889257E9D4F2002935585D9AA2265929948E37BAB7 +ADF12F1A22B3C68D09A6B6C4E14B1470ECF0874D92D964CFBB8E2A0E4CBD1A114CC05BBDEE4699 +A576AB8C0BD8499B166E9E60B21F45561279F6474BB497E3D55DD09A26264FFA6E8D9F228E894C +456756D321BB5D5932C5BBCD39EB95F5B7D4DC2DA25D6773EA6BF8B758972BEF890ED520777E90 +B017BB4F0F1A7076DA33C972773E8ECFDF76B347FE529109A1EA0D91B80161C32E4DFB08EF07F2 +3680182631BAF1BEA4A5B9E505311402D9263290E3CF4409B44EDFE28038A0F2101424A9AA4CE8 +3A902FAAA4EE6DA88833898CD9EFB74A321458332CC9A62C93501CD1EB799C6DA44F94C61ADA58 +024D0CED31CD07BA36A70D986AAAD1D3B9C04D6ACBA7ECAE982A8712BA24B26BC4BF9B042C6FCC +9BF7D3404804E72D2B93FD4F56771495070AA0FD181C35CC11CF251BE8DEA12600643F2B79D09A +A1BCF2636F70EDF1F7E0E434DF83B888598ECE0100492A48645305B4BB8BF16CC994ABDAF88EE7 +CA62FA459E421580531F5BDFD3BD83467260F184AFA17ABFF39208581863ACD6632867C05EC9C1 +1A910E396F09359713C5B37AE855D3A2FF8657FB89CAD579EB1BAA0979EB227202E44306B7C89D +6B32C41795F994B293A6BAF7DF640C3F68CBA7674E695121892C8DF86D2C12158D6628BA8643AF +6C51D4241FE528EEAC4653FE8A99CC319F7B1351325AA04461810D536E61F220D309E0BF6A55EB +EB2D1605B65B5550F6DF814FC3E80ADD43E595DFD4C947C4126521D740199C6F98826DE413EDA3 +0F7D91CAF64987B9519B8329E91644DB1EABD71A9BFF215C4691D38024D081D4F769B5CD39ECA1 +67E006B69D797D17D6B9623B7A86AFE5C6E7528FD6D2338146CFA3F34D31A526CA389AC1AF9D72 +83931EA406E45980A3A56107885A74F2FFC195F0A44AA3747B7A4F2B35E7ABE1C949ABEC591E58 +50B654494A5081D0752358A7D90814CE9531D9857C3B127EDD77C3ED727BD0BE7A8143701624AD +DF7C7D84D37CDC05E3E97357D51E3CA329EC76C1924D84091FD864C03D6681136DBC5A81B93FC5 +81BCB2AE6BC9EAAF56BD9A4B7EBFC9A87B6828856BF2A0FD3D744755C02404518AA492077EDF15 +27A71C3A07A751EA11D80E1CA421EAC1F10E29DC40327C0E0F1F6E171E2CBCA87CEE30BA697735 +1361E221A57879D8E1AA7A59F69714389D2C861DF37439BC8713D1771269DA938C8712BB8D868F +D89084A7A8D843AA906C85D1F7EAFEC4DCCE5A8AB542C082B6DCD262C4CA3DA711CA55F28FFEA8 +48E8CCF3BB482CE7ED0D0F1476DBC00704E58207E89AFF346B09DA6000AEA0E6DF562AEC72B822 +6F1C0A9FD7D2378B0CDB7B9A6D51CD54E90051D47F382449D5D23CF6D176913E82474C08F6E4E3 +4577374CE08643CC099DB37FAF73F9D768C3AD7FB7E632FB2EBC0DDDFE6233B00AB0B3E17E0C81 +6093F5D0BCD6A575E587A677670BF7D7250689C7BCDEC50559B82AC0B3B0633638EC5D98AD125D +A00409EEF477825168094F02D3898DCF2C2EC2BBBD4E1BA25E5A4B8E15A6DEDE6005EB2B36EC46 +5B2FEF9532ADF7D35CA2EAEB5F8780AE3D7C09AF01A444FC709E3B2954D504F53D52050F17CAFC +9F57E64535C8FE2213E72DF4A9E8A38F4D4AABAC1FFD1145F5AE667C8A01CFD78DC45DDACB09F2 +7BBD5D23201AC648891138787900E880D512875E6CA58CC884933B164B53B4D288FF85B9B94B03 +EDD9D577670F4842870603BD0F6DA5C01613B9A8D43CD874D4FC67DA17BD49320FED903E5B5787 +9FC5795689C812D74BAE79B680544E8C6482BA00FD3581A366F61345B6936493B2BC8450AFB363 +3FD514D71ED865B791F73CE883AA7A86368EBDC60FE713081D2C0AB4057260AF002E5D298EE067 +1F04C33B7BA068B476BAE2DA48C383663A4921C02FFABFD5915125BAF1CBA2E26014CB589D6710 +A4E722B2C642786DD2B783A4347FC66E0158F699BDB8BD2D037FDBBC89580597C87EDC84C9412F +6BB07FF97A9EAE3DA693BB8E576D3849D244FF89F24A9A5809120A76037A6085BBCC89D096EF93 +DDF6B33D3969A28A0E33777774499D00595B4C4FB6BEB5DB1CB20AC0628CE23BD0211708801129 +42830CC65438739442C1101F09EA0FBF2686B6317CF0269278B451B03090E9604503A6B9D3798C +5F1C925BFBFCEB527C1262B8CD9C0F18A4A254171BB0BF44FA6BF978DE049096B8B39670EF6AE5 +790F6435F0C5509E1FF24334085429E3B64B48F3F91077F8CA3C21B0877ABE2EA0779736ABB492 +D050CD016D127FA3EDD0FC7413E7E4439A122C37E009B8EC4F958921F0D8501F6AFBA85A2FD614 +F9FF40AE81D821AAF6208C1CAD31ACE6EF57F7BB10F21D81BE5C2EC55730425770C35DE27F6630 +641AF6D39FE9B2610C965C867C001ABEF1AD4D4C7D262D602719E5DBBC327E609FF1F4982006B7 +C45681AE3EBAFE8AA4EF1DCCA0F37D3FF2CD55B1609B5A654B6A2890A53A9CE022BF9965720959 +0D14EB79D6E380ED246B1A632D8FA7795D22184917B063B58E9E2D87DE7655EFDC207DBAA36A2B +FF92BA88C5919FF06D085FB9FD0AB19F01F4C3181D9D82B88344C63A75401862F92282E49241CA +CC5C0AC86C72A5D75BE7D819940F21C8F6477BA35C5EB5DE7E244CB12C25ADE420823E8933FCB2 +407AAB99AD7A7B56DE0A21A3D7FBBD04C90C58A3504A9B5ECEAD94043A16EE8E766E550F6D0947 +30699B58FF84366C47BC2D2A99AEE14499E86A236A2344DAD2263C09C6F982AA252A4180880D9F +D7E90C16FFAA55A36EBED8A1E23E4792B3C7EB8EA63F60A08075F0E4BFB0379CE0DC4B7FB5C113 +CBD837F25C0B6F2CD5FE795E300F1245C99C842EE44DE3B8A352841DFA72B9CD6BECDBB51E7A95 +6470E5F081105AB88CC28DFFB66A85D0C75D86F3D7F34C6AA8B0DFFC8B9FC516602116FDD4858E +7DE3AC948F05877B83B7ED7FFDB0B69DE973127B626973AF1CAB5DB213AAFD9C6CA273D5485DC3 +90225252E0DA375406D26011CAC71A7B0C6B3372D2F1C9DABAA5A31C7F8D040B2E099FD7429824 +36C64D34E053C3DAE86B94E16EDCA81ECA39395F8BB552CB2DB50C7F2A9ABD3710C87017248D6A +1EB7416CE5EDAE99EC4270FEFF0DF173A7C18C13A75BE389A4A5412F69C4EE52E411CFE3716425 +DEAF057C40E0F9B2008E69BED121CC9EC4471A210D71823E8EBA1FAF6D88C1F8B2DB2375FF469B +E556CC6208EDF9AF791AC411E80D74BC6F395AD859BE71805E908A0047A12F958A4022FD1EBD48 +37087F283BA1F1B623A584A390663DA5548E43C314D2486E3831F8494C789AB4C636B78482E830 +662A15FC0CA3030C25A481740DB53C4200EF8206F0E097740F3D031544530FA10558CDABEADA04 +6EB00F7C807C73AAD1E3C60D9057A03CD8DC22946E637BB60A776A65164D24BF91A0C9FBC19DBF +BF3B8A0FFA91F438F3422595161200360D3321892D0192AC05BC7A74E52506A620A810AC0C7A5A +C13FE0BBB2A4B2090D1778595191FE755C48148BAEA2AB58DD6CA75F6E4028C9C836E6216C9090 +3ED51C1C33F7B5C8FFFE3E2DE23B0B25AB93FD935C408C678BDA7D623B1861B230BC8F5D21B8EB +AF6A2DC806FDFB21D662993F4DE3A85284BDE964FE7899B541BB17F4C4808BCFABC3A746A2F330 +77AEC41DB37637F4B5105EF1D58C64AC52CC86BF963F875919B3FD33F12A7147B3437B6894CF91 +6D6D3972830B4F849DC2E06CA9444D0EAC059C3B20705B77810C916554C94C7BB36070783A3757 +4CC482215D03C436D2AB7A1B705BC5C2939172839973E4D89D5F57D71A5D1297EBCA20A2947B15 +90907D172FCC7BB1488B1C663A06B91C139DA00AB40B16D933172C3EA66601AA0CA05828B35FF2 +5326184555BE5D36956F04A1BCE10F90D2DF77263E1AA8D79859BEE17780C64187224E1739FA8A +4AC464D07EF68101480E0925E7EE98FD8C0CF5AAF30F771383366BAEBC03D5636C1A1A81D92921 +05B67FDC74576EF3C2D4089BC68657B15733898A0B26B54D9BE19CB9990CB054E9BBB5BCD4BE87 +ADD1629A0D436884CB3E5CAF84C55093278393568251B4450EA719A857379E027FD259028CA68D +313F997616D51FA918B91DBCE6213FC3ECACD4585BAD71068F27243CDF7708F46EAE16A7F67913 +D201387A98776EA8B0C5E459E52B13754C191E27B3BBF8CED1D54A72DFC6D7EB1578AE9826441C +B476E54856E2F9BAC9F10E0B5FACEFBD3250F232F611666F5212CBA21862BA9060523BB0B44002 +F2FB29B038332C893EE3313C62AAEB1FF0DADC860AD1F179489C06C9BB96D843CEABF5196E7C1A +57DFF4502BA71B2B711653BE32A7003D6EE97209B2FB6C4F22B8DB8094166A28B993B6246B792E +D65DD84000F0D4A547B134E46BD4E495B2763C48E93BB7008EA14C2FC7C3461460711572C70699 +03BF49F11F3CE4556FCE122A015D54BD188BF6FDE4889DDF7A92CA1FD50E6604D11DE3B3380ECE +1987E9A446BF220E0C93230AB2A7C6084DD955C3ECC1CDCE0187A0E564CBCF68F6133C0F261320 +8179CABDE9FC93685DBF8B845C25B7249F11EE48DD48504759C765D17D387E0CF0B20C70B57377 +AD90EEB2793FC47ECFF08645BC4F47A702EA24FD69001CE5283266B371DD80882C9886F231E2F9 +838D9E765093B77E19247365F559B075CE1AFF75671E60152047D44BD0B69B168B39582210A09D +224F5226715581F43A9A6BA2D46968227D071CBF3EE13801CDD7F823F3141BBDB8EBEA60B48B26 +7898D5E27D431BBF528A5EF830E26E880734F6E1375ADDF92739347E128551D7E126ACC2A82FB7 +C57336E5653BF97A69027C90DC7179E65F76A7C43598F000A723A7EBB299E5B2EC549859FFED96 +28198C2C02A4FF2A58C0EAC12497B16A06F67CEE100BCF8AB48BA229F930C3D80752D05EE821A0 +C226AB62858FDBC6CF53E9B225456FD4F8ADC62B582CE583054547E14D0EC426E1B00B5A8E3421 +41C52E36C05FF715953F1BEF7AD3A36C92205198A2EE73144D89ECDE4E5B760BF5E64D09858B8A +DEA9C12FF4BE89B345F2032B7D40F1F94832BBF21E7B6FDF42A7602688D0545E1AEF166B8F78DA +BA20110D765981BCD22C6560B769B52A4B5B7A14A329BBF34E5395F218EDCA121500E3D698A705 +B524A3A448C2EED6E5F17FABDC7ACC3182959C7D969A5E37E9C39C1ECFE85DC9154C84301DCFC5 +8337ED83103EB593D165CF7F5339D748662AFDD55060BF1E33A0D73DCCEFAB95EBC614E23E5B0B +F9B900E92FE25E6AD98692A39B164EA46B88368F9AB8DE07953B3A9F0D889EB2B9BD06CD6FB265 +15699BFDE76CADE3A9ADF56CCD694408A776682CABD4CFB8D3CA37FE900B46F4D153CC3C58C36A +D79C692B71B36FF152CF92FD8898D193D3053A16067EC47FB0A5EF1BB806C5BBD5D75B613667A8 +5D1E73D8B72BA47ECD1702B524B9DDACE9ECFF9B10FB9C83E12D7C9D7220EB8C74759FB0C45F68 +92E5C6B3A502F06F45608DDEDAE2D178344D938CB36B6EE82D7321106D2C948201B3D7A95DFCC7 +BD3A1086A584718E3E62962E613E380CD99EFDA0DC033EB33E316BC8E9363B67EE5E04119EA06B +EFAC94C4C44448812B1A7F7FCDD0824783FFCD97707304D8275AD1746A6990C3C2D5607C72F775 +4F150A3B5F6175F453EAE89CF9E3A53BADF80115B7858E113DEBD4ADC2918F3BB2454C35C3F107 +7C2D97E067C98B0205613B145F340A37FD60F7176D265BF6451256269CAA16A48D998D80581F48 +CBED667D690E855E235B4266E8F3461933D9645CC35214AF73C4FC5A42B978A54BAFC561FAEF93 +BE0316B2E4B9927C100CEA3016DC42B8EDC939AC6AD5DA1B6FC86F21D92A5B9841B21412607402 +7559CC1C3DA05536033F2A0AE7F10F8A064AA145DD79DECBE6FCEEAB4C91DB9DFAC173AD124DFF +0BBA9097A84E8D351780382F7713E15F73C5CFD3C5BB48726C45D383FC2BE2732C8FFED42C8766 +6E0AAC7BF6AECC01E98A701526D642B90ADEFF9C48D5B70728EB378E93267E1ADFB7444BFEAF47 +25FB5CE72D8EE7DDCD03D3165CC32429D87565E7DCEC9E21FB34C1099E4AFA0D1993D4EA3B2AD6 +8D2796A5FD2CB2000DF2D8C730C7426854554D5D2D42041BE13AC3731860774B540D88806493CC +E8188C2F8BEB189A484D9F639E3D350A6776B56C2E51A56BC96E2773BDDA339098928E095207B8 +B485BD0652F107B8E5ECAEB68B7136F12AE4630EC2D9BD452283C4F5499BDC4A20073E37CF77F8 +68A417708EA7DEA3E7915AF3D4B3F1EBDABB60E37C3CA374D96B31BA0031D53DE839CCE388FE55 +3C073C1BE5CAE06DCE8012B1A91942068BF1EC74EC261F28EC5DEE7953DFE6C4C346F5E44EC312 +7610389D265A7530E18EBA2D3BEB6D0FC64F32DD4D288DE6FCED7086A0FBFC506F736279F97F05 +2E4CEADA7AA92A5F23EE5120FD2DFC954E5C8DA037E52D63C723C55DBF0CCFDDEB20741D16F5DF +0C2A5A0D1275BF9D3F37B6086429FEF89F59A970D44581BA0B66213F51C4CE33F104AE08A32017 +06E285C69151968DA35B2A78082E587028B405806CDF366C5D4C6E04A6F39D49C0BC23A36A4BF7 +681A3BC69E93FC3063F81F277400D2B45B931BEC7D087F31BD3B47B3F17AE6A6E4B49EC5A44234 +E55193D981033EEE43B79ABAD0752ED28F01BF12051B4511A43C2E8ED484D9D363FDE0129A311F +A62E3D2BCA70577AF1179DEE5137D50C011F74EEEC1230651E071BA0CC9DD9D7D4FDFD21F190A4 +25E8988DD779AF006009435AABA80EA233B9A68823DAB1580742CD026EE9EE874723BE5AD6BABC +FD9DAE0CC9A3E4567E1BAB53A5774550768EB4344062525D0836827569EF9A9BD2CE53CF85D7B9 +14C8AB0BF01A9743B86EDD1764BE91F100CDC9270C813D8B3895A55B46528B0B90CA2820034395 +8C566F25ECAB193C2C126E594A38EC6548BD47CECBF94550CC9DDA5DA4AACBA2AFD4CA53970935 +7FF3E4BA59BBCBAFAE3086F4D45C02B8592ABF94200CB8BB560645794014B384A5AB8C34478222 +BB942AFF1C95477C997B0FDEE302F01F7A52E461D10B0241737574BE4545889FB58642A3672A63 +CA19E8357396D54E18B6054BC91278159C22B391134A997007B04E98B8B036D8CBFCC457959A98 +858B734485736A5D1C932BCE464BDC7CFFA86FF1A7DABF37959D23C9E436FF6DF665E147EFFB5F +7CC0794B01F3B87CB74020A272A798697D12B88BE43BB192BF8AB33B474AF17AA13C3CA3190C10 +F6AB16C589D121738CD71EC64A610E73A2111220C2804D3C602CBD9047DDBEAEC51296203F4DDD +130D6748C819305196501904A00E0A52DC656A463DA07805852235ADD5BCD6953F07C700000DF1 +FFB52C5EBE6373747117DF5587D35BE15B4854054B0CB08AB96D07FA4355E038ED868841A3B4A1 +FA58FCA715CBD29D4D34FF42DAFB7F65A3990B974AF26D1BE701AE5E696EABDC7A997C4288C4C8 +CF6C10028C49E763DA39F26AA17F7BE65AA155D49B7594D702AEEDDA87891CD3D32D198F0CB233 +5369EBCB171287550EBC0394DBBAE9A637A789D052C7C51BC9FF6ED08791005BC6C0D730A49016 +AEDDD6563730AB510EC2BFBB8890D289DFF714DD074848DB372B453844EAB8396536AA5B93B6C2 +9516218F50622EA5B44B15066AC27026C40224FAE3C0A0A7B26E7271251E2CE70EFDA448B83665 +29B147BE0C81E4FA0A67D40D440CD80A0D5649D4EA919FDB09D20E4FD7AF7A8BE4168045097931 +7EDD65B6F16012995935C27F7318CAFE60494B2DE7B81D6B3813CD0075B5C93A3E4C907F277347 +32B553689DD7E1BD92033FECD1425DEE94E68DDB2983555FABBEFC10B3EE02D5836DB9632FA5E0 +6E3D18335BD999F4F2AF2222997392B905A262E87D379F3828E4225082DBD1F805FACFF2B6EB2D +A85C06DC8BC7A1B6D7FB7E33F30E57E75133246946D05A16A6D5F2BB73F46B1AAC466005BC64A7 +0C4ED52EE20E31DC101B1053FAB7D4D8CD2159CB260421B3261D18AAF221A0E17DF1B84035F573 +83D3FBBB1509D7744BEDDC79A21FC6E4E2CCF6EE21F7C1AA792823C4813A812A903402D36EC76A +B3840BB45D31277811B0CAFE17A7909B39B8B139A6AF831D928F751539625CF88E56353E2559B1 +E8BF899677561617726941B20A123D6EE3C6EA8F5FDFCE7EDB24C47FDF560127E219C7B70E359A +2F8BF5ED5696C589BC3DC55B8067609C69022CEAACA887F4D42F5ACDCB1B7A20730739D9F64A35 +9D76372939492FD3054DCD0543D608401A557058DA16E13041135E9E7A6A0DACCF3E4050E01E4A +F27531777C2EFA12F82281B7CED3A3B49FDBD0FD218CFB3407858EA0CB5401769E5583CAA61ABE +0351F66424144EC51F4C969C160FF37477F887139BFDFEE290FE77F0BE527103A6A30DE6C3494D +269386B8525B30CBEDF4D6C2BA04B5C843F76B07A11935954F48C55B9BA63F2B1DC3231B5FF9F8 +75D2DD2A071B63DFA057CF9988A8646035F625F63E892C449CE2A90A2324FC7474B53ADF072F5F +6B389DE6D4243B13DEA6D5DEEBC9EA428FD35B13B3648B8084AD3034C40E683FA6AB99B322DC91 +A946911A63B70B0B0A604ECE8F5E74DDE98261781218DF73B6666ED2C2E5F4E317BB6CEB2555CD +82A6A1DCCA0564AE1C7111BBEFA789880448DF720129F80F856439F261172671801EE0A690C2AD +B81434FF0A56F008A6B35CE08C8832EC2393DC62578CBA2EA45C07E61FDB658B31E80EF9EEF1F7 +1C776ABD17A17EDCF9E852386C0698A55F384F4342547CB07C038CC38426457C67C1E8FEE0D424 +33B7FB9E68DD533550F1E321E0221BB47658C784E1F2D81E40205F919590B71658F02DAA29CE3E +DD19A2AE8191CAB3430F61D4899DC44E7B8883A3E6384B63180F500891BF54C75A7E0B679C6CFE +9C71DCB785404DE3279F228B9389953BE4330497B00D90E0D164433FD693B3AFDD4639A669CDBF +F930558CD2A9C54031FF23EAC02FA2FC878FD29894FC2A3C181BE30D7C80FD5026B0E933B1875A +EC4A1C3B09F0AB78B686FDBC60C7CE7998EC2A610DD543C70D1E7000F3C4BA6EF15C0A0CD618FD +08A0646D582003E1BB8C4C28CDB11FFB0B764023F023C1BB8486BDBC341D865E04839820CEE2B8 +F0FE22513A8AD2DFACDE078504648010888BAB29011996575E1869D1F8CA4784B8488511080E98 +3EDA926D56FF4ECA3BC6A6B16B0D0C720A62F363CE48E83AB5FD243121F08AD6B47E326BDBD5D5 +FFC684307F3C40BADACDCC8049118E49EFAF4F9570823A9EDBF3FE8121C94CCEEB2600347CBCDB +C08FBCA3A972B4411F7A5EA4E8F1D890779AC095FAF29103242B8C090F645AD8CBABB555D50B29 +69019113712C6F058408F1080BC71302C2B9B79647FCB1CF9DBD9ABA4C5D6AD2FFB010E8C734BE +14E618AD1B735B099F0FB59B084C11CCD5579071E8655430474F7306CA9F49C46DC0BB548E5A8F +0D608E85881BD83A1EB98B4E92FE12B39E9C7ED86C46627B6CD527C4D3D92894835F47A80F1F4D +B0C73387E31A429002C4045AE770576E543B63B2A1EE2DD7F4EF11A1223E9514C9D75141101170 +F2774E52201AD076FF942ED6C97FB6D1D15E7D7C8391C3D25A0A08422202F93B33F38E58F8AC97 +5A41B2549E95C5268D79208143E420DDD94B97EF2ADF9E7C77A2F38BA50E03B6BF43972FC9B19C +22D071CD79F26BC6A2AE9442E57A3E0DC49F30B1A3F9A30D8985900DEB6CA9090B90656EE40CD4 +4F483415C71D4BF140E3D9A1617CE38320955680F74E120F40503C712E4438EED9354969E3217C +2F297BD277D1B0C120A8DA45E2BCD0DDBCE00EE2A5553AB493918AD82EAA20AA736DC5B93BD0E8 +094BEAFE5E3181D39028C1A2E30CD6B2816150A81BC3DC69C9A3B732600C45FCC2F0B485FC9B69 +23338458A054C570AB6F8E3B284E07F223B843BF38122A2E816A458D6A062E2E0E1B76060082D2 +DF3B4A5FF911C089698FBDA697CF2A3FA47C17A734FDBB33EE87A5AA068D21745CC4661C19AA1A +E05A8C6030739EB01685E839793CD5BD566353436380622A0D597517B684C04965DC1F13B5C611 +6C549DBDB42AFA964789A223EDEFD10C57EE4B1BB1B06B6942B64EE66E1D67E82D4CEADFE47ACC +35080AFE3657BBE687E353F4C94A3788A260436FA1C114B9003DF5DA81A3A471624D73472D61E9 +A616FDAB3ABABC225C845FD8F12103B8F67474D7414833074E47222BC00E86ABEB6D8630DF3A9D +84E981EFD99C9FAB64494894F6BF88045FFCE054C50945B75D2A00BBFF2F68EEEA5FA19D5F863E +128CF160182CA8B38EB1560F07F4DDB97E0E759077E70BC4C2B309020840C288951B56803394D1 +D57B46DF96DDC9777224BCE81E9797549F18CCC16CA7C25202C4569EECCA6E48EC9C0D911C7D9D +A2FD831635D913E54A181E56F8808E9A8D27BCA1C4DF10CC927794F64018A4B14E003B885F0C18 +DE9DB23401ED18890021623ACF1AB9C9DE1FDD33D4F6903E4CA4C668534F99F05CDE08647B3FA1 +A8DE467C565D9BA0F6E1D09595B886353C8C67E5095BE53F1A841E258BF2B8FBCDBA798CE77B7D +20D39940E6F6C8DD9A004778BFDB57BCB735DB413236F0A7B864CB6CC3BBFB1B33A23EDC484920 +E5582F8248933D9EEEFC1E5E5386567B576D0362FD750EA3FC631B31E61EE1C5D3D6A0AF9F4E8A +436212D359F7BBC9C69DCF4169EE4A5DB65A990AE63E4773607DE4A7DBB85CDDDEE4FA65018C23 +0900CB9F868885CF80AE58907134616D78B7179130F76557557BEA8F19B62EF87F9F8AA93A5F0B +DD78C6CEB352ED458806DCE1DF7DF2E2CC34B724C61364D707EFC4EAD4A8E3DB732E8FD1B5DFCF +8C3C46D531D266113B63B7D01FA053EC28347FD23A35CF986F5C73378C8ABD12D1A02B98EA98B4 +0F4ADD4F4226D773BE1ADC9841082A9C9E7A5F99534FD6846127054B2437D220A04BF83D16EEFA +7BDB4799DFDBD2DADB1276FFC40C6C24F2253245F21E230C822E323CAC694FC0B7903574CE5175 +94F6C22557E231C26768C5DA5572F3D473712C85225BFBDA924766D9544ADFC177ACF94798AB07 +985FBBB8A9F230702F3302B1511665B81E33EC69A61F6EE5AF160A034784C83D0BC0039E04AF3D +C8EBDE4DC0EEED8F1FA37D462EE55E63A3526E8278AF663BF5BA1902CA695E8AA7C4EE020FCA14 +BA93AB5A0DEFF681E7602135A13DE7567192764DD5D26B1B5862238FF3ACF20711FE0C24DA756A +E629E477DDABF428FE4E10AF898CBB8606BAF96D29627E68A78A483D47DB135DE7FC53ECD46A12 +9D64D17C3FB16BC53CEF1F1581976BEE603964EC3CFB28EC4DCABD6DAFE9FC854C69341DBCD4AA +1CBEB29789AAAE56A5C411437ACE39B035C26F77ABAAB2524B7EA71BB664815BBA7F1BD857BC69 +281071E74CDDB91C28E59C3007EB2280BEE16E14110AE00324B0A72C65547E3A0509B769608FF7 +4073E2BE295BB71ADAFF01E81EC86561C7095A2E5840F54C3030A83045593C43216B8B53269CF3 +BFA5A16BC7F258B34F46B5B505BCA9B5349F181D9DAB84372994660A77742AEC03AB32A3A95253 +7782C7F489219B19393A0C1A5D9EEAEE305A1BED8376E534163B3303AE930E816F818AC3C5314A +5E23460D8E6B08DEEF8FCCEB7F89E83A8805708CF5A6B2961455693109059C09182B7E08AA1C32 +61863F6F546CBAB64E249BA5ECD7AC030973CA1C69E3A37FD5474594181F53528300070F404F5D +4C2B9D43AD4445A7CA703F67B46B2735F7EC1D01B3A2D023B11AED0891AC2BDE28F32ED40DA342 +0B6F94EE07E269F4A8D07E29F13DCA62E59E14F3C84FB1836073DD34E29BAE513F9888BBBAE7FD +0F0EE251534E4D7FA6F27C64992A134E8ED6910B29FCE7AA2DA8A58113422E4798DEEEAA323035 +170A1D20F6A4BD68C5F495F42648210BB8F056F5DE8420240651AEB4B03A43D18589E2F8CA7380 +3864002F2709D60BC735C6CD5692DAA22D8BAD66144ECA52DB3F0910680EF1376CDD3886A37579 +A1AC30E349F9EC89AC8F5D7BB880D459BDD538FD516E9780B09A907E1C047F2D5EA6D385CA7B11 +32BB7FF7E81539D4D7EBD5C59C32DC82B44BC5DD698048789CD16C51B072F73E5A6E68546BDC32 +306E7D197E6D4288D715C1902E58B6E93CA321D45F7E82E379D569D040BC64352060E138CA4494 +61CF8E51BEA1CC4A9ADB6B5C26A72E6EE8C089E5198615A621323FC9620FA12770C36A22AF2277 +823090F7D058D3434A894FFCCCE04022686AB11670DBB6E68FB6E2336D6C18569675D219E7B6F9 +FCD6866FF8AD749B6CDC7EBFB573757AF230A1E9BA4F2F53E8F0F20660E105F5733B3553DC17B0 +580317BF4B87376B53D6C668F169723EEDDDD1776DE62B7E0E0E966C5F2F43DAE61339596C436C +64A2369EDED778D98A65B3222148921E381BB46FC0BA1DC3DDCAC224D0B9F0816C00BE91C50376 +9D969FE0BA42B89452E84B4F794B7D9688B66030C7734F63FCBDAE262E6B4FFC1AC235BA67E0E5 +1331118FC59B325B630E6E22CB55321928B7D153759A11A47DF9D679CB9D10714C5FBDADDFA765 +60CBE22A4D25943AA856B0B0E190FF911980914072C697C556A91B894D3B1A096E0AE9A74D2610 +5CDD88630F89A00EE9BD92BDE8B806A2D1D4AF265C796D1EE519D25CF196BFAE5CD837A0BD2F76 +A76B4EE2241B2CF9D89810807AC10B3BBE67179F216FC44920E28F1FEBD64C2750E1FDAABDF1AC +1DEC065CD4AC4239B3DD6A93CAEBC22BB7097FBB4122ED104DF6A7D1F4C76A1C8132FF188B2438 +67B38708F8CF59563E72D5F82B302F2B0FA4EF4D877138C14E250D36032E9D53B48F6906D73DF3 +A682439B8AFC64FBFA324C56D825315C8F3FEC5FB3D8F73F6292D617D29F427FE5DFC85C3F2DB0 +882BEBBBB704102B3A53918441A507F6F468E4EA1B8C46A4E2DFFC654107FAF494C035C0A03359 +1B83E8BF142162C7530A1BE5618206B97EC7E92B1B80EAB0061746AB3717ED65EC0ED719F2A1C7 +3F105D88687FC5B00617CC7CD288CE7A938C9F9C4522B7B43ECCF67EC5F342B62085938BA3C1D6 +0255A9DFFAF237D6CF752A52B252BB6C5AE4D6EC39F7DA8427D6BC715D7ADA63743E813AFCFFE0 +A07F8229FE2074A82E315EB7DA0448BBFD41D06C4CBDAB1DC014A259CCE764AE969B1C6322A1BF +CB703816FABA522713B50878897A91870943B20869D52A01DD76695BFC30C39595409EB8F2FD69 +97D7A3820E2DA1BB4F7555EAB7422CC31783E2A20F54D9B8759CE29F0461DD43885545FAB24357 +C1013C1FF6D778A01853AD30356382830F7653BAF57E2F6C3AD79CDDB2BD9376EB94616F975D83 +D85214593FF76FEB63297FA6F9A2566A1CE29811D81A03FF5C5493686DE4C5AFAB19283ED36241 +BBD6BAF5573CB6EBBF8DF5EDCAD5F69E8B65580AD4D6A4FF6C02D73BD52D21B73A6E69D4857E99 +BBD2AE2714A953DEA568878E338166311B45CD51A8FE1E0B6E6CF1A03193F82A8E428D9C3D2BB5 +1D26E0AF099F2464E235DCA9899BB75FD54C37AC15098E1AC9F33E49FB89E0F106FE9BE1F152E4 +E33DC4050C3517B5EF7BA154F0B267A7C35115F6EB6BFA3D061831BE470F5478A664DFC4E0AEE1 +1300B30526F50AB8274F3D56BABFB9623B0C7D7030C67EA7088E4B1C767F8A00A01EDAE880EB13 +D2E57C909556D6AF8E067AD42A1250E61D50ECCC72F67B50BEE2302AD6E670E0C940C6D3FCFD8F +426FC6B8EC86DD4461545742E2C1952AE52EBEB78FE286B72B75A3D7C0F0FB97876A85421BC38C +CAB03A436E42A09835569D741679103A52ECBE764C4E1B6FFC50738E98C154CA75C51925C5744E +A5299C85331D7BA5DFBB67E8AA8DB9C4EA559C4F6404D760EC9FCFC572B691E747FB7D6BC47D9A +43DF3F8B6873E929058A30D37087CCD0A7A7C2593E219B19B2095EE0542FC49E7B7EBC8FA6208B +96E891014B4BE49BA7510784271E2E8B4D2E4F6520BCC4EE5C7633B79150CAB9807A1B01B50E81 +BFC2B7B190A3A848B3DFC15E8B47AFBBAD5C7497A564D927B680B0976C5DA2693C87F18356931D +8CF9AC134A4A496FE850E6A5091956B89776BE6D893981E0279F5D01E605CCA08F6B4C32A6D01F +1FD9E2B243EC60D5781F4B2D6FCA13CFFDAC188F4F39A155B0F64E1BAD587E8C1953723C6C59D4 +7321289D9A086DC57FC08F7F2DA512C57A3B9CE4461D711F25E495C5E50740A364798E6B5B732D +6F17EAEA63ED222DEAF39D2E813601F3B2F416465776CE7154242C5CEB14F6CCBF23EEE181EB1F +92DC7C580610902C6CDA5FD15E096317549184CCD14F1AE54CD5688D5FC329114DD48AF6DB7524 +414DEE65B3528674768F9DA68CA2552A770E111D3327943CEC52A7B23DC55A98CBF2C0D3A6E2EC +F15A1F093E391AC11CAA0922696275B87137473FF0EA59A1ADAD12C529D76568DF36713DC914D5 +7DD5E298A6034F6D918DB3BEDAF88E74907F4B03C41B5ECB0773FEF89237C9C611F0DB6F3BF1A3 +1EB60AF8343680184FBBC3136257D2777802039F57F2BCA2B1515742C64026848B669F8D0DF5A6 +871858230EA9A9DBA628CD40269F33D9B8AF5DBA58D4BCA52F8A7A2A38E817B7039D6C4B40DA09 +B4F2DAF8CC12E14D96BFF75D61B4166121E56DC3D0B2D89E31BABC8E1308A86D0F6E3F28B4E873 +28CC47BBFA115500E22416BC153A68AC0299BD50C833E3C1AEE97EEF711449DCB33B20763E2E65 +1D429B9D3EBC3429E942429A00641715E268F9E226C0FCDA7A2193C42FDBC3F6A6E668F27DA5AF +D2539C04D7CE3DC030880DB21B7958F625ABC5E6DC94FAF9B8469790DBFDE65C89955F83CA117F +8E43D8AB9E5D8664F08A7CBBDAF4C86D786F4F0FF19D9947D08317BB5E184346EA5A164D9A558C +EE77581AA92DAC056584ED36663EB708D1114D73A00A001D440C8C338E7CC7710DFFAC6E93696C +FD245663F457C5BC29B9029BF91566E8B147016F0B3104BD8863F104A6F0E431CD33BEC307FDA8 +17BC5571D98C3DD1AC57A899787F2903D410941CFC818BB56C19DDEDC91295ACAC20931525182C +091AF85AC3E161FEA22F8E65B44E746F8FD40754226439FD9A660E2D02E1AEC9D9BC214F5F16A4 +D5BA4E1364D8E8C80A8E57096B510B5A8FBA5FE6715046BFC52EAC796F23B4CF996F8CA9ECD236 +1AF5D627A4076F02BBF615556801BC06D014A020C7A4D7BF87CDAB9EECFB90B4C8F6438E28EF59 +9C08E1646D023449FE2563F481B23C5765CE24ECBFC6EDFD5E69294E7910313DA056CD9C75DCD4 +722371BCF97AC6DD6D2DF99B35BC98C05932BAD200E1F5CE5F1A39BF2F14AE9BCE79157ACBDF8A +E4193C18FBA2271AAE398BB618DACE59C98424D17B4A9F152912B5AC21345C1E0C94631CAF2B51 +1DCAB35876A204F0BDE78BDB5F82148131DAD9C0BA3D98EA870BDFD86DFB920006DBA5B4037B83 +1255A44112C3C04BA51E3EE35B72E271640F37E6D1929615D75B8574BA58A2CF22264E1EBE3AE4 +74C0CC9EF06F251D9A702469CC838F7DA8EE2FFC1EB92368E839D658DA04AD3FD83325A439043E +6489945004F7383B5B77F9D799F3CB07D8E4446A00A8C1DE81D01F48AE998A898785609A498CE2 +FB0526FA2485F06F4F17E54141455D0C6E1D8D337BCE938A70FA1F9EA9B2C1FBF1166E26A0512D +E4C347254DF67369F91B82A1743F1F26794DC06C7DABA10079FAD6FD2B559DACC704EAFC12C204 +CB0A6BF8C97971D1094F307953947B309DA4823059A83AFA23ECDA8FCA4870E5949DE858F036E5 +0D3F193A705537E7A131256E72FC4F4949C49FB40C470480464629F987D6E4058A70D28ED1FAF4 +82C3E8E402BA5D2E9A8ED50177C356160F2D38A5D18775E2F204D9767953F3FA4C0A0F05EAFA33 +AA5788CEC8E64948D6DEFEC409901F7C2611110827B401F3A7A309DE2311FE4A27BC9ADEFD3B29 +7E86C696C57C2C70066438FA37876F8C0275458F82E6FC15D6B55DE4CBB8646452A26FC3D8248B +CADE704766582D20946FB5EAC8739837DCFF5A1E84EEA8D9C21D137CB93DB74925250A0336839D +32C115A5FEF9ED71D4E5A505230F6AC17AD3773A5E5A094BB3900FA0BF3055897966A0BD052AD2 +1E5CB6F327300D77CCD2A0283B5868023E86E50E064E850E45DFB3278799854C055CF83FE98AEF +8A5ED9059EA6C1EA5B4916F4673782335EAC2836507A3A2AB61917E24140454924863F30E5C7ED +786B5379227D4BF411FF8FFDD037FC30522BC8CBB887E860D871F59628E1FFA0BFD7FF2DC25700 +8E5DF7FDE2F02DCA442646EE35238075CAFB8ED068E50EB4D6B82EA5F7EB3DEC3C9132A8ED6F15 +59F530A04A4550E83A87A09CE39F699CE8B42D17EBC0EBAA6B916CD36C766160357404B227FC43 +1E1AA8E34B68864C18BE49995C92581AAA084D6FC95599770D84E567C3A45745D84A9DDCC9ED17 +9582B3F4BD021A28E9913D8BC40FF6178C7D0233BB2D876F91B3DB7F9B74A6EEDB70D2C363E8BA +D3D69B1C028752D95086EDC8CFCDB2DAD247ECDF88A28F245BCE710B796C554914CE83E4D967AF +C305D6BC70A004ADCAF4D354BDA1427DD0CCFFDCA32D9E5E8EAA67A37E145252D468ECED627F20 +38BB4533B00475AE81BAD8A49B9C8031E3AFE5AAE493E4864D5B9AFEF5331E4AA436BD6B6FAFE4 +3073C9DEDA76821B787C8C4CDD42F14DC97383648AFAC72F50E40671ABEC730DC100D4E442B762 +42726C8E569AACF6E43ECF9E5376F0BF839E7EE78689EA1DFFF44E97F93D0A98D19520DAE6F4D8 +8A6159B19FD2897878C26B816FA99DF3C99A5DD18A702A0E285B0256326636259700ADB9D79608 +F0341F6753120DCD82D4D80DB3F3AFC0A84BECE5C6AD87F7E0BF915ABE08E7F39D92A58894AE7C +3753A68CAEB56529E899D29EFCA137553DE0CEC1E27FE7D09198237B25B33EE059424E032BFAB5 +E8AE55336A9A22BD84B267B8141EEA7A0660C75C32CC9040C91694DE84E975BC52797CC4983A44 +044E9EC79183C985AA9994A8547A9AD5FD9BA515A79671B7E912974B4BFB58F3C1F4218987DEF2 +5753839C5A335C4EF125596A19DE6D28C10D648FFABE683D55957737AAF73E85593F5173E70A8F +9136943175FC0A1CBA166FAD4857AB9405F3CB1C96A824EE045D579436967ED9295FDD3C7D931D +9A77539F886F768FAB2D8EF6A987BC0452AE7DFC2BFB25620EC056246B7DDCD11E68BB3A2D055D +F0714AAEC08E88067B6C4DB719E49F1C310BC367B67AAC68CB72588D9A11E22DDD65215EEDB812 +78813D9C09A97E219CB5E968A8882C79EC2BF4A0B55761384D585A7E48981FE624117FA09AC46D +5B6E538609292D9C63874A192C1CD25FD5EB5BF30E1602213CCC5708AA7A28775AB1D669EED45B +8AD5BB8AE72CF4C827F34228BE33A0CD40DD3C1FA757DE434485E36D09800F1C2D28323B4E7E73 +C8F5F79346D87C617C5BFBF6E908322FAA26ED50BC66CBF71E0C026705E162A370822AEF8AA022 +860164E7FD1E7FB81C5E14DB0A81659DA7BCFA650B72112994922D416E98D30E3169F696E843B7 +B34C554DBCF8029FF5910539A66F55B7666B861BD7E2BE7A9B00D44CE2EAF55A98AAD03319380A +8F8378EBAD79823A27057276F9FE454C119C03E20241674F5896B67AD005130498711BCC8CADD0 +265157093D22A1F7CBDBF2A3381AE5A4BC07F316872418AB2F6588BA21DB31D7B0CC304CC2E23D +0F810DBC488F91954F5F28A82D3D53782F399113460B0DFDEF872FA825C94262A70B1FE72933BF +40FD4BECB14BC70B3F43911BC04948231139FC4D86B2F0854F782AE4B9CE7AC33EF50275AFB769 +C73435800D212094117D0DA5B694819DDA8600BBB6A098091C888E32CE9F8B3BC4E67757719B13 +420F989143F2E0B85B2DA6A695AA91DCB5B69186A59CC232F2F434F2D3FC1657DE90D3698230FB +D39C19B3B62F18ED9258D1D7CC8CBD1CBF58592BDBCCDD164C8A483AB70127F4C9E660BBC673C6 +3EED28CE5822C2BF20A785C0D2AEABA3F4061A585F5F48270A36F11B6C5077310BD00FA21475A4 +E2E60D99C8A1DD5D74B74CA470D964157C7D4D4992566D36558E58B7E07D091D7F9AA07CABF586 +F248D120917AADEFCFA4F689636185D53AE061401AEF4A3A19F8E0D9CB30B54979525D47AC3ACD +E79FE768CBB1AE7B0A2BF509D102CF924D0D859F89CD39BB99E2883C30A4E148D1918F1EDEA095 +149B37774ADCB4B3FD6C0345EA23F0213DB4F29A8F167324C2A1E8CD9BEE21AE8CA621BAF73145 +1AA582E9FD1EB460899A8C38B08ED183929A81ED396448BDF527F409644D17B4A005B9862F5F7F +B95F2155BB93063FDB7E545886477B5B710CD2BAE103A9CE1DEAD4F15F63F41C892CA84C62680D +D511324931D4E51831C25CB2C119DEF8E5D75A9A585B0E4C89FBF74B21A1A8E2206E6EBECB7304 +CB1DAFB7D0C4000DCE1A244A29525B3872B14F29CA1C9BC17CCE10B135E0C3F530F77AC7AA7C0B +059D07AD74EA9A7C55E9FA75B381CA902F13846C90A2F7C48383D1BEFC94BBD0103B991B79C1F4 +DB3EA8B83CAAE65FFF6B077ED2471AA551BAC92FFBD6100210C1CEB57225697BFDCC5C414B8EC7 +59A4C3AFE8034A9EEDA112D991D078CE7522CF3990462CA35F03CC7509BA2E30F7B5BE75F0352D +6F96D914A53F9AF8975DCBF3688201102A3162F68E4EA8E249B94D0781011FD9E0CEFF944455DB +2F6517FF96E2958EA69B86D96F267251044AE073089373B7822513E0FB589769391BCF2DB62ACA +DF995F020A2BAB02E0C972BC4A7F6B5F7410CAA369022F2D1B5F861C5C5276FCF4EFC65449DCBE +10E069725ADFA61DB972476EC495B544A174ADB5177C080C5EAE6B44E6E044DF660C748A935F0E +7AD665C390C73CB698B1FD187F9085F58AA14BFEBDA9BB1730B2BA5907CE8C790438D4EB02280B +B2B611BEEF36F75B636177E6096C0E1E31F8240B38318DEA7626688B8A0CA5817D8F281AA804EF +2B41A8CD7605F02D032498D51FE3368A00336084D38B29372931C2CCF738731F9EC569E3B2D54B +24411425B6D39C891393D00FAD30A4939848B4B1D5BB9FF68B345D5901CFC4DF9DEFE9B522C000 +086469D59A6BF467840C9EB5C491FE50ADFC769535E452878A8CF06968FA0E8B9DD30F35BBE61B +4C548344379489E5DC966E09588FE4F269DF0409713211C7299327BB0294D45FBA35EC304B7B07 +F5A67D46A786C8247807067086142816F3ACF77F03D5EE6FF5F8A2B8369C0F1CC922B59FA31564 +3271CFD550D6927E21CCE4E8FB93F7A920339D721CB2EF9F4848AE3D96F85BCEA64B4AE93F5254 +D9D4B18991CD8C5BD76871B9EBC855663EF043A8230B344539D2EC6906F58372B1DDAC014C189F +E9E3F73E25790CF11DB0ACB93A64D3ED9A57E11826825926629F23F332CDEF103DB74634DDBB3E +444BF96DBE0898E440587D86F5EE18C01CA829E5D1E30D1A06F1E42CCDE92ED96A1B5AD7362F36 +F0A3E12A98CC4A9E450AB2909475814D5CD4E06C6EC137D49B31716BD1CF579B668C189A49E9A0 +CD2DD4224388F1457FD508DF001BF9F1F7DBF9251589282F55EFEC08995A305605AFDB7A611212 +B8602A817B2B5A632888886921BC94BBF3BFB1C25A518741C8477C3E445485BE65BB0C90CEC0F4 +148734EBCE7E096314163C57F1F72E083253BCF06B45580086BBD0F3A3C6626708CA8E11D9C4E5 +28B6FF99B7C5FB64060C4B7C2AE76AE9C98E5A5071688AC1010FB0A81669E63745A26E027D6A21 +505594325EDECABEAB4CE8C6DCB221AC9789676F23B2B05EDDDD215539604BF3F82880F505D282 +F824C853442E8E39FB9C71BC55E793118BA5BC398F476930AAA980CCF7DC12D24B41D2E7589381 +8405E76FA5AE74586DD032C5C8540223BD218D5622DC8A6B0587D133D0FE9F31A636C07913C27F +20BE650D79B35F1616A6846B573B0D4B6BD560B50028C02390BB52ED835984B8F6630BB7C1967F +DFD2DC734068516352AF4B0F207E0143B24B22530EA7F058FA80487D7C1DAA8E6E049CE8F5E0BE +E2BD29DB095A48DD4242EF9B7388FC24EF655A2184965166E569C4D0F1DEDDD3B6B14D1E92D400 +8F8911D54E60822F4679AEA8F739E22BB7B03A5B04ECBD75A95DF15AD365068B7883264C139C4B +4BB9D7D65CB95D2D69008696443D3EA461E1543ACBDC42BF7CB9E3AE13D5EAA317F90414A3BB1B +94AF1A419845A8DD13E392F4359B4D145DE20BDC83B9559FE0A9FFAFFD71079A6F7FCE6F825085 +CC3577AE98BBDDDF39BB10C19541B2D65F230CC807B71D7EE35C35250775F8FC255FFF201D681E +CF7184D3551DAF6632374E2C0066B90B3F2FBA38DEBEC7E1AAFB9E75C25E1690EF1FB008BE0827 +38C42606443B9072A0C2EF27BCDCC51CC63B751D40EB50C8138680C07F213AE287E902E8E86DCD +FF44CDEA064F4F6DFE1E619165EF8CF42922A25A4716A110B92A83B4D2C439485893541FDAD9E5 +638BF0578FA0497F5E7D3C666B1183B830AC1925C267C1B4FFC87469A522BBC2E07D8270FEF5BD +A7C02846F5DF4216083CB0D110809A8BD08E3BD01F3E19C096D692E481ED952D8AF6870C1FBEAB +011BF3604A950871ABB2B3489EC07CB79102C15CFAAFAEB098D0B34040CC4D3FFC34CDAB240A40 +C26AA74C22C90B58B90AEDF1A4291C84B5E3AB0EF1D41EF30AF5E760518786C347B4AF86FBB861 +EF38C8ECAC757E2495F358E9B71C8BFC4A5F0604CADB5689F17993523FFFA64B39E9685AC9D503 +9224FCDB0EDEC24655E97530C827A587D375C9A40685CCFB532F9BC01F27B26553D8656DC07B53 +6AF6690434FF8F5BFEAE26460BEF05D4CC0358102FCE94223C048C96E004CC086D440D88799A47 +72C20DF93B83052131CD455A5498716EC46119EAD40F30FC1AE46019531490B4EB0919D54BDE0A +1D65304A9D9DDC4684E2E0AE546F9E54AA498403FD978D029CFA934D5D4C021C97C995A43179E9 +60255181BCA8860670A701939C0B2EFF33788ED38760D6DE2B19161AC68EACC2E9EE06E8147F16 +9E17F3849F9A8459439E4CE00D9FFBA40B01D0C92C5C5CC805BB825D9D03C4E8A299AAC9122E04 +0A234B4F973E00A1B2524E0278A04EA00D5F7AB15347B967DC5A8226E57577761ED08EC081DDD9 +E1BA28FE92A9520A9E86C14B7C40C9DD49EE603EBDA359F2C39F1E399949353FBA12E1EA1A0316 +E56D615C4F6C5A481D161EA6E225994FF7419E4408C7A0778CED1FB84090BF6F774E26E2264BD8 +E55CDFC33D0F970A992F683F0272ABE717F98F46AB271E68117E6339BC0AECB9E45F230FF57742 +D4CA51C9D0E3EF7CC82A7FD880C3EB4A24BADDA4EA12C1B7DD77E002EF91AEF22038DC0EFEAE71 +D7B86B32ABC84A6983C613EC3A5C40F180FD5E68F1CE8E6AAC0E880B35DB366408237ADE529FE2 +C497CA863B61955815B9E4438087605B952CC6B2AC37F2DA0FF60B8C208DCC873ABED2E02B65D1 +F107102BD0D8459A5AE4B23950A0796B610B3EA310B25709922C0537C88CB2F4770224A3A17F35 +F48BA498AAB10F423B9958EB9025D5F041F31A312B32A264B07067B8D27EB167056E9CA67462B3 +31AF4B55ECFE51D794493A508C09BC244B700380C01AFEC1F340149AE6544437EEE9C1222861AA +17B647D700CD75D95A51827226B1FA55D0BD6A780F31828580EB192E2E9072AD88E9A4D9C50752 +11583ED95AA662D563744CC8831F92D72A72EC2CB7FC7CFB76C89119810345026F15B4E5B9FE0B +09C83EA32147D38FB50D003E8897CE50A77AAB784700F3892A399EDC3CB5F5A95ABE85617C2983 +DBA02690B3789BCEAC789247547C3A39BE33AE871FF808D70B3D6D12BD51E1030A23C8356BBC76 +C901868694896882C90E40C1C1940BEAFF8BFEAEC1D426A1C44B6308EF4ADAF38D88766D6FE1DE +A163B9203E33E2807AB582AC0763BFB7E730CEE12F374108C84DF65966DCF77953C2793552E7EC +526C553B2B66348888BE30DF7DCAA1F4EB4BFC852C231358ABC89A3630D794D7B7B5581041050D +093998A61446FC8651C83C36986197AEA67C8F85EFCBA6A2E90249F15974598D11461012B2044B +0C730E6525C37D1196214394EC7A6D2A92F00F9DBCF62FDB8C1D41E70C1C655A4A25D30BD009A3 +FCAAE8DE1574E5359936E6680A3081D2C1648D1A5853D8EEB72E63DDE6885578D8DFBF7E90C5EE +A7D6F9F6CCED6C22C72177D58B8E05BCE2AB63D353D1C7DDB9AEC88E5E709CD645EC956CD1AF54 +34007DA54B7B0590AB5013E50758AA9D3AA1486DF2B7A368070DAE49C9C83C5FF98F33012DA73C +E02827F8209AE8182282EE67E936BF65B137D85F9458DF930E668FCC2CE7B1BC157223372A425A +E92B16556CEC07891AF58192EBF36340CA66D275D26AB19F5EB2A5031040D9A2472A0D1547FE42 +C302E23127C9BF7080B718192A4611888E1431B79C19BD95E8A0D1134E115D60F5CED1064D2B19 +59C21A9645673653752B0CFBEB9097F7747E6D45AF059338649875C5167BC91600250A8067F8AA +9652FA4CA4F08A42B95C6279A6A5BAF6320C3FF1AB33C6D7BEDB602AA4C81E4D53C2662D9A220A +CED6982B2F6F4D14C552248185D61D07E2A585CB87A93E38870F1C1F4D007A994126B4B6D37110 +5122A8C99FCDF07E4E05938EF82644DFEC40525F01BB06B958F787B3F94B4467EDC4F0515C9D69 +896A442EF69E9123012121EEE3B9CB2CA3F1AD1D07AA0E45 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark + +%%EndFont +%%BeginFont: RMTMI +%!PS-AdobeFont-1.1: RMTMI 1.1 +%%CreationDate: 1993 May 10 16:52:31 + +% Copyright (c) 1992, 1993 The TeXplorators Corporation +% Hinting Copyright (c) 1992, 1993 Y&Y, Inc. + +11 dict begin +/FontInfo 9 dict dup begin +/version (1.1) readonly def +/Notice (Copyright (C) 1992, 1993 The TeXplorators Corporation) readonly def +/FullName (RMTMI) readonly def +/FamilyName (MathTime) readonly def +/Weight (Medium) readonly def +/ItalicAngle -14.036 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /RMTMI def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 161 /Gamma put +dup 162 /Delta put +dup 163 /Theta put +dup 164 /Lambda put +dup 165 /Xi put +dup 166 /Pi put +dup 167 /Sigma put +dup 168 /Upsilon put +dup 169 /Phi put +dup 170 /Psi put +dup 173 /Omega put +dup 174 /alpha put +dup 175 /beta put +dup 176 /gamma put +dup 177 /delta put +dup 178 /epsilon1 put +dup 179 /zeta put +dup 180 /eta put +dup 181 /theta put +dup 182 /iota put +dup 183 /kappa put +dup 184 /lambda put +dup 185 /mu put +dup 186 /nu put +dup 187 /xi put +dup 188 /pi put +dup 189 /rho put +dup 190 /sigma put +dup 191 /tau put +dup 192 /upsilon put +dup 193 /phi put +dup 194 /chi put +dup 195 /psi put +dup 196 /Omega1 put +dup 0 /Gamma put +dup 1 /Delta put +dup 2 /Theta put +dup 3 /Lambda put +dup 4 /Xi put +dup 5 /Pi put +dup 6 /Sigma put +dup 7 /Upsilon put +dup 8 /Phi put +dup 9 /Psi put +dup 10 /Omega put +dup 11 /alpha put +dup 12 /beta put +dup 13 /gamma put +dup 14 /delta put +dup 15 /epsilon1 put +dup 16 /zeta put +dup 17 /eta put +dup 18 /theta put +dup 19 /iota put +dup 20 /kappa put +dup 21 /lambda put +dup 22 /mu put +dup 23 /nu put +dup 24 /xi put +dup 25 /pi put +dup 26 /rho put +dup 27 /sigma put +dup 28 /tau put +dup 29 /upsilon put +dup 30 /phi put +dup 31 /chi put +dup 32 /psi put +dup 33 /omega put +dup 34 /epsilon put +dup 35 /theta1 put +dup 36 /pi1 put +dup 37 /rho1 put +dup 38 /sigma1 put +dup 39 /phi1 put +dup 40 /arrowlefttophalf put +dup 41 /arrowleftbothalf put +dup 42 /arrowrighttophalf put +dup 43 /arrowrightbothalf put +dup 44 /arrowhookleft put +dup 45 /arrowhookright put +dup 46 /parenleft put +dup 47 /parenright put +dup 48 /Gamma1 put +dup 49 /Delta1 put +dup 50 /Theta1 put +dup 51 /Lambda1 put +dup 52 /Xi1 put +dup 53 /Pi1 put +dup 54 /Sigma1 put +dup 55 /Upsilon1 put +dup 56 /Phi1 put +dup 57 /Psi1 put +dup 58 /period put +dup 59 /comma put +dup 60 /less put +dup 61 /slash put +dup 62 /greater put +dup 63 /star put +dup 64 /partialdiff put +dup 91 /flat put +dup 92 /natural put +dup 93 /sharp put +dup 94 /slurbelow put +dup 95 /slurabove put +dup 96 /lscript put +dup 118 /v put +dup 119 /w put +dup 124 /dotlessj put +dup 125 /weierstrass put +dup 126 /kappa1 put +dup 127 /Omega1 put +dup 160 /space put +dup 128 /psi put +readonly def +/FontBBox{0 -213 987 680}readonly def +/UniqueID 5018946 def +currentdict end +currentfile eexec + +80347982AB3942D930E069A70D0D48311D70C1E2528F01045F8CAEC9829F31D648C8D0A29EA8 +51AF41C327A0D569ABAAFE5AFE94DAD818C312D3CEE72F1ACEA0B701B6A5608521A2866790BD +D5776D6CD0C7D971B9A48B96AA970DCBB8B76EDCB90DA356DC2529B665EB4BB80AC4F5B0F4C0 +ED76861E399638AD3DB1BE4759C78D4F2E81A2FF688D366B91D729D63AB5FC9556FE10A07B81 +904D879A7446DA82DC107FF41B0E3B7C2245D57B2EE9BAB31ECCFE9B79E3EC32CB1F10C622F4 +BCE18DF0E5C4B98EC714593D6F127C5CF6D719A79B83C627433D3AA39CB88EF85D274184C4B4 +C46CA5B496F20460ED75CCFB3D66073B710CC1AD2F2BEC4AC64065ED5E03930ED9EC97810F36 +845DD5048D90D724A88FD3C814CE17C417C84BA45C43F5569A4D73739F71544ED91C657705E1 +31F4D0C61752509FBE0212BDE9C02A833910DFF28F7C53F64B032C8E3CD2BA95C22177C3E053 +2F8699D106F119B80549C45726D793B9AEC38FF4C3120C259083FD13C644DEA026E1E7C75DEA +2EC2341983AFF4D712C27C024393022797DB1500C6543D620F20C9CE973EF7D917E7FB3E6CFE +E0999E06C9DFFF2D01BAC5B3BE0C47B2D5ABC02E1F0F383588F430FA64BFD5250E56DA323C91 +F033C8F0F4E0F9CBB36EB8D4D25B127FDA1BB032A7088CF6FB34B617290DE038198297F2AF32 +3602E5E96D475E4678E129D88AA15D5AD9CB58E244028CD8D9A8210FB1AECFC3F29299986C1D +F1CB3FFA0FC203626E8E2F6F3A6AB198963ACB2B528D6BC06687D59EFDDB9C88535C1C69DA5D +81812B911C5EF9985179796D2B2E4E92BEEC47A4075E306C8D26431D8E0732768DFF70EF2270 +D1FDDDDD4CCA0F209AD05C9AF2F26DA7CA0ACCCDAC0EA4F479B548C741193594D515F614BDA3 +F394C77BD7296981AC947CA0D6D6CCAFD9A05547B28F0CE449FFBDE2744249AF134A1D3629ED +FEC122C615E4A74067A7F8358519BFAC0F31D1A46D260A3DB271750D02CD6A12D019AB6C1C2F +9955CA205F12D8A03DE3203BB5EB869ED8B66B53D1C29EAA26B4D20F9460891B018031BF81EB +A788B77CCCCC5FF99ACB5B025A4DCBAFAFC1B34BB2ADBD17CDD741DA586AF1B784CF74CF8860 +3B20D68AFAB47D21C1A0C6BEE297777DB1A8231237A40EC89AA97CE1C848C9DA6804D3B98C11 +590B239616E0E6D668FC5B987075D77769EAF4877F1A359217B40731293574EAE905BD7A5C46 +719EC7F8A97FAC1C46DCD76B0344E8378FD61D02C9905B194613DF280648E2F86EF15A2DD8E6 +BEC1CAC0D90B8302B2846127B2D50D8FFB7D210C7826FDE88F2D165FA6AFD755DB04910140E0 +70126A663F3D57EA417ED6D2128BF21A7CC2911F8BF0F2668EADBE8E042A1CDCEA38C5C9A712 +26F6F4EDBC85DDF8C25D80933A42F5F303E5495C247E973DF20E2195B07B60657205DE149D86 +DBD56BB2594FEA81688F21573A8210F6FBF48C82425BF58215B3D91D3255012F7B2BC17357BF +B35CD40B0C1D5536CDE7BD0B29DEA7674B32BC83CB453BBF76807CF4A5AEECE57FAE3D291AE5 +0098B85E357E9606694FCFE15CC48406012BF12EFCEA89892D1811B5EF93ABAD0E929160090F +AD55766535E605ECB8381777DF5A2AC4A3E332A7E1B7AB9713A37619293BC7C8A69652EAEEA2 +9721F81FDEA87C0F323FA843325904149416D36CAD4BF4FF795DFE8F5F9073474A5CB2A662E8 +47B438BE9CF54058F1AE7F41CB8F298ADD3159AF95A1CFCE85FD603ED88F301B04D4E8BB4024 +D354FA4B27711651101B499AC32D80E83E0BC11535DDD465D0C061CC7E03513CAD0C2943CE6A +A5B6F9AB3133108A0F41C3AB724D46E10838205287C2EFE6AB5354A24CC5B7677BFC15E067A0 +FFBDE26300A5962A8E9609F4EA1E06811CE576D04DEB46C49CBE1412C01CDEF6DC45FE015123 +E1CAF9F40FE635F580687BB54E1D90C4F19A3B0F94E78D2820A4FA2D29E40D53C86025AB7B83 +43ACED39A4456E73347CC33843F7B1C7B6286BD315C88E891E5600E9140DB753BF076226CC23 +2786E952176F8767BA9F124FD73991B3D280B017AB0064C5EF5BF63267D054C69C9F08B50259 +6475D8B5083A23488867DAD890E37658D1407E6DD0E225280D43B36EE8FA7C6AF944A9A92BA4 +55F3452D2781965DF4A67FFD9EB6F2C7DAC8DA44B2655D8AF179C50DDA090970D9A15F7A742A +FA84435C72DF5C6627633B7ED52EBD8C4D5C835C93BE5FA7CB58F43A930D22513C88FA7DE196 +E7CF4AD21F59E85E4D5A1E45DC0807572D81C9A863EFFD54BE878B4223DD885187233D71B713 +A4A4D49606AAD372CAEF27DB943CE13592AE7B60B8355C4D4A4F65BF1A7292CC4566D8DE3148 +6FBF77E4C357D7F9D152AD67106F4E73C5D718583D7329CB086189B069F8AB1D372015A8A37C +753CE0701EE56F35BFCB78C3337DE4889AB74EEE983A3C6F6987790FF1B3FF67F4C95D32B524 +3A6557171F1C4A8E7D7113056E051964883404E5F748E060A4F2C83E0B909AD58E90E55C8201 +548BBF6BA31C7861B79995181E0723255A769DEE58BB098091A80505C59E671936CD2550B38F +F4AC0D4C8A2199EC15311FD5A7A659C8028742CF72A318AB3AD7171D8C8DB3115D49290B63B3 +C49330B9CD1F0DFBF5D41DEB9F5AD6FFA10DA0478239E0EB837D8A18FBB6C95FC36478B7BA9D +F0767283514A2317D0C868788D9A77FD6B341C71B9A3F56CD796727877DD4052CB9D00EA8E6F +B4D7344830366860D0FF5E42238C0E7C800DB4DC9ED75FC3104B60EDE11C7D51EFB2D54039A3 +56F6FC3362142F921068B5894FAF946F0391C009EC59392B7E3FD20FD42EDDAB0E92E0232701 +04D80365D513007A85B65A08ECAB836BB70D538221C6167E73E9B60B22FB122FF5F15E77B398 +43762CC2D11F166FAA06F7FB61DAF0A05A370FC47602E019A4656F585B913248070FF2C8EC8D +25AEE6FA7062471A562AAA8EB026260A67221E77F05D3EF6F79C2440F0ACD4AB03DA13405FD3 +39E3BC047412D0F503063F98B8FA0E6BD5E52EE9E2C2BBD3DDF5D07122869BA8F08F8F127DE4 +EA963E21B2DD27E050FDDCD751008BD32B731480FB0CB7E81D25B78F3A85B26EBDCD12062435 +47D82E7AE4AB9D573BB01EF4E6482CE8612EB67A1237B87D7515B51E1A218CBB724E745DA73C +72DCC1ED013E80D4D95C303642D0DB099158D108637EBA62A28A5E7AFF8DF1AFCF12E29455A7 +4EAA4C8FF91A9AC69E20FB107D6A4192743026FF10F2A48E3C83A06F3D8BD3127E3B9BC63324 +DB4C7840B91079D76A3163FCD35B13911A7703876B57331C6E67AD3A8177BE5D0F0519B5B7F5 +A9342FDE21FCED195C67BEF73C786C86F6E8E9E612A1467C3E1B1BBA763C882549017016918F +0AB2DCB6A3FAA0A25AEB632B2E5F5A01964D08E86FC8AC0E219AFF0802E8C561743CD4BC2558 +39707BDA8D0E318E257FABC2AAB156344DE064CF7D02F03956B02DEAD4607975EACAA0199AE6 +71FF07042879C5E604231E5700E13BFCF142361851CFAD31F6B90BF4C9677BCC985E2A6BA4BE +B0D492894F41D089EE969E7F59104AADCF79764BB5BEB1D4677A6D445C53AC9F9608183784C0 +33B991668671B222BF3DB336268DEAE34A12F8C4B27C5C38BAD94CCFF3C298D34F56CB3F53A5 +DF8A0FC9EE29B8A55B18843B9E53F5EECE43531B5B09DD483D831425648F27DBFD112C768176 +96C6A59AF58B35525FD6211D839FC4934D935CAFED49D86A0BB6885C0C2744BF6F59C3A84F09 +E1939B7ABA98844A9FD1B65E061EDD24ED129FC1E6E680549024594215FD43ABE89A3A2BBB91 +2D8831A6A571345897D49C6980EB77EBD00417EA3FE223F51155FEB010ED274F27DA8CF2FD8A +A2E2BA0BF8DE662B7A5A7051B4D4CC35F0AC975B9ED28609644F4BEDDB11017DBC8A29C86B4B +20328A9D76664F48C939BB0BD68170DFB6302F690570D02ECE0E08BAD62CA854F97D0E1B1351 +53EBE36C7FD037EE8F6004F535696DEC5D6F857038774E4A0F706CF419C4BE0FBC39F572DB79 +39D223065275454F26738DDABA3698E3CDAF49A2E932CA91BBF8270970F6CC22E313F40EF677 +71E3EBF14CBDCEADEC46D026D8746AE0AC3CD0EFCB874906DD3A861B04550131DE1E7852B76C +5FC8408A4038E239012491B1517A86CF14CB7E1A81B5C34F9C22ECE6C1C7DAE7363F0D200FB0 +3DD93D80DE49107E89D14B91CFF6CDC741C6BED3790FB03E484BE455A4218E9AAC7497C7B691 +4E0F108CC2995400F53E88D9650A0080E00E17AB94B4A0DD0F0BD227F85F8673986F8E2272B3 +C724F204565FE2A81A5B2C33FAD93821943A280BC4305108B0DCC7340C65957FC146CBA4B95A +E9A4415FC38B87493816AF1C4602DABEB64555B225B9FD1001156D6C94A1331258227CF8C043 +2C1EA27DC647EA7F2127A2FDB4AAB8203D85CDB25D2B057EAC6AF8D198D0CA763056C278C2F3 +A06513175ADBB14B33DBE438F9D7706C241CFF6626D750D2239C814E61BF1C6B278B3A2CF8E1 +5B2F93E2F2339A5F3FC17EC74FA00B2B4EA34379DA24058F4CED29453E59082E11DCA4C109DC +020C7574FDEBA6E6A5280DAAF1C8330AD5EB604AE9DB28920D86CB4018244C2BEC0B817651BD +65C7E5FB42BC4478FB72E15CA9EFCCC083CBD1122BBCD7D168FE296C86DEF11858F50ACB2C97 +5DFBC19EA4420429503B110B738C44E779D79BF2E0783A8EEB14C507ABBB7ADFC369959A2291 +904F03FC9E8A4D8AB895AF131D1879E33BBF68FC8FDFE22F0C801363CEE4C95286317E6A9055 +9456C766BFC5B4B08B765722E728EF7970E83AA83A67481098C7C2353BBDF25CED5C9AF6E3E7 +DBA81D4E95D52E2009EA9CC386322154CCD55B7AED8D1128028E8C31BBA7A73642A3FDAC7BC2 +2861A9B2A057F0E283B8AEB8F0CAA25439FF63BCA1B1EE1DA65D9D92D2EA2BF7AFE23F2B7D7B +A5B30104A2DAAC28651AEA8A603A2787FDC6AD72560B64F8A2BC8075ECC00030BDB8796E1CCF +EB6D6D95122F5C5A5080233F0533A92A93197432130625E00C75947326A72F9457F0883560FB +465F5DCEFDF279E5BDC645A0ADFA6E7C810526D4834D34317175BCF8F9E96D92BEEF971507FB +193E027F3AF309E5004CEEEC6434E1E5416B6BE2EE39658F31572514104E22FA6465A76EF978 +2CF7F94E9AE9AD133FE793B3CA411CB8DC4FDD0824567811B4A131046C7B2F70D28422428F57 +31D15AE5DCEE894EF5E8F882CEAB923470F67EDF67BEA6E72645E66D2406A9F3CBF7F4DC7E9D +71F22827A233C74D5781D528AB240E81B8F3C6162B7EB8D7A68FA6BA3EBC23EEF184B3FAC790 +1A38DCC662A18344F33C7349CE7BD8224A00EB7B039AB8F316D28020A6CAE42FA2DEE8798F34 +131A928B52511C1253683BDD9273862D02A693B50EF7FE7CCA8898278064620B3D460328FBB8 +75B4B2BAFADE2D784FD517F2678610E2C7E90C35DC082787537DC1DF0367F26992E03A3D3FA5 +5BD62B6B4D61E92E3CB9130D22C2A7C67A56050C43FADF7EF1962C61A70E98B6FBB5ADC5F014 +A5D42DD7B5C920A43C4E9E6ABD2F0F893E82E6BB4938D197F3FBAF120E79E105BB002BB9F981 +224763EA0FCD4018191497851C1323A85AF4E2022FDCD7173D3B590D7035FB65AEF28451B132 +24A79576D088823F6FE06152AE0F96E05A42532E425DBFCD9C4494C0E912B93AEB4829DC6E34 +ADDFDE3AAD7CF31E4CA44DE6D9D67CBA2516243F26DB4C9AFDB34A0A67F91CC689585E03A250 +5132B9A05285862574D7D3BAAEB1CF9A3571C147660F5E84FE69CD5C1FF8908D29415EA7707F +C04D0FB46425BEB9A1E3289FB938F11BA8808072F88E2EB5996CAAF6D1B90A5861E0962F3809 +706659BA963123221C2E7546417CF3D9BD4EA07FC6F3C212860CC0E9A5ABF469426655981A2C +0B54268DCC635B2883E2786FC5DBB46E09A5FE329FC32680250B744AA0D80E51C3524A8FBA6E +31C8B0899065ED33192C796383AB20FC7D9A9964EAEE7F9D7467B57787DD06C212028F08C538 +1EAEA92AE48A38BC67B9AA3C54009BFBCAA6027A13915EABEBBD3EECFA8F26132EF5F72C3491 +5A4857BE9B1457BDD1E04FD1E963BDDAE7BBA8C16AA459BBEE2ED112D7D7F63EDC21082BFD7B +702E3E7EC8241907E4176AA0CC537EA5C2DE58157F8221C7528E26B356188EAA7D7B35F7D721 +081C4406C96399A94798A6E47C443F8303B807BC8335061EFF884B59FCCF814B973600658E1A +092E5F0B9A16B964CDB55D1AF2D85B7534F85A46759668E472231EBD0B71B3595D5E13CA65E9 +2B97F882AD6375B0E8133C00CA86585A1DFE5482302B012D5EA2526F1A100BECEEAF4CE9D5A7 +C12FA5D9C951A2DC27B0D8CF87A1FE8767BC48594403F8E1A39D32D4AEA89D666471130A500B +2A0674D531FBB95F28C974FF9E76A2EE9D384373691772CECDE7CDA6C201CD6C4C29D5E15874 +F91193220133C0CDBE8B201B854D568FCF73B3964DF7D0EC3D43DA92D0578947D2B8276C1A0C +50DF18572A5B96A6EB90CB26EB6A11618D6BE38DCEAF72D19DE63942108BC32415B006258C9A +5AC732112E7EAE2CB6C8DDEF064CC23E2FF05916C6B79B17DF6FBBAC607E056EBAB1058D96F2 +A3472651FA35C4FC8299847C22480084885AE4E60763246A7763B05FB45CC2C8197C3C69E573 +E7150CC2AE980A165A159E7D4082D10DF64FC4269E7A71784161B3F21FAF7DAC3F1F74532591 +9C5029264AA34F7D2CE425D2C2B664D8AC10B220ACB4BECD94A935CCB220785DF617F156E310 +926D73B87B34F9FB33975EC74278D0B2FF7B8D9A0A93CE6FA9F7D722F894A9294F34CE8242B7 +20F6E438CACB7DBA554E29A319E3B54A7B6B6FE13FEB357D42FCB140F21BADD8BFB0690F086A +3E4931BF0EA1089BB7460744A36E33DAA66CCD029F30F0E7607D8554D9A9C7405EF8DB9A7EC1 +3C5517BE5094C2365F237CF5A28BBB49F29221A28EF95032C8EB4D4283C233E87D30C12254FB +084AB93D970C7245FE4673284367A9FBDC86EFC2EEE2998CFB9E9B60DDCA3EA54259701CA4BF +C7AB830268065C19A64F3661D4DE3968C8AE46D321426A1970F76568548DBA717059AA6B3D46 +49322B7F5231745FC65F73F383F711655383449AF2E0E99982CC796CBDCD8BF628783C3DA0F1 +509DC884EA0639C8FF8F7CDDE18820586D251166AF758D43D2DB9870449F1676B66CDC0C87B4 +F92EA1A6BBFCF0639AD7BDC990ECEA0A0F893D8E862488F28D35F1C83C2FC2DD164C8A1CE27C +8F0BB27F50776F2F30479C644618AA4A2E9F7F32BB7AD6A7454EAE1EFF844727A8189848EDAE +28BBADA3803148C563AC4769E8F7C3E109BA1BF2E8D1FD27F3ABB9A9A332C0A8D3980CCE846B +C64F6F598B1C048D2C29DF51E48AE2DD478B5132ED5C28DFC08F350834CD2CD7031F11EFCB37 +F8D8A26451A6578C10E4192CCE42230B0BD398AB2E38D45CD4F5FDB3EC6AA7A244EA0AE43BA0 +ED9B2E8712B41188FD037093BC9E16534C61211E36F21B2B69938197FBDBC459B02F950847C8 +941F7246177F2F6705BFA5A454BC8A3947C7FD9F70F41D2F3A15F6BA14340C4B1F1D97BAD850 +90AEAFEC1C1D79D2CFAA9915BD79FC3554F37CCAF7C89E496B6A8A0E641BE345B1F51D4EE651 +B9A85F56AE0515A25915B3F53EEA2DF8B78E79268595CCA76760D9509541F8641B9C455D23B8 +44206901DEE2F78DE37943FDE09A02B41A05BDE3AACECCB1CE6AE2E57C2F418785AE69556273 +F27D6089B5D1F5F3C41F9AA0280479885523B9614981FB6C0FA35AE488402DD9666F2F500992 +DE9DB83C1474D2A80F04FA78440674BA1F6A0561F2320716245CE4D4D34E3600FF4B880B02B2 +59B4F1672D714A8180C63DF5AA7A6811144CF3F21D1DA2F23D9ECB249FE4E76E87C759CAD386 +6701BF658919A9DD28ADCFA5E0CEA43E75BBC1C4CE94189FD435F8098BFB3D39E7736C45282E +B1575CA1FF186B9279BE2C61582FFC713A77DF22569C456722A3DF4B21DEEB398662144291A8 +74A104DDC60A521C723E89555DD66703CD79F4A7A07295097CEDE9F33B16C0BEB690B5BD379B +9225C099B048568A4589FD07570CF90FC6E8F0EFA16C566FE736D05A0E104AF10D2DF778057B +207F328EEFD63CDDF755F71CC5BC39B6778943178B172CF1F596EB17C89B9272E99B0069294D +D6C29278F3D2C097069A51F03E22B81596FE5A77931E436E0B06FAF45D2C383146C56746773B +63BA9AB3E49AB94F1600D4C0B15C82FDC17A2A869ABDE1FD79AFE9ECF07DD4241CB49DE6812E +DDCFD46F6E05C7FA95D1D1FF0CFED15FE25E4613C623E4B17D041179E943C2ADF392411B3B70 +1868942C6790089193058ECE47AC2B29BD55AE0A401677D1BE3F4214B0896065991F5D8595DB +9AE3EA4813F35B377C6E95A6156702BC1F675E7A88AFBCBA6E9D0ADE968374928418149B52C2 +05C306DA737D78FCCBFA2FEA01F09A2F19AC9AEA0D8878D5D2FD4F622A5DD64635E3B2E17779 +EF3BCD3C47466078222AFE4498194294CD1CB4D7DEA3F522867FF34F3A294B2FC69AB54CCE03 +54BB3AAE536E884A908B0EC384A0CA7DEA0BEB5423C08F7C5DC186E42410DEFC4DB8D51F02A6 +82C529439C3E3EA35552F0B459F0060361A9E695002BD293DA7D2C02E1B0DAEE6901CA644BF6 +141290A33B8682E03BD0DB0F5138F86868FB2A0549743AF7EE962F9DF241FE3A98A2377F158D +EE435C64E13DFF529D36DA039DDF7B5F3ACE1253F3EAC1549273704907EDF51576CA85D4A728 +F0C3E5381D06C5F7E052C08B75F64072DC77BD9C42CA097227A44C3F7A61002C5E89D1159784 +00F3A736E013019309C841A6896A885F307D1D7215F39D088B8E37BC61F08D7661B6EC99F956 +D65BAC784CBDB8B80F0C67AADED9E9E5E4D8C6E755764AFF57BF01EDDFEB8E6922B70EE999FD +A1F8B8309162E0885CCF0977400FF81F5B17DADF1953E39061EC7460FB06059E42BED7A2573F +1162152BBBC61375ED90F0779DB59B287C8EBB701A5799694D591B809E3EFCFD4BBD7254822F +4CC6C627D70F22414D1974EDF46B65BB1096288DF0D9EBB03E3821207E3C330F968678FD1BCD +697815CB606A7B596B030E15FA11BBE9B75BA02E0A70204E14C339C3F17EE4B6801402AF29CC +A09E6ED34F3AE9B46C78C54D92EC5B26619E721E55CBFAA4EC6085B4622F004D29914E0E7516 +10548F3AD23AB0570A8EC4F3F6A4CF0CBF89500C751EE8ED1E2222B447CFEB96A555256A3666 +659A11323F957AD376EC8FED66B381405EF270C7E888DFFBD36EA2EED15E8AE9F56EE6AA5736 +CD179C71F015625AD20F48A2CA9787FE4723CF9342909450D9920C0733A5FBEFBC408D3878CE +8355D805EFE4EBC0A6FFE6DDFBA64ADD9ED57411D98A9C94E5B76D465B8753FD409E748D7254 +2EE4B48CA6C2F0F21F0356CD41C64B0050B02DF20603FB71B8441D08C0B7BBDEA4B7D77D5390 +296E8410184B9529A698D028CFAD9FB9A476E9E22E93761CB2A00598430AF7FC18B2574C4551 +7465B6892AACF6E5E7B7D49C0FE801EB0D5E91A3ADA03C997B8D106D0FF348B1C028BD333B2C +AFE17304FAD94CD34F29F890E59FEC18A7474152596EE9971087C05C6E3AC02B66BF10E7A8E0 +37296B4F3B15F7312B81EE170FCF46ED6F6CF323CA8132CAD6C5694C52383BE49AFEDEE87D41 +E9770BAC679C9FFCF6337313AFCF77749BA31CDA260AADF7E8D901ADEDB5C5E9D107F2812F09 +2C552A4BBCF2C19AB9861751A69A05B5E846EE90CDBFBD17CCAD9CDE772470A1EC546C2A2B85 +0319C0EE72E0FA0C0ED628DB2402F755DCCBA80415CDDF0963AD7F61CB18C9EF41A53A1ED0D1 +B4596A6C2F0C790DEB3141C572A9ACCDF80A621A3F7D32051E94DD0E76053F9466AC6207B2C4 +A2182AB0CF0914F5431C73CABD9DCC87EE2AE54E888BF9ACE0D3CE786824069A70A69CC18B9A +14B458C4A7BB0DE1092C70ED33D294D16EDB8467DEA27B31BBD06049B511A6B6A81FDC9975EF +949C07A1B97993E0153C310BF7B9103350437183DB224EB19193FFA6518D97ACEAE1FD9B0557 +90B101A0A75DB04053CB4C4DB282A7342E1A57C2F97A9EC04EF07A4DE01300CBC51C2BE078CF +6097AC313E97F816CC9AA854A4E691D97B894EB9AE630B6BB676277E01BE16149E5E66B82850 +4584290F86C50CD4C3C115955DD6FEA544C8672D8FFC6DFC9AB940EDC3A37D58D1627FD3B100 +1D3FC2A67C0129FE64FD8ACD1395F555E8120E6AD855FED3F8DA57F850C6506B4BA17C9984AE +505F026F25B61C0CD9C6BDF3C83A11446E11BD3C60CF67C45144C7457D4C0A51667315C48004 +CEFA327E35B3593B568C722DF9A67DF323DFC13FD665CD56DEDAE2EED49567C128F2D1E7E485 +C1658B36441AA5CE8774FB11EDCC4994E15834C59397F84A4295EE44F8B8F71CDF5773AFED6D +74A42461C66C3CED2497F4527C28FC763067F082DC5E8A89242645A37A9A946247BB821E8527 +99B3D3AC1216A7B311DE1B7819D9A89D79878D877015D5ECC1410E380012FD570D8A20FC64D7 +FEE86025FBBBB5D6E9FD293226BB406570C32C2A6741474E0F001A5C0180DD32644B61ED4411 +5A018EADC5A832E1DFC7A5F8F255FF9871F4C959F23A1262F254855A44B49CC888395AFF5717 +AEE21A2DA5457D419A04780C2609DDFE2424D9B96C6B2B52FBDCBEB9CC99D1A9E224992F71B8 +51D694D99B306766E6C1BABFF7A11A3771321066FC5F73C334091972E0558392ECDF9C099B73 +8CF53BE2A04FAB67BE46C651C1FF3A6D19ACEE84DA8970E8C79CAD04A11A474B7FA560C11844 +82584A334B0217C22AA75C2FAB7C470CAE49C58265AD543A09C9FD1ED4ED40546F3138826637 +5DAC12975D10C8A4D65DE6A4166943ABCDF0E9A72CFECB9F2E5F8FE923108150201A812C9A8C +33FD567CF1B65978AAAC11D6CBD208F08758C1F5D9962282296A84B3052D924F25553D58D9F1 +14B88FDE7AA71593B0B7D01ACF64864D8A321ECEDD1A1AC4E0C381552E581B116452EF86173C +AE8F26C68B3B11EF710BCF432AAD4669CED707AAB0886E18694B0CCF1110D877D6CDD06A7B75 +0A4B7FDDC3EAFEA3F8C6A5E74A75D8DD8E4BD2F8033BC913468318D799C95D8F980F450C6C7B +CF178BF622989873D83270872C4C4004F00830B720EF4FD25A0A9C2D709B34EDBD8071036F3F +B8CCE42124C309009C01167FFDD0CD902772AE83A601904EAFA3684464DB245515D6AF6A1A2E +5AFD0B90F6D2C121B4B86CAF7D801C4FDE6A2CE664772F092120EEE81A93D9E3070F750E4809 +1AA0DFCD366592E12D17B627514C9F00F5F1858537DF0DDB2CA4E3BDEC9CFB76FB1F5A638E3C +7D399B369F7A003A55599EA3C1225246BB164A7EFA2DBBCDECDB3A662ED554B41B63E16A3501 +98F19B7B5BAB796915685B88108C713277B6733733E56EDFD8DB620781262ECED9875A756D77 +4230969057B06E2C33D3C7854F1ADBA2EB15B8A9DD3ABF30D7BD953DA804B83125D76BEA7C1E +0EBC885E07B4F03F1DCF33ADC5FA6592DB3B0E2B7100BCAB89F14D997D6E9169F581129DEDCB +6276E161AD6B80BA0ED346708EC2E73B018F923A6A2EE7282545C7B929A977007F0CE8BBE450 +940198D3404CDB88972BAD4296E62266672A0AC99D38C68DB786E3872A4E1B19C17C3E1901BC +B8D87785FB5EDA9DB640B1124D430A6C90F3EBBEFD70CA6C46792CB54037BDCC4C99430E4488 +EC64EBDDABA17B58098674ED45E0FBDFA2E7E8E99E9BF853FB2A4C12C5988552091832374459 +28FCE34910336AA490FDC251CFEBF2A95B38E649F050736208BD2DEAF23348B416C9765500D3 +678EA5649A2F8498A0B8E3888A168AD93CE3E3B1C4238A149A7FF1DCD8C2C0100034B94FD42C +1C33EE40BFB7C5B1EF47B021704E9A1839186432AD1A65AE0B2F2B899DE7484F5AA106804DD8 +1F0CE6F89A92720E4C38C7DB42817F0FAE2E7675B3B166A81B91F91E84A62B3969BE8A82A5BB +80A4CC87BDD4C3AD0E55EBDCE59BC9C84F049B68D9E4069B06A6FC4C7C89189EEEB70BA99CA9 +0D003FA72C8A17722015C2E47C36F649896C0F7C19C0DB88EBCD0352CFA77FE21F6A4B949DF0 +64847E1CD39C9D00E047AF4F5733955F71BCC7FB34D22D3C0CD5EF7011A97258B07569C68CE1 +536BD1C8E0864D8F5329BEBAEBFBE44599C3BA7680FE07FD3413C5A86893DAA16F77E167A8F6 +CDAE51C18E01F1A15C622BDE3C52DA37FC70102533031F914FC70540292EA1EE75C22BA10F6C +3C6501BA9F04F46B8F15FC457D931105CBB354828F7891C41DDF1ABD192FF5A912D8E5E9B0E4 +FC9D7B729BD63D0E7398A8E3EE729137D53C8E716563990F9D7A745574597777AC286ED35AB0 +F6571449E7D5FE6B251123D54D968F4136FFB04AFC97CCB5BC6C5AF8694982ECF269DADC8426 +9465AFA8247C099BF6D8B76F09003FC9450F12BAD9535686CA32CC36F0E5FA4E3C809BD4681E +D91214DC9A30796C3C854C051E2022DEFEB689D6BC100266D0D268FEA73A461B56228477AD34 +66DC50ED731F7146FDAB4EFDA869F3A28AB9D380AE308843CE4EFC29304DF9F9AEFF085335A4 +803BF0A8D69FB9FD0C2C3988CB136BCDFA47E99BEDAA6EB73EA3E996CFCD1F0B244AC604C280 +BBD6EBDD6270F3A64FCD0A18C90FAB3EA578CB79465BB6253FD7A45729429A936F58CAC73F47 +FE96920A21E1DB23BA1E200CC47890899817573A5C4D059194DDFEA14FDD8BEAA62ED7D7FCBD +CBAAA75E5A225A74EC2799AAA1E5E27127FF2D668B13DDD330817D292F650FD0747B3E403A1D +C15BA8BA9A86271A049C8CDC5C8CA2C231EE4287B8B6AD1D1A46BACB4DF6069A577E8FBE54A8 +0947425996DA313C2BD0FD12049BC24397AFD1C0E5BE145432DE54729D09B2B340F6AE470F86 +836B42EB0E46B0C1FBC033C0A9956681B243F7D6039F0F9EEE6D44130400228C48A7A5AA0A10 +22C7E141A6E9B618F6EF01DFC0E00D8219BB749352D2F6DFBE8B9018A5622216AD49C2894600 +654F6A34090AFA712C2A343A0FE43748A0F04044D5AB485FC474BEC3E2F9392AA8490ACD52D1 +255FD8E239D4415BB2C3DA4C38D68BCB36ED6E84B292EB09347D063FA852DDB16174EF574CBE +31BBEC0CBB5C121A949E0C191F86F29A81EA0C9252AD1C8E6E1C3FD7F8D114EBCD9501251758 +4C802CB3C98947C1F661D39DF1A1A4D327D293A088F03A683702C80E2303AC5E78E1CB295704 +AEC4326C0100495A79CB9007EB715A8CEF5A1CBA69F8C22AE7F60027C39C507B06E2A1D85B76 +087BCCAAF3AD091250D4976A0AABE280EED51F065D388BAEF2C4717673221B7D2C529771644F +05728DB0E647D3A9654ABE37E90B27B8B1F64CC7CC44AE5215491A54B16A4D4D2FCECEBF8812 +76633CD36ADD5A39CC58E395095B338A42B30E960A7AAE507AB018474EBD4D31DE34FD580912 +059DAA8D653D72BE8C00B29629F67FD820E7DDCD27A834B13482D9BD3CC73ECF907386E58DA6 +9E3405BBDA49CF5D289CAB230D1F12A885C76D9ED5E6F664537AC268F04096F405192F734DE5 +18E3EE750C0A4A59D570254DAEE61B1FF42CCC72DB585677351B0BF64F66940E1AD956768E84 +E38C85A89F647BA5B2C585E9F999E3D2CE5EE8D2C952E429DC7F055DEF3A814886CF49AD6BA1 +C891B7A3E3BFD464BD9F8E78B8F6E89E4FBC94CF284644788ABBC6C7412C2B4FA744C0EFB31D +93B8B1070766F2E7DA2912A075507622D04BEE1853BC9512BEA9F8F1921FC730ADAF63C8E34A +9877AA60DECAE43DCC128941F7F1372F164651073435A2F1F41BB598277F7BACAEF46382FD34 +C4E12E29DEDC340DDF9043926C00A5063993AC3918F4F3F459EEBE9D47EF868AF77F3B8D841E +0F65F8A3A31A65AB20DB5B6D48A96B2E50038C35484DB0B6724D29562F78312E184ECE38AE5B +631F0816C2C8261B06B6E654434FF4D42122F225FC0B199C6AB1943AF9E2B25151D64537DBC8 +CBEBAA55EE7A28DD0F194C512F28D3BD9042B095736E306446821E8F485B7401D9FC86C39A06 +1289B17F36EB173EC2772B469662E5F0F91301C15735F092D436DFB259F2D7EBA9D0A70CE7C6 +6D120A503D62CD6CA034FDD4D788ABD214BE1F48F78AD669AB5414E7BF99922D9A25404232EA +A88E7E154EA686F27146353ADE207AC6681EDEE54C78DFF47FB22C751236DF01774D20D692BC +218B8B2254F3FED353B9FD0D8670E19448F527CB8D1929A86052BB51EF3EC7CFB53863F2C5A9 +EF802DFBC4B1854251796B564EB7476B2FF6B6AB0CE99BD25E3844F4196653D0E11AE7404CEB +7E5994B78B1DB6E3AB153B47EE62DD5E4B384A511C71C79077BB0329E9A41E2D89913517A216 +DA292797B86951CC8FA43FFA64C7D7C48C1A00DE6710EC7D8D17439074ED3CD7CD3DA79B54E4 +247EDBE6087D8F71A1F5215DC2D35496CF3656B7A1D28BEB7F023781F1A68BB16356B1CAB4E0 +DA51B5C436F3D603D8198808461063EABC2F7D9764442595B850BE047EABD819B75D6ADF1A3F +9E4591777382742521ED08FD8A3D36594D288F2DE8363E893BAC702DAB04F0E5505FA54EB416 +3508ED09A61D284736D91683CB9688A3CD16637F71672B35A757A3C921BBC9E700EE41872B1B +8679ABAB584C72C7EC17C870CE0D8FA5B13DAB0E5B573E6E84E8F6613DB208615FE69E0EB951 +2032EDBDF33BA8FEA1EEFB0DB8FDB418A89B9C5221D25D9BAA0EE357E246C45F21FF73741F72 +A29A8F5EE9C139FEF8357641C900F79D648B201995D50D6694EAB86CF5B53141AC7F1FF45277 +67654BE31EE45773E48D791A162B2DE625B0A3AE12B3ABDB1B4BA72F49CCCE822E402E174C67 +B74874DD1923810FF1C641CEDCCBF00089F2C5D9D4BD6F2917ACEB0CACFAB51DE810A00715C7 +2414105CDEA8931BBCE2E2BDF218E91532E3CECD704E00ECAB6BD9327BB994C60A9D05532890 +F5C30F6099418289285FC9794D78F02D5032F91FFD96055E6AF3A1879DAF140EE73BC128FE6C +D084593D925F79732F23CF234A79028F916A1DFCE5F28D142FEBC8448780D14B7769A55BA217 +79DE070A6E9B4C17AD66AF7B7291A4F10AF69A82D541737E1C14801C6D724DADE22C399975B5 +3EC0604FA2F5260042BF9021B2AA68EAE6C7F505BBC213A8F87C249DC89A10EDA8702FA603CF +4C14F40FD09E9CD55D6DEC1DF20F3EAD890FE2EDD6972DDC06CBDCC09F6967D615E73F3F0452 +8BFD00C9C4926575F6037F858B28F48F2121A4955CE2A1C84EC8C3FBA59949DAC7117CBB037B +60C2B08FF325F74B8D6D9735BBAD7008B6AE79E8420523A899C6B796EFFC2828129F9674F6A9 +EE55B2CAB086439A731B9898EAC8D7C23B43FAFCD045E69E6C886617C9E999721531E5C78A91 +AD8B322C319A083673F429DCF09CAAA37CDCD31BA3B259AA4CBF5E9A6C70E5450226EF07D7C7 +C297D9541244E6ABDE1E2858EABB131C4E4E20EE1C2B143B9E24B7678DFF7C90481E0AF5451C +1B87DBB81CEE6AF6219CDB8CF93139B58C39314F530A4A8992D2C6EAC3115EE77F7363D81DAA +B0359C6118FB78BBF21589B3D7D75834733F8CF23D3E6BB17F6C31F56E5BEE74BCC7C4FF9AE3 +1CB9BCD5BA8BD82D2C3AA80D1E8BC391EEFEE1C00E04CC44134D0F29F1CBE237894AE72BAF49 +061B171F3DD077E5B4F64B3DCD3183797AE3938AB7E84695A9CF153419238ADEDBFDFF7D1676 +C4BA02EB00F19FC1E682B727201C1E20B75EB284BCE2756ED63974ADB2F4FE7FA3FBC117BF28 +14AEA5F78450A69B09BF39CE3D308863636AA4F4DA59115681866C5B225480BBA8FC219DC8BB +D8A89A891197D7B5773C9D2BFF4088143003EF10B8A3B29C7596D4C160BA4C1D87D3828CB1AD +A463B35211B11BAD337301B29463CCE7ED6F5C0CA763ACDD2CD4FCCEC6CF0387E0620C7662B4 +3DF04778F0DFEABE49F06B0B2E344D5C9BF59E898771DA82A1D8BFB33E67F0AB0FCA4B3E2771 +3BEB2ACFD2D4EFE88A6E93BDD52EF9BE9E5E93B4B88F3D8C961D3E9E8202D77B9FBFDCFF139A +00365DB1A7741E9E70FA62803DE7ACDBBE559B968E1290BFEA47816E15C8D2B419A66EACEF52 +A6C71173F5CE6B99C1343C9CDD6A11A729BBC54BF4B14574F7AF4B33DBE529521D9EFC471EDD +26DBA914DBAE2DE73EAA36CEC82EDE487F709A1A56B32EDD5AE039026D2B57B85A0189079BD1 +D6B1BE32CD05706832A55AECF57E946C4A0DCD4D976B7583A9FF609EA291AC03BB5AD0466ED5 +5C22B2ECF7A573E6120F2478F357E7B7B7476E2B8F00F82F4FE170F3D5D71041359DC21BA93F +338727386327638FDEDB37A4F10FDF9C4F548D971194CD4109482EBF2ED92CDD3D21B15646DD +46EA6E010B6B0CFE064D387E9EFBF6236FD618FFFC979D69B8BC50BEB143370E5061B2E65DB0 +4423CE2A8F0C9C880207E78C320241E311CE42C077AA89DD228BF28F0153836DA150332B050C +82ADB32FEE6DBFDAB3ED18680A0AB9BDFEDCFC2203C588AFFB481AFF930F26A1F7A0326BD1D6 +E786AFE43553280AB61D1B24FE33E7019C045A3EA01E4E8D125ABCD2F09B4F54771D1E94A206 +C5742DB08B79DC50BB5E44549A5C8BA98DA6AF2C2CE3A5E40FB0C94E4039EAC994F6E11AC94D +E42AC5A57217C1D37BF132765D6775D5D5A959ECDA55B081908D9AE8907CBEC2265FF56DD8C8 +E10732118883596567390E42471A8145098FE08253182C0969209B553ECB0098E4C9F3133A41 +10B15E13FC2AC00F9A247642AE2FF04D096378FE8C32F36BF5F0435D2B70AE96BD9DDC376C2B +DDFE12AD43F92FF4DD3C060AFE90F9ED2F3F579A54F72F8F8A1246254DC2F879D34AE11C0CB4 +37AFF31E320CC46B2F7B614D3ABE06FC42AE3A2FB03DB3E592F2CD0273AEA93EE12C60C7E371 +2FEDED8E9217E67EB18BD6688B83B75474475EE3A3963117F58E4A8F78129338D59EFC9E0898 +8F35BA35E04B4C15F2384CD74AC955776D883A34B8409F2FDE5335F259B60AB2DDC64629A10C +67A15FED67DD579C6A1442ACBC0D43F4BD371553E1A16AB01B030274C61D3013A6582EFC2BC7 +5E4E0454A7452A8E22A6159DF3A7EF74DF19DCD3F764B9C11CB9A6BAD0BF2B7C9BA5BB3F574E +3A9C0CB690E3D49E3ECEEBA3D04827BD87FC3546EF3C7E8155CE4991F501030EA2C89AE5F883 +B1AD24041308517D68066B9B4B40C91E74491A5E772BB452563AF50F190E6EB705180C674E25 +F897930928F29BC68C250170D5B54C1930A1D496B210CE54DBD1FCF8095FDA8B65C63EB0DC3B +C519602ED48139A09C3291B421AB403C95AA19E3F384108C54C83F3592F1D73D469054E239BA +011EC3024C02872C2F5F4D6E5B1CE3BCCB92F633D11235E3F8CEF92B9B5DAB50A4CB88A1C872 +7D1DB2B0776E162BCAC66AB3399721E2BD3B58993C386798E58A4FD0E370771EC6B0E0130221 +AF9842295C3AF9C2B6BAC8AF8FDB127D34C0F6BBBB24A9515C79A6695D78E14BCE78FC3E2143 +738BA7E0DF2904498E0214522EE3D8233D5166C6F35D14319FEA345213EC86E89EA473E35AAF +94BC5C2FFFE94377929661CB1171748DF2F56C889B62EC9FB1AFD06769CC7072CD356D3912FB +EAFAD4FD13A3D7E33010693C26527F33C27AC8B1DEDC441A75367D1378CD6F3D76B88A0F5B4C +1354C0456F99193A35EB6BA9B21270ADBD2769EBF66A9E6A023E873F3B9167B292FD95DB3796 +9C9B8A4E33E7E7FEF0D0F0E752E14F0B38B2C6320BD823135969798F4A127A8B7553A04526A0 +EBBCD4FD2D4B01C3438D167EBA0D4DCC11D271B3C48B796B616C9D4F5AACA25BA8CC2DD35038 +95CA8AE322FAE131F8A5E0CD911FE2E77A942D52F35DFA567E9044D9C1B73F8112ADEE7E1DE0 +8834D5DA281E9DFBB6B9C6B71252066584B0D38B40D8AD4369F7AB779A5B7191E56D30DF619B +00BB9B261E867185E078291D6206B114CE7C63B25D3DEFA60C9883E6BC8C98E3BD0E42EEC829 +C9313E55BB3D702FB1D7B66C8A226B62E8B1DC69C176409E52D85025AB01683C04370AA2CE06 +DBD286C3E1BD833C7FBC75FB26B9B8676B6A554C0AE8870E6921D50A2FAD1EB75C8418653843 +A02990F342CDAABC87E68717A872CB18EE805CF6D093C02E1893F588F8A6DC7894C39C45E1A8 +390F6B76E9D2292F06DA5A3AEF9F0E553F09715A7357A6B6D801518EAE2528D02DEB22982B04 +4D13503EFE857B1BC3D62449440421A04720AABC615A8815817D2D3D8EF337B8D8C0FB7D89B7 +D973CA876F595209E7D41464176C5B3796C41A1CBADD1BA3B5D928819788B395DF9E50C16D85 +8DB9E86E972AEE3B94FC822D91176A8F3B13ACC097BF8712F222C23369D2CE4855C5201C92E4 +60661DEACC951ED9D2C114E06967BB091C5451476403279760E3AC917187FC8189DFBE4BD204 +0774725E8B140CB4F8B4EC17BEA93A8AB22FDD4A0B21A1EBC43C7E5D481451EABC02CE3A48B1 +7F822FDECE44694EC09B0866D2ABA5B5BFF8BD17E261C58A48956C476FD979C40346C1D6145D +B7F5201BFD9733D1DB645E1565D9ABCC2F03CE5316BB44102C07E12880AC4E9565FB716815D8 +9FC47F553F85CEBA858C57EC7C7A6C1DF4CA3AC7BA4E7E71A0378E3DD7816F3043A78A380C10 +C5C5CDAC4EB0AA36B6ACC95989A5266C16C362F7F17CC3439D0E1943719E9EB52D582E271E88 +DC31F5790D6CA84AC3406B8CBED0E3705CA2616F43A7616D7056B500C7F9FCABF3A5E0CEB41F +8F9F3879DB6315269E52273C9358ED7D7E72EB21DE208788F43AD9F404B02869BB6B5C73D313 +40C29D4B5DE5229C168A7074B4DD97E5E2BCF468E97FC29AFB055049CD365B273D5DC7F0926B +7DF4882ACE772FD63A151AF5A0CB9E70EF5F416EE3D17B2D06315CEC1A6B0D96DE9D26839DC9 +E7BA7B392AA4E7197F20FA681FC5478B750A7C6E04214E257AB15B1C7C1DDE9E6D44D604C61C +5E47E2C7851E4C1C0CA2575FAD71710C35C85B87FC55080D5F08B6640BEFCDF88B427589E940 +442681FCC09E3FAE3A77E4113F29E7F54A8878CF49AA28FA2A1138A521A0658EB07DD2BF6419 +3C0E996EB89711026FC687897F3F7FAE6F540D9537B5088E5C0C16EB9819911CC8AEBE36B36D +B254E304ECE01D2F3B1277D11A8E2F5ADF183054E8516A0FC40CB03316C0F538EA6B1199C3D5 +6F9C6FA65D22B125B83571A326A915C6B3200DC798F50FECCDFBB826B8A6388CEE22BB526AD8 +834D3633DC50211E933C979D37B11F2ADCBBD6331FEF4F3B9992F7748086E52DDA3F3B47B027 +38DFA6124B9E14449128FD7747BB2E16C25CC8606993A593570742511977847C0126A1218742 +FFCA4AB7A08CED8BB1266E8018710DF2A7312A21608CF2C545340F62BF1A40063E03076713D9 +5130CF04D76FFB1BBAA7EA2EEEA5D9FC691686E4F6338A477E2AC59A108C8F4BC2DAA4456FC6 +0D91734637DAC47B65FD74B9B619B94774D1B58B0A14DD423202706C332133E49284268685C0 +ECDED7F63C0B9D1E16B77CB558892E59031590EB933C2A8B603A1F8B656358322EDC7308146D +082833D49AE7CBE009419F78623E73FEAFBD092A438F4861B8C07B78DD962CA0C34F82491F98 +14F1925344447712A921B1D26ABC6C89E8DD00F69775E6C0A8C580CFAF9743BD0149A31798C4 +50B97528723DDDDD1C10E79C2F79ECDF1A1479063C6D17B0568B767CCAB08AF0CFDF68BB46B1 +8F61780021A1008B6E7CF21B93347849102AA673B8107D0C34DD29C59878549E6A098E4EB5D8 +E1D532F0DF9B058CD32847171C7617F696BECE34A7B90DEB9AE28C866EB172F876F6A2A80728 +624E027CF5664203E27D34C2E8558BB67E43F241A457A37C21E8E9C55DE5DBADA35CB5D805EF +5ABB4F422E62BC4FF9EA332C616F2F881C6A6CAB91BD5066CF8E938F5AB5F6365B17D8D02FBD +957AEEEDAAF21EFD4F94973EF1C00A86CEFFE5E3C27CE6CCE082D0776850AEE702D2336A8A26 +74AFE34E4BBAB7C92B0D512C51734C629845119E636278874501510B0DC3F6E14E0E02326708 +9F66F37433E57E7CA920F574916EDAE9FF42738B14888487D87E744FA29543E1269978D9C6FB +71BD7D9D6D4646F6C2F702354B6442E1627AB0711B528F67CA90AB398169D8840DFF6CB09D30 +BF3CE8822FC14099C9CE2A1F8F5BB873F11B71BD5DD09CEE0E5F6E14B6FAC5DA098793A5356E +0C0CEBDC52F890CB295DD54E63040A801DD51A3ABEF3F2226F6D27A5C71612C156A0CECEDABF +D956F35A5EA4AD07225866EC415211A81957C32771D3DEF24104F0BBEA854AFD309EFB79B05D +C32A27D5E36A1402772FC5CFA29664BA3BDD1E0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark + + +%%EndFont +%%BeginFont: MTEX +%!PS-AdobeFont-1.1: MTEX 1.1 +%%CreationDate: 1993 Jun 26 10:30:36 + +% Copyright (c) 1992, 1993 The TeXplorators Corporation +% Hinting Copyright (c) 1992, 1993 Y&Y, Inc. + +11 dict begin +/FontInfo 9 dict dup begin +/version (1.1) readonly def +/Notice (Copyright (C) 1992, 1993 The TeXplorators Corporation) readonly def +/FullName (MTEX) readonly def +/FamilyName (MathTime) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /MTEX def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 161 /parenleftbig put +dup 162 /parenrightbig put +dup 163 /bracketleftbig put +dup 164 /bracketrightbig put +dup 165 /floorleftbig put +dup 166 /floorrightbig put +dup 167 /ceilingleftbig put +dup 168 /ceilingrightbig put +dup 169 /braceleftbig put +dup 170 /bracerightbig put +dup 173 /angbracketleftbig put +dup 174 /angbracketrightbig put +dup 175 /vextendsingle put +dup 176 /vextenddouble put +dup 177 /slashbig put +dup 178 /backslashbig put +dup 179 /parenleftBig put +dup 180 /parenrightBig put +dup 181 /parenleftbigg put +dup 182 /parenrightbigg put +dup 183 /bracketleftbigg put +dup 184 /bracketrightbigg put +dup 185 /floorleftbigg put +dup 186 /floorrightbigg put +dup 187 /ceilingleftbigg put +dup 188 /ceilingrightbigg put +dup 189 /braceleftbigg put +dup 190 /bracerightbigg put +dup 191 /angbracketleftbigg put +dup 192 /angbracketrightbigg put +dup 193 /slashbigg put +dup 194 /backslashbigg put +dup 195 /parenleftBigg put +dup 196 /arrowdblbt put +dup 128 /parenleftBigg put +dup 0 /parenleftbig put +dup 1 /parenrightbig put +dup 2 /bracketleftbig put +dup 3 /bracketrightbig put +dup 4 /floorleftbig put +dup 5 /floorrightbig put +dup 6 /ceilingleftbig put +dup 7 /ceilingrightbig put +dup 8 /braceleftbig put +dup 9 /bracerightbig put +dup 10 /angbracketleftbig put +dup 11 /angbracketrightbig put +dup 12 /vextendsingle put +dup 13 /vextenddouble put +dup 14 /slashbig put +dup 15 /backslashbig put +dup 16 /parenleftBig put +dup 17 /parenrightBig put +dup 18 /parenleftbigg put +dup 19 /parenrightbigg put +dup 20 /bracketleftbigg put +dup 21 /bracketrightbigg put +dup 22 /floorleftbigg put +dup 23 /floorrightbigg put +dup 24 /ceilingleftbigg put +dup 25 /ceilingrightbigg put +dup 26 /braceleftbigg put +dup 27 /bracerightbigg put +dup 28 /angbracketleftbigg put +dup 29 /angbracketrightbigg put +dup 30 /slashbigg put +dup 31 /backslashbigg put +dup 32 /parenleftBigg put +dup 33 /parenrightBigg put +dup 34 /bracketleftBigg put +dup 35 /bracketrightBigg put +dup 36 /floorleftBigg put +dup 37 /floorrightBigg put +dup 38 /ceilingleftBigg put +dup 39 /ceilingrightBigg put +dup 40 /braceleftBigg put +dup 41 /bracerightBigg put +dup 42 /angbracketleftBigg put +dup 43 /angbracketrightBigg put +dup 44 /slashBigg put +dup 45 /backslashBigg put +dup 46 /slashBig put +dup 47 /backslashBig put +dup 48 /parenlefttp put +dup 49 /parenrighttp put +dup 50 /bracketlefttp put +dup 51 /bracketrighttp put +dup 52 /bracketleftbt put +dup 53 /bracketrightbt put +dup 54 /bracketleftex put +dup 55 /bracketrightex put +dup 56 /bracelefttp put +dup 57 /bracerighttp put +dup 58 /braceleftbt put +dup 59 /bracerightbt put +dup 60 /braceleftmid put +dup 61 /bracerightmid put +dup 62 /braceex put +dup 63 /arrowvertex put +dup 64 /parenleftbt put +dup 65 /parenrightbt put +dup 66 /parenleftex put +dup 67 /parenrightex put +dup 68 /angbracketleftBig put +dup 69 /angbracketrightBig put +dup 70 /unionsqtext put +dup 71 /unionsqdisplay put +dup 72 /contintegraltext put +dup 73 /contintegraldisplay put +dup 74 /circledottext put +dup 75 /circledotdisplay put +dup 76 /circleplustext put +dup 77 /circleplusdisplay put +dup 78 /circlemultiplytext put +dup 79 /circlemultiplydisplay put +dup 80 /summationtext put +dup 81 /producttext put +dup 82 /integraltext put +dup 83 /uniontext put +dup 84 /intersectiontext put +dup 85 /unionmultitext put +dup 86 /logicalandtext put +dup 87 /logicalortext put +dup 88 /summationdisplay put +dup 89 /productdisplay put +dup 90 /integraldisplay put +dup 91 /uniondisplay put +dup 92 /intersectiondisplay put +dup 93 /unionmultidisplay put +dup 94 /logicalanddisplay put +dup 95 /logicalordisplay put +dup 96 /coproducttext put +dup 97 /coproductdisplay put +dup 98 /hatwide put +dup 99 /hatwider put +dup 100 /hatwidest put +dup 101 /tildewide put +dup 102 /tildewider put +dup 103 /tildewidest put +dup 104 /bracketleftBig put +dup 105 /bracketrightBig put +dup 106 /floorleftBig put +dup 107 /floorrightBig put +dup 108 /ceilingleftBig put +dup 109 /ceilingrightBig put +dup 110 /braceleftBig put +dup 111 /bracerightBig put +dup 112 /radicalbig put +dup 113 /radicalBig put +dup 114 /radicalbigg put +dup 115 /radicalBigg put +dup 116 /radicalbt put +dup 117 /radicalvertex put +dup 118 /radicaltp put +dup 119 /arrowvertexdbl put +dup 120 /arrowtp put +dup 121 /arrowbt put +dup 122 /bracehtipdownleft put +dup 123 /bracehtipdownright put +dup 124 /bracehtipupleft put +dup 125 /bracehtipupright put +dup 126 /arrowdbltp put +dup 127 /arrowdblbt put +dup 159 /radical put +dup 160 /space put +readonly def +/FontBBox{-23 -2958 1456 766}readonly def +/UniqueID 5018948 def +currentdict end +currentfile eexec + +80347982AB3942D930E069A70D0D48311D70C1E2528F01045F8CAEC9829F31D648C8D0A29EA8 +51AF41C327A0D569ABAAFE5AFE94DAD818C312D3CEE72F1ACEA0B701B6A5608521A2866790BD +D5776D6CD0C7D971B9A48B96AA970DCBB8B76EDCB90DA356DC2529B665EB4BB80AC4F5B0F4C0 +ED76861E399638AD3DB1BE4759C78D4F2E81A2FF688D366B91D729D63AB5FC9556FE10A07B81 +904D879A7446DA82DC107FF41B0E3B7C2245D57B2EE9BAB31ECCFE9B79E3EC32CB1F10C622F4 +BCE18DF0E5C4B98EC714593D6F127C5CF6D719A79B83C627433D3AA39CB88EF85D274184C4B4 +C46CA5B496F20460ED75CCFB3D66073B710CC1AD2F2BEC4AC64065ED5E03930ED9EC97810F36 +845DD5048D90D724A88FD3C814CE17C417C84BA45C43F5569A4D73739F71544ED91C657705E1 +31F4D0C61752509FBE0212BDE9C02A833910DFF28F7C53F64B032C8E3CD2BA95C22177C3E053 +2F8699D106F119B80549C45726D793B9AEC38FF4C3120C259083FD13C644DEA026E1E7C75DEA +2EC2341983AFF4D712C27C024393022797DB1500C6543D620F20C9CE973EF7D917E7FB3E6CFE +E0999E06C9DFFF2D01BAC5B3BE0C47B2D5ABC02E1F0F383588F430FA64BFD5250E56DA323C91 +F033C8F0F4E0F9CBB36EB8D4D25B127FDA1BB032A7088CF6FB34B617290DE038198297F2AF32 +3602E5E96D475E4678E129D88AA15D5AD9CB58E244028CD8D9A8210FB1AECFC3F29299986C1D +F1CB3FFA0FC203626E8E2F6F3A6AB198963ACB2B528D6BC06687D59EFDDB9C88535C1C69DA5D +81812B911C5EF9985179796D2B2E4E92BEEC47A4075E306C8D26431D8E0732768DFF70EF2270 +D1FDDDDD4CCA0F209AD05C9AF2F26DA7CA0ACCC0349D554800072FE70FE3F12F846085405A3E +13764F457E887846DB5ECA49493FB685ACAC9E0D4C5CA63C7B16408CB7EB5DECB4429557ACBE +97A89D9360F0D29566678E6C2E3569923451905D8951F729D6E4E166C0150CFADE571C25F928 +20FC6FB202F2D010BDB81E8BAA6232CD15F94AF4804B08CDDBC782C1295ED9D18025F1C453A6 +78F58A7E1B7BCFBA4400DDA52BD25CCAEF380AF4B5003DCC06F75960AC763EC42A6EF95EAF46 +F77B3AA68BBC3C182D192D602A713F8082AF7E531B1282E701D3A39904E4802C94B6DF379CC5 +FAF66B0FBC4E279EBE2154C755887098745EA0303640D9ECD80AD923DEDA40CCA8136F760A6E +4EAA342751FEF587651A7C6394ED4FE12A07E33FCDC615954AB2599F9A75CCF54E560B978ADD +203D169AD883C855F40EC67C410BF468E7AD9A8FE58C601BF464797F492CB9354C0A21DEB7E6 +E0B951770086D598FBD0138393A017903AC875192D5DA1D671E70F91C6CD9722D168EEBB3CFF +B58E56373712AE6823A0B39FE863CE84E8A867C5D1F5611AEFDF25D31C9896DCF5E320B0875D +D95C3A3F8BA7A6331558180E833AF7C1625D0A0EFD6266B95BA0A2DC769E694D43AB27088F81 +E8A7F25A9207EFD5AB98F0390B28D219AC289FA217FA1E67D801778DA34B6CA048034A044E83 +294061D64A98E7B5989EA55D9E4B046545C841452C7E8F23ED381387E1EA4E2912922C12ECF8 +C2822605C9934C37FDE6571C287AE7D66B15AFCACC0063F3EBD6FC91F5483928FFC85FDC712E +C46352ED74FD90778B8EA75A41AB0CF6A619FBB4187C77274565241CDACB46D3A96A66DE00BC +129825D7210A09757E2EAA6F6399E49A2FA7CAC9A2EB475EE8DECC5785DD1AD632A308872F86 +B8789E949DE16E8DC5B9BFF155EBCFBCE24CB82077EA65F147D6D2070BBC33C7B2AFB4A55369 +0CBFCE3FE274EFE7CCDD768B257FABC2EF28CCC3C361799EB6365F41927A1859EC2CE5A07EB9 +FDC066040ABBB17E98C5287CF3DDB94E5EB10375B52239AF35B012882A8F3D338801490D3F3F +FA3160C62D9E5E82EA6A456005BFA2279CC7E72397B09419D539EF1864ADC733AE203B2D8F72 +15B1A449228AF2666A8E5CE4C03C09E85AFE5B179C139027E0249D75A2EB070463CDCEEC2CBD +5D113829A137081D755ED274ED76D511C332222FCCFEC4E75FA82960F8D544A384D7A3760675 +E76312EABE9CBDA8B23716F835E358859A7A6468A890A0E5726F161F6D9FC73C83B27325E9E1 +8CC902D1CB601CDC9C66CD1ECE834FA07A0FA67AB883E1A415429E238093EBFEFD0911283CD9 +698B571A023B18E1BF83878518DF8F783E42202CF653BE501F77AB4074A5A2D10C569177DA76 +0FEE25D893676DE5025DF26685782D2EC98BD168DF71B5041F9F1E502513235B3A0198AA12A3 +91F664BCE4148D328685938AD62A83D215FA65AF0A2242FF495C97C08708BE977F3A0F635DA6 +85FA0224E9A3106AFD6606C580DF1EFDAB02F51B8D1409688A2FE0937DC74503D713BD217815 +8C6E89304F691C05DDC18B9501A0EC292B6900DB8DC47AF1D118336C459327E4E9134485AB76 +4D7E150A1204B61FA48D6C64F70704118DDFC63F7FB133FFDE65F278E2C61A5913DFBF4C6C77 +C019A13933B9C84DC671FA376BDBCF684EEBEF270C7C9BE054DD27DA19CB46C8AE6770A8C375 +3F44D645C626E640A1328B864A6038310AC575AA8D563040E7979F5B7128841F208C1DEAB059 +F4A125F72E3F508540C6D2338730B5AC7375E158CF49BAA7A095845ADB6BCCB32ADAF8163BE8 +4FA8B8652FEB9D9E4C3A8660233CD8BCEABBE97F90DABE0D18B04018C129C7A5F5FA0C7D4188 +68904E005BE329EC6A9B977FEF88806F0FFF2F285DFCAEBAA69E1780EE9BFD643EB41E380E16 +B87BDAB8C7622BBE4F26C356929692E3269715482FBA49A1C638A01BC95D764AB297DFE358C5 +0DC4384C443CE04BD2D5CC334870981F4F66F46388415CAE55F3CCCD74B189495505D75F945F +6F1BD6B7954FDC5A49BF2DDF4A32EA9437E1540BA8389C5197AF1D84091244AB411AC98AA6DE +D62AF3C2A8D7027A055A23F486A62CB8C9B727ABA8D05638E4CE62735A66AE83DE1191C9D32F +5BAEC262235F051F6EA5F9AC9618B3DAC8C805085CE8D6C03C94E63C96052C776BAC710C4BD1 +D34587B13356203A8B603F1095A582350E8EE92DC0F17037CC1C7A93ECBFF488AEECECE7AF19 +CA0ADF364C275BFD819067BD6557EC7B726E28111B3F3A137CFEF5F9EEAD77DA5C079A67A0F9 +EAF10656091E274CB52CB8196A3CC157720DA741E833758FF502507191B876D588AEF7E53B98 +1F87015B3A597A93E1B26AD08892956A4055AA05EA2273E84F288B004027DDEAA151BD24F504 +127206FED840BF1634F21A8C0E63BACBFABD1632E951D10912EAC843D2B956F12364C6B03C8E +0AE65C8FDDCBB882A5D6C99D79BEEA1BF8C76DB4AB6497B532FDE33C2CCFAF6CDD6B04B630F7 +3365E16F9212D3F75C1D655663FA2F9FAE6A872B8F4DFD4FBF357D7B22700A26BFC882A33AB2 +327E92A3070C72DC798687D2F01178971189BDB62A83936E0C0319073B037E96B6D125D401A5 +325725ECA5E701A51B3B6AED5FDCAE2B5B6284F671E855BEF502EED95E9CDFF7184F09754B72 +0292C91383363102EE9D37E6A8033631A0F4C11E197780D23486E647113B222E6547B115A899 +A46FE587AE36FE3C6AA75DD596227975FD55213EDA6DA9AFC0B39BE1D81C4932E4AE224954BE +F7E8FDB0FF8813F5F8D75E68F06B36F0796CE1E43F5B9D93627B630D2094269493161CADD19C +075CE39D381277496215F8B64AACB40BF623E2D68767DD05781909A1242156FEF405C0ADA5C3 +6F50ABC723F4BE18CBCCC097DB5FB48E30E18B657D54F4C1154ED50B342B4A00F1A4C0CB45AA +61F4483B0691DD6D52F310451F68C58DE913DE1FAB27849D9B9AAD9DB3C7C4D25B797306F2C1 +39CC43DCFEED1D0866ECA6F0321E6F49FE12965592F82DDB775EBA4E9C63A484BA1B36E636A8 +420B80D044C3CA74E7D02F3DD99833F979B2BEDB78D9E95B060B4D8EEE1B9CA4D3DA02FAAA9F +37680338851C6DC9E2DA0C1A17DF83190E9FD53DAEBF360E0777C7282DBCF02CBE01C7183E9B +BBB66649F3A4E1F30652D7A3D2D718CF9C44978E614025A9EA26A8F10F23EDDC9D7C563C2A9C +D406563C9202F35E760ABD0BDA1B3B7AAF882094C8524F1D0F5F7EC20FF38BAA21C8D47B1C50 +3EB79C31CD2A8133799EE820F71F04D1F71586D11C369AE5F131100B0D9538FE37786AEC273A +45223CF10AADE8D0E55F27916C4A6A3DC45F8FB0BFEC06F54DED4FA2F280191002E804E4558D +F64015EAD87DA779CAA0AD5F30EFF42738901A1E9F067ADBF578755C4CBD14455A7658E468DF +3C3D37CE976809259716459BB849E94FA803C1D7CC9BB6EE349E12A0E64676161434CA1AF6FB +72F6F3D28776F147AB78B522B76625C0567E945BCA6A04502B17F5F876E6828F59852F3294D3 +C7F4451A7A561E0CB4F19616E55C01257E2B673DCD05F939FFE995A8821D159324337BB2534C +1B9B07E1B9132C53AADC91AF43698D52ECAAC6B45AE7813AE95FE9B3C09A6676DB5E248C3CED +2D34D3162C6B7B121EE0B641473F8264836390FD68787D13EF6754AAD7478C4706D17E9E2FED +78491084131C407BFAF7281E8C64B65A11FE07EB111372FFA056FCBACA81D412080F53D2D837 +0252A767C4D67FB55D9133D7FCC1256C0258942FC094F1DCF076ACD3DB978C00968B021D802B +D11DBE9B4C0C0FD89468C05AC183606DA96A56A14C9851317DD75052A86E30B7EC13AD0E6474 +8354F40A5F38DD025F581EE1B813B5BCB4DF38240DFA342A39321DD3AA32D1D206CD5681E3F4 +B5C638C14BDBBA48381D18A4765C04525A43AED29F47BC2F41F09E98F9942462137BDD76EBE8 +AE60C03970CAB12B113B0F15D931F848AC1201DBA25F4E81B7F158E033CF2A4DA3856CF6A74A +EC130376A132AF3E763826B26BE54117AA646BED395228062EFCDFE78AF46ECF686871A570F2 +B20CC2AD65D09F868189128F7D41AAE20DFBE729870552C0F56F8C4005D9161CA4A5498AE2FB +F3E1FF9E02C050D3634D0B88A32EB75B3D225633B85085252F5939CEEB540D8B5F60A090B4BD +F2BFA14E1CB911BF23E7C3DA05BB28AA3BFE0676A3DAAF56CE804D425DDAE061281B248506F3 +88D9F7C4C95E2F0971316BC3E9BC783A30CE88A80BB247B6319721CFF31603EB1D1670F522C1 +46FED5F0B12ACA993397C06BD37FB7D439D003007853719A9FE2FB3B67D27D546FA8F762BA53 +18417F0D2CBA448345CC86A2338300D429A16B3453969EBC5D41BFCCE59F0EB5E443C6C706E2 +ACBDD250F74936E53F443019F97D86536913756995AFF9A5A91D93E093EB18EEB08F88C9F8B3 +354E6EF643E93937C2BE255C876272098538F181E68E686860DA6D6792D1FB2B2E1FE30F0662 +ECEEA87B37C436584B153C615CA7703738F708224C0D6B58BE2C3AE36C0E892A563F68AE1B11 +67C84B6527E34B98AFA281E4D03BB1BF6DD356D31DC794F92384A3BDA7EC3FE9FAA036575951 +0EA74B8937E0E38A04A58C623F0AA1787BC826DAA2364EE4CFA8B01B81EE5DD843DCB4048998 +E0CF8D18B10CA883233DE06779C332D29C87A7EA33F057ADD9F4C29A6970C56E170A80AF2A1F +56DDE778FC149469C5399F3E2C4EE34E3DDE95EB0CBD2A332B91679AAB4042DFF4CA9F2AB97D +06973892401B0F45A6E9FB9E7AD6C9B451DDE4072D7B68FA8C54A40276CA033E22783DF35753 +C60AB951A49CDD141DD12330D13CB7A205941D2A9B303BB5AF4A7E14A0FCE57192BFFFDB7414 +F4DC3262BE1E60DE8E4B5BBA84661DEC9B6C570E857F5905AC639E19DD553D57C2FF30F563C9 +1C4CFC74A8B08A961C3892633F988DD2C43BDB34A0F6C1ACA3700C1EAA12EA6FB3424F693A7A +CDCBA056556D7CD8E7AE6A966896A83E3AA73583A4196615ADA7082E964508EC5B20793A93C1 +ED113A816EB7CF05C2177F127958AAE01E23A3E11D81C4A0718CA2897E1DEB6B911F70A0DDDC +1EDAFCFCCB9030BF887F859B2B9D471EEE0BA651D858B196A19CF76F3F896649CD0ABE276D3A +C48EE62636C457F55E7C2621FB81EB168B861FD588FBC53EE99936E31AF2174A93F37C856421 +CF04098EE6E737030C47CEA6465A967D3B15038507DDE2D3AB2ECB82F5601D04CD74E38D8C17 +7CCB0E4209A5F83A5273FD99167B8ABB8DA1B3C661E8280D5A3552E1DFD6A53C6BA68118F6BB +86FC0205B1DCD030D4C20769A5BA10CDDAC3180CDAEAA8D689051D517B10E505EE47D2E75898 +B66A8B12046EF9DC2857B96B15DF161B7EC0E2A6B32E11DFDAFE47031338CDF0263E80B3EC9F +488A00C564784C0F5C5C62F6587C6FED0FBEABE0D5AEA15703000D0616E74FD52A80A6BEB318 +D7CBD787F16EB8BA66CB3AFF1D663DF6EFC7B2FD3497A9C5C7B4CA39001C65AC18D5E9F9E0C9 +899D972CE5E6AC875CBEFFEC6E5342A3F213DA1AD0EDB5204F2708327DAE47EFD3BACC26EDCB +44E553CF419A6CDD855A0661D409B06EBC76C9E5393797E33C5C9A1D3F40F85AADDF78C4D48B +DEDDBF3852AB90BB2212C9A479547E7137AB49E96AAA1EB6511A25F8A39FF0502AE15FB3B198 +79573F54EA6C822945F4BC9585C23C6A7712830A89ECC8E03001EB382358E186492971698748 +431E65800A19D6099650763E5399800A598D8794B042CBC59F5939716E2F33B5133DF9F60F7E +5AD538AAC1C67BC4C4888D4A966961BB879A4B1F6461F1868FFC4CC38C67471D7F5228E9511F +ADDADB25216E255CE86F25C74B682435DC57FEFC0DDF09012D401060356AA17EA9A72FD6E485 +4FB46EC0D4C5BE714979280F4C5472E746489B97D11B97D736F74604F4B61D907FD41DC25736 +CD9A3962245BB7B889613EB3209A064C8DA94260C0BD5D3489DFFAFD3CFC6B897E144DDF5075 +897CC74778692C369324580948CC0536033BDF403E7AD308C79A71FDC89ED669888E9DC7C9E8 +4D094AECFD4136CC3225CACF9EED5BB84BF0B5B865C015010F1D23AB7AA2A9B1AE50801FCA0F +BB9B37DFDF942F49884F2A1D988FC17A3665C00817272566907DAB9BC3FDD0C457542E91CCEF +013D2CB09464589552DCB8C0C9C1F9E43BE6238D12F2AD0B0FD5F91CA43BE45C92A6622B36A2 +162CC138AAA8371F75F3EE74290951C3F560662A5BF77E37145593AAB1AE4F5BDA574A176C34 +868F351C39997D7A725137EEA7A46096E0766EA71BA1E5DA00E33440EFA6BAF2346896EBDDEB +C3C87CCE018920B1D0BEBB660A81EB233EA9923199963FFBC0B30E6AF15704CCBA48CCED2167 +899B66CC3534EE33406F44D8E2C0ABED37E07217DA2F8C4516D98EF10BED1A355E8E8DBD593A +7724979770DD4E67B977829DB9F89F22AC31D7FF6637E02ED68E377600A438880A19FD377933 +0BEC227FBA1631D1EA18730F5FD88A9E7B66DE04327921A52F52EA62D33F338FDDCA44951983 +5FDB98FC4690EEA8EF5C90A9073352983540CDB356B91DEA0BE868F5EA905B2DB36FEAE31387 +4274442BD6A3C7709EAE9A3637504E1686453D4E7D41B8F6CE63AFE7F8C4F3F70F8BC03D4DA0 +B43A3A61106C6C757996FEE8450BE9D1D4E4B7A302E610F6E9E34762248A42A14F1AB4415387 +4DEE34FC1F0805008D6105BE49F30DE3228E6F56BFB1AA7638E691DDB1F9A5F8B2B70B6F4365 +9CF2133100306C9897131F0604930CB664B922790831C3F50E43D568B9916F47BD4A2F583184 +A86684C8E44C23648A1CAAF49602004907C06E466AB016390233180E7E9D2C1B4353288A7366 +F07A5D60B435068D3E0FB35351FF72A4A06C31E710E820B5874ABFB98CCF6B0FC2F1DC25F353 +00C01E54A07EDD2AFF15194DD710F77BDDA55F7ACE05210362D3D29CE1AA7C338538B2595B52 +3216B6F724F314A5968072C47C0A36198B7A0DA3BF2350281B8A635A83AD7B9F055383E8D675 +3537187EAC6B24F21CB4F840BCA22E1A7417D730C9CCD0A97DB533723253F92A2B00BB5DC945 +2485D1E0B0905DF2C6CAB95C9C4D501E9D45FE306FAB2CD8379669D56EDDB75D0F67E1C05C3B +47934CAFD125943FDB781C7393B2C426EB609C951A9D1E9222D16527C20C8DE9F6CFA0DEABA6 +9E31F28A7253EC6EC44CF054AF4DF1B7E3C655A91FB8FD88D79ED755B45C39C02A7D73A3F888 +F99AAE2586ED69F775384FB89B695358344BC3110BCEB38867A8CD54E8BA5687A552A30454A4 +4C8D089E67A19A15E65849DB7B39576FBB2CB4074AD8B4ED440CCF3EC2E932AEA4AF06D87997 +A1967737006392D6AF327387556A5CD54A991E5C23D862E9A6BD378E54BBD63FAAA3C18A133E +B47227C3F87A3F70324E24D7E975873815F6140969942F53D36917C7DC8012509973022CE814 +57FB43989D9F158810C3995C1D24A884853B9D6C250BBD49CDBA3080B3D59BB2F01812D59DD7 +C1823325DF1609A51E4CAD16E75669DC416590B526402DFDC0A966A284E950B96A489DF5EA1F +C52CC43738ABF53BEEFF55840C3894019C23AC6319F2DAE587BBD9119E64869E087C221E9EA8 +AE59CC5F7945E133F18575D39F00B920BCAE3105332DD77E876A4CE7A71E278F63DEEA7408AB +B4B110D52981C057B881CD06DD3091A8645231AF350126B7C7CADB6B89D2BCB1F3778F7F9C34 +623C2CB1537923D336DC75F2B3F06FD16DFA756B5C37F7EDCD0999583ABE6FB56FDEA2A64B7E +D3DFEC1D064166E57B821BDE93CEBEE3F41266927EFE03E646824BA6332B5D2A8B24A469D453 +508DAB6EF30E56FB17467416039E877CA59088FCF3D76682605698D61837448F272A9EEEE609 +E4E44B72B16031480A7ACCE56C042253B2761E8ACFFE13D09BAA39991AC83F7A7BFA671960E4 +BB054C66A544FE3D7CEC4732A77BDB619E0410E61B93BB45463FABAE0E8D44A5CD77E58AB55C +6E3A9F076AFE892FA9E43BC038380B5D1EB9EEEB5BB5CF0C96E91730BF186AC6D9D337C989F9 +4611C06666627266D0D304524CE7A87907D9C022E23000BAD7AB7743F2FCDA576D745B7D3346 +827966287BB484DA9873C7F491F02401A864ED4836E5920E3AC084B2D47098FBCE36EA223195 +6347B9CFF7942D60315119D3DD428B097AC82E009209A4CED3C5CD3B30F12457022D7E841959 +CAC6AEBC2DFD9287ECC7AC2D5B3A1DA280BD4E1CFAF1D17CE1FE5C3451949A8ECEE3368DF1BD +A3E5515C5C0F80B6273375BDEC432BDF1B78FE55F92B4B362DBD8C129C949DEB07715C8794D3 +5C3F49107430C4A604CA833093BCE1B95163A0D1345406FF054EB3B54FD5BCDCED531E01D252 +E6DB7162CFEF34AED6453BB7C61B7BD034B46703AE80309B4F5DDF1B15A40088BBA0FC55EB0A +174B97BB1D934C0BA8E5E6ADC41617CEBE9F18047663C635EC18B9FD1C0FAE76CC9038933BE8 +8C704A95D2F0D67F57FD061CA9757F46DF057D57D5826E2B49FE4454AD2671C7A4AE5F24F83D +F0A6A878F4F3A00720067DCD7B05E55564DE4D8AAC16A8C30DEF7155855D68DBC9453D5AEA88 +4D332E150A2AD5537E481D74DF2AE87FD227C08993741E9ABD9543D98767B4FF873969BD40CA +F3D153352A9B3430B46B88A4BEA305D955B277116090A3DFC81F56384E2666CC1F36E102C546 +4D09870A2EEB97FECED0B99C2862943C6DF1877E178141CF7361F74399268F4B77453E0731F4 +BB8DF0011E6328346253E12D881124534C9A64BA85D272A4FDAFB1DA8FF50C4F149D37C251D8 +3B5B4135C805D90F33E1AAD01914156A98A6AC178639D10387460A56D0C0B50E331131BA5522 +AF79ED5347EC80164A111D7C2286C88B851C43E893580DE162FFF77C0887DDEBFC82218434C2 +9B33A86140E4E1C9E46E8B49A83F656F0B46C917F603CD7CDF15CE8B0D49165E569B3BF18BCF +9BFCEC7DFD8B2010DB8D863C5C5AEDB36C0193392D565C24AD764497AB5331E7DF468ACF96D9 +8707CF755765D22C8876B2F15FF1C4AC403285BC2F21737675153288EDB766C6ED80588A503C +2291960EACAB24838E0F300C36D0E2050AB6C8D39022DA292FECDE19A62D5D539D3C66DBBAB1 +7AB4E9DDD0F3A4DE5A49D513786FEA2F0DACA2F3D52196FAEEF953F7C20386783323946EB1DB +BC774740333C5F3E6AB79D59D2C712D7AA90D8E96C5573925879D922E1807DE2039E381D1E6E +07D373D4C30F09253F4DEB3C8EE7ECDFF7A141F7450D0B63749256D96FFE8D8BE744786B4C28 +A762FD6A6403D8AEA0D4FDE81DF3986C7FCF3AEF0823176E1D7B234E4FD9C97CC3CDF7308E76 +BEFE9F11828AE7038C3C0D6E7ECAC8220FB9D05D99DA6B263A316A552E5070DBDB9582242492 +62706696970665B510F39182A7B79AF809B018353DE9E33FF4A745F777AB78E35BF901BF74E0 +45973BA70C96F2CE2F102AA4B5B5C997DF01FDF12A278247577D70275A2EB629D613898899EE +B39DFE950A7CB1B9F99F6EDFC378CE0B1490BDCA4F7E5614D369DA821C105D8D52C7FFB12F9A +B8DC180F59B137BB128BBC6C3764E3B8A44FE7152535D1DDFD152E2B9C2411EA530937F11EE6 +379D027AB5EBDE8BAC03BB9697836D2981749A4634A772063F04C81D54FA0CB61899788562C9 +AE5BBD0E3ACAF3E4607986851F7DC7F46C48B89BDB9A18E25A053BB3E84740760E91D2342225 +6109FB8F64F26F5E1E2EC47A09CF9392FD00FD61B422D597FF9C3FB325D4E8FD6FB892D24E28 +CC2FDEBB9E004D10A5AFB10D4467032075BF0B44DB26FB866E1730A60F87A3FE2E940E982A6E +4633B744D5E5CA36D6F6BD6714ED3478D64F8CD7F5A764E4EA4EB60639DA4E3B5DD0B6532381 +5820A6C70EF2D53A47B5085F9C74BE5E5E42E8BC5DADD35EBFD9E41C44A3B04651C5D62EA746 +B77182A81207D83D855F981CF2D1A23979D485A93658DBE1C69A003FE86AA64C6E7C382C83DE +F48927EB05BEC2C78466FBE79CBD59E73FC933485689D410A078C59A70B2B5496D1622AF30E7 +888EA2D3C0706045584AB89BB2A5ECA93A686D7BAD8F2DF0BBEC73F4B011EA252FA4987922E0 +A1E9CB93B9F3AC9273F78233BF8E3C9B9CA538D170E01785846EC6CBA18234C2027659D0252F +AC7E392C40CA3BAD479B154DDC418708731E1A70446D67F69E73957922114413A1C8921B91C5 +B542C2C646744128FB255A6CB3485F1CF409EF9776F200053BC89A499DACDCBA22613FE30654 +08DDA78A9741D102CD5EC74F7B6E80DE740E45D4A64DD13B70B2DCA6CA65442B12F922119471 +CD610408731735DAB12FF45494BD15D990EA4D6EE33AC20C00BB528C91CB7A5F049B187B9D7C +502DD7DA643FB5CED04AEB894ACB2CCF3D56D656E0551E5757104BDC29DAFB6C80A10B609494 +1EC1041FABDC2AAF1559E032AAA1B79575C4FA9D4A8917FEF7FA6C349A389E1F0D36D5FCCAF6 +A6CF66ADECE06D92592EE8867F2B142A8FC2FB772DA6C814FC6F6F66373329F2CCF69289085B +8AD7AA5B88C6F7A19CFA5E37BDC61561A82DDF0939844D8ED64BF11084F32C55E09852C6FA41 +A1D9115D0C68DABA31E4FB77D04E5A2B7EB79B521669C629BC9A7CCF129A2A67C92826A435AF +47F0243E14F1F976EA5B58DA6D79499332E85BF2DB5A7E95230979B6C567614E6370A9B341A0 +7D7813C42E8A1251D77AC6A59B6F5B6082F249879D2122B19E7E5AC42026B1EFA799BAAFE866 +B4A6DA7444C903FC0B45122857BD20B602883FE1E2705C0A27BAA636D0356A102093CED97308 +1BC38EE530B62CAE35C5847EAC973F02BBB7461895C526AC25674C972C4E61BDD86F4A852E15 +AB6D94403A030F32C8F3263113A2D1413E624A8143EA7A9613A2DED2C243266932359120A083 +673020E4134CE6483987A1C77E140E6FF5DCD2B3ECF571A52D3411CD5DB601EF4147C4F1DBD1 +EB16C4B838CB9A6640D8AD1A526C312E5CC7BD5AAA9442A6B38AC29FBA0994C91FE575840038 +13F9B8FEB92B20AF8B890BEC220BF995E3680AD69833D08B0357B6606FD60EAE95F497FFF1A8 +02BBE1D3BB3BF6905FBBC1F97A20F78A1B106DB9C158ECF1CCD16E55048CFB4C50E40EA9B9E6 +0768D440A4507F3E76123616FF79745C76F9135BC1104A9F98D6B8A9D299C0E8D3C0BA2FF429 +47CF866B5487F10194A1A8E672A330C0B9CC2202636A5360E10E53FAD86A2D3C88DFF64D4840 +681B6F96E9E797C459A07D0812550908F2AC36E684B1DBF3DEC6074B922E091277493485153C +93ABA41FD097D94F4BBB95581670A1EFF27A0D267B9DF689E2BF6FA657F87B390EF731538E34 +E776DCC1D14F8959A99AF11EB15FC59376BD1A136E6947B9076DCF62AAEFB50C8D6F9E10E090 +FCC17B6D90A0B05726F9BBF4FD92E08E5CF4CE66C426959A9F2E185B6B395B0DD4C80BB283E6 +16E6001DCA44A820C18F62521F1F1117263401E30F84C5974461E6E270B72E50E81CFE305D92 +4D26924E5B7675B52EDED59B87AB5606EE5ED95EDBCCE5DF07A0D41492A366C35DE50A4BF365 +5E6E0F24AA7DE91A16EEC22A9EC0F9667C831759C688928E217DFC6C7E33516D46A225E44A6F +AF58C72236D9FB9F2C13F05FA5F92AE1DD970420B7887E6DFA6C01D9C95DD674863AD81AF472 +3413C430CC912FD0FCEFF72EE9119C4A496C888C0562548F0792897DAC12479411BD39D5C969 +75B9140107D14C8BE1EAA5C482455352C2C5ED15172B9DAC379BDF76FC2E8F11AE24057F851B +0F41A7325994B1B20802F0CD520D439770029EB53E5E989E549F3C055CDA4E37F78E01E9D2E6 +A3D2DAA41232F7CFE9B7E74D87F4B75FB38F72D541D5EAC0D64567AFD28D6D3F07A4E649A853 +2288416A5A51242077DE5138F6BCC2EBF7524D43A6445BBAD2C4E934FD7BB827FD564209347A +C988F9DD9DA8C73A4CBCCACA945CA135FE83DBDFF85E2622728199FC975EB14B425AD1299F3E +69BA41D466CD8E6E9146C0ADB8E93ABE70D43A06CCB205313FEFF9B0F22F7CE37E0F132B8474 +5708C1BB0CE575D972524FA551F2E9F8A06C0B2312137578553D9D6C98838F06FA690278E7EB +A4A3344665C7E7F79C7096238D5CD9FBB12BAF120D1A287B831255A457532BE861B5A8D78972 +2AF86F49EE59915E456E27A3283EF8939AF44119DA2F508B0F0E6DF46B124DB8EC8454B048FB +6D29261E5819785EAEB7740EBAB7049A5641942407861D6B31E06AF206E51F62DBD88057FD58 +A1E41DDC6FAC15D6ABBF4A50ED13A464ADC608BAC45A230955B5E827CC57C2260387CAE9DB47 +D0E35812414D2CDD6C643ADF736AD15E1759BCC714C45CF38CA8E4C617EA8E6453EE4A908267 +8C3F90B8416AB1F4BCB0D0B3E50198F36346F778F7B572FECC635AC8429C17E2CCB4D8424C01 +69FCD29D4F8BD4364AAA30202D285DB593005D826B29F0AC6AB3A226B394E80580B2D7DE2DDA +C4C34D35668D3EC1B34199FFFD25D8DDAB1EC7CEC39BB76614E4BA8B30E75253B529C27823BE +8FDBD9C7103414836F2F955B40B174890B625F54C723E728D0AAB99CE7D73C2AC582ACCEDF5B +0671C07A97D0A9ED3AB5A4B163C83EA4C1C05F4D6DB2609D1E785D42229D59EC182C0C02719D +4420F72C6A9224B62FEA5C885EAA2D61DB6E56D29EA8C091803A2222B6683577A1867796F2C9 +F5175615F6D5FBF9E620AAFA4E60C20CF733EEE1D51F5696AF482AC4AD11278E56EDDFA7E0AD +533FF3ECD2D379C573FBF8E16E3CE11D8EF293967D76408C9C8A3B6A884A5DE9B1D4D40F8086 +48A7BDDE93624BDBED92CE790151E0081B9530DB07E8E982353CB80B50D8B63BCA09A6C42A33 +991C1A305F36857BDC4D18C5679D5716C1B82039C9C9E303B79378B012340DE204495D66A06A +4415980D023C07148785F6A2DCCAF9E86FF0C9835B47524F9A5ACFE9EBC53F7AA3299D595B3E +A3867D71AE686FF0FC9F194279746358C72B2B5AA73E6E92B41AB468964567CA14DC213338B6 +4079965E53EFB8E7EB5474E32D67916A66B896D5A88DBF605CFB36E2224E748FE4259844E6F8 +A20C1E0FB06F24772E06EC3C0E53075AF7072AFB2BA562A691B8D98418F38E4A7C7CD0CF7F45 +0C15BFFA0A267FAA6CFA0E82D49D1AB398442119493CC2A2E15689C7B01992CB73AD2EA3DC8E +4939739AFFF6C7F1D715DA77488F2B5E87E1FE3FF2477B5079705DF17BE7C6ECC949F0904C2E +89DB22A6890AE6B915896C47A74C3ADD1F8FA3FB08CD8C0FE48D380871B84E0E2E418CC81629 +3DA3F3425B19A66C05C24C7B5F2336EB7D3F57EB972EEE70A6CE9D8A8286025B1DA5130B9465 +AB5A097CF05F99F2F5265BF748D9573EA0CEEBC1F2FD5033141264DEDFD7746B65D207FF6CDF +E8124AFF6593C6443F8411DC9F5039D02324B14AD8EA9B1A361AAA6168BFA7C813C39CD0E6B3 +2EE696F8C67E5D15C273C12415C40C1B0F2736BFA6731FF10391DC0E23983905BF3235100413 +7986EDE64D0C3345417C1186AB1AE9E09A98C116DF8B0715FF2B1E99A2FE5FEE1B89F3468DEB +AF2DDDA899B9C1ABA9B2A762B5EA826727E30E158877E646D3CBACF83FD7691BD69E39C448FF +0339101CF7D47622F295A26A884B236B7E9E4BAE6A8DC38A9BEC2E986552DEA9355C1DF792F0 +3DDC318582918C8BAFBCD567638C99398AF9AC3940F3E3A37D5FB6B2129BB3620742B278A0AA +044C096B674CD2F6CB4526552FDCB51BD1E7832CF1F57D95D92CB43F409EFA47C0DAD18FA479 +F72F8657970287AF54C70B695ED1F157A3D171D7A16C30DF4F9530D8489A9A4720F5749659AF +864F1FCCF90B870A3EDBEAE4242893C425F5F0189DB04E3738209737979E12214482DE3E42C8 +9D9E2E8413AF5DE8E2BCF48862E35CDBC822B75CE3475799DB6E1C50071A91C9E0B8B2A23B4C +78F63DBE558CF5F8D026E1150A0A5A56EAC99C7B3BD7201B86ABA3A24845CC22630B2927CBEF +55CE3931698AA96AC1B7B17D9DA16983B3DC05C428184A0F86C818DDF1AC539BEA71ACAC2FC5 +4FA6B0B63E3B8FA4647B972815677003482A8851BF2DD7757698A85E892753ADCA249E607FD9 +7724FD34D5B978B683B7478A1F7C931DD1696B7049C8E4A949C28C540FADC908674E517CCF69 +FFECA21FA70C6034F2C1DFDAB530A6C0DC6F8F9963147F7F393BE5AEC11F95674712FAC4083E +4729A74D31B88516C169B62385D34423047A3A5AC7CF4EC1B3C0755498A06EBEEF941844066F +140F69FB48D6E0CF4FB678196E13A991BE17A8C9681A535EB0E379DB700C3703BC7C948B84FC +2E983B77AE2E926005FDA1DABC948CFB557EBBA947F0395FC7866685499C22E3812206F16DA4 +0776AFC8AC141FDA9A1E3C06FFABD1F1471E1D7149ECED3A9F318932EE192A85D04C26697381 +F4C9E5B3FA36BC2C071C08D4C2EE9D51BDAA5D91419CC54F6327353825BF4D983307A7371CDC +9F8736C6A79DE8FC34182262F5D8F58AFC30254DF5E9B6346BCFB6AE5739E9A5257596AB8D60 +FE0B539A5F8CCF794AB021762104EE69FB1305665D2AD8A04D1C872ED9F45803EAB198402647 +FE98E189FCAE485E55A5198745851D39330456DA286731440167C05ED527A3A3592736FD58EF +A01209F5D5BD52C873E31DBE8913ED626C61D8F759B31A49A0464CC8CCA713CD8C9796C28EF4 +4F6EDCFD2158C8753F04175175DFA7D174F2261B1D531D3DA4B683FCCD094BE75D58C533CDCE +AB481E9E72650164F34C32689B9E5B3E15FA75451CD0412CBCDCDEE1C55202F63018E2479E12 +66B31DFCD8EB29EAB003CDE8F9B00708871829E9E482F9F84DABF50E04A005758FB6F79A4B04 +BB349944962E38958F188FA33DA2D33032517B33A7BC638567C2C09BE64996495ED9DDCE44B4 +2C015F39FE9DFE6A486C1D3EE47FCC92241A54272966B90F9168136BD5E4B9902247BD370827 +4247EBB014FE046B87477898AD03893824065CC8D7D7E269158CE72321B28597BEC407EB9DA6 +E06F7A5079080273BB51BACFE3C2A233C6A5CC3F7009A981D593911C8074C8497A097D7F368C +FBEFC87293DACED1B267D8029C9341235FA531E9B9CD99A47BD939067EC1035778E9F90C4BBD +42C11F99FC4E2DEF0C65DD628717F794FE3AE20508D39A88F300D5FB033223A295507A212F85 +5344571D2A09E4644AEDA2414359CED6977507B64A4ACA4106584CDE9766482E61B8B21E2F9F +365670308D51E73E805137B7EC6E0CC773B0B71EF2B216A8FD98709723AE86757E29C5C47495 +57C682614C9E6B9BAC63388312C2CC5DFE9A63E7C8E1D30D02D5F787142385DDE69E3EF14C2C +F7A1C30389ED2C63B1D19C1530150BC1DCEA91AE06280B9D1C0CAF0AB2C48025D164B37A1983 +0DBE39932823E0B9978FF7D401636AC47300F86148290E0DF001B22B62483740CEAAD2A98F82 +54DBA38D848A15B3EE2C80604624E26B5A45127F58BDB3F1E021C8E0BCF4258F33AFBE778AAD +8390B6E7E82EA8114169E2775AE75EFCB67FC4F104AD327701A3F81807FCFE47C6060061AB35 +DCD77BF335D806B26C45648F5EE0B5AE053389310D80AE22F9EA2EEF1D068EAF4C776C0D3B2C +70C8D533F6B6C869B2CB9BE1104C638AB9057764353011728C2EF17E19DEB436B0D4FD544DE8 +0C0D5570FE9250FB028FE5C4F12A6353B65F87E28B2DDDCCA0936BD847E3498B0E05E53553E1 +49B0A2DE1E57E4D84FD6516259C91ACED13FB6EA70FFC03362E35146369FC6D2F943C4881A9E +68FAD45AAE9361B0EA34749817B3F98DAE65BBE2260F5A8B06F6CA003D16416717B7C740732F +E19663240670C04C558033793F21BDE8107F8655C7365D7C2EB1A6495F5FDE6D185A85A68C09 +4A96303FACEFE684CB75B2AACCEF45AD68C46B817BFDB41553FF360D07DDEBA08F5441E098E4 +E4A70704C4A6A3E07F6E0E28A582F19942FD7F53ECA391F40865EFA5AE9D6EA2359F8EC74C23 +D92585C206FD8AE87264A06DDDCF36720A8026525A84D0D68AC93171EE2E87571567F300D2DE +3CFB7DF541128107227D4949F4D2E6BC7FCFB1909DAFBCA11414C31F9A9C6DE380CE616B9143 +5C212C7F52F705BD46620EC2CE434BF73760D3F574894CEAE00E82DFDEF94B74E1A54117B4AA +B523186ED86DB61A8B842E3869BC2BBB3CB0B587E80963CF1C01D385F20F762CBCEECB1F5E12 +B551447AA9B8A8FCFE74E29C3AE2FD8F651553F80C1AD8D32EA25890D1B3D7BC9EE3571ED872 +BFC14AA5E14B1E24572CF6DEE0A37F30CC26AC91E405957E09EC263DDFEB7870CC24962505FD +B586FE0D2D9148E7DEC517034D87A3D59AB534362BE565A0B0E83C7036D25F912ECFF4C87BCA +1CCDED9037E2B51F1411455F1767974B52C9C040ED0F340DF403C70BB2AEDE49D0411037F27D +E9723419734B3B62613A6AD0D7FFB6B4AD60A927E7A0F6D0770734D886D9CFEFB3D38B701DF0 +88A05738AABDF63CBA03E97CC40943CABD85AE31F3AC3F741945067636CB58B705CF2B6EDE2D +26E721E0DB36F4355F2493E01347869F8452E7CF368B78A163711524FEB83A87F032BE27C9A8 +D0EEFBD78680F8196640D575A360D916E0C3C4BCF0BAF6209CCE3AB17ABBF315BA689BACDB46 +4C8E64F989B3491D8644C937DF9FBD9BDF4A46F377673575215D5951A67DDD00FFC27F4AF099 +B69A0E42B06A1D012D81C03E7A90893F4E7A9E979EA66C1BE4008443AE66D2237D61E1D51981 +D7E98E2BEB93425C27A9C5A2111B4806A9C55DD63E02B8E519E3B4DEFBAFA1D97C0CD09D5548 +89E67A37FE6E7843DB388AD4B211990DCA56CFAE1A1421E137E340DD93A13F82300F3BAC6C14 +801160D7A486E4D6D86612A34C3CDD889D310A4FF1DDFE9E086C93DCDDC7C9C855E57B2FF11E +EEB1602AB284A3C16C90471E355EEADFE60D7A4605471A2CF73F6E8C618BC3EDB50022194C23 +F6843929A63DDC83166B7804D5692BB462C2D9D536630BA9E7D09607F5F3D234C39EBF4514E4 +A66525D654D3F85CD8671B8FC7EAED36FAEAB0EBE66B435286C4F1BC9A7260A249FA6AA4534D +905333700E8575207D7CF4572CAF801E341438866624BF5DB014FA1D54E078241BE2796DFD0C +41A33A665C77302D6789152BEE35AB214762250491A8F6E2E5163DECAB37F324A6B24E4FC60B +4E8D09A98E8CA001AC6005742C697F2AEBE6DD2D6A315EB1C2130C62F0BA71A7E623979845CA +61CAFDE6CD3DC0E3862364E0326BB4505BA76C2E1ABA60F605C5CF16FFB22CD2D473B814B6C7 +1F274218E489C1DA40FDDD1275069D5A3FB8898B3D886B235ED23520CD36D888C484FC952F13 +E7A9A184B4892B88236319881EB0375F631D87C49C5881FB5F9BE508B2CF479496AF4B0A7816 +CA21921563296D2537DBA7A6A5E3C2EE64D14FCD53973AB4C8623CD3E0574BB76D50145AAAB9 +C01EE99218BDCA2250AD2773900B3FE46FB429F636F8A03AA3F85B15A65DB103C3DEA7A70ADC +8367C3F20425F614C09D7EDF1141E4200B22B0F0ABF246C4B1F3FB4534B0AA0193B35C6C9282 +3BD246C28A8FA1FB8CDD16C35E08577D7CB9D54EA4ED905ACBB4068933A0F0D8BE557A8CAC5B +9974E12FBC08ED8B3046ECB8F02F618E1AB086BCD379433EF63A578B05A4C0046C083808E858 +1B93B2F0ABF4A2A6416617C8C167BFEB25DD348729DF48BD207D8649234B5AD4DB4387B53015 +BC48ED1305D24AF73F02C649427FAF78003B5CE8952199763A7638133EF3D3B0AA5B84E44146 +73963276A76A6B8953A023D3643E4B860C4847978F5995FEB031C904466DAB7219BC833903E9 +90E24467D0797B8780238ED5B1AB05FAC6F2D8168CF727E0E688020D72D68ACA98B62FC686A8 +1AE8B9F9AFBA4DA0CFC118D04A81DE89ABB0FECC2EFAC05B98724E55FB884A83DE2A0543B235 +466CA665ADFB740D962D89F5D9E0A4BAD4FC8301371AEBBBB28AC5B6636C8892B997FDFEA2E1 +3FD233E46F988F95559290A7C61A93EDF933533D804BA77DE5CFF35B4BE7B4DA25E7A5ACFE76 +F9BE34CECB3F02C706CB40E260CCA8EE8F68E005F87608AF65A7296C0B4C2F90A3802B11FE3E +6663B5A046CA1EEDB52C50A2849B2996525A5176358B3C91286885B67469EED54AD644F4452C +9175871355ABAD45682F3DE3FA693B76B6F1B71DA5BEBDE7F7B4AD091FCAC8A7029F7EB3DA1E +88794777B6213A9C78F6218F025F81BCB0A79CACCBA5872485272508B8D9D17995E11E8B02B2 +95EFFEC42C0CD4A8299011A31D6354859E96343334B32D5F7E14A1AAE407077FE249C5182BA3 +39AE08750A3EA81206AC36E3BAD944E4795F2D5BE769245D83C76311BECEF343192A611C940D +679D1C2E5A9E7CDE3018A11800C6EE7902B628FB365ED37E115F4C96629CA4C7936EC37437C2 +B6F02A7F5AE65C1E88A6F382BBACE20015403ABB85B52FD484684A2C850C907AAB14B8AAA0B6 +0EDF2314B64ED3F1950A058D0D9D8D6AEB6CFDEA33EEAB955A70953B430EB9ED9E553D594297 +FB154F799A5B4A0FD82B067D8F234003B0023643CBC4FB636D3FF6B7F318F9C64DED734ADA11 +8AB8F138CD94C1564E43B92CBADCFA54FF3BFE5B647A5179CC92FABCB3638063DF444F17C18F +19DB63066D4B2FD7CF2B3DE63D1CF486DE54991B73D27E6DF0B63A54D45946CEB5C4BDCC9515 +E97A435349D7035155A42C280B075B59BC89845C6E294641D8BA2B49629C9DCEC496EFB8C323 +692347122D0BCEB8E793EE381647B5C922BF838A8568C2CBF709DD6EB70D38923AF564F04242 +EEFE46752AA083AD0F19B0A3492F5721A85A377A9C160A604446C2887E3123BF14D0CEDD2CFE +179C11DC231F9B3F06EC99C1C6D18671DD57204FF482E1E4D93639246EA912D6CD1005E10225 +F8C8DC2F2E540C93D9DB908AA8B1EA4140B152277A8AA3D3452ABD078741B546012FC73FEB4E +B882AB0C15D125B6B3DEC6E82A4EC1E11C837C28326E27D17879D9F3688DB1F38191426AA4C5 +0C42113E3A7005F92254B7A338E19C4A06CB706D903FC5359D408261F75F9E9C63D9307BB8DF +8C9F1FEB572D2BB11470CBE05E9C45B7C17D8A34DE703FF63355599448EA18BD15D7E8FDCF6B +EBBB2A89C27278A64A154E2C777E1502499D9A51C1E9236F70567DE5B748AF1949BED1C5409C +151F510424C00EBE7AF3A82D9FB8E898900C787ED304D05159B118B52C8826DA36049B70D6A1 +7BB445711402F8D6217A349B134CFF7C9852515EAAA496CCFDBC768970D464542F1076340507 +DC62041D7F32E25BA02EC9D78F737BD0ECFC7E2B725A050214DFEF8FD72EE67C0624A54B2C00 +B15768B0165F006764B85385426915CA8A3D8782DC05C9F516D85E5ECB5C594A4AC4E42365BB +4477AFC353E5F248142A3D5A22632DEB3DAC54A79CE890C7EF134703CE3B1C1949858B17F18B +BCB1FF377C562D6281C3C08A053B50CCD07CDB20C8D002CABEB082BBF179B9A081C16C3F7772 +6C44F8A3D5270BB63B34E8CFEFACD347F448ED5E690129D33812DC4BA7853B24735BD23149B9 +9D73654B4A22EAC87D19FDCAEDDD519EC97C6024B22BA98162DB5B0769327AE6B9D6F7ABE791 +3BBE25CB9156492D57F4F32E47661851DC82BDBEF74F3FDB433ABA59D6799F9B5FB956950656 +9FA852949ED182BD50D4DE2FF1BAD9EB9BB4D617A127ABB7070278A2AB2FB5E518C03B0E4E3E +15D7531C6B929C74AEE4B275D4AFB0000A309C7AEC9A10C9473FDF77A50F9AFB139ED61E0919 +944E72A0ADB6CC74B9609DFC9CD923C3C5C1BFB3546628E26FD5338005FE9389A493A27594B5 +8469454C2E2530C711F3F02951081DD33BF7A3DB773EA7E446912A18D75841C5B1239D752D48 +48FB8AD79B4B79504A41AB82BB6B43F425909C44853A8A3159BB75B7342F3CB7281AFC25FA76 +93B409FF5DCCD59DAA16E5FDEB1DC19CD1D303BD00D2154F0EC08E04B5FC441010349998C2C6 +EFA036734540532E588FA2A3FF65367997896DFC6A4AC97A31CF6434AEAD822890AA62621F8A +3E93785EA32CFC4EACF582AE356EBFD7134160519F91A50753898F505AE6BC39BF63F3599C07 +9AFCB6812D2D9B159BDC9017152F4A050B08014AC846F970F2DAD485EF15AAF397898584BBEF +2FCDD970786C41AF8B2D3728D3D4C5053EAA1FFBBB2C85752F4E8C0D6F6BF783ABB49796D75C +0F95A0DA58239580180B033816608D8B3C2D5D52A3D50A82D88C0EA92FDE25C314B1F7FB5D22 +0439E685975D29750A878EC4332BC74A67CBC345095DEF613CBD058AAD37EAAF7FF039673D4B +ECCA0E38398CF8B9CA775AF365AD16572FD1899342BB76C248886190C9B7540324CF7AB6E076 +8BA6CE39B012882AD64B08AAD4C1C40BF75FCB05F85C8CDE44C523D42B47B4C906BDF6CF27D0 +6689352A2004728F724FC37601BFE0C7FFEB527E7070F435D0453C0F996055F80B2AF2A36309 +46ECD88DD8E864DE048C09D0BD90C4F970A005FD1AB27DC2F374C4DB8D6E690CA525E313ECE3 +F8F8AB88E50000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark + + +%%EndFont +%%BeginProcSet: texps.pro +TeXDict begin /rf{findfont dup length 1 add dict begin{1 index /FID ne 2 +index /UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll +exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]/Metrics +exch def dict begin Encoding{exch dup type /integertype ne{pop pop 1 sub +dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def} +ifelse}forall Metrics /Metrics currentdict end def[2 index currentdict +end definefont 3 -1 roll makefont /setfont load]cvx def}def +/ObliqueSlant{dup sin S cos div neg}B /SlantFont{4 index mul add}def +/ExtendFont{3 -1 roll mul exch}def /ReEncodeFont{/Encoding exch def}def +end +%%EndProcSet +%%BeginProcSet: special.pro +TeXDict begin /SDict 200 dict N SDict begin /@SpecialDefaults{/hs 612 N +/vs 792 N /ho 0 N /vo 0 N /hsc 1 N /vsc 1 N /ang 0 N /CLIP 0 N /rwiSeen +false N /rhiSeen false N /letter{}N /note{}N /a4{}N /legal{}N}B +/@scaleunit 100 N /@hscale{@scaleunit div /hsc X}B /@vscale{@scaleunit +div /vsc X}B /@hsize{/hs X /CLIP 1 N}B /@vsize{/vs X /CLIP 1 N}B /@clip{ +/CLIP 2 N}B /@hoffset{/ho X}B /@voffset{/vo X}B /@angle{/ang X}B /@rwi{ +10 div /rwi X /rwiSeen true N}B /@rhi{10 div /rhi X /rhiSeen true N}B +/@llx{/llx X}B /@lly{/lly X}B /@urx{/urx X}B /@ury{/ury X}B /magscale +true def end /@MacSetUp{userdict /md known{userdict /md get type +/dicttype eq{userdict begin md length 10 add md maxlength ge{/md md dup +length 20 add dict copy def}if end md begin /letter{}N /note{}N /legal{} +N /od{txpose 1 0 mtx defaultmatrix dtransform S atan/pa X newpath +clippath mark{transform{itransform moveto}}{transform{itransform lineto} +}{6 -2 roll transform 6 -2 roll transform 6 -2 roll transform{ +itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}}{{ +closepath}}pathforall newpath counttomark array astore /gc xdf pop ct 39 +0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if}N +/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 -1 +scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 get +ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip yflip +not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 +TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{noflips{TR +pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop 90 rotate 1 +-1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg +TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr 1 get neg +sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr 2 get ppr +0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 -1 roll add +2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S TR}if}N /cp +{pop pop showpage pm restore}N end}if}if}N /normalscale{Resolution 72 +div VResolution 72 div neg scale magscale{DVImag dup scale}if 0 setgray} +N /psfts{S 65781.76 div N}N /startTexFig{/psf$SavedState save N userdict +maxlength dict begin /magscale true def normalscale currentpoint TR +/psf$ury psfts /psf$urx psfts /psf$lly psfts /psf$llx psfts /psf$y psfts +/psf$x psfts currentpoint /psf$cy X /psf$cx X /psf$sx psf$x psf$urx +psf$llx sub div N /psf$sy psf$y psf$ury psf$lly sub div N psf$sx psf$sy +scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub TR +/showpage{}N /erasepage{}N /copypage{}N /p 3 def @MacSetUp}N /doclip{ +psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2 +roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath +moveto}N /endTexFig{end psf$SavedState restore}N /@beginspecial{SDict +begin /SpecialSave save N gsave normalscale currentpoint TR +@SpecialDefaults count /ocount X /dcount countdictstack N}N /@setspecial +{CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto +closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx +sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR +}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse +CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury +lineto closepath clip}if /showpage{}N /erasepage{}N /copypage{}N newpath +}N /@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{ +end}repeat grestore SpecialSave restore end}N /@defspecial{SDict begin} +N /@fedspecial{end}B /li{lineto}B /rl{rlineto}B /rc{rcurveto}B /np{ +/SaveX currentpoint /SaveY X N 1 setlinecap newpath}N /st{stroke SaveX +SaveY moveto}N /fil{fill SaveX SaveY moveto}N /ellipse{/endangle X +/startangle X /yrad X /xrad X /savematrix matrix currentmatrix N TR xrad +yrad scale 0 0 1 startangle endangle arc savematrix setmatrix}N end +%%EndProcSet +TeXDict begin @defspecial + + TeXDict begin /box{newpath 2 copy moveto 3 copy pop exch lineto 4 +copy pop pop lineto 4 copy exch pop exch pop lineto closepath } bind +def /min{ 2 copy gt { exch } if pop } bind def/max{ 2 copy lt { exch +} if pop } bind def/roundedbox{/radius exch store 3 2 roll 2 copy min +radius sub /miny exch store max radius add /maxy exch store 2 copy +min radius sub /minx exch store max radius add /maxx exch store newpath +minx radius add miny moveto maxx miny maxx maxy radius arcto maxx maxy +minx maxy radius arcto minx maxy minx miny radius arcto minx miny maxx +miny radius arcto 16 {pop} repeat closepath }bind def /rectcartouche{box +gsave .95 setgray fill grestore 1 setlinewidth stroke }bind def /cartouche{roundedbox +gsave .95 setgray fill grestore 1 setlinewidth stroke }bind def end + +@fedspecial end TeXDict begin +40258431 52099146 1000 600 600 (manual.dvi) @start /Fa +157[25 98[{}1 50.000001 /Times-Italic rf /Fb 256[{}0 +50.000001 /RMTMI rf /Fc 167[117 88[{}1 83.333337 /MTEX +rf /Fd 144[50 50 10[50 99[{TeXBase1Encoding ReEncodeFont}3 +83.333337 /Courier-Oblique rf /Fe 205[40 1[17 48[{}2 +63.333383 /MTSYN rf /Ff 144[32 32 2[28 7[28 32 11[39 +86[{}6 63.333383 /Times-Italic rf /Fg 137[31 118[{}1 +63.333383 /RMTMI rf /Fh 139[19 34 23 1[38 2[57 1[34 2[38 +38 19 38 1[34 38 38 44[38 38 38 38 2[19 46[{ + TeXBase1Encoding ReEncodeFont }18 83.333337 /Helvetica-Narrow-Oblique +rf /Fi 4 40 df[<3FFF80000000000000000000000000000000000000007FFFFFE00000 +00000000000000000000000000000000FFFFFFFF80000000000000000000000000000000 +0000FFFFFFFFFC0000000000000000000000000000000000FFFFFFFFFFE0000000000000 +000000000000000000007FFFFFFFFFFE000000000000000000000000000000003FFFFFFF +FFFFE00000000000000000000000000000000000FFFFFFFFFC0000000000000000000000 +000000000000003FFFFFFF80000000000000000000000000000000000000FFFFFFF00000 +0000000000000000000000000000000007FFFFFE00000000000000000000000000000000 +0000003FFFFFC000000000000000000000000000000000000003FFFFF000000000000000 +0000000000000000000000003FFFFE0000000000000000000000000000000000000007FF +FF8000000000000000000000000000000000000000FFFFE0000000000000000000000000 +000000000000001FFFF80000000000000000000000000000000000000003FFFE00000000 +00000000000000000000000000000000FFFF800000000000000000000000000000000000 +00001FFFE00000000000000000000000000000000000000007FFF8000000000000000000 +0000000000000000000001FFFE00000000000000000000000000000000000000007FFF80 +000000000000000000000000000000000000001FFFE00000000000000000000000000000 +000000000007FFF00000000000000000000000000000000000000001FFFC000000000000 +00000000000000000000000000007FFE0000000000000000000000000000000000000000 +1FFF800000000000000000000000000000000000000007FFE00000000000000000000000 +000000000000000001FFF00000000000000000000000000000000000000000FFF8000000 +00000000000000000000000000000000003FFE0000000000000000000000000000000000 +0000001FFF000000000000000000000000000000000000000007FFC00000000000000000 +000000000000000000000001FFE00000000000000000000000000000000000000000FFF0 +00000000000000000000000000000000000000007FFC0000000000000000000000000000 +0000000000001FFE00000000000000000000000000000000000000000FFF000000000000 +000000000000000000000000000003FF8000000000000000000000000000000000000000 +01FFC00000000000000000000000000000000000000000FFF00000000000000000000000 +0000000000000000003FF800000000000000000000000000000000000000001FFC000000 +00000000000000000000000000000000000FFE0000000000000000000000000000000000 +00000007FF000000000000000000000000000000000000000003FF800000000000000000 +000000000000000000000000FFC000000000000000000000000000000000000000007FE0 +00000000000000000000000000000000000000003FF00000000000000000000000000000 +0000000000001FF800000000000000000000000000000000000000000FFC000000000000 +000000000000000000000000000007FE0000000000000000000000000000000000000000 +03FF000000000000000000000000000000000000000001FF800000000000000000000000 +000000000000000000FFC000000000000000000000000000000000000000007FE0000000 +00000000000000000000000000000000003FE00000000000000000000000000000000000 +0000001FF000000000000000000000000000000000000000000FF8000000000000000000 +000000000000000000000007FC000000000000000000000000000000000000000003FE00 +0000000000000000000000000000000000000003FF000000000000000000000000000000 +000000000001FF000000000000000000000000000000000000000000FF80000000000000 +00000000000000000000000000007FC00000000000000000000000000000000000000000 +3FE000000000000000000000000000000000000000001FE0000000000000000000000000 +00000000000000001FF000000000000000000000000000000000000000000FF800000000 +0000000000000000000000000000000007FC000000000000000000000000000000000000 +000003FC000000000000000000000000000000000000000003FE00000000000000000000 +0000000000000000000001FF000000000000000000000000000000000000000000FF0000 +000000000000000000000000000000000000007F80000000000000000000000000000000 +00000000007FC000000000000000000000000000000000000000003FC000000000000000 +000000000000000000000000001FE000000000000000000000000000000000000000001F +F000000000000000000000000000000000000000000FF000000000000000000000000000 +0000000000000007F8000000000000000000000000000000000000000007F80000000000 +00000000000000000000000000000003FC00000000000000000000000000000000000000 +0003FE000000000000000000000000000000000000000001FE0000000000000000000000 +00000000000000000000FF000000000000000000000000000000000000000000FF000000 +0000000000000000000000000000000000007F8000000000000000000000000000000000 +000000007F8000000000000000000000000000000000000000003FC00000000000000000 +0000000000000000000000003FC000000000000000000000000000000000000000001FE0 +00000000000000000000000000000000000000001FE00000000000000000000000000000 +0000000000000FF000000000000000000000000000000000000000000FF0000000000000 +000000000000000000000000000007F80000000000000000000000000000000000000000 +07F8000000000000000000000000000000000000000003FC000000000000000000000000 +000000000000000003FC000000000000000000000000000000000000000001FE00000000 +0000000000000000000000000000000001FE000000000000000000000000000000000000 +000000FF000000000000000000000000000000000000000000FF00000000000000000000 +00000000000000000000007F0000000000000000000000000000000000000000007F8000 +000000000000000000000000000000000000007F80000000000000000000000000000000 +00000000003FC000000000000000000000000000000000000000003FC000000000000000 +000000000000000000000000001FC000000000000000000000000000000000000000001F +E000000000000000000000000000000000000000001FE000000000000000000000000000 +000000000000000FE000000000000000000000000000000000000000000FF00000000000 +0000000000000000000000000000000FF000000000000000000000000000000000000000 +0007F0000000000000000000000000000000000000000007F80000000000000000000000 +00000000000000000007F8000000000000000000000000000000000000000003F8000000 +000000000000000000000000000000000003FC0000000000000000000000000000000000 +00000003FC000000000000000000000000000000000000000001FC000000000000000000 +000000000000000000000001FE000000000000000000000000000000000000000001FE00 +0000000000000000000000000000000000000000FE000000000000000000000000000000 +000000000000FE000000000000000000000000000000000000000000FF00000000000000 +0000000000000000000000000000FF000000000000000000000000000000000000000000 +7F0000000000000000000000000000000000000000007F00000000000000000000000000 +00000000000000007F8000000000000000000000000000000000000000007F8000000000 +000000000000000000000000000000003F80000000000000000000000000000000000000 +00003F8000000000000000000000000000000000000000003FC000000000000000000000 +000000000000000000003FC000000000000000000000000000000000000000001FC00000 +0000000000000000000000000000000000001FC000000000000000000000000000000000 +000000001FC000000000000000000000000000000000000000001FE00000000000000000 +0000000000000000000000001FE000000000000000000000000000000000000000000FE0 +00000000000000000000000000000000000000000FE00000000000000000000000000000 +0000000000000FE000000000000000000000000000000000000000000FE0000000000000 +00000000000000000000000000000FE00000000000000000000000000000000000000000 +0FF000000000000000000000000000000000000000000FF0000000000000000000000000 +000000000000000007F0000000000000000000000000000000000000000007F000000000 +0000000000000000000000000000000007F0000000000000000000000000000000000000 +000007F0000000000000000000000000000000000000000007F000000000000000000000 +0000000000000000000007F0000000000000000000000000000000000000000007F00000 +00000000000000000000000000000000000007F800000000000000000000000000000000 +0000000007F8000000000000000000000000000000000000000003F80000000000000000 +00000000000000000000000003F8000000000000000000000000000000000000000003F8 +000000000000000000000000000000000000000003F80000000000000000000000000000 +00000000000003F8000000000000000000000000000000000000000003F8000000000000 +000000000000000000000000000003F80000000000000000000000000000000000000000 +03F8000000000000000000000000000000000000000003F8000000000000000000000000 +000000000000000003F8000000000000000000000000000000000000000003F800000000 +0000000000000000000000000000000003F8000000000000000000000000000000000000 +000003F8000000000000000000000000000000000000000003F800000000000000000000 +0000000000000000000001F0000000000000000000000000000000000000000000F0> +173 173 294 134 332 36 D[<000000000000000000000000000000000000000000F000 +0000000000000000000000000000000000000001F0000000000000000000000000000000 +000000000003F8000000000000000000000000000000000000000003F800000000000000 +0000000000000000000000000003F8000000000000000000000000000000000000000003 +F8000000000000000000000000000000000000000003F800000000000000000000000000 +0000000000000003F8000000000000000000000000000000000000000003F80000000000 +00000000000000000000000000000003F800000000000000000000000000000000000000 +0003F8000000000000000000000000000000000000000003F80000000000000000000000 +00000000000000000003F8000000000000000000000000000000000000000003F8000000 +000000000000000000000000000000000003F80000000000000000000000000000000000 +00000003F8000000000000000000000000000000000000000007F8000000000000000000 +000000000000000000000007F8000000000000000000000000000000000000000007F000 +0000000000000000000000000000000000000007F0000000000000000000000000000000 +000000000007F0000000000000000000000000000000000000000007F000000000000000 +0000000000000000000000000007F0000000000000000000000000000000000000000007 +F0000000000000000000000000000000000000000007F000000000000000000000000000 +000000000000000FF000000000000000000000000000000000000000000FF00000000000 +0000000000000000000000000000000FE000000000000000000000000000000000000000 +000FE000000000000000000000000000000000000000000FE00000000000000000000000 +0000000000000000000FE000000000000000000000000000000000000000000FE0000000 +00000000000000000000000000000000001FE00000000000000000000000000000000000 +0000001FE000000000000000000000000000000000000000001FC0000000000000000000 +00000000000000000000001FC000000000000000000000000000000000000000001FC000 +000000000000000000000000000000000000003FC0000000000000000000000000000000 +00000000003FC000000000000000000000000000000000000000003F8000000000000000 +000000000000000000000000003F8000000000000000000000000000000000000000007F +8000000000000000000000000000000000000000007F8000000000000000000000000000 +000000000000007F0000000000000000000000000000000000000000007F000000000000 +000000000000000000000000000000FF0000000000000000000000000000000000000000 +00FF000000000000000000000000000000000000000000FE000000000000000000000000 +000000000000000000FE000000000000000000000000000000000000000001FE00000000 +0000000000000000000000000000000001FE000000000000000000000000000000000000 +000001FC000000000000000000000000000000000000000003FC00000000000000000000 +0000000000000000000003FC000000000000000000000000000000000000000003F80000 +00000000000000000000000000000000000007F800000000000000000000000000000000 +0000000007F8000000000000000000000000000000000000000007F00000000000000000 +0000000000000000000000000FF000000000000000000000000000000000000000000FF0 +00000000000000000000000000000000000000000FE00000000000000000000000000000 +0000000000001FE000000000000000000000000000000000000000001FE0000000000000 +00000000000000000000000000001FC00000000000000000000000000000000000000000 +3FC000000000000000000000000000000000000000003FC0000000000000000000000000 +00000000000000007F8000000000000000000000000000000000000000007F8000000000 +000000000000000000000000000000007F00000000000000000000000000000000000000 +0000FF000000000000000000000000000000000000000000FF0000000000000000000000 +00000000000000000001FE000000000000000000000000000000000000000001FE000000 +000000000000000000000000000000000003FC0000000000000000000000000000000000 +00000003FC000000000000000000000000000000000000000007F8000000000000000000 +000000000000000000000007F800000000000000000000000000000000000000000FF000 +000000000000000000000000000000000000000FF0000000000000000000000000000000 +00000000001FE000000000000000000000000000000000000000001FE000000000000000 +000000000000000000000000003FC000000000000000000000000000000000000000003F +C000000000000000000000000000000000000000007F8000000000000000000000000000 +000000000000007F800000000000000000000000000000000000000000FF000000000000 +000000000000000000000000000000FF0000000000000000000000000000000000000000 +01FE000000000000000000000000000000000000000003FE000000000000000000000000 +000000000000000003FC000000000000000000000000000000000000000007F800000000 +0000000000000000000000000000000007F8000000000000000000000000000000000000 +00000FF000000000000000000000000000000000000000001FF000000000000000000000 +000000000000000000001FE000000000000000000000000000000000000000003FC00000 +0000000000000000000000000000000000007FC000000000000000000000000000000000 +000000007F800000000000000000000000000000000000000000FF000000000000000000 +000000000000000000000001FF000000000000000000000000000000000000000003FE00 +0000000000000000000000000000000000000003FC000000000000000000000000000000 +000000000007FC00000000000000000000000000000000000000000FF800000000000000 +000000000000000000000000001FF000000000000000000000000000000000000000001F +E000000000000000000000000000000000000000003FE000000000000000000000000000 +000000000000007FC00000000000000000000000000000000000000000FF800000000000 +000000000000000000000000000001FF0000000000000000000000000000000000000000 +03FF000000000000000000000000000000000000000003FE000000000000000000000000 +000000000000000007FC00000000000000000000000000000000000000000FF800000000 +000000000000000000000000000000001FF0000000000000000000000000000000000000 +00003FE000000000000000000000000000000000000000007FE000000000000000000000 +00000000000000000000FFC00000000000000000000000000000000000000001FF800000 +000000000000000000000000000000000003FF0000000000000000000000000000000000 +00000007FE00000000000000000000000000000000000000000FFC000000000000000000 +00000000000000000000001FF800000000000000000000000000000000000000003FF000 +000000000000000000000000000000000000007FE0000000000000000000000000000000 +0000000000FFC00000000000000000000000000000000000000003FF8000000000000000 +00000000000000000000000007FF00000000000000000000000000000000000000000FFE +00000000000000000000000000000000000000001FFC0000000000000000000000000000 +0000000000003FF80000000000000000000000000000000000000000FFF0000000000000 +0000000000000000000000000001FFC00000000000000000000000000000000000000003 +FF80000000000000000000000000000000000000000FFF00000000000000000000000000 +000000000000001FFE00000000000000000000000000000000000000007FFC0000000000 +000000000000000000000000000000FFF000000000000000000000000000000000000000 +01FFE00000000000000000000000000000000000000007FFC00000000000000000000000 +00000000000000001FFF00000000000000000000000000000000000000003FFE00000000 +00000000000000000000000000000000FFF8000000000000000000000000000000000000 +0001FFF00000000000000000000000000000000000000007FFE000000000000000000000 +0000000000000000001FFF80000000000000000000000000000000000000007FFE000000 +0000000000000000000000000000000001FFFC0000000000000000000000000000000000 +000007FFF0000000000000000000000000000000000000001FFFE0000000000000000000 +000000000000000000007FFF8000000000000000000000000000000000000001FFFE0000 +000000000000000000000000000000000007FFF800000000000000000000000000000000 +0000001FFFE000000000000000000000000000000000000000FFFF800000000000000000 +0000000000000000000003FFFE000000000000000000000000000000000000001FFFF800 +000000000000000000000000000000000000FFFFE0000000000000000000000000000000 +00000007FFFF800000000000000000000000000000000000003FFFFE0000000000000000 +0000000000000000000003FFFFF00000000000000000000000000000000000003FFFFFC0 +000000000000000000000000000000000007FFFFFE000000000000000000000000000000 +000000FFFFFFF000000000000000000000000000000000003FFFFFFF8000000000000000 +000000000000000000FFFFFFFFFC0000000000000000000000000000003FFFFFFFFFFFE0 +0000000000000000000000000000007FFFFFFFFFFE000000000000000000000000000000 +00FFFFFFFFFFE000000000000000000000000000000000FFFFFFFFFC0000000000000000 +000000000000000000FFFFFFFF8000000000000000000000000000000000007FFFFFE000 +00000000000000000000000000000000003FFF8000000000000000000000000000000000 +000000>173 173 294 300 332 I[<3C0000000000000000000000000000000000000000 +007C000000000000000000000000000000000000000000FE000000000000000000000000 +000000000000000000FE000000000000000000000000000000000000000000FE00000000 +0000000000000000000000000000000000FE000000000000000000000000000000000000 +000000FE000000000000000000000000000000000000000000FE00000000000000000000 +0000000000000000000000FE000000000000000000000000000000000000000000FE0000 +00000000000000000000000000000000000000FE00000000000000000000000000000000 +0000000000FE000000000000000000000000000000000000000000FE0000000000000000 +00000000000000000000000000FE000000000000000000000000000000000000000000FE +000000000000000000000000000000000000000000FF0000000000000000000000000000 +00000000000000FF0000000000000000000000000000000000000000007F000000000000 +0000000000000000000000000000007F0000000000000000000000000000000000000000 +007F0000000000000000000000000000000000000000007F000000000000000000000000 +0000000000000000007F0000000000000000000000000000000000000000007F00000000 +00000000000000000000000000000000007F000000000000000000000000000000000000 +0000007F0000000000000000000000000000000000000000007F80000000000000000000 +00000000000000000000007F8000000000000000000000000000000000000000003F8000 +000000000000000000000000000000000000003F80000000000000000000000000000000 +00000000003F8000000000000000000000000000000000000000003F8000000000000000 +000000000000000000000000003FC000000000000000000000000000000000000000003F +C000000000000000000000000000000000000000001FC000000000000000000000000000 +000000000000001FC000000000000000000000000000000000000000001FC00000000000 +0000000000000000000000000000001FE000000000000000000000000000000000000000 +001FE000000000000000000000000000000000000000000FE00000000000000000000000 +0000000000000000000FE000000000000000000000000000000000000000000FE0000000 +00000000000000000000000000000000000FF00000000000000000000000000000000000 +0000000FF0000000000000000000000000000000000000000007F0000000000000000000 +000000000000000000000007F0000000000000000000000000000000000000000007F800 +0000000000000000000000000000000000000007F8000000000000000000000000000000 +000000000003F8000000000000000000000000000000000000000003FC00000000000000 +0000000000000000000000000003FC000000000000000000000000000000000000000001 +FC000000000000000000000000000000000000000001FC00000000000000000000000000 +0000000000000001FE000000000000000000000000000000000000000001FE0000000000 +00000000000000000000000000000000FE00000000000000000000000000000000000000 +0000FF000000000000000000000000000000000000000000FF0000000000000000000000 +000000000000000000007F0000000000000000000000000000000000000000007F800000 +0000000000000000000000000000000000007F8000000000000000000000000000000000 +000000003FC000000000000000000000000000000000000000003FC00000000000000000 +0000000000000000000000001FC000000000000000000000000000000000000000001FE0 +00000000000000000000000000000000000000001FE00000000000000000000000000000 +0000000000000FF000000000000000000000000000000000000000000FF0000000000000 +000000000000000000000000000007F00000000000000000000000000000000000000000 +07F8000000000000000000000000000000000000000007F8000000000000000000000000 +000000000000000003FC000000000000000000000000000000000000000003FC00000000 +0000000000000000000000000000000001FE000000000000000000000000000000000000 +000001FE000000000000000000000000000000000000000000FF00000000000000000000 +0000000000000000000000FF0000000000000000000000000000000000000000007F8000 +000000000000000000000000000000000000007F80000000000000000000000000000000 +00000000003FC000000000000000000000000000000000000000003FC000000000000000 +000000000000000000000000001FE000000000000000000000000000000000000000001F +E000000000000000000000000000000000000000000FF000000000000000000000000000 +000000000000000FF0000000000000000000000000000000000000000007F80000000000 +00000000000000000000000000000007F800000000000000000000000000000000000000 +0003FC000000000000000000000000000000000000000003FE0000000000000000000000 +00000000000000000001FE000000000000000000000000000000000000000000FF000000 +000000000000000000000000000000000000FF0000000000000000000000000000000000 +000000007F8000000000000000000000000000000000000000007FC00000000000000000 +0000000000000000000000003FC000000000000000000000000000000000000000001FE0 +00000000000000000000000000000000000000001FF00000000000000000000000000000 +0000000000000FF0000000000000000000000000000000000000000007F8000000000000 +000000000000000000000000000007FC0000000000000000000000000000000000000000 +03FE000000000000000000000000000000000000000001FE000000000000000000000000 +000000000000000001FF000000000000000000000000000000000000000000FF80000000 +00000000000000000000000000000000007FC00000000000000000000000000000000000 +0000003FC000000000000000000000000000000000000000003FE0000000000000000000 +00000000000000000000001FF000000000000000000000000000000000000000000FF800 +0000000000000000000000000000000000000007FC000000000000000000000000000000 +000000000007FE000000000000000000000000000000000000000003FE00000000000000 +0000000000000000000000000001FF000000000000000000000000000000000000000000 +FF8000000000000000000000000000000000000000007FC0000000000000000000000000 +00000000000000003FE000000000000000000000000000000000000000003FF000000000 +000000000000000000000000000000001FF8000000000000000000000000000000000000 +00000FFC000000000000000000000000000000000000000007FE00000000000000000000 +0000000000000000000003FF000000000000000000000000000000000000000001FF8000 +00000000000000000000000000000000000000FFC0000000000000000000000000000000 +00000000007FE000000000000000000000000000000000000000003FF000000000000000 +000000000000000000000000001FF800000000000000000000000000000000000000000F +FE000000000000000000000000000000000000000007FF00000000000000000000000000 +0000000000000003FF800000000000000000000000000000000000000001FFC000000000 +00000000000000000000000000000000FFE0000000000000000000000000000000000000 +00007FF800000000000000000000000000000000000000001FFC00000000000000000000 +000000000000000000000FFE000000000000000000000000000000000000000007FF0000 +00000000000000000000000000000000000003FFC0000000000000000000000000000000 +0000000001FFE000000000000000000000000000000000000000007FF800000000000000 +000000000000000000000000003FFC00000000000000000000000000000000000000001F +FF00000000000000000000000000000000000000000FFF80000000000000000000000000 +0000000000000003FFE00000000000000000000000000000000000000001FFF000000000 +000000000000000000000000000000007FFC000000000000000000000000000000000000 +00003FFE00000000000000000000000000000000000000000FFF80000000000000000000 +0000000000000000000007FFE00000000000000000000000000000000000000001FFF800 +00000000000000000000000000000000000000FFFE000000000000000000000000000000 +00000000003FFF80000000000000000000000000000000000000001FFFE0000000000000 +0000000000000000000000000007FFF80000000000000000000000000000000000000001 +FFFE00000000000000000000000000000000000000007FFF800000000000000000000000 +00000000000000001FFFE00000000000000000000000000000000000000007FFFC000000 +0000000000000000000000000000000001FFFF0000000000000000000000000000000000 +0000007FFFE0000000000000000000000000000000000000001FFFFC0000000000000000 +000000000000000000000007FFFF8000000000000000000000000000000000000001FFFF +F0000000000000000000000000000000000000003FFFFF00000000000000000000000000 +0000000000000FFFFFF000000000000000000000000000000000000001FFFFFF00000000 +0000000000000000000000000000003FFFFFF80000000000000000000000000000000000 +0007FFFFFFF0000000000000000000000000000000000000FFFFFFFFF800000000000000 +000000000000000000001FFFFFFFFFFFF000000000000000000000000000000001FFFFFF +FFFFF0000000000000000000000000000000001FFFFFFFFFF80000000000000000000000 +000000000001FFFFFFFFF800000000000000000000000000000000000FFFFFFFF8000000 +0000000000000000000000000000001FFFFFF00000000000000000000000000000000000 +00000FFFF0>173 173 128 300 332 I[<00000000000000000000000000000000000000 +0FFFF00000000000000000000000000000000000001FFFFFF00000000000000000000000 +0000000000000FFFFFFFF80000000000000000000000000000000001FFFFFFFFF8000000 +000000000000000000000000001FFFFFFFFFF800000000000000000000000000000001FF +FFFFFFFFF00000000000000000000000000000001FFFFFFFFFFFF0000000000000000000 +000000000000FFFFFFFFF80000000000000000000000000000000007FFFFFFF000000000 +000000000000000000000000003FFFFFF8000000000000000000000000000000000001FF +FFFF0000000000000000000000000000000000000FFFFFF0000000000000000000000000 +0000000000003FFFFF00000000000000000000000000000000000001FFFFF00000000000 +0000000000000000000000000007FFFF800000000000000000000000000000000000001F +FFFC000000000000000000000000000000000000007FFFE0000000000000000000000000 +00000000000001FFFF0000000000000000000000000000000000000007FFFC0000000000 +00000000000000000000000000001FFFE000000000000000000000000000000000000000 +7FFF8000000000000000000000000000000000000001FFFE000000000000000000000000 +0000000000000007FFF8000000000000000000000000000000000000001FFFE000000000 +0000000000000000000000000000003FFF80000000000000000000000000000000000000 +00FFFE0000000000000000000000000000000000000001FFF80000000000000000000000 +000000000000000007FFE0000000000000000000000000000000000000000FFF80000000 +000000000000000000000000000000003FFE000000000000000000000000000000000000 +00007FFC0000000000000000000000000000000000000001FFF000000000000000000000 +00000000000000000003FFE0000000000000000000000000000000000000000FFF800000 +00000000000000000000000000000000001FFF0000000000000000000000000000000000 +0000003FFC00000000000000000000000000000000000000007FF8000000000000000000 +0000000000000000000001FFE00000000000000000000000000000000000000003FFC000 +00000000000000000000000000000000000007FF00000000000000000000000000000000 +000000000FFE00000000000000000000000000000000000000001FFC0000000000000000 +0000000000000000000000007FF80000000000000000000000000000000000000000FFE0 +0000000000000000000000000000000000000001FFC00000000000000000000000000000 +000000000003FF800000000000000000000000000000000000000007FF00000000000000 +000000000000000000000000000FFE00000000000000000000000000000000000000001F +F800000000000000000000000000000000000000003FF000000000000000000000000000 +000000000000007FE00000000000000000000000000000000000000000FFC00000000000 +000000000000000000000000000001FF8000000000000000000000000000000000000000 +03FF000000000000000000000000000000000000000007FE000000000000000000000000 +00000000000000000FFC00000000000000000000000000000000000000001FF800000000 +000000000000000000000000000000003FF0000000000000000000000000000000000000 +00003FE000000000000000000000000000000000000000007FC000000000000000000000 +00000000000000000000FF800000000000000000000000000000000000000001FF000000 +000000000000000000000000000000000003FE0000000000000000000000000000000000 +00000007FE000000000000000000000000000000000000000007FC000000000000000000 +00000000000000000000000FF800000000000000000000000000000000000000001FF000 +000000000000000000000000000000000000003FE0000000000000000000000000000000 +00000000003FC000000000000000000000000000000000000000007FC000000000000000 +00000000000000000000000000FF800000000000000000000000000000000000000001FF +000000000000000000000000000000000000000001FE0000000000000000000000000000 +00000000000003FE000000000000000000000000000000000000000007FC000000000000 +000000000000000000000000000007F80000000000000000000000000000000000000000 +0FF000000000000000000000000000000000000000001FF0000000000000000000000000 +00000000000000001FE000000000000000000000000000000000000000003FC000000000 +000000000000000000000000000000007FC0000000000000000000000000000000000000 +00007F800000000000000000000000000000000000000000FF0000000000000000000000 +00000000000000000000FF000000000000000000000000000000000000000001FE000000 +000000000000000000000000000000000003FE0000000000000000000000000000000000 +00000003FC000000000000000000000000000000000000000007F8000000000000000000 +000000000000000000000007F800000000000000000000000000000000000000000FF000 +000000000000000000000000000000000000000FF0000000000000000000000000000000 +00000000001FE000000000000000000000000000000000000000001FE000000000000000 +000000000000000000000000003FC000000000000000000000000000000000000000003F +C000000000000000000000000000000000000000007F8000000000000000000000000000 +000000000000007F800000000000000000000000000000000000000000FF000000000000 +000000000000000000000000000000FF0000000000000000000000000000000000000000 +01FE000000000000000000000000000000000000000001FE000000000000000000000000 +000000000000000003FC000000000000000000000000000000000000000003FC00000000 +0000000000000000000000000000000007F8000000000000000000000000000000000000 +000007F8000000000000000000000000000000000000000007F000000000000000000000 +000000000000000000000FF000000000000000000000000000000000000000000FF00000 +0000000000000000000000000000000000001FE000000000000000000000000000000000 +000000001FE000000000000000000000000000000000000000001FC00000000000000000 +0000000000000000000000003FC000000000000000000000000000000000000000003FC0 +00000000000000000000000000000000000000007F800000000000000000000000000000 +0000000000007F8000000000000000000000000000000000000000007F00000000000000 +0000000000000000000000000000FF000000000000000000000000000000000000000000 +FF000000000000000000000000000000000000000000FE00000000000000000000000000 +0000000000000001FE000000000000000000000000000000000000000001FE0000000000 +00000000000000000000000000000001FC00000000000000000000000000000000000000 +0001FC000000000000000000000000000000000000000003FC0000000000000000000000 +00000000000000000003FC000000000000000000000000000000000000000003F8000000 +000000000000000000000000000000000007F80000000000000000000000000000000000 +00000007F8000000000000000000000000000000000000000007F0000000000000000000 +000000000000000000000007F000000000000000000000000000000000000000000FF000 +000000000000000000000000000000000000000FF0000000000000000000000000000000 +00000000000FE000000000000000000000000000000000000000000FE000000000000000 +000000000000000000000000000FE000000000000000000000000000000000000000001F +E000000000000000000000000000000000000000001FE000000000000000000000000000 +000000000000001FC000000000000000000000000000000000000000001FC00000000000 +0000000000000000000000000000001FC000000000000000000000000000000000000000 +003FC000000000000000000000000000000000000000003FC00000000000000000000000 +0000000000000000003F8000000000000000000000000000000000000000003F80000000 +00000000000000000000000000000000003F800000000000000000000000000000000000 +0000003F8000000000000000000000000000000000000000007F80000000000000000000 +00000000000000000000007F8000000000000000000000000000000000000000007F0000 +000000000000000000000000000000000000007F00000000000000000000000000000000 +00000000007F0000000000000000000000000000000000000000007F0000000000000000 +000000000000000000000000007F0000000000000000000000000000000000000000007F +0000000000000000000000000000000000000000007F0000000000000000000000000000 +000000000000007F000000000000000000000000000000000000000000FF000000000000 +000000000000000000000000000000FF0000000000000000000000000000000000000000 +00FE000000000000000000000000000000000000000000FE000000000000000000000000 +000000000000000000FE000000000000000000000000000000000000000000FE00000000 +0000000000000000000000000000000000FE000000000000000000000000000000000000 +000000FE000000000000000000000000000000000000000000FE00000000000000000000 +0000000000000000000000FE000000000000000000000000000000000000000000FE0000 +00000000000000000000000000000000000000FE00000000000000000000000000000000 +0000000000FE000000000000000000000000000000000000000000FE0000000000000000 +00000000000000000000000000FE0000000000000000000000000000000000000000007C +0000000000000000000000000000000000000000003C0000000000000000000000000000 +00000000000000>173 173 128 134 332 I E /Fj 133[40 40 +1[40 40 40 40 40 40 1[40 40 40 40 40 40 1[40 40 40 40 +40 40 40 40 40 10[40 40 40 40 40 1[40 40 40 40 1[40 1[40 +1[40 40 40 40 40 40 7[40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 2[40 1[40 35[{TeXBase1Encoding ReEncodeFont}61 +66.666667 /Courier rf /Fk 145[33 48 1[29 107[{}3 66.666667 +/Times-Italic rf /Fl 194[31 61[{}1 66.666667 /RMTMI rf +/Fm 205[28 28 49[{TeXBase1Encoding ReEncodeFont}2 56.666690 +/Times-Roman rf /Fn 205[32 32 49[{TeXBase1Encoding ReEncodeFont}2 +63.333383 /Times-Roman rf /Fo 139[23 32 32 1[42 1[46 +65 23 2[23 46 42 1[37 42 2[42 18[60 74 5[60 55 23[21 +46[{TeXBase1Encoding ReEncodeFont}18 83.333337 /Times-BoldItalic +rf /Fp 133[50 50 50 50 50 50 50 50 50 1[50 50 50 50 50 +50 50 50 50 50 1[50 50 50 50 50 3[50 1[50 6[50 50 4[50 +1[50 2[50 7[50 14[50 50 1[50 50 50 45[{TeXBase1Encoding ReEncodeFont}37 +83.333337 /Courier rf /Fq 182[22 3[53 69[{TeXBase1Encoding ReEncodeFont} +2 79.999924 /Helvetica-Bold rf /Fr 134[55 55 1[55 61 +33 55 39 1[61 61 61 89 28 1[28 28 61 61 1[55 61 55 61 +55 12[61 66 72 1[66 78 1[83 3[28 1[78 61 1[72 72 1[72 +8[55 55 55 55 55 55 55 55 2[28 33 5[28 39[{ +TeXBase1Encoding ReEncodeFont}44 100.000003 /Helvetica-Bold +rf /Fs 103[28 30[37 37 55 37 42 23 32 32 1[42 42 42 60 +23 1[23 23 42 42 23 37 42 37 42 42 3[32 1[32 4[51 1[46 +3[51 60 55 69 5[60 51 51 1[55 2[76 2[56 2[28 5[42 1[42 +42 42 23 21 28 1[56 7[42 31[42 3[{TeXBase1Encoding ReEncodeFont}49 +83.333337 /Times-Italic rf /Ft 135[37 2[42 6[42 60 1[37 +23 23 3[37 42 2[42 10[51 5[51 1[55 6[60 1[51 3[51 65[{}16 +83.333337 /Times-Italic rf /Fu 136[61 40 55[65 2[27 23 +10[31 31 46[{}7 83.333337 /RMTMI rf /Fv 182[15 3[36 69[{ + TeXBase1Encoding ReEncodeFont }2 66.666667 /Helvetica-Narrow +rf /Fw 212[78 43[{}1 83.333337 /ZapfDingbats rf /Fx 134[34 +34 49 34 38 19 34 23 38 38 38 38 57 15 2[15 38 38 19 +38 38 34 38 38 12[42 45 49 2[53 1[57 9[49 1[45 10[38 +38 2[38 38 38 1[19 23 3[23 23 37[34 2[{ TeXBase1Encoding ReEncodeFont } +40 83.333337 /Helvetica-Narrow rf /Fy 138[42 2[26 5[19 +2[19 1[42 1[38 2[42 38 12[42 13[42 12[38 38 38 38 38 +38 38 38 38 38 48[{ TeXBase1Encoding ReEncodeFont }20 +83.333337 /Helvetica-Narrow-Bold rf /Fz 134[42 1[60 42 +46 23 42 28 1[46 46 46 69 18 42 1[18 46 46 1[46 46 42 +46 46 7[55 1[78 55 1[51 55 60 1[55 1[60 69 1[55 1[23 +60 65 1[55 60 60 1[55 22[32 42[{TeXBase1Encoding ReEncodeFont}39 +83.333337 /Helvetica rf /FA 182[26 3[62 69[{ +TeXBase1Encoding ReEncodeFont}2 93.333301 /Helvetica-Bold +rf /FB 133[42 46 46 65 46 51 28 46 32 1[51 51 51 74 23 +46 1[23 51 51 28 46 51 46 51 46 9[78 55 1[51 55 60 1[55 +65 60 69 1[60 1[23 1[65 51 55 60 60 60 2[51 8[46 46 46 +1[46 46 2[23 28 45[{TeXBase1Encoding ReEncodeFont}49 +83.333337 /Helvetica-Bold rf /FC 133[37 42 42 60 42 46 +28 32 37 46 46 42 46 69 23 1[28 23 46 42 28 37 46 37 +46 42 9[83 60 1[55 46 60 1[51 1[60 1[55 2[32 5[60 1[60 +8[42 1[42 42 42 42 42 42 3[28 21 4[28 5[28 29[46 46 2[{ +TeXBase1Encoding ReEncodeFont}49 83.333337 /Times-Bold +rf /FD 134[65 1[90 1[71 39 65 45 71 1[71 71 103 32 2[32 +71 71 39 65 71 65 71 65 9[110 78 1[71 78 84 1[78 1[84 +97 71 2[32 5[84 1[84 10[65 65 65 65 65 65 3[39 5[32 39[{ +TeXBase1Encoding ReEncodeFont}40 116.666669 /Helvetica-Bold +rf /FE 103[22 30[37 1[52 1[41 22 37 26 1[41 1[41 59 1[37 +1[18 41 2[37 41 37 1[37 23[18 3[44 10[22 10[18 18 46[{ +TeXBase1Encoding ReEncodeFont}22 66.666667 /Helvetica-Bold +rf /FF 133[29 33 1[48 33 33 18 26 22 33 33 33 33 52 18 +33 1[18 33 33 22 29 33 29 33 29 9[63 1[48 41 37 44 1[37 +48 1[59 41 2[22 48 48 37 1[48 44 44 48 6[18 33 33 2[33 +33 33 33 33 33 18 17 22 17 6[55 33[37 37 2[{ +TeXBase1Encoding ReEncodeFont}57 66.666667 /Times-Roman +rf /FG 171[41 44 5[55 3[18 3[44 69[{TeXBase1Encoding ReEncodeFont}5 +66.666667 /Helvetica rf /FH 182[15 3[35 69[{ +TeXBase1Encoding ReEncodeFont}2 53.333281 /Helvetica +rf /FI 252[29 3[{}1 56.666690 /MTSYN rf /FJ 134[33 33 +50 33 37 21 29 29 1[37 37 37 54 21 33 1[21 37 37 21 33 +37 33 37 37 25 5[42 5[42 37 2[46 2[62 42 1[33 25 1[54 +1[46 54 50 1[46 6[25 11[19 6[25 36[37 2[{TeXBase1Encoding ReEncodeFont} +41 75.000000 /Times-Italic rf /FK 103[25 1[37 27[33 37 +37 54 37 37 21 29 25 37 37 37 37 58 21 37 21 21 37 37 +25 33 37 33 37 33 3[25 1[25 3[71 54 54 46 42 50 1[42 +1[54 66 46 54 29 25 54 54 1[46 54 50 50 54 6[21 37 37 +37 37 37 37 37 37 37 37 21 19 25 19 2[25 25 25 39[{ +TeXBase1Encoding ReEncodeFont}68 75.000000 /Times-Roman +rf /FL 104[83 28[37 42 42 60 42 42 23 32 28 42 42 42 +42 65 23 42 23 23 42 42 28 37 42 37 42 37 28 2[28 1[28 +2[60 78 60 60 51 46 55 1[46 60 60 74 51 60 1[28 60 60 +46 51 60 55 55 60 76 2[47 1[23 23 42 42 42 42 42 42 42 +42 42 42 23 21 28 21 1[42 28 28 28 65 69 33[46 46 2[{ +TeXBase1Encoding ReEncodeFont}78 83.333337 /Times-Roman +rf /FM 149[24 2[31 31 16[28 28 15[65 65 12[0 3[52 85 +22[65 22[43 3[{}12 83.333337 /MTSYN rf /FN 134[50 2[50 +50 28 39 33 1[50 50 50 78 28 2[28 50 1[33 44 1[44 50 +44 11[72 1[55 66 1[55 1[72 89 4[72 3[72 66 1[72 7[50 +50 2[50 50 1[50 50 50 28 2[25 44[{TeXBase1Encoding ReEncodeFont}37 +100.000003 /Times-Roman rf /FO 134[60 3[66 1[60 40 1[66 +66 66 100 3[27 1[66 1[66 66 2[66 10[80 10[80 3[93 71[{ +TeXBase1Encoding ReEncodeFont}16 119.999948 /Helvetica +rf /FP 140[53 38 2[77 72 4[29 3[77 14[84 33[67 3[67 1[33 +46[{TeXBase1Encoding ReEncodeFont}10 119.999948 /AvantGarde-Demi +rf /FQ 136[115 1[86 43 63 46 1[95 92 86 135 34 83 1[34 +86 95 40 92 95 92 1[95 11[92 1[75 83 1[80 121 1[129 5[121 +69 2[112 1[106 19[60 40 44[{TeXBase1Encoding ReEncodeFont}31 +143.999997 /AvantGarde-Demi rf /FR 252[66 3[{}1 126.665747 +/MTSYN rf /FS 171[126 138 5[172 77[{TeXBase1Encoding ReEncodeFont}3 +207.333362 /Helvetica-Bold rf /FT 182[46 3[110 69[{ +TeXBase1Encoding ReEncodeFont}2 165.866715 /Helvetica-Bold +rf end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin +%%PaperSize: Letter + +%%EndSetup +%%Page: 1 1 +1 0 bop 1700 560 a FS(M)-11 b FT(E)-42 b FS(T)g FT(I)p +FS(S)2202 499 y FR(\003)280 760 y FQ(A)40 b(Softw)l(ar)o(e)f(P)m(ac)n +(kage)g(f)m(or)i(P)m(ar)s(titioning)g(Unstr)s(uctur)o(ed)399 +961 y(Gra)s(phs)s(,)e(P)m(ar)s(titioning)i(Meshes)s(,)g(and)e +(Computing)484 1162 y(Fill-Reducing)i(Or)o(der)s(ings)f(of)g(Spar)s(se) +f(Ma)q(tr)s(ices)1640 1363 y FP(V)-12 b(er)r(sion)32 +b(4.0)1076 1749 y FO(George)j(Kar)t(ypis)e(and)h(Vipin)f(K)l(umar)167 +1929 y FN(Uni)n(v)o(ersity)23 b(of)i(Minnesota,)e(Department)h(of)h +(Computer)g(Science)g(/)g(Army)f(HPC)i(Research)g(Center)1459 +2057 y(Minneapolis,)d(MN)h(55455)1443 2214 y FM(f)p FL(karypis,)19 +b(kumar)p FM(g)p FL(@cs.umn.edu)1550 2406 y FN(September)25 +b(20,)g(1998)208 2756 y FK(Metis)16 b([MEE)g(tis]:)21 +b FJ(`Metis')16 b(is)g(the)h(Gr)m(eek)g(wor)m(d)g(for)g(wisdom.)22 +b(Metis)16 b(was)h(a)f(titaness)h(in)f(Gr)m(eek)i(mytholo)o(gy)l(.)23 +b(She)17 b(was)g(the)f(consort)208 2856 y(of)i(Zeus)h(and)h(the)f +(mother)g(of)g(Athena.)24 b(She)19 b(pr)m(esided)h(o)o(ver)g(all)f +(wisdom)g(and)h(knowledg)o(e)o(.)p 0 4929 1560 4 v 86 +4981 a FI(\003)122 5005 y FG(M)m FH(E)-13 b FG(T)g FH(I)q +FG(S)18 b FF(is)h(cop)o(yrighted)j(by)d(the)h(re)o(gents)g(of)f(the)h +(Uni)n(v)o(ersity)h(of)e(Minnesota.)28 b(This)19 b(w)o(ork)g(w)o(as)h +(supported)g(by)f(IST/BMDO)g(through)h(Army)f(Research)i(Of)n(\002ce)0 +5084 y(contract)d(D)m(A/D)m(AAH04-93-G-0080,)g(and)d(by)h(Army)f(High)g +(Performance)i(Computing)g(Research)h(Center)f(under)f(the)g(auspices)h +(of)e(the)h(Department)h(of)f(the)g(Army)l(,)0 5163 y(Army)i(Research)i +(Laboratory)g(cooperati)n(v)o(e)i(agreement)e(number)f(D)m +(AAH04-95-2-0003/contract)24 b(number)18 b(D)m(AAH04-95-C-0008,)j(the)e +(content)h(of)e(which)h(does)0 5242 y(not)g(necessarily)i(re\003ect)f +(the)f(position)h(or)e(the)h(polic)o(y)h(of)e(the)h(go)o(v)o(ernment,)h +(and)f(no)f(of)n(\002cial)i(endorsement)h(should)e(be)f(inferred.)26 +b(Access)19 b(to)g(computing)h(f)o(acilities)0 5321 y(were)14 +b(pro)o(vided)h(by)e(Minnesota)i(Supercomputer)h(Institute,)f(Cray)f +(Research)h(Inc,)f(and)g(by)f(the)h(Pittsb)o(ur)o(gh)g(Supercomputing)i +(Center)l(.)22 b(Related)15 b(papers)f(are)g(a)o(v)n(ailable)0 +5400 y(via)k(WWW)d(at)j(URL:)f FE(http://www)m(.cs.umn.edu/\230kar)q +(ypis)1929 5649 y FL(1)p eop +%%Page: 2 2 +2 1 bop 0 85 a FD(Contents)0 277 y FC(1)83 b(Intr)o(oduction)3281 +b(3)0 470 y(2)83 b(What)20 b(is)j FB(M)l FE(E)-17 b FB(T)g +FE(I)p FB(S)3237 b FC(4)0 663 y(3)83 b(What)20 b(is)h(New)f(in)h(This)h +(V)-8 b(ersion)2724 b(6)0 855 y(4)85 b FB(M)l FE(E)-17 +b FB(T)g FE(I)p FB(S)r FC(')m(s)22 b(Stand-Alone)d(Pr)o(ograms)2637 +b(8)125 965 y FL(4.1)85 b(Graph)20 b(P)o(artitioning)e(Programs)53 +b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g +(.)h(.)f(.)g(.)g(.)143 b(8)125 1074 y(4.2)85 b(Mesh)21 +b(P)o(artitioning)d(Programs)76 b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)143 +b(9)125 1184 y(4.3)85 b(Sparse)21 b(Matrix)e(Reordering)g(Programs)58 +b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g +(.)102 b(11)125 1294 y(4.4)85 b(Auxiliary)19 b(Programs)43 +b(.)e(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h +(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.) +g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(13)315 1403 +y(4.4.1)c(Mesh)20 b(T)-7 b(o)21 b(Graph)e(Con)m(v)o(ersion)75 +b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g +(.)102 b(13)315 1513 y(4.4.2)c(Graph)19 b(Check)o(er)56 +b(.)41 b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.) +g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h +(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(14)125 1622 y(4.5)85 +b(Input)19 b(File)i(F)o(ormats)h(.)41 b(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g +(.)102 b(15)315 1732 y(4.5.1)c(Graph)19 b(File)79 b(.)41 +b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(15)315 1842 y(4.5.2)c(Mesh)20 +b(File)40 b(.)h(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h +(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(16)125 +1951 y(4.6)85 b(Output)20 b(File)h(F)o(ormats)28 b(.)41 +b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(17)315 2061 y(4.6.1)c(P)o +(artition)20 b(File)63 b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 +b(17)315 2170 y(4.6.2)c(Ordering)19 b(File)48 b(.)42 +b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(17)0 2363 y FC(5)85 +b FB(M)l FE(E)-17 b FB(T)g FE(I)p FB(S)r FC(')m(s)22 +b(Library)e(Interface)2784 b(18)125 2473 y FL(5.1)85 +b(Graph)20 b(Data)g(Structure)52 b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g +(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.) +g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 +b(18)125 2582 y(5.2)85 b(Mesh)21 b(Data)f(Structure)75 +b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(19)125 2692 +y(5.3)85 b(P)o(artitioning)19 b(Objecti)n(v)o(es)62 b(.)41 +b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g +(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.) +g(.)g(.)h(.)f(.)g(.)g(.)102 b(19)125 2801 y(5.4)85 b(Graph)20 +b(P)o(artitioning)e(Routines)77 b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 +b(21)504 2911 y(METIS)p 759 2911 25 4 v 29 w(P)o(artGraphRecursi)n(v)o +(e)60 b(.)41 b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)102 b(21)504 3020 y(METIS)p 759 3020 V 29 +w(P)o(artGraphKw)o(ay)68 b(.)41 b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(22)504 +3130 y(METIS)p 759 3130 V 29 w(P)o(artGraphVKw)o(ay)70 +b(.)41 b(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)g(.)102 b(23)504 3240 y(METIS)p 759 3240 V 29 +w(mCP)o(artGraphRecursi)n(v)o(e)65 b(.)41 b(.)g(.)g(.)h(.)f(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(24)504 3349 y(METIS)p +759 3349 V 29 w(mCP)o(artGraphKw)o(ay)72 b(.)41 b(.)h(.)f(.)g(.)g(.)h +(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(26)504 +3459 y(METIS)p 759 3459 V 29 w(WP)o(artGraphRecursi)n(v)o(e)44 +b(.)e(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +102 b(28)504 3568 y(METIS)p 759 3568 V 29 w(WP)o(artGraphKw)o(ay)52 +b(.)41 b(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)g(.)102 b(30)504 3678 y(METIS)p 759 3678 V 29 +w(WP)o(artGraphVKw)o(ay)54 b(.)41 b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(32)125 3788 y(5.5)85 +b(Mesh)21 b(P)o(artitioning)d(Routines)38 b(.)j(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 +b(34)504 3897 y(METIS)p 759 3897 V 29 w(P)o(artMeshNodal)23 +b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g +(.)h(.)f(.)g(.)g(.)102 b(34)504 4007 y(METIS)p 759 4007 +V 29 w(P)o(artMeshDual)65 b(.)42 b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(35)125 +4116 y(5.6)85 b(Sparse)21 b(Matrix)e(Reordering)g(Routines)h(.)41 +b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +102 b(36)504 4226 y(METIS)p 759 4226 V 29 w(EdgeND)67 +b(.)41 b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.) +g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h +(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(36)504 4336 y(METIS)p +759 4336 V 29 w(NodeND)58 b(.)41 b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 +b(37)504 4445 y(METIS)p 759 4445 V 29 w(NodeWND)42 b(.)f(.)g(.)h(.)f(.) +g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h +(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +g(.)102 b(39)125 4555 y(5.7)85 b(Auxiliary)19 b(Routines)67 +b(.)41 b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(40)504 4664 +y(METIS)p 759 4664 V 29 w(MeshT)-7 b(oNodal)70 b(.)42 +b(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.) +f(.)g(.)g(.)102 b(40)504 4774 y(METIS)p 759 4774 V 29 +w(MeshT)-7 b(oDaul)50 b(.)41 b(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f +(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.) +h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(41)504 +4883 y(METIS)p 759 4883 V 29 w(EstimateMemory)29 b(.)41 +b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g +(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.) +g(.)g(.)102 b(42)125 4993 y(5.8)85 b(C)22 b(and)d(F)o(ortran)g(Support) +81 b(.)41 b(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)h(.)f +(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)h(.)f(.)g(.) +h(.)f(.)g(.)g(.)h(.)f(.)g(.)g(.)102 b(43)0 5186 y FC(6)83 +b(System)20 b(Requir)o(ements)g(and)h(Contact)e(Inf)n(ormation)2011 +b(44)1929 5649 y FL(2)p eop +%%Page: 3 3 +3 2 bop 0 85 a FD(1)116 b(Intr)n(oduction)0 261 y FL(Algorithms)17 +b(that)h(\002nd)g(a)h(good)d(partitioning)g(of)i(highly)f(unstructured) +f(graphs)h(are)h(critical)g(for)g(de)n(v)o(eloping)d(ef)n(\002cient)j +(solutions)f(for)0 370 y(a)25 b(wide)f(range)f(of)g(problems)g(in)h +(man)o(y)f(application)g(areas)h(on)g(both)f(serial)i(and)e(parallel)h +(computers.)35 b(F)o(or)24 b(e)o(xample,)f(lar)o(ge-scale)0 +480 y(numerical)f(simulations)h(on)g(parallel)h(computers,)e(such)i(as) +g(those)f(based)h(on)f(\002nite)h(element)f(methods,)g(require)f(the)i +(distrib)n(ution)0 590 y(of)e(the)h(\002nite)g(element)f(mesh)g(to)h +(the)g(processors.)31 b(This)22 b(distrib)n(ution)g(must)g(be)h(done)e +(so)i(that)g(the)g(number)d(of)j(elements)f(assigned)0 +699 y(to)28 b(each)g(processor)e(is)j(the)f(same,)h(and)f(the)g(number) +e(of)h(adjacent)g(elements)h(assigned)f(to)h(dif)n(ferent)e(processors) +h(is)i(minimized.)0 809 y(The)20 b(goal)g(of)h(the)f(\002rst)h +(condition)e(is)j(to)e(balance)g(the)g(computations)f(among)g(the)i +(processors.)k(The)20 b(goal)g(of)g(the)h(second)e(condition)0 +918 y(is)25 b(to)g(minimize)e(the)h(communication)e(resulting)h(from)g +(the)i(placement)e(of)h(adjacent)f(elements)h(to)h(dif)n(ferent)d +(processors.)37 b(Graph)0 1028 y(partitioning)20 b(can)h(be)g(used)h +(to)f(successfully)g(satisfy)h(these)g(conditions)e(by)h(\002rst)h +(modeling)e(the)h(\002nite)h(element)f(mesh)g(by)g(a)h(graph,)0 +1138 y(and)e(then)f(partitioning)g(it)h(into)g(equal)g(parts.)100 +1247 y(Graph)31 b(partitioning)g(algorithms)g(are)h(also)h(used)f(to)h +(compute)e(\002ll-reducing)f(orderings)h(of)h(sparse)g(matrices.)62 +b(These)32 b(\002ll-)0 1357 y(reducing)d(orderings)f(are)j(useful)f +(when)g(direct)g(methods)g(are)g(used)h(to)f(solv)o(e)h(sparse)f +(systems)h(of)g(linear)f(equations.)55 b(A)31 b(good)0 +1466 y(ordering)25 b(of)i(a)h(sparse)f(matrix)g(dramatically)f(reduces) +g(both)h(the)g(amount)f(of)h(memory)f(as)i(well)g(as)g(the)f(time)h +(required)d(to)j(solv)o(e)0 1576 y(the)23 b(system)g(of)g(equations.)32 +b(Furthermore,)21 b(the)i(\002ll-reducing)e(orderings)h(produced)e(by)j +(graph)e(partitioning)g(algorithms)h(are)h(par)n(-)0 +1685 y(ticularly)28 b(suited)h(for)g(parallel)g(direct)f(f)o +(actorization)g(as)i(the)o(y)e(lead)h(to)g(high)f(de)o(gree)g(of)h +(concurrenc)o(y)d(during)h(the)i(f)o(actorization)0 1795 +y(phase.)100 1905 y(Graph)19 b(partitioning)f(is)j(also)g(used)e(for)h +(solving)f(optimization)g(problems)f(arising)i(in)g(numerous)e(areas)j +(such)f(as)g(design)g(of)g(v)o(ery)0 2014 y(lar)o(ge)25 +b(scale)i(inte)o(grated)e(circuits)h(\(VLSI\),)f(storing)g(and)h +(accessing)g(spatial)h(databases)e(on)h(disks,)i(transportation)c +(management,)0 2124 y(and)c(data)g(mining.)1929 5649 +y(3)p eop +%%Page: 4 4 +4 3 bop 0 85 a FD(2)116 b(What)31 b(is)k(M)-6 b FA(E)-23 +b FD(T)g FA(I)p FD(S)2 259 y Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)34 b FL(is)d(a)f(softw)o(are)f(package)f(for)h +(partitioning)f(lar)o(ge)h(irre)o(gular)f(graphs,)i(partitioning)e(lar) +o(ge)h(meshes,)i(and)f(computing)d(\002ll-)0 369 y(reducing)21 +b(orderings)g(of)i(sparse)g(matrices.)32 b(The)23 b(algorithms)f(in)j +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)27 b FL(are)c(based)f(on)h +(multile)n(v)o(el)e(graph)h(partitioning)f(described)0 +478 y(in)30 b([8)o(,)f(7,)h(6)o(].)53 b(T)m(raditional)28 +b(graph)g(partitioning)f(algorithms)h(compute)g(a)i(partition)e(of)h(a) +h(graph)e(by)h(operating)e(directly)i(on)g(the)0 588 +y(original)17 b(graph)h(as)h(illustrated)f(in)h(Figure)f(1\(a\).)24 +b(These)18 b(algorithms)g(are)g(often)g(too)g(slo)n(w)h(and/or)f +(produce)e(poor)i(quality)g(partitions.)100 698 y(Multile)n(v)o(el)23 +b(partitioning)g(algorithms,)h(on)g(the)g(other)g(hand,)g(tak)o(e)g(a)h +(completely)e(dif)n(ferent)g(approach)f([5)o(,)j(8)o(,)g(7)o(].)38 +b(These)24 b(algo-)0 807 y(rithms,)19 b(as)h(illustrated)f(in)g(Figure) +f(1\(b\),)g(reduce)g(the)i(size)g(of)e(the)i(graph)d(by)i(collapsing)f +(v)o(ertices)h(and)g(edges,)f(partition)g(the)i(smaller)0 +917 y(graph,)25 b(and)f(then)h(uncoarsen)e(it)j(to)g(construct)e(a)h +(partition)f(for)h(the)g(original)f(graph.)40 b Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)30 b FL(uses)c(no)o(v)o(el)d(approaches)g +(to)j(succes-)0 1026 y(si)n(v)o(ely)h(reduce)f(the)h(size)g(of)g(the)g +(graph)f(as)i(well)f(as)h(to)f(further)f(re\002ne)h(the)g(partition)f +(during)f(the)i(uncoarsening)e(phase.)45 b(During)0 1136 +y(coarsening,)19 b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)24 +b FL(emplo)o(ys)19 b(algorithms)f(that)h(mak)o(e)g(it)h(easier)g(to)f +(\002nd)g(a)h(high-quality)d(partition)h(at)i(the)f(coarsest)h(graph.)j +(During)0 1246 y(re\002nement,)h Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)28 b FL(focuses)23 b(primarily)e(on)i(the)h(portion)d(of)i +(the)g(graph)f(that)i(is)g(close)f(to)h(the)f(partition)f(boundary)-5 +b(.)31 b(These)23 b(highly)0 1355 y(tuned)c(algorithms)g(allo)n(w)j +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)25 b FL(to)20 b(quickly)f(produce) +f(high-quality)g(partitions)h(for)h(a)g(lar)o(ge)g(v)n(ariety)f(of)h +(graphs.)450 2607 y @beginspecial 0 @llx 0 @lly 1129 +@urx 433 @ury 3600 @rwi @setspecial +%%BeginDocument: ./figures/slide78.eps +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {} def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-48.0 455.0 translate +1 -1 scale + +/clp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/l {lineto} bind def +/m {moveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit + 0.06000 0.06000 sc +% Polyline +% +% Begin Imported EPS File: slide7.eps +% +n gs +825 1606 tr +15.284974 -15.278970 sc +0 -233 tr +-35 -330 tr +save +/showpage {} def +% EPS file follows: + + + + + + + + + + + + + + + +/defineresource where{pop}{userdict begin/defineresource{userdict/Resources 2 + +copy known{get begin}{15 dict dup begin put}ifelse exch readonly exch + +currentdict 1 index known not{dup 30 dict def}if load 3 -1 roll 2 index put + +end}bind readonly def/findresource{userdict/Resources get exch get exch get} + +bind readonly def/resourceforall{pop pop pop pop}bind readonly def + +/resourcestatus{userdict/Resources 2 copy known{get exch 2 copy known{get exch + +known{0 -1 true}{pop pop false}ifelse}{pop pop pop false}ifelse}{pop pop false + +}ifelse}bind readonly def end}ifelse + + + +/Pscript_Win_Driver 200 dict dup begin + + +/FatalErrorIf{{initgraphics findfont exch scalefont setfont counttomark 3 div + +cvi{moveto show}repeat showpage quit}{cleartomark}ifelse}bind def + + +/VM? {vmstatus exch sub exch pop gt { [ + +(This job requires more memory than is available in this printer.) 100 500 + +(Try one or more of the following, and then print again:) 100 485 + +(In the PostScript dialog box, click Optimize For Portability.) 115 470 + +(In the Device Options dialog box, make sure the Available Printer Memory is accurate.) 115 455 + +(Reduce the number of fonts in the document.) 115 440 + +(Print the document in parts.) 115 425 + +12 /Times-Roman showpage + +(%%[ PrinterError: Low Printer VM ]%%) = + +true FatalErrorIf}if} bind def + + +/|/def load def/,/load load |/~/exch , |/?/ifelse , |/!/pop , |/`/begin , |/^ + +/index , |/@/dup , |/+/translate , |/$/roll , |/U/userdict , |/M/moveto , |/- + +/rlineto , |/&/currentdict , |/:/gsave , |/;/grestore , |/F/false , |/T/true , + +|/N/newpath , |/E/end , |/Ac/arc , |/An/arcn , |/A/ashow , |/D/awidthshow , | + +/C/closepath , |/V/div , |/O/eofill , |/L/fill , |/I/lineto , |/-C/rcurveto , + +|/-M/rmoveto , |/+S/scale , |/Ji/setfont , |/Lc/setlinecap , |/Lj/setlinejoin + +, |/Lw/setlinewidth , |/S/show , |/LH/showpage , |/K/stroke , |/W/widthshow , + +|/R/rotate , |/b{bind |}bind |/bd{bind |}bind |/xd{~ |}bd/ld{, |}bd/lw/Lw ld + +/lc/Lc ld/lj/Lj ld/sg/setgray ld/L2? F/languagelevel where{! languagelevel 2 + +ge{! T}if}if |/g{@ not{U/DefIf_save save put}if U/DefIf_bool 2 ^ put}b + +/DefIf_El{if U/DefIf_bool get not @{U/DefIf_save get restore}if}b/e{DefIf_El ! + +}b/self & |/reinitialize{[/TextInit/GraphInit/UtilsInit counttomark{@ where{ + +self eq}{F}?{cvx exec}{!}?}repeat cleartomark}b/initialize{`{/ADO_mxRot ~ | + +/TextInitialised? F | reinitialize E}{U/Pscript_Win_Data 200 dict @ ` put + +/ADO_mxRot ~ |/TextInitialised? F | reinitialize}?}b/terminate{!{& self eq{ + +exit}{E}?}loop E}b/suspend/terminate , |/resume{` Pscript_Win_Data `}b/snap{ + +transform 0.25 sub round 0.25 add ~ 0.25 sub round 0.25 add ~ itransform}b + +/dsnap{dtransform round ~ round ~ idtransform}b<04>cvn{}|/setjn{{statusdict + +/jobname known{statusdict/jobname 3 -1 $ put}if}stopped cleartomark}b/solid{[] + +0 setdash}b/setdsh{0 setdash}b/colspRefresh{}b/rp{4 2 $ M 1 ^ 0 - 0 ~ - neg 0 + +-}b/rr{1 ^ 0 - 0 ~ - neg 0 - C}b + + + +L2? not g{/rf{N rp L}b/fx{1 1 dtransform @ 0 ge{1 sub 1}{1 add -0.25}? 3 -1 $ + +@ 0 ge{1 sub 1}{1 add -0.25}? 3 1 $ 4 1 $ idtransform 4 -2 $ idtransform}b/BZ{ + +4 -2 $ snap + +S fx rf}b/rs{N rp C K}b/rc{N rp clip N}b/sg{setgray}b/sco{ + +setrgbcolor}b/sgco{{sg}{sco}?}b}e + + + +L2? g{/colspA/DeviceGray |/colspABC/DeviceRGB |/setAorABC{{colspA}{colspABC}? + +setcolorspace}b/rf/rectfill , |/fx{1 1 dtransform @ 0 ge{1 sub 0.5}{1 add -0.5 + +}? 3 -1 $ @ 0 ge{1 sub 0.5}{1 add -0.5}? 3 1 $ 4 1 $ idtransform 4 -2 $ + +idtransform}b/BZ{4 -2 $ snap + +S fx rf}b/rs/rectstroke , |/rc/rectclip , |/sg + +{@ @ setcolor}b/sco{setcolor}b/colspRefresh{colspABC setcolorspace}b/sgco{{sg + +}{sco}?}b/UtilsInit{F setglobal}b/definecolorrendering{/ColorRendering + +defineresource !}b/findcolorrendering{@/ColorRendering resourcestatus{! ! + +/ColorRendering findresource T}{! F}?}b/selectcolorrendering{@/ColorRendering + +resourcestatus{! !/ColorRendering}{!/DefaultColorRendering/ColorRendering}? + +findresource setcolorrendering}b}e + + + +/bullets{{/bullet}repeat}b/ANSIEncoding[/grave/acute/circumflex/tilde/macron + +/breve/dotaccent/dieresis/ring/cedilla/hungarumlaut/ogonek/caron/dotlessi 18 + +bullets StandardEncoding 32 95 getinterval aload ! 3 bullets/quotesinglbase + +/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron + +/guilsinglleft/OE 4 bullets/quoteleft/quoteright/quotedblleft/quotedblright + +/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe 2 bullets + +/Ydieresis/space/exclamdown/cent/sterling/currency/yen/brokenbar/section + +/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered + +/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph + +/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter + +/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis + +/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute + +/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis + +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls + +/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute + +/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve + +/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex + +/udieresis/yacute/thorn/ydieresis]| ANSIEncoding @ 39/quotesingle put 96/grave + +put/ANSIEncodingOld ANSIEncoding 256 array copy | ANSIEncodingOld @[138 153 + +154 169 172 174 177 178 179 181 185 188 189 190 208 215 221 222 240 247 253 + +254]{/bullet put @}forall 166/bar put 176/ring put + + + +/TextInit{TextInitialised? not{/Pscript_Windows_Font & |/TextInitialised? T | + +/fM[1 0 0 -1 0 0]|/mFM matrix |/iMat[1 0 0.212557 neg 1 0 0]|}if}b/xUP null | + +/yUP null |/uW null |/xSP null |/ySP null |/sW null |/copyfont{1 ^ length add + +dict `{1 ^/FID ne{|}{! !}?}forall & E}b/rF{3 copyfont @ `/Encoding + +ANSIEncoding &/CharStrings known{CharStrings/Eth known not{! ANSIEncodingOld} + +if}if | E}b/mF{findfont ~{@/Encoding get @ StandardEncoding eq{! T}{{ + +ISOLatin1Encoding}stopped{! F}{eq}?{T}{@ ` T 32 1 127{Encoding 1 ^ get + +StandardEncoding 3 -1 $ get eq and}for E}?}?}{F}?{rF}{3 copyfont}? ` + +/OrigFontType ~ |/OrigFontName ~ | & E 2 ^ ~ definefont fM 5 4 -1 $ put fM 4 0 + +put fM makefont Pscript_Windows_Font 3 1 $ put}b/xF{scalefont + +Pscript_Windows_Font 3 1 $ put}b/xMF{mFM astore makefont Pscript_Windows_Font + +3 1 $ put}b/xF2/scalefont , |/xMF2{mFM astore makefont}b/sLT{: Lw -M + +currentpoint snap M 0 - 0 Lc K ;}b/sSU{N/uW ~ |/yUP ~ |/xUP ~ |}b/sU{xUP yUP + +uW sLT}b/sST{N/sW ~ |/ySP ~ |/xSP ~ |}b/sT{xSP ySP sW sLT}b/sR{: + R 0 0 M}b + +/sRxy{: matrix astore concat 0 0 M}b/eR/; , | + + + +/mBF{@ 4 copyfont `/FontName ~ |/OrigFontType ~ |/OrigFontName ~ | 0 + +FontMatrix idtransform ! &/PaintType known{PaintType 0 eq{/PaintType 2 | + +/StrokeWidth ~ |}{PaintType 1 eq PaintType 2 eq or PaintType 3 eq or & + +/StrokeWidth known and{StrokeWidth add/StrokeWidth ~ |}{!}?}?}{!}? @ & E + +definefont Pscript_Windows_Font 3 1 $ put}b/xBF{Pscript_Windows_Font ` 1 ^ + +/FontName get 1 ^ scalefont 3 1 $ scalefont 2 copy ~ | ~ ! | E}b/xMBF{mFM + +astore Pscript_Windows_Font ` 1 ^/FontName get 1 ^ makefont 3 1 $ makefont 2 + +copy ~ | ~ ! | E}b/xBF2{/sB0 ~ mBF/sB1 sB0 3 -1 $ xBF sB1}b/xMBF2{/sB0 ~ mBF + +mFM astore/sB1 sB0 3 -1 $ xMBF sB1}b/sB{: Pscript_Windows_Font currentfont get + +Ji @ S ; S}b/asB{: Pscript_Windows_Font currentfont get Ji 3 copy A ; A}b/wsB{ + +: Pscript_Windows_Font currentfont get Ji 4 copy W ; W}b/awsB{: + +Pscript_Windows_Font currentfont get Ji 6 copy D ; D}b/sBT3{: @ S ; 1 1 -M S}b + +/asBT3{: 3 copy A ; 1 1 -M A}b/wsBT3{: 4 copy W ; 1 1 -M W}b/awsBT3{: 6 copy D + +; 1 1 -M D}b/mIF{iMat 4 3 -1 $ put 2 copyfont `/OrigFontType ~ |/OrigFontName + +~ | @ & E definefont iMat makefont Pscript_Windows_Font 3 1 $ put}b + + + +/SavedCTM null |/CTMsave{/SavedCTM SavedCTM currentmatrix |}b/CTMrestore{ + +SavedCTM setmatrix}b/mp null |/ADO_mxRot null |/GDIHMatrix null | + +/GDIHPatternDict 22 dict | GDIHPatternDict `/PatternType 1 |/PaintType 2 | + +/Reps L2?{1}{5}? |/XStep 8 Reps mul |/YStep XStep |/BBox[0 0 XStep YStep]| + +/TilingType 1 |/PaintProc{` 1 Lw[]0 setdash PaintData , exec E}b/FGnd null | + +/BGnd null |/HS_Horizontal{horiz}b/HS_Vertical{vert}b/HS_FDiagonal{fdiag}b + +/HS_BDiagonal{biag}b/HS_Cross{horiz vert}b/HS_DiagCross{fdiag biag}b/MaxXYStep + +XStep YStep gt{XStep}{YStep}? |/horiz{Reps{0 4 M XStep 0 - 0 8 +}repeat 0 -8 + +Reps mul + K}b/vert{Reps{4 0 M 0 YStep - 8 0 +}repeat 0 -8 Reps mul + K}b/biag + +{Reps{0 0 M MaxXYStep @ - 0 YStep neg M MaxXYStep @ - 0 8 +}repeat 0 -8 Reps + +mul + 0 YStep M 8 8 - K}b/fdiag{Reps{0 0 M MaxXYStep @ neg - 0 YStep M + +MaxXYStep @ neg - 0 8 +}repeat 0 -8 Reps mul + MaxXYStep @ M 8 -8 - K}b E + +/makehatch{GDIHPatternDict/PaintData 3 -1 $ put CTMsave GDIHMatrix setmatrix + +GDIHPatternDict matrix mp CTMrestore ~ U ~ 2 ^ put}b/h0{/h0/HS_Horizontal + +makehatch}b/h1{/h1/HS_Vertical makehatch}b/h2{/h2/HS_FDiagonal makehatch}b/h3{ + +/h3/HS_BDiagonal makehatch}b/h4{/h4/HS_Cross makehatch}b/h5{/h5/HS_DiagCross + +makehatch}b/GDIBWPatternDict 17 dict @ `/PatternType 1 |/PaintType L2?{1}{2}? + +|/RepsV L2?{1}{6}? |/RepsH L2?{1}{5}? |/BBox[0 0 RepsH 1]|/TilingType 1 | + +/XStep 1 |/YStep 1 |/Height 8 RepsV mul |/Width 8 |/mx[Width 0 0 Height neg 0 + +Height]|/FGnd null |/BGnd null |/SetBGndFGnd L2?{{BGnd null ne{BGnd aload ! + +sgco BBox aload ! 2 ^ sub ~ 3 ^ sub ~ rf}if FGnd null ne{FGnd aload ! sgco}if} + +}{{}}? b/PaintProc{` SetBGndFGnd RepsH{Width Height F mx PaintData imagemask + +Width 0 +}repeat E}b E |/GDIBWPatternMx null |/pfprep{save 4 1 $ + +/PatternOfTheDay 4 1 $ GDIBWPatternDict `/PaintData ~ |/BGnd ~ |/FGnd ~ | E + +CTMsave GDIBWPatternMx setmatrix GDIBWPatternDict matrix mp CTMrestore ~ !}b + +/hrf null |/prf{pfprep ~ 6 1 $ 5 hrf restore}b/GraphInit{GDIHMatrix null eq{ + +/SavedCTM matrix | : ADO_mxRot concat 0 0 snap + : 0.48 @ GDIHPatternDict ` + +YStep mul ~ XStep mul ~ dsnap YStep V ~ XStep V ~ E +S/GDIHMatrix matrix + +currentmatrix readonly | ; : 0.24 -0.24 +S GDIBWPatternDict ` Width Height E + +dsnap +S/GDIBWPatternMx matrix currentmatrix readonly | ; ;}if}b/cirp{360 0 An + +C}b/ellp{CTMsave + +S 0.5 0 M 0 0 0.5 360 0 An C CTMrestore}b/rrp{/rad ~ |/y2 + +~ |/x2 ~ |/y1 ~ |/x1 ~ | x2 x1 add 2 V y1 M x1 y1 x1 y2 rad arct x1 y2 x2 y2 + +rad arct x2 y2 x2 y1 rad arct x2 y1 x1 y1 rad arct C}b/RRp{CTMsave + +S/dyS ~ + +|/dxS ~ | dxS 2 V 0 M 0 0 0 dyS 0.5 arct 0 dyS dxS dyS 0.5 arct dxS dyS dxS 0 + +0.5 arct dxS 0 0 0 0.5 arct C CTMrestore}b + + + +L2? not g{/arct{arcto ! ! ! !}b/GDIpattfill{@ ` BGnd null ne PaintType 2 eq + +and{: BGnd aload ! sgco fEOFill{O}{L}? ; FGnd aload ! U/fGray 2 ^ put{2}{4}? + +-1 $}if E @ patterncalc : 4 ^/PaintType get 2 eq{fGray{6 -1 $ sg}{8 -3 $ sco}? + +}if fEOFill{eoclip}{clip}? N patternfill ; N}b/hrf{/fGray 1 ^ 6 eq | -4 $ N rp + +C/fEOFill F | GDIpattfill}b/hfMain{/fEOFill ~ |/fGray ~ | GDIpattfill}b/hf{T + +hfMain}b/hfW{F hfMain}b/hs{currentpoint strokepath M hfW}b/pfMain{/fEOFill ~ | + +pfprep GDIpattfill restore N}b/pf{T pfMain}b/pfW{F pfMain}b/ps{currentpoint + +strokepath M pfW}b/mpstr 1 string |/mp{~ @ length 12 add dict copy ` + +/PatternCTM matrix currentmatrix |/PatternMatrix ~ |/PatWidth XStep mpstr + +length mul |/PatHeight YStep |/FontType 3 |/Encoding 256 array | 3 string 0 1 + +255{Encoding ~ @ 3 ^ cvs cvn put}for !/FontMatrix matrix |/FontBBox BBox | + +/BuildChar{! @ ` XStep 0 FontBBox aload ! setcachedevice/PaintProc , E : exec + +;}b & E ~ @ 3 -1 $ definefont}b/patterncalc{` : PatternCTM setmatrix + +PatternMatrix concat BBox aload ! ! ! + pathbbox ; PatHeight V ceiling 4 1 $ + +PatWidth V ceiling 4 1 $ PatHeight V floor 4 1 $ PatWidth V floor 4 1 $ 2 ^ + +sub cvi abs ~ 3 ^ sub cvi abs ~ 4 2 $ PatHeight mul ~ PatWidth mul ~ E}b + +/patternfill{5 -1 $ @ ` Ji PatternCTM setmatrix PatternMatrix concat 0 2 ^ 2 ^ + +M 0 1 mpstr length 1 sub{1 ^ mpstr 3 1 $ put}for ! 2 ^{currentpoint 5 ^{mpstr + +S}repeat YStep add M}repeat ! ! ! ! E}b}e + + + +L2? g{/mp/makepattern , |/hrf{6 eq setAorABC setpattern rectfill}b/hf{ + +setAorABC setpattern O}b/hfW{setAorABC setpattern L}b/hs{setAorABC setpattern + +K}b/pf{pfprep setpattern O restore N}b/pfW{pfprep setpattern L restore N}b/ps{ + +pfprep setpattern K restore N}b}e + + + +/iw 0 |/ih 0 |/im_save 0 |/s 0 |/polarity 0 |/smoothflag 0 |/mystring 0 |/bpc + +0 |/setup1asciiproc{[currentfile mystring/readhexstring cvx/! cvx]cvx bind}b + +/setup1binaryproc{[currentfile mystring/readstring cvx/! cvx]cvx bind}b + +/setup2asciiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}b + +/setup2binaryproc{currentfile/RunLengthDecode filter}b/mycolorspace{colspABC}| + +/myimagedict{/myimagedict 10 dict | myimagedict @ `/ImageType 1 | + +/MultipleDataSource F | E}b/imageprocarray[/setup1binaryproc/setup1asciiproc + +/setup2binaryproc/setup2asciiproc/setup1binarydecodeproc/setup1asciidecodeproc + +]|/L2Polarity{{[1 0]}{[0 1]}?}b/Q{/im_save save | imageprocarray ~ get/s ~ , | + +L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring ~ + +string |/bpc ~ |/ih ~ |/iw ~ |}b/X{/im_save save | imageprocarray ~ get/s ~ , + +| L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring + +~ string |/bpc ~ |/ih ~ |/iw ~ |}b/Z{im_save restore}b/Y{sgco myimagedict @ ` + +/Width iw |/Height ih |/Decode polarity |/ImageMatrix[iw 0 0 ih 0 0]| + +/DataSource s |/BitsPerComponent 1 |/Interpolate smoothflag | E imagemask}b + + + +L2? not g{/setup2asciiproc{[/Level2ImagesError , aload ! T FatalErrorIf}b + +/setup2binaryproc/setup2asciiproc , |/L2Polarity{}|/Y{sgco iw ih polarity[iw 0 + +0 ih 0 0]s imagemask}b}e + + + +L2? not g{/testsystemdict{where{systemdict eq{T}{F}?}{F}?}b/c 1 |/colorimage + +where{! T}{F}?{/c 0 statusdict `/processcolors where{! ! processcolors}{ + +/deviceinfo where{! deviceinfo/Colors known{!{deviceinfo/Colors get}}if}if}? E + +| c 0 ne{/colorimage testsystemdict/setcolortransfer testsystemdict + +/currentcolortransfer testsystemdict/currentcmykcolor testsystemdict and and + +and not{/c 0 |}if}if}if c @ 1 ne ~ @ 3 ne ~ 4 ne and and{/c 0 |}if c 1 eq g{ + +/expandbw{expandfactor mul round cvi bwclut ~ get 255 V}b/doclutimage{!/bwclut + +~ | bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/expandfactor ~ |[/expandbw ,/exec , @ + +currenttransfer ~]cvx bind settransfer iw ih bpc[iw 0 0 ih 0 0]s image}b}e c @ + +3 eq ~ 4 eq or g{/nullproc{{}}|/concatutil{/exec , 7 -1 $/exec ,}b/defsubclut{ + +1 add getinterval |}b/spconcattransfer{/Dclut ~ |/Cclut ~ |/Bclut ~ |/Aclut ~ + +|/ncompute ~ , | currentcolortransfer[{Aclut ncompute}concatutil]cvx[{Bclut + +ncompute}concatutil]cvx[{Cclut ncompute}concatutil]cvx[{Dclut ncompute} + +concatutil]cvx setcolortransfer}b/setuprgbcluts{/bit3x rgbclut length 3 sub | + +/bit1x bit3x 3 idiv |/rclut rgbclut |/gclut rclut 1 bit3x defsubclut/bclut + +rclut 2 bit3x defsubclut}b}e c 3 eq g{/3compute{~ bit3x mul round cvi get 255 + +V}b/doclutimage{/rgbclut ~ | ! setuprgbcluts/3compute rclut gclut bclut @ + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @]cvx nullproc nullproc + +T 3 colorimage}b}e c 4 eq g{/ftoint{1 ~ sub 255 mul round cvi}b/stuffclut{ + +cmykindex 3 -1 $ put}b/4compute{~ bit4x mul round cvi get 255 V}b + +/invalidcolortable? T |/computecmykclut{setuprgbcluts/bit4x rgbclut length 3 + +idiv 4 mul 4 sub |/cmykclut bit4x 4 add string |/cclut cmykclut |/mclut cclut + +1 bit4x defsubclut/yclut cclut 2 bit4x defsubclut/kclut cclut 3 bit4x + +defsubclut/cmykindex 0 | 0 1 bit1x{@/cmykindex ~ bit1x ~ sub 4 mul | 3 mul @ + +rclut ~ get 255 V ~ @ gclut ~ get 255 V ~ bclut ~ get 255 V setrgbcolor + +currentcmykcolor ftoint kclut stuffclut ftoint yclut stuffclut ftoint mclut + +stuffclut ftoint cclut stuffclut}for}b/doclutimage{/rgbclut ~ | ! + +invalidcolortable?{computecmykclut}if/4compute cclut mclut yclut kclut + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @ @]cvx nullproc + +nullproc nullproc T 4 colorimage}b}e c 0 eq g{/a{3 mul 3 getinterval + +putinterval ~ 3 add ~ 3 copy}b/8lookup/a , |/4lookup{/byte 1 ^ | -4 bitshift a + +byte 15 and a}b/2lookup{/byte 1 ^ | -6 bitshift a byte -4 bitshift 3 and a + +byte -2 bitshift 3 and a byte 3 and a}b/colorexpand{mystringexp 0 rgbclut 3 + +copy 7 -1 $/mylookup , forall ! ! ! ! !}b/createexpandstr{/mystringexp ~ + +mystring length mul string |}b/doclutimage{/rgbclut ~ | !/mylookup bpc 8 eq{3 + +createexpandstr/8lookup}{bpc 4 eq{6 createexpandstr/4lookup}{12 + +createexpandstr/2lookup}?}? , | iw ih bpc[iw 0 0 ih 0 0][s/exec ,/colorexpand + +,/exec ,]cvx F 3 colorimage}b}e/colorimage where{! T}{F}? g{/do24image{iw ih 8 + +[iw 0 0 ih 0 0]s F 3 colorimage}b}DefIf_El{/rgbtogray{/str ~ |/len str length + +|/smlen len 3 idiv |/rstr str |/gstr str 1 len 1 sub getinterval |/bstr str 2 + +len 2 sub getinterval | str @ 0 1 smlen 1 sub{@ 3 mul rstr 1 ^ get 0.3 mul + +gstr 2 ^ get 0.59 mul add bstr 3 -1 $ get 0.11 mul add round cvi put @}for ! 0 + +smlen getinterval}b/do24image{iw ih 8[iw 0 0 ih 0 0][s/exec ,/rgbtogray ,/exec + +,]cvx bind image}b}e/doNimage{bpc 24 eq{do24image}{iw ih bpc[iw 0 0 ih 0 0]s + +image}?}b}e + + + +L2? g{/doclutimage{/rgbclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[ + +/Indexed colspABC hival rgbclut]setcolorspace myimagedict @ `/Width iw | + +/Height ih |/Decode[0 hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s | + +/BitsPerComponent bpc |/Interpolate smoothflag | E image}b/doCMYKclutimage{ + +/CMYKclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[/Indexed/DeviceCMYK + +hival CMYKclut]setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 + +hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent bpc | + +/Interpolate smoothflag | E image}b/doNimage{bpc 24 eq{colspABC}{colspA}? + +setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode bpc 24 eq{[0 1 0 1 + +0 1]}{[0 1]}? |/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent + +bpc 24 eq{8}{bpc}? |/Interpolate smoothflag | E image}b/doCMYKimage{ + +/DeviceCMYK setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 1 0 + +1 0 1 0 1]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent 8 | + +/Interpolate smoothflag | E image}b}e + + + +/GreNewFont{10 dict @ 3 1 $ | @ ` 4 1 $/FontType 3 |/FontMatrix ~ |/FontBBox ~ + +|/Encoding 256 array | 0 1 255{Encoding ~/.notdef put}for/CharProcs 257 dict | + +CharProcs/.notdef{}put/Metrics 257 dict | Metrics/.notdef 3 -1 $ put/BuildChar + +{/char ~ |/fontdict ~ |/charname fontdict/Encoding get char get | fontdict + +/Metrics get charname get aload ! setcachedevice fontdict ` Encoding char get + +CharProcs ~ get E exec}| E definefont !}|/AddChar{` Encoding 3 1 $ put + +CharProcs 3 1 $ put Metrics 3 1 $ put E}| + + + +/FEbuf 2 string |/FEglyph 3 string |/FE{(G00)FEglyph copy ! 1 ~{@ 16 lt{ + +/offset 2 store}{/offset 1 store}? @ 16 FEbuf cvrs FEglyph ~ offset ~ + +putinterval 1 ^ ~ FEglyph cvn put}for}bind |/Type1Hdr{11 dict `/FontName ~ | + +/PaintType ~ |/FontType 1 |/FontMatrix[1 3 ^ V 0 0 1 6 ^ V 0 0]| !/Encoding + +256 array 0 1 255{1 ^ ~/.notdef put}for 3 ^ 3 ^ FE | ! !/FontBBox{0 0 0 0}| & + +E currentfile eexec}bind | + + +/pp 1 string |/ss 1 string |/rledecodebinary{/DC 0 |/BC 0 |{DC mystring length + +ge{exit}if currentfile ss readstring ! 0 get/BC ~ | BC 127 le{/BC BC 1 add | + +DC 1 DC BC add 1 sub{mystring ~ currentfile ss readstring ! 0 get put}for}{/BC + +257 BC sub | currentfile ss readstring ! 0 get/pp ~ | DC 1 DC BC add 1 sub{ + +mystring ~ pp put}for}?/DC DC BC add |}loop mystring}b/rledecodeascii{/DC 0 | + +/BC 0 |{DC mystring length ge{exit}if currentfile ss readhexstring ! 0 get/BC + +~ | BC 127 le{/BC BC 1 add | DC 1 DC BC add 1 sub{mystring ~ currentfile ss + +readhexstring ! 0 get put}for}{/BC 257 BC sub | currentfile ss readhexstring ! + +0 get/pp ~ | DC 1 DC BC add 1 sub{mystring ~ pp put}for}?/DC DC BC add |}loop + +mystring}b/setup1asciidecodeproc{[/rledecodeascii cvx]cvx bind}b + +/setup1binarydecodeproc{[/rledecodebinary cvx]cvx bind}b + + +userdict/Pscript_Win_Compat 13 dict dup begin/bd{bind def}bind def/ld{load def + +}bd/CB{pop pop pop pop}bind def/B{pop pop pop pop}bind def/$x matrix def/SS{ + +/pagesave save def}bind def/RS{/pagesave where{pop pagesave restore}{$x matrix + +invertmatrix concat}ifelse}bind def/ANSIVec[0/grave 1/acute 2/circumflex 3 + +/tilde 4/macron 5/breve 6/dotaccent 7/dieresis 8/ring 9/cedilla 10 + +/hungarumlaut 11/ogonek 12/caron 13/dotlessi 39/quotesingle 96/grave 124/bar + +130/quotesinglbase 131/florin 132/quotedblbase 133/ellipsis 134/dagger 135 + +/daggerdbl 136/circumflex 137/perthousand 138/Scaron 139/guilsinglleft 140/OE + +145/quoteleft 146/quoteright 147/quotedblleft 148/quotedblright 149/bullet 150 + +/endash 151/emdash 152/tilde 153/trademark 154/scaron 155/guilsinglright 156 + +/oe 159/Ydieresis 160/space 161/exclamdown 164/currency 165/yen 166/brokenbar + +167/section 168/dieresis 169/copyright 170/ordfeminine 171/guillemotleft 172 + +/logicalnot 173/hyphen 174/registered 175/macron 176/degree 177/plusminus 178 + +/twosuperior 179/threesuperior 180/acute 181/mu 182/paragraph 183 + +/periodcentered 184/cedilla 185/onesuperior 186/ordmasculine 187 + +/guillemotright 188/onequarter 189/onehalf 190/threequarters 191/questiondown + +192/Agrave 193/Aacute 194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198 + +/AE 199/Ccedilla 200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204 + +/Igrave 205/Iacute 206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve + +211/Oacute 212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash + +217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn 223 + +/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde 228/adieresis 229 + +/aring 230/ae 231/ccedilla 232/egrave 233/eacute 234/ecircumflex 235/edieresis + +236/igrave 237/iacute 238/icircumflex 239/idieresis 240/eth 241/ntilde 242 + +/ograve 243/oacute 244/ocircumflex 245/otilde 246/odieresis 247/divide 248 + +/oslash 249/ugrave 250/uacute 251/ucircumflex 252/udieresis 253/yacute 254 + +/thorn 255/ydieresis]def currentdict{dup type/operatortype eq{[exch]cvx def}{ + +pop pop}ifelse}forall/initialize{currentdict exch begin begin}bind def + +/terminate{/@FL where not{pop end end}{pop}ifelse}bind def/suspend/terminate + +load def/resume/initialize load def/M/moveto load def end put/Courier findfont + +10 scalefont setfont + + +end /ProcSet defineresource pop + + + + + + +Pscript_Win_Compat dup /initialize get exec + +[ 0 1.000 -1.000 0 0 0 ] false /Pscript_Win_Driver /ProcSet findresource dup /initialize get exec + + + + + +/mysetup [ 0.240 0 0 -0.240 8.880 592.800 ] | + + + + + + +userdict begin /pagesave save def end mysetup concat colspRefresh : 1.000 1.000 1.000 sco 0 0 2550 3300 rf ; + + + + + + +114 70 N M 1 1 rr + +114 70 N M 3000 2250 rr : 1.000 1.000 1.000 sco O ; + +114 70 N M 1 1 rr + +114 70 N M 1 1 rr + +114 70 N M 2401 1026 rr : 0.800 1.000 0.800 sco O ; 1 Lw 0 Lc 0 Lj solid 0.800 1.000 0.800 sco K + +234 176 N M 2131 295 rr : 114 70 3000 2250 rc 0.647 0 0.129 sco %%IncludeFont: Helvetica-Bold + +(F0) cvn + +0.960 + + (Helvetica-Bold) cvn /Type1 + +T + +(Helvetica-Bold) cvn + +mF + +(F0_100) cvn + +F0 + +100 + +xF + +F0_100 + +Ji + +264 193 M + +-0.100 0 (T)A + +0.100 0 (r)A + +0.400 0 (a)A + +-0.100 0 (d)A + +-0.800 0 (i)A + +0.700 0 (t)A + +-0.800 0 (i)A + +-0.100 0 (on)A + +0.400 0 (a)A + +1.000 0 32 -0.800 0 (l )D + +-0.100 0 (p)A + +0.400 0 (a)A + +0.100 0 (r)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.100 0 (o)A + +-1.100 0 (n)A + +0.200 0 (i)A + +0.300 0 32 -0.100 0 (ng )D + +-0.600 0 (a)A + +0.200 0 (l)A + +-0.100 0 (go)A + +0.100 0 (r)A + +-0.800 0 (i)A + +0.700 0 (t)A + +-0.100 0 (h)A + +0.100 0 (m)A + +0.800 0 32 -0.600 0 (s )D + +0.400 0 (c)A + +-0.100 0 (o)A + +0.100 0 (m)A + +-0.100 0 (pu)A + +-0.300 0 (t)A + +0.400 0 (e)A + +; : 114 70 3000 2250 rc 0.647 0 0.129 sco F0_100 + +Ji + +339 336 M + +-1.200 0 32 0.400 0 (a )D + +-0.100 0 (p)A + +0.400 0 (a)A + +0.100 0 (r)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.700 0 32 -0.100 0 (on d)D + +0.200 0 (i)A + +0.100 0 (r)A + +0.400 0 (e)A + +-0.600 0 (c)A + +0.700 0 (t)A + +-0.800 0 (l)A + +-0.200 0 32 0.400 0 (y )D + +-0.700 0 32 -0.100 0 (on )D + +-0.300 0 (t)A + +-0.100 0 (h)A + +-0.200 0 32 0.400 0 (e )D + +-0.100 0 (o)A + +0.100 0 (r)A + +-0.800 0 (i)A + +-0.100 0 (g)A + +0.200 0 (i)A + +-0.100 0 (n)A + +0.400 0 (a)A + +1.000 0 32 -0.800 0 (l )D + +-0.100 0 (g)A + +0.100 0 (r)A + +-0.600 0 (a)A + +-0.100 0 (ph)A + +0.700 0 (!)A + +; + +428 664 N M -7 1 - -9 0 - -20 1 - -22 1 - -23 1 - -23 3 - -21 5 - -9 3 - -8 5 - -7 5 - -6 6 - -4 8 - -4 8 - -3 11 - -2 11 - -2 25 - 0 26 - 2 27 - 3 27 - 5 23 - 2 11 - 3 9 - 7 17 - 9 15 - 11 14 - 12 13 - 13 10 - 14 10 - 13 8 - 14 6 - 14 5 - 16 4 - 17 2 - 17 1 - 17 -1 - 16 -2 - 14 -4 - 13 -5 - 6 -3 - 5 -5 - 9 -11 - 8 -13 - 7 -14 - 6 -14 - 7 -14 - 7 -11 - 3 -4 - 4 -4 - 7 -4 - 7 -2 - 5 -1 - 6 1 - 7 2 - 8 2 - 10 1 - 12 1 - 15 0 - 18 -1 - 20 -2 - 21 -1 - 21 0 - 21 0 - 21 1 - 18 3 - 9 3 - 9 4 - 17 10 - 17 12 - 16 12 - 16 11 - 7 5 - 7 4 - 7 2 - 7 1 - 6 0 - 6 -2 - 6 -4 - 6 -5 - 5 -7 - 6 -9 - 5 -9 - 5 -11 - 10 -22 - 8 -24 - 6 -24 - 4 -22 - 1 -9 - 0 -9 - -1 -14 - -4 -13 - -5 -12 - -7 -11 - -10 -11 - -10 -10 - -12 -11 - -13 -11 - -14 -12 - -17 -14 - -17 -14 - -20 -14 - -20 -13 - -22 -11 - -22 -9 - -23 -6 - -12 -1 - -13 -1 - -29 1 - -31 4 - -31 5 - -31 6 - -27 7 - -13 3 - -11 2 - -10 3 - -9 2 - -7 2 - -5 2 - -5 3 - -3 2 - -4 4 - -1 5 - 0 4 - 0 4 - -2 3 - -4 2 - -5 1 - -6 0 - -12 -1 - -7 -1 - -9 0 - -11 0 - -12 1 - C : 0.502 0.502 0.502 sco O ; + +420 656 N M -7 1 - -9 0 - -20 1 - -22 1 - -23 1 - -23 3 - -21 5 - -9 3 - -8 5 - -7 5 - -6 6 - -4 8 - -4 8 - -3 11 - -2 11 - -3 24 - 0 27 - 2 27 - 4 26 - 4 24 - 3 11 - 3 9 - 7 17 - 9 15 - 11 13 - 12 13 - 13 11 - 13 9 - 14 8 - 14 7 - 14 5 - 16 3 - 17 3 - 17 0 - 17 0 - 16 -3 - 14 -3 - 13 -5 - 6 -3 - 5 -5 - 9 -11 - 8 -13 - 7 -15 - 6 -14 - 7 -13 - 7 -11 - 3 -5 - 4 -3 - 7 -5 - 6 -2 - 6 0 - 6 1 - 7 2 - 8 2 - 10 1 - 12 1 - 15 0 - 18 -1 - 20 -2 - 20 -1 - 22 0 - 21 0 - 20 1 - 19 3 - 9 3 - 8 3 - 17 10 - 17 12 - 17 12 - 15 12 - 8 4 - 7 4 - 7 3 - 7 1 - 6 0 - 6 -2 - 6 -4 - 6 -6 - 5 -7 - 6 -8 - 5 -10 - 5 -10 - 10 -23 - 8 -24 - 6 -24 - 4 -21 - 1 -10 - 0 -8 - -1 -14 - -4 -13 - -5 -12 - -7 -11 - -10 -11 - -10 -10 - -12 -11 - -13 -11 - -14 -12 - -17 -14 - -17 -14 - -20 -14 - -20 -13 - -22 -12 - -22 -8 - -23 -6 - -12 -1 - -13 -1 - -29 1 - -31 4 - -31 5 - -31 6 - -27 7 - -13 3 - -11 2 - -10 3 - -9 2 - -7 2 - -6 2 - -4 2 - -3 2 - -4 5 - -2 4 - 0 5 - 0 3 - -1 4 - -4 2 - -6 1 - -5 0 - -12 -1 - -8 -1 - -8 0 - -11 0 - -12 1 - C : 0.200 0.200 0.800 sco O ; + +1820 653 N M -7 1 - -9 0 - -20 1 - -22 1 - -23 1 - -23 3 - -21 5 - -9 4 - -8 4 - -7 6 - -6 6 - -4 8 - -4 9 - -3 11 - -2 11 - -2 26 - 0 27 - 2 28 - 3 28 - 5 24 - 2 11 - 3 10 - 7 17 - 9 16 - 11 14 - 12 13 - 13 11 - 14 10 - 13 8 - 14 7 - 15 5 - 16 4 - 16 2 - 17 1 - 17 -1 - 16 -2 - 14 -4 - 13 -5 - 6 -4 - 5 -4 - 9 -11 - 8 -14 - 7 -15 - 7 -15 - 6 -13 - 7 -12 - 3 -4 - 4 -4 - 7 -5 - 7 -2 - 5 0 - 6 1 - 7 2 - 8 2 - 10 1 - 12 1 - 15 0 - 18 -2 - 20 -1 - 21 -1 - 22 -1 - 21 0 - 20 2 - 18 3 - 9 3 - 9 3 - 17 11 - 17 12 - 16 13 - 16 11 - 7 5 - 7 4 - 7 3 - 7 1 - 6 0 - 6 -2 - 6 -4 - 6 -6 - 5 -7 - 6 -9 - 5 -10 - 5 -11 - 10 -23 - 8 -25 - 6 -25 - 4 -22 - 1 -10 - 0 -9 - -1 -15 - -3 -13 - -6 -12 - -7 -12 - -9 -11 - -11 -10 - -12 -11 - -13 -12 - -14 -13 - -17 -14 - -17 -15 - -20 -14 - -20 -13 - -22 -12 - -22 -9 - -23 -6 - -12 -2 - -13 0 - -29 1 - -31 3 - -31 6 - -30 6 - -28 7 - -13 3 - -11 3 - -10 3 - -9 2 - -7 2 - -5 2 - -5 3 - -3 2 - -4 5 - -1 4 - 0 5 - 0 3 - -2 4 - -4 2 - -5 1 - -6 0 - -5 0 - -7 -1 - -7 -1 - -9 0 - -10 0 - -13 1 - C : 0.502 0.502 0.502 sco O ; + +1812 645 N M -7 1 - -9 0 - -20 1 - -22 0 - -23 2 - -23 3 - -21 5 - -9 3 - -8 5 - -7 5 - -6 7 - -4 8 - -4 9 - -3 10 - -2 12 - -2 25 - 0 28 - 2 28 - 3 27 - 2 13 - 3 12 - 2 10 - 3 10 - 7 17 - 9 16 - 11 14 - 12 13 - 13 11 - 14 10 - 13 8 - 14 7 - 14 5 - 16 4 - 17 2 - 17 1 - 17 -1 - 16 -2 - 14 -4 - 13 -5 - 6 -4 - 5 -4 - 9 -11 - 8 -14 - 7 -15 - 6 -15 - 7 -13 - 7 -12 - 3 -4 - 4 -4 - 7 -5 - 7 -2 - 5 0 - 6 1 - 7 2 - 8 2 - 10 1 - 12 1 - 15 0 - 18 -1 - 20 -2 - 21 -1 - 21 0 - 21 0 - 21 1 - 18 3 - 9 3 - 9 4 - 17 10 - 17 12 - 16 13 - 16 12 - 7 4 - 7 4 - 7 3 - 7 1 - 6 0 - 6 -2 - 6 -4 - 6 -6 - 5 -7 - 6 -9 - 5 -10 - 5 -10 - 10 -24 - 8 -25 - 6 -24 - 4 -22 - 1 -10 - 0 -9 - -1 -15 - -4 -14 - -5 -12 - -7 -11 - -10 -11 - -10 -11 - -12 -10 - -13 -12 - -14 -13 - -17 -14 - -17 -15 - -20 -14 - -20 -14 - -22 -11 - -22 -9 - -11 -4 - -12 -2 - -12 -2 - -13 0 - -29 1 - -31 3 - -31 6 - -31 6 - -27 7 - -13 3 - -11 3 - -10 3 - -9 2 - -7 2 - -5 2 - -5 2 - -3 2 - -4 5 - -1 5 - 0 4 - 0 4 - -2 3 - -4 3 - -5 1 - -6 0 - -12 -1 - -7 -1 - -9 -1 - -11 1 - -12 1 - C : 0.200 0.200 0.800 sco O ; + +N 1929 615.500 M 2 1 rr : 0 0 0 sco O ; + +N 1928 616.500 M 4 1 rr : 0 0 0 sco O ; + +N 1927 617.500 M 6 1 rr : 0 0 0 sco O ; + +N 1926 618.500 M 8 1 rr : 0 0 0 sco O ; + +N 1927 619.500 M 8 1 rr : 0 0 0 sco O ; + +N 1928 620.500 M 8 1 rr : 0 0 0 sco O ; + +N 1929 621.500 M 7 1 rr : 0 0 0 sco O ; + +N 1930 622.500 M 7 1 rr : 0 0 0 sco O ; + +N 1931 623.500 M 7 1 rr : 0 0 0 sco O ; + +N 1931 624.500 M 8 1 rr : 0 0 0 sco O ; + +N 1932 625.500 M 8 1 rr : 0 0 0 sco O ; + +N 1933 626.500 M 8 1 rr : 0 0 0 sco O ; + +N 1934 627.500 M 8 1 rr : 0 0 0 sco O ; + +N 1935 628.500 M 8 1 rr : 0 0 0 sco O ; + +N 1936 629.500 M 9 1 rr : 0 0 0 sco O ; + +N 1937 630.500 M 9 1 rr : 0 0 0 sco O ; + +N 1938 631.500 M 9 1 rr : 0 0 0 sco O ; + +N 1940 632.500 M 8 1 rr : 0 0 0 sco O ; + +N 1941 633.500 M 8 1 rr : 0 0 0 sco O ; + +N 1942 634.500 M 8 1 rr : 0 0 0 sco O ; + +N 1943 635.500 M 8 1 rr : 0 0 0 sco O ; + +N 1944 636.500 M 8 1 rr : 0 0 0 sco O ; + +N 1945 637.500 M 8 1 rr : 0 0 0 sco O ; + +N 1946 638.500 M 7 1 rr : 0 0 0 sco O ; + +N 1947 639.500 M 7 1 rr : 0 0 0 sco O ; + +N 1948 640.500 M 7 1 rr : 0 0 0 sco O ; + +N 1948 641.500 M 8 1 rr : 0 0 0 sco O ; + +N 1949 642.500 M 8 1 rr : 0 0 0 sco O ; + +N 1950 643.500 M 8 1 rr : 0 0 0 sco O ; + +N 1951 644.500 M 8 1 rr : 0 0 0 sco O ; + +N 1952 645.500 M 8 1 rr : 0 0 0 sco O ; + +N 1953 646.500 M 7 1 rr : 0 0 0 sco O ; + +N 1954 647.500 M 7 1 rr : 0 0 0 sco O ; + +N 1955 648.500 M 7 1 rr : 0 0 0 sco O ; + +N 1955 649.500 M 8 1 rr : 0 0 0 sco O ; + +N 1956 650.500 M 8 1 rr : 0 0 0 sco O ; + +N 1957 651.500 M 8 1 rr : 0 0 0 sco O ; + +N 1958 652.500 M 7 1 rr : 0 0 0 sco O ; + +N 1959 653.500 M 7 1 rr : 0 0 0 sco O ; + +N 1960 654.500 M 7 1 rr : 0 0 0 sco O ; + +N 1960 655.500 M 8 1 rr : 0 0 0 sco O ; + +N 1961 656.500 M 7 1 rr : 0 0 0 sco O ; + +N 1962 657.500 M 7 1 rr : 0 0 0 sco O ; + +N 1963 658.500 M 7 1 rr : 0 0 0 sco O ; + +N 1963 659.500 M 8 1 rr : 0 0 0 sco O ; + +N 1964 660.500 M 7 1 rr : 0 0 0 sco O ; + +N 1965 661.500 M 7 1 rr : 0 0 0 sco O ; + +N 1966 662.500 M 7 1 rr : 0 0 0 sco O ; + +N 1966 663.500 M 8 1 rr : 0 0 0 sco O ; + +N 1967 664.500 M 7 1 rr : 0 0 0 sco O ; + +N 1968 665.500 M 7 1 rr : 0 0 0 sco O ; + +N 1969 666.500 M 7 1 rr : 0 0 0 sco O ; + +N 1969 667.500 M 7 1 rr : 0 0 0 sco O ; + +N 1971 668.500 M 6 1 rr : 0 0 0 sco O ; + +N 1971 669.500 M 6 1 rr : 0 0 0 sco O ; + +N 1972 670.500 M 6 1 rr : 0 0 0 sco O ; + +N 1972 671.500 M 6 1 rr : 0 0 0 sco O ; + +N 1973 672.500 M 6 1 rr : 0 0 0 sco O ; + +N 1973 673.500 M 6 1 rr : 0 0 0 sco O ; + +N 1974 674.500 M 6 1 rr : 0 0 0 sco O ; + +N 1974 675.500 M 6 1 rr : 0 0 0 sco O ; + +N 1974 676.500 M 7 1 rr : 0 0 0 sco O ; + +N 1975 677.500 M 6 1 rr : 0 0 0 sco O ; + +N 1975 678.500 M 7 1 rr : 0 0 0 sco O ; + +N 1976 679.500 M 6 1 rr : 0 0 0 sco O ; + +N 1976 680.500 M 7 1 rr : 0 0 0 sco O ; + +N 1977 681.500 M 6 1 rr : 0 0 0 sco O ; + +N 1977 682.500 M 7 1 rr : 0 0 0 sco O ; + +N 1978 683.500 M 6 1 rr : 0 0 0 sco O ; + +N 1978 684.500 M 7 1 rr : 0 0 0 sco O ; + +N 1979 685.500 M 6 1 rr : 0 0 0 sco O ; + +N 1979 686.500 M 7 1 rr : 0 0 0 sco O ; + +N 1980 687.500 M 6 1 rr : 0 0 0 sco O ; + +N 1980 688.500 M 7 1 rr : 0 0 0 sco O ; + +N 1981 689.500 M 6 1 rr : 0 0 0 sco O ; + +N 1981 690.500 M 7 1 rr : 0 0 0 sco O ; + +N 1982 691.500 M 6 1 rr : 0 0 0 sco O ; + +N 1982 692.500 M 7 1 rr : 0 0 0 sco O ; + +N 1983 693.500 M 6 1 rr : 0 0 0 sco O ; + +N 1983 694.500 M 6 1 rr : 0 0 0 sco O ; + +N 1983 695.500 M 7 1 rr : 0 0 0 sco O ; + +N 1984 696.500 M 6 1 rr : 0 0 0 sco O ; + +N 1984 697.500 M 7 1 rr : 0 0 0 sco O ; + +N 1985 698.500 M 6 1 rr : 0 0 0 sco O ; + +N 1985 699.500 M 7 1 rr : 0 0 0 sco O ; + +N 1986 700.500 M 6 1 rr : 0 0 0 sco O ; + +N 1986 701.500 M 7 1 rr : 0 0 0 sco O ; + +N 1987 702.500 M 6 1 rr : 0 0 0 sco O ; + +N 1987 703.500 M 6 1 rr : 0 0 0 sco O ; + +N 1987 704.500 M 7 1 rr : 0 0 0 sco O ; + +N 1988 705.500 M 6 1 rr : 0 0 0 sco O ; + +N 1988 706.500 M 7 1 rr : 0 0 0 sco O ; + +N 1989 707.500 M 6 1 rr : 0 0 0 sco O ; + +N 1989 708.500 M 7 1 rr : 0 0 0 sco O ; + +N 1990 709.500 M 6 1 rr : 0 0 0 sco O ; + +N 1990 710.500 M 6 1 rr : 0 0 0 sco O ; + +N 1990 711.500 M 7 1 rr : 0 0 0 sco O ; + +N 1991 712.500 M 6 1 rr : 0 0 0 sco O ; + +N 1991 713.500 M 7 1 rr : 0 0 0 sco O ; + +N 1992 714.500 M 6 1 rr : 0 0 0 sco O ; + +N 1992 715.500 M 7 1 rr : 0 0 0 sco O ; + +N 1993 716.500 M 6 1 rr : 0 0 0 sco O ; + +N 1993 717.500 M 7 1 rr : 0 0 0 sco O ; + +N 1994 718.500 M 6 1 rr : 0 0 0 sco O ; + +N 1994 719.500 M 7 1 rr : 0 0 0 sco O ; + +N 1995 720.500 M 6 1 rr : 0 0 0 sco O ; + +N 1995 721.500 M 7 1 rr : 0 0 0 sco O ; + +N 1996 722.500 M 6 1 rr : 0 0 0 sco O ; + +N 1996 723.500 M 7 1 rr : 0 0 0 sco O ; + +N 1997 724.500 M 6 1 rr : 0 0 0 sco O ; + +N 1997 725.500 M 7 1 rr : 0 0 0 sco O ; + +N 1998 726.500 M 6 1 rr : 0 0 0 sco O ; + +N 1998 727.500 M 7 1 rr : 0 0 0 sco O ; + +N 1999 728.500 M 6 1 rr : 0 0 0 sco O ; + +N 1999 729.500 M 7 1 rr : 0 0 0 sco O ; + +N 2000 730.500 M 6 1 rr : 0 0 0 sco O ; + +N 2000 731.500 M 7 1 rr : 0 0 0 sco O ; + +N 2001 732.500 M 6 1 rr : 0 0 0 sco O ; + +N 2001 733.500 M 6 1 rr : 0 0 0 sco O ; + +N 2001 734.500 M 7 1 rr : 0 0 0 sco O ; + +N 2002 735.500 M 6 1 rr : 0 0 0 sco O ; + +N 2002 736.500 M 7 1 rr : 0 0 0 sco O ; + +N 2003 737.500 M 6 1 rr : 0 0 0 sco O ; + +N 2003 738.500 M 7 1 rr : 0 0 0 sco O ; + +N 2004 739.500 M 6 1 rr : 0 0 0 sco O ; + +N 2004 740.500 M 7 1 rr : 0 0 0 sco O ; + +N 2005 741.500 M 6 1 rr : 0 0 0 sco O ; + +N 2005 742.500 M 7 1 rr : 0 0 0 sco O ; + +N 2006 743.500 M 6 1 rr : 0 0 0 sco O ; + +N 2006 744.500 M 7 1 rr : 0 0 0 sco O ; + +N 2007 745.500 M 6 1 rr : 0 0 0 sco O ; + +N 2007 746.500 M 7 1 rr : 0 0 0 sco O ; + +N 2008 747.500 M 7 1 rr : 0 0 0 sco O ; + +N 2008 748.500 M 7 1 rr : 0 0 0 sco O ; + +N 2009 749.500 M 7 1 rr : 0 0 0 sco O ; + +N 2010 750.500 M 6 1 rr : 0 0 0 sco O ; + +N 2010 751.500 M 7 1 rr : 0 0 0 sco O ; + +N 2011 752.500 M 7 1 rr : 0 0 0 sco O ; + +N 2011 753.500 M 7 1 rr : 0 0 0 sco O ; + +N 2012 754.500 M 7 1 rr : 0 0 0 sco O ; + +N 2013 755.500 M 7 1 rr : 0 0 0 sco O ; + +N 2013 756.500 M 8 1 rr : 0 0 0 sco O ; + +N 2014 757.500 M 7 1 rr : 0 0 0 sco O ; + +N 2015 758.500 M 7 1 rr : 0 0 0 sco O ; + +N 2016 759.500 M 7 1 rr : 0 0 0 sco O ; + +N 2016 760.500 M 9 1 rr : 0 0 0 sco O ; + +N 2017 761.500 M 9 1 rr : 0 0 0 sco O ; + +N 2018 762.500 M 9 1 rr : 0 0 0 sco O ; + +N 2019 763.500 M 9 1 rr : 0 0 0 sco O ; + +N 2020 764.500 M 10 1 rr : 0 0 0 sco O ; + +N 2022 765.500 M 9 1 rr : 0 0 0 sco O ; + +N 2023 766.500 M 9 1 rr : 0 0 0 sco O ; + +N 2024 767.500 M 10 1 rr : 0 0 0 sco O ; + +N 2025 768.500 M 10 1 rr : 0 0 0 sco O ; + +N 2027 769.500 M 9 1 rr : 0 0 0 sco O ; + +N 2028 770.500 M 10 1 rr : 0 0 0 sco O ; + +N 2029 771.500 M 10 1 rr : 0 0 0 sco O ; + +N 2031 772.500 M 10 1 rr : 0 0 0 sco O ; + +N 2032 773.500 M 10 1 rr : 0 0 0 sco O ; + +N 2033 774.500 M 10 1 rr : 0 0 0 sco O ; + +N 2035 775.500 M 10 1 rr : 0 0 0 sco O ; + +N 2036 776.500 M 10 1 rr : 0 0 0 sco O ; + +N 2038 777.500 M 9 1 rr : 0 0 0 sco O ; + +N 2039 778.500 M 10 1 rr : 0 0 0 sco O ; + +N 2040 779.500 M 10 1 rr : 0 0 0 sco O ; + +N 2042 780.500 M 9 1 rr : 0 0 0 sco O ; + +N 2043 781.500 M 9 1 rr : 0 0 0 sco O ; + +N 2044 782.500 M 8 1 rr : 0 0 0 sco O ; + +N 2046 783.500 M 7 1 rr : 0 0 0 sco O ; + +N 2047 784.500 M 7 1 rr : 0 0 0 sco O ; + +N 2047 785.500 M 7 1 rr : 0 0 0 sco O ; + +N 2048 786.500 M 7 1 rr : 0 0 0 sco O ; + +N 2049 787.500 M 7 1 rr : 0 0 0 sco O ; + +N 2049 788.500 M 7 1 rr : 0 0 0 sco O ; + +N 2050 789.500 M 7 1 rr : 0 0 0 sco O ; + +N 2051 790.500 M 6 1 rr : 0 0 0 sco O ; + +N 2051 791.500 M 7 1 rr : 0 0 0 sco O ; + +N 2052 792.500 M 6 1 rr : 0 0 0 sco O ; + +N 2052 793.500 M 7 1 rr : 0 0 0 sco O ; + +N 2053 794.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 795.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 796.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 797.500 M 7 1 rr : 0 0 0 sco O ; + +N 2054 798.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 799.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 800.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 801.500 M 7 1 rr : 0 0 0 sco O ; + +N 2055 802.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 803.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 804.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 805.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 806.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 807.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 808.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 809.500 M 7 1 rr : 0 0 0 sco O ; + +N 2056 810.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 811.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 812.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 813.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 814.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 815.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 816.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 817.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 818.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 819.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 820.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 821.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 822.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 823.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 824.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 825.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 826.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 827.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 828.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 829.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 830.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 831.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 832.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 833.500 M 7 1 rr : 0 0 0 sco O ; + +N 2055 834.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 835.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 836.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 837.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 838.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 839.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 840.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 841.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 842.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 843.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 844.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 845.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 846.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 847.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 848.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 849.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 850.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 851.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 852.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 853.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 854.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 855.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 856.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 857.500 M 7 1 rr : 0 0 0 sco O ; + +N 2054 858.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 859.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 860.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 861.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 862.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 863.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 864.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 865.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 866.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 867.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 868.500 M 7 1 rr : 0 0 0 sco O ; + +N 2053 869.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 870.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 871.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 872.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 873.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 874.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 875.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 876.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 877.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 878.500 M 6 1 rr : 0 0 0 sco O ; + +1394 762 N M 0 22 - -257 0 - 0 46 - 257 0 - 0 23 - 86 -46 - -86 -45 - C : 0.502 0.502 0.502 sco O ; + +1386 753 N M 0 23 - -257 0 - 0 46 - 257 0 - 0 22 - 85 -45 - -85 -46 - C : 0 0.800 0.600 sco O ; + +LH + +pagesave restore + + + + + + + +/Pscript_Win_Driver /ProcSet findresource dup /terminate get exec + +Pscript_Win_Compat dup /terminate get exec + + + +restore gr +% +% End Imported PIC File: slide7.eps +% +% Polyline +% +% Begin Imported EPS File: slide8.eps +% +n gs +9900 389 tr +15.269291 -15.269767 sc +0 -430 tr +-35 -150 tr +save +/showpage {} def +% EPS file follows: + + + + + + + + + + + + + + + +/defineresource where{pop}{userdict begin/defineresource{userdict/Resources 2 + +copy known{get begin}{15 dict dup begin put}ifelse exch readonly exch + +currentdict 1 index known not{dup 30 dict def}if load 3 -1 roll 2 index put + +end}bind readonly def/findresource{userdict/Resources get exch get exch get} + +bind readonly def/resourceforall{pop pop pop pop}bind readonly def + +/resourcestatus{userdict/Resources 2 copy known{get exch 2 copy known{get exch + +known{0 -1 true}{pop pop false}ifelse}{pop pop pop false}ifelse}{pop pop false + +}ifelse}bind readonly def end}ifelse + + + +/Pscript_Win_Driver 200 dict dup begin + + +/FatalErrorIf{{initgraphics findfont exch scalefont setfont counttomark 3 div + +cvi{moveto show}repeat showpage quit}{cleartomark}ifelse}bind def + + +/VM? {vmstatus exch sub exch pop gt { [ + +(This job requires more memory than is available in this printer.) 100 500 + +(Try one or more of the following, and then print again:) 100 485 + +(In the PostScript dialog box, click Optimize For Portability.) 115 470 + +(In the Device Options dialog box, make sure the Available Printer Memory is accurate.) 115 455 + +(Reduce the number of fonts in the document.) 115 440 + +(Print the document in parts.) 115 425 + +12 /Times-Roman showpage + +(%%[ PrinterError: Low Printer VM ]%%) = + +true FatalErrorIf}if} bind def + + +/|/def load def/,/load load |/~/exch , |/?/ifelse , |/!/pop , |/`/begin , |/^ + +/index , |/@/dup , |/+/translate , |/$/roll , |/U/userdict , |/M/moveto , |/- + +/rlineto , |/&/currentdict , |/:/gsave , |/;/grestore , |/F/false , |/T/true , + +|/N/newpath , |/E/end , |/Ac/arc , |/An/arcn , |/A/ashow , |/D/awidthshow , | + +/C/closepath , |/V/div , |/O/eofill , |/L/fill , |/I/lineto , |/-C/rcurveto , + +|/-M/rmoveto , |/+S/scale , |/Ji/setfont , |/Lc/setlinecap , |/Lj/setlinejoin + +, |/Lw/setlinewidth , |/S/show , |/LH/showpage , |/K/stroke , |/W/widthshow , + +|/R/rotate , |/b{bind |}bind |/bd{bind |}bind |/xd{~ |}bd/ld{, |}bd/lw/Lw ld + +/lc/Lc ld/lj/Lj ld/sg/setgray ld/L2? F/languagelevel where{! languagelevel 2 + +ge{! T}if}if |/g{@ not{U/DefIf_save save put}if U/DefIf_bool 2 ^ put}b + +/DefIf_El{if U/DefIf_bool get not @{U/DefIf_save get restore}if}b/e{DefIf_El ! + +}b/self & |/reinitialize{[/TextInit/GraphInit/UtilsInit counttomark{@ where{ + +self eq}{F}?{cvx exec}{!}?}repeat cleartomark}b/initialize{`{/ADO_mxRot ~ | + +/TextInitialised? F | reinitialize E}{U/Pscript_Win_Data 200 dict @ ` put + +/ADO_mxRot ~ |/TextInitialised? F | reinitialize}?}b/terminate{!{& self eq{ + +exit}{E}?}loop E}b/suspend/terminate , |/resume{` Pscript_Win_Data `}b/snap{ + +transform 0.25 sub round 0.25 add ~ 0.25 sub round 0.25 add ~ itransform}b + +/dsnap{dtransform round ~ round ~ idtransform}b<04>cvn{}|/setjn{{statusdict + +/jobname known{statusdict/jobname 3 -1 $ put}if}stopped cleartomark}b/solid{[] + +0 setdash}b/setdsh{0 setdash}b/colspRefresh{}b/rp{4 2 $ M 1 ^ 0 - 0 ~ - neg 0 + +-}b/rr{1 ^ 0 - 0 ~ - neg 0 - C}b + + + +L2? not g{/rf{N rp L}b/fx{1 1 dtransform @ 0 ge{1 sub 1}{1 add -0.25}? 3 -1 $ + +@ 0 ge{1 sub 1}{1 add -0.25}? 3 1 $ 4 1 $ idtransform 4 -2 $ idtransform}b/BZ{ + +4 -2 $ snap + +S fx rf}b/rs{N rp C K}b/rc{N rp clip N}b/sg{setgray}b/sco{ + +setrgbcolor}b/sgco{{sg}{sco}?}b}e + + + +L2? g{/colspA/DeviceGray |/colspABC/DeviceRGB |/setAorABC{{colspA}{colspABC}? + +setcolorspace}b/rf/rectfill , |/fx{1 1 dtransform @ 0 ge{1 sub 0.5}{1 add -0.5 + +}? 3 -1 $ @ 0 ge{1 sub 0.5}{1 add -0.5}? 3 1 $ 4 1 $ idtransform 4 -2 $ + +idtransform}b/BZ{4 -2 $ snap + +S fx rf}b/rs/rectstroke , |/rc/rectclip , |/sg + +{@ @ setcolor}b/sco{setcolor}b/colspRefresh{colspABC setcolorspace}b/sgco{{sg + +}{sco}?}b/UtilsInit{F setglobal}b/definecolorrendering{/ColorRendering + +defineresource !}b/findcolorrendering{@/ColorRendering resourcestatus{! ! + +/ColorRendering findresource T}{! F}?}b/selectcolorrendering{@/ColorRendering + +resourcestatus{! !/ColorRendering}{!/DefaultColorRendering/ColorRendering}? + +findresource setcolorrendering}b}e + + + +/bullets{{/bullet}repeat}b/ANSIEncoding[/grave/acute/circumflex/tilde/macron + +/breve/dotaccent/dieresis/ring/cedilla/hungarumlaut/ogonek/caron/dotlessi 18 + +bullets StandardEncoding 32 95 getinterval aload ! 3 bullets/quotesinglbase + +/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron + +/guilsinglleft/OE 4 bullets/quoteleft/quoteright/quotedblleft/quotedblright + +/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe 2 bullets + +/Ydieresis/space/exclamdown/cent/sterling/currency/yen/brokenbar/section + +/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered + +/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph + +/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter + +/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis + +/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute + +/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis + +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls + +/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute + +/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve + +/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex + +/udieresis/yacute/thorn/ydieresis]| ANSIEncoding @ 39/quotesingle put 96/grave + +put/ANSIEncodingOld ANSIEncoding 256 array copy | ANSIEncodingOld @[138 153 + +154 169 172 174 177 178 179 181 185 188 189 190 208 215 221 222 240 247 253 + +254]{/bullet put @}forall 166/bar put 176/ring put + + + +/TextInit{TextInitialised? not{/Pscript_Windows_Font & |/TextInitialised? T | + +/fM[1 0 0 -1 0 0]|/mFM matrix |/iMat[1 0 0.212557 neg 1 0 0]|}if}b/xUP null | + +/yUP null |/uW null |/xSP null |/ySP null |/sW null |/copyfont{1 ^ length add + +dict `{1 ^/FID ne{|}{! !}?}forall & E}b/rF{3 copyfont @ `/Encoding + +ANSIEncoding &/CharStrings known{CharStrings/Eth known not{! ANSIEncodingOld} + +if}if | E}b/mF{findfont ~{@/Encoding get @ StandardEncoding eq{! T}{{ + +ISOLatin1Encoding}stopped{! F}{eq}?{T}{@ ` T 32 1 127{Encoding 1 ^ get + +StandardEncoding 3 -1 $ get eq and}for E}?}?}{F}?{rF}{3 copyfont}? ` + +/OrigFontType ~ |/OrigFontName ~ | & E 2 ^ ~ definefont fM 5 4 -1 $ put fM 4 0 + +put fM makefont Pscript_Windows_Font 3 1 $ put}b/xF{scalefont + +Pscript_Windows_Font 3 1 $ put}b/xMF{mFM astore makefont Pscript_Windows_Font + +3 1 $ put}b/xF2/scalefont , |/xMF2{mFM astore makefont}b/sLT{: Lw -M + +currentpoint snap M 0 - 0 Lc K ;}b/sSU{N/uW ~ |/yUP ~ |/xUP ~ |}b/sU{xUP yUP + +uW sLT}b/sST{N/sW ~ |/ySP ~ |/xSP ~ |}b/sT{xSP ySP sW sLT}b/sR{: + R 0 0 M}b + +/sRxy{: matrix astore concat 0 0 M}b/eR/; , | + + + +/mBF{@ 4 copyfont `/FontName ~ |/OrigFontType ~ |/OrigFontName ~ | 0 + +FontMatrix idtransform ! &/PaintType known{PaintType 0 eq{/PaintType 2 | + +/StrokeWidth ~ |}{PaintType 1 eq PaintType 2 eq or PaintType 3 eq or & + +/StrokeWidth known and{StrokeWidth add/StrokeWidth ~ |}{!}?}?}{!}? @ & E + +definefont Pscript_Windows_Font 3 1 $ put}b/xBF{Pscript_Windows_Font ` 1 ^ + +/FontName get 1 ^ scalefont 3 1 $ scalefont 2 copy ~ | ~ ! | E}b/xMBF{mFM + +astore Pscript_Windows_Font ` 1 ^/FontName get 1 ^ makefont 3 1 $ makefont 2 + +copy ~ | ~ ! | E}b/xBF2{/sB0 ~ mBF/sB1 sB0 3 -1 $ xBF sB1}b/xMBF2{/sB0 ~ mBF + +mFM astore/sB1 sB0 3 -1 $ xMBF sB1}b/sB{: Pscript_Windows_Font currentfont get + +Ji @ S ; S}b/asB{: Pscript_Windows_Font currentfont get Ji 3 copy A ; A}b/wsB{ + +: Pscript_Windows_Font currentfont get Ji 4 copy W ; W}b/awsB{: + +Pscript_Windows_Font currentfont get Ji 6 copy D ; D}b/sBT3{: @ S ; 1 1 -M S}b + +/asBT3{: 3 copy A ; 1 1 -M A}b/wsBT3{: 4 copy W ; 1 1 -M W}b/awsBT3{: 6 copy D + +; 1 1 -M D}b/mIF{iMat 4 3 -1 $ put 2 copyfont `/OrigFontType ~ |/OrigFontName + +~ | @ & E definefont iMat makefont Pscript_Windows_Font 3 1 $ put}b + + + +/SavedCTM null |/CTMsave{/SavedCTM SavedCTM currentmatrix |}b/CTMrestore{ + +SavedCTM setmatrix}b/mp null |/ADO_mxRot null |/GDIHMatrix null | + +/GDIHPatternDict 22 dict | GDIHPatternDict `/PatternType 1 |/PaintType 2 | + +/Reps L2?{1}{5}? |/XStep 8 Reps mul |/YStep XStep |/BBox[0 0 XStep YStep]| + +/TilingType 1 |/PaintProc{` 1 Lw[]0 setdash PaintData , exec E}b/FGnd null | + +/BGnd null |/HS_Horizontal{horiz}b/HS_Vertical{vert}b/HS_FDiagonal{fdiag}b + +/HS_BDiagonal{biag}b/HS_Cross{horiz vert}b/HS_DiagCross{fdiag biag}b/MaxXYStep + +XStep YStep gt{XStep}{YStep}? |/horiz{Reps{0 4 M XStep 0 - 0 8 +}repeat 0 -8 + +Reps mul + K}b/vert{Reps{4 0 M 0 YStep - 8 0 +}repeat 0 -8 Reps mul + K}b/biag + +{Reps{0 0 M MaxXYStep @ - 0 YStep neg M MaxXYStep @ - 0 8 +}repeat 0 -8 Reps + +mul + 0 YStep M 8 8 - K}b/fdiag{Reps{0 0 M MaxXYStep @ neg - 0 YStep M + +MaxXYStep @ neg - 0 8 +}repeat 0 -8 Reps mul + MaxXYStep @ M 8 -8 - K}b E + +/makehatch{GDIHPatternDict/PaintData 3 -1 $ put CTMsave GDIHMatrix setmatrix + +GDIHPatternDict matrix mp CTMrestore ~ U ~ 2 ^ put}b/h0{/h0/HS_Horizontal + +makehatch}b/h1{/h1/HS_Vertical makehatch}b/h2{/h2/HS_FDiagonal makehatch}b/h3{ + +/h3/HS_BDiagonal makehatch}b/h4{/h4/HS_Cross makehatch}b/h5{/h5/HS_DiagCross + +makehatch}b/GDIBWPatternDict 17 dict @ `/PatternType 1 |/PaintType L2?{1}{2}? + +|/RepsV L2?{1}{6}? |/RepsH L2?{1}{5}? |/BBox[0 0 RepsH 1]|/TilingType 1 | + +/XStep 1 |/YStep 1 |/Height 8 RepsV mul |/Width 8 |/mx[Width 0 0 Height neg 0 + +Height]|/FGnd null |/BGnd null |/SetBGndFGnd L2?{{BGnd null ne{BGnd aload ! + +sgco BBox aload ! 2 ^ sub ~ 3 ^ sub ~ rf}if FGnd null ne{FGnd aload ! sgco}if} + +}{{}}? b/PaintProc{` SetBGndFGnd RepsH{Width Height F mx PaintData imagemask + +Width 0 +}repeat E}b E |/GDIBWPatternMx null |/pfprep{save 4 1 $ + +/PatternOfTheDay 4 1 $ GDIBWPatternDict `/PaintData ~ |/BGnd ~ |/FGnd ~ | E + +CTMsave GDIBWPatternMx setmatrix GDIBWPatternDict matrix mp CTMrestore ~ !}b + +/hrf null |/prf{pfprep ~ 6 1 $ 5 hrf restore}b/GraphInit{GDIHMatrix null eq{ + +/SavedCTM matrix | : ADO_mxRot concat 0 0 snap + : 0.48 @ GDIHPatternDict ` + +YStep mul ~ XStep mul ~ dsnap YStep V ~ XStep V ~ E +S/GDIHMatrix matrix + +currentmatrix readonly | ; : 0.24 -0.24 +S GDIBWPatternDict ` Width Height E + +dsnap +S/GDIBWPatternMx matrix currentmatrix readonly | ; ;}if}b/cirp{360 0 An + +C}b/ellp{CTMsave + +S 0.5 0 M 0 0 0.5 360 0 An C CTMrestore}b/rrp{/rad ~ |/y2 + +~ |/x2 ~ |/y1 ~ |/x1 ~ | x2 x1 add 2 V y1 M x1 y1 x1 y2 rad arct x1 y2 x2 y2 + +rad arct x2 y2 x2 y1 rad arct x2 y1 x1 y1 rad arct C}b/RRp{CTMsave + +S/dyS ~ + +|/dxS ~ | dxS 2 V 0 M 0 0 0 dyS 0.5 arct 0 dyS dxS dyS 0.5 arct dxS dyS dxS 0 + +0.5 arct dxS 0 0 0 0.5 arct C CTMrestore}b + + + +L2? not g{/arct{arcto ! ! ! !}b/GDIpattfill{@ ` BGnd null ne PaintType 2 eq + +and{: BGnd aload ! sgco fEOFill{O}{L}? ; FGnd aload ! U/fGray 2 ^ put{2}{4}? + +-1 $}if E @ patterncalc : 4 ^/PaintType get 2 eq{fGray{6 -1 $ sg}{8 -3 $ sco}? + +}if fEOFill{eoclip}{clip}? N patternfill ; N}b/hrf{/fGray 1 ^ 6 eq | -4 $ N rp + +C/fEOFill F | GDIpattfill}b/hfMain{/fEOFill ~ |/fGray ~ | GDIpattfill}b/hf{T + +hfMain}b/hfW{F hfMain}b/hs{currentpoint strokepath M hfW}b/pfMain{/fEOFill ~ | + +pfprep GDIpattfill restore N}b/pf{T pfMain}b/pfW{F pfMain}b/ps{currentpoint + +strokepath M pfW}b/mpstr 1 string |/mp{~ @ length 12 add dict copy ` + +/PatternCTM matrix currentmatrix |/PatternMatrix ~ |/PatWidth XStep mpstr + +length mul |/PatHeight YStep |/FontType 3 |/Encoding 256 array | 3 string 0 1 + +255{Encoding ~ @ 3 ^ cvs cvn put}for !/FontMatrix matrix |/FontBBox BBox | + +/BuildChar{! @ ` XStep 0 FontBBox aload ! setcachedevice/PaintProc , E : exec + +;}b & E ~ @ 3 -1 $ definefont}b/patterncalc{` : PatternCTM setmatrix + +PatternMatrix concat BBox aload ! ! ! + pathbbox ; PatHeight V ceiling 4 1 $ + +PatWidth V ceiling 4 1 $ PatHeight V floor 4 1 $ PatWidth V floor 4 1 $ 2 ^ + +sub cvi abs ~ 3 ^ sub cvi abs ~ 4 2 $ PatHeight mul ~ PatWidth mul ~ E}b + +/patternfill{5 -1 $ @ ` Ji PatternCTM setmatrix PatternMatrix concat 0 2 ^ 2 ^ + +M 0 1 mpstr length 1 sub{1 ^ mpstr 3 1 $ put}for ! 2 ^{currentpoint 5 ^{mpstr + +S}repeat YStep add M}repeat ! ! ! ! E}b}e + + + +L2? g{/mp/makepattern , |/hrf{6 eq setAorABC setpattern rectfill}b/hf{ + +setAorABC setpattern O}b/hfW{setAorABC setpattern L}b/hs{setAorABC setpattern + +K}b/pf{pfprep setpattern O restore N}b/pfW{pfprep setpattern L restore N}b/ps{ + +pfprep setpattern K restore N}b}e + + + +/iw 0 |/ih 0 |/im_save 0 |/s 0 |/polarity 0 |/smoothflag 0 |/mystring 0 |/bpc + +0 |/setup1asciiproc{[currentfile mystring/readhexstring cvx/! cvx]cvx bind}b + +/setup1binaryproc{[currentfile mystring/readstring cvx/! cvx]cvx bind}b + +/setup2asciiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}b + +/setup2binaryproc{currentfile/RunLengthDecode filter}b/mycolorspace{colspABC}| + +/myimagedict{/myimagedict 10 dict | myimagedict @ `/ImageType 1 | + +/MultipleDataSource F | E}b/imageprocarray[/setup1binaryproc/setup1asciiproc + +/setup2binaryproc/setup2asciiproc/setup1binarydecodeproc/setup1asciidecodeproc + +]|/L2Polarity{{[1 0]}{[0 1]}?}b/Q{/im_save save | imageprocarray ~ get/s ~ , | + +L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring ~ + +string |/bpc ~ |/ih ~ |/iw ~ |}b/X{/im_save save | imageprocarray ~ get/s ~ , + +| L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring + +~ string |/bpc ~ |/ih ~ |/iw ~ |}b/Z{im_save restore}b/Y{sgco myimagedict @ ` + +/Width iw |/Height ih |/Decode polarity |/ImageMatrix[iw 0 0 ih 0 0]| + +/DataSource s |/BitsPerComponent 1 |/Interpolate smoothflag | E imagemask}b + + + +L2? not g{/setup2asciiproc{[/Level2ImagesError , aload ! T FatalErrorIf}b + +/setup2binaryproc/setup2asciiproc , |/L2Polarity{}|/Y{sgco iw ih polarity[iw 0 + +0 ih 0 0]s imagemask}b}e + + + +L2? not g{/testsystemdict{where{systemdict eq{T}{F}?}{F}?}b/c 1 |/colorimage + +where{! T}{F}?{/c 0 statusdict `/processcolors where{! ! processcolors}{ + +/deviceinfo where{! deviceinfo/Colors known{!{deviceinfo/Colors get}}if}if}? E + +| c 0 ne{/colorimage testsystemdict/setcolortransfer testsystemdict + +/currentcolortransfer testsystemdict/currentcmykcolor testsystemdict and and + +and not{/c 0 |}if}if}if c @ 1 ne ~ @ 3 ne ~ 4 ne and and{/c 0 |}if c 1 eq g{ + +/expandbw{expandfactor mul round cvi bwclut ~ get 255 V}b/doclutimage{!/bwclut + +~ | bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/expandfactor ~ |[/expandbw ,/exec , @ + +currenttransfer ~]cvx bind settransfer iw ih bpc[iw 0 0 ih 0 0]s image}b}e c @ + +3 eq ~ 4 eq or g{/nullproc{{}}|/concatutil{/exec , 7 -1 $/exec ,}b/defsubclut{ + +1 add getinterval |}b/spconcattransfer{/Dclut ~ |/Cclut ~ |/Bclut ~ |/Aclut ~ + +|/ncompute ~ , | currentcolortransfer[{Aclut ncompute}concatutil]cvx[{Bclut + +ncompute}concatutil]cvx[{Cclut ncompute}concatutil]cvx[{Dclut ncompute} + +concatutil]cvx setcolortransfer}b/setuprgbcluts{/bit3x rgbclut length 3 sub | + +/bit1x bit3x 3 idiv |/rclut rgbclut |/gclut rclut 1 bit3x defsubclut/bclut + +rclut 2 bit3x defsubclut}b}e c 3 eq g{/3compute{~ bit3x mul round cvi get 255 + +V}b/doclutimage{/rgbclut ~ | ! setuprgbcluts/3compute rclut gclut bclut @ + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @]cvx nullproc nullproc + +T 3 colorimage}b}e c 4 eq g{/ftoint{1 ~ sub 255 mul round cvi}b/stuffclut{ + +cmykindex 3 -1 $ put}b/4compute{~ bit4x mul round cvi get 255 V}b + +/invalidcolortable? T |/computecmykclut{setuprgbcluts/bit4x rgbclut length 3 + +idiv 4 mul 4 sub |/cmykclut bit4x 4 add string |/cclut cmykclut |/mclut cclut + +1 bit4x defsubclut/yclut cclut 2 bit4x defsubclut/kclut cclut 3 bit4x + +defsubclut/cmykindex 0 | 0 1 bit1x{@/cmykindex ~ bit1x ~ sub 4 mul | 3 mul @ + +rclut ~ get 255 V ~ @ gclut ~ get 255 V ~ bclut ~ get 255 V setrgbcolor + +currentcmykcolor ftoint kclut stuffclut ftoint yclut stuffclut ftoint mclut + +stuffclut ftoint cclut stuffclut}for}b/doclutimage{/rgbclut ~ | ! + +invalidcolortable?{computecmykclut}if/4compute cclut mclut yclut kclut + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @ @]cvx nullproc + +nullproc nullproc T 4 colorimage}b}e c 0 eq g{/a{3 mul 3 getinterval + +putinterval ~ 3 add ~ 3 copy}b/8lookup/a , |/4lookup{/byte 1 ^ | -4 bitshift a + +byte 15 and a}b/2lookup{/byte 1 ^ | -6 bitshift a byte -4 bitshift 3 and a + +byte -2 bitshift 3 and a byte 3 and a}b/colorexpand{mystringexp 0 rgbclut 3 + +copy 7 -1 $/mylookup , forall ! ! ! ! !}b/createexpandstr{/mystringexp ~ + +mystring length mul string |}b/doclutimage{/rgbclut ~ | !/mylookup bpc 8 eq{3 + +createexpandstr/8lookup}{bpc 4 eq{6 createexpandstr/4lookup}{12 + +createexpandstr/2lookup}?}? , | iw ih bpc[iw 0 0 ih 0 0][s/exec ,/colorexpand + +,/exec ,]cvx F 3 colorimage}b}e/colorimage where{! T}{F}? g{/do24image{iw ih 8 + +[iw 0 0 ih 0 0]s F 3 colorimage}b}DefIf_El{/rgbtogray{/str ~ |/len str length + +|/smlen len 3 idiv |/rstr str |/gstr str 1 len 1 sub getinterval |/bstr str 2 + +len 2 sub getinterval | str @ 0 1 smlen 1 sub{@ 3 mul rstr 1 ^ get 0.3 mul + +gstr 2 ^ get 0.59 mul add bstr 3 -1 $ get 0.11 mul add round cvi put @}for ! 0 + +smlen getinterval}b/do24image{iw ih 8[iw 0 0 ih 0 0][s/exec ,/rgbtogray ,/exec + +,]cvx bind image}b}e/doNimage{bpc 24 eq{do24image}{iw ih bpc[iw 0 0 ih 0 0]s + +image}?}b}e + + + +L2? g{/doclutimage{/rgbclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[ + +/Indexed colspABC hival rgbclut]setcolorspace myimagedict @ `/Width iw | + +/Height ih |/Decode[0 hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s | + +/BitsPerComponent bpc |/Interpolate smoothflag | E image}b/doCMYKclutimage{ + +/CMYKclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[/Indexed/DeviceCMYK + +hival CMYKclut]setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 + +hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent bpc | + +/Interpolate smoothflag | E image}b/doNimage{bpc 24 eq{colspABC}{colspA}? + +setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode bpc 24 eq{[0 1 0 1 + +0 1]}{[0 1]}? |/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent + +bpc 24 eq{8}{bpc}? |/Interpolate smoothflag | E image}b/doCMYKimage{ + +/DeviceCMYK setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 1 0 + +1 0 1 0 1]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent 8 | + +/Interpolate smoothflag | E image}b}e + + + +/GreNewFont{10 dict @ 3 1 $ | @ ` 4 1 $/FontType 3 |/FontMatrix ~ |/FontBBox ~ + +|/Encoding 256 array | 0 1 255{Encoding ~/.notdef put}for/CharProcs 257 dict | + +CharProcs/.notdef{}put/Metrics 257 dict | Metrics/.notdef 3 -1 $ put/BuildChar + +{/char ~ |/fontdict ~ |/charname fontdict/Encoding get char get | fontdict + +/Metrics get charname get aload ! setcachedevice fontdict ` Encoding char get + +CharProcs ~ get E exec}| E definefont !}|/AddChar{` Encoding 3 1 $ put + +CharProcs 3 1 $ put Metrics 3 1 $ put E}| + + + +/FEbuf 2 string |/FEglyph 3 string |/FE{(G00)FEglyph copy ! 1 ~{@ 16 lt{ + +/offset 2 store}{/offset 1 store}? @ 16 FEbuf cvrs FEglyph ~ offset ~ + +putinterval 1 ^ ~ FEglyph cvn put}for}bind |/Type1Hdr{11 dict `/FontName ~ | + +/PaintType ~ |/FontType 1 |/FontMatrix[1 3 ^ V 0 0 1 6 ^ V 0 0]| !/Encoding + +256 array 0 1 255{1 ^ ~/.notdef put}for 3 ^ 3 ^ FE | ! !/FontBBox{0 0 0 0}| & + +E currentfile eexec}bind | + + +/pp 1 string |/ss 1 string |/rledecodebinary{/DC 0 |/BC 0 |{DC mystring length + +ge{exit}if currentfile ss readstring ! 0 get/BC ~ | BC 127 le{/BC BC 1 add | + +DC 1 DC BC add 1 sub{mystring ~ currentfile ss readstring ! 0 get put}for}{/BC + +257 BC sub | currentfile ss readstring ! 0 get/pp ~ | DC 1 DC BC add 1 sub{ + +mystring ~ pp put}for}?/DC DC BC add |}loop mystring}b/rledecodeascii{/DC 0 | + +/BC 0 |{DC mystring length ge{exit}if currentfile ss readhexstring ! 0 get/BC + +~ | BC 127 le{/BC BC 1 add | DC 1 DC BC add 1 sub{mystring ~ currentfile ss + +readhexstring ! 0 get put}for}{/BC 257 BC sub | currentfile ss readhexstring ! + +0 get/pp ~ | DC 1 DC BC add 1 sub{mystring ~ pp put}for}?/DC DC BC add |}loop + +mystring}b/setup1asciidecodeproc{[/rledecodeascii cvx]cvx bind}b + +/setup1binarydecodeproc{[/rledecodebinary cvx]cvx bind}b + + +userdict/Pscript_Win_Compat 13 dict dup begin/bd{bind def}bind def/ld{load def + +}bd/CB{pop pop pop pop}bind def/B{pop pop pop pop}bind def/$x matrix def/SS{ + +/pagesave save def}bind def/RS{/pagesave where{pop pagesave restore}{$x matrix + +invertmatrix concat}ifelse}bind def/ANSIVec[0/grave 1/acute 2/circumflex 3 + +/tilde 4/macron 5/breve 6/dotaccent 7/dieresis 8/ring 9/cedilla 10 + +/hungarumlaut 11/ogonek 12/caron 13/dotlessi 39/quotesingle 96/grave 124/bar + +130/quotesinglbase 131/florin 132/quotedblbase 133/ellipsis 134/dagger 135 + +/daggerdbl 136/circumflex 137/perthousand 138/Scaron 139/guilsinglleft 140/OE + +145/quoteleft 146/quoteright 147/quotedblleft 148/quotedblright 149/bullet 150 + +/endash 151/emdash 152/tilde 153/trademark 154/scaron 155/guilsinglright 156 + +/oe 159/Ydieresis 160/space 161/exclamdown 164/currency 165/yen 166/brokenbar + +167/section 168/dieresis 169/copyright 170/ordfeminine 171/guillemotleft 172 + +/logicalnot 173/hyphen 174/registered 175/macron 176/degree 177/plusminus 178 + +/twosuperior 179/threesuperior 180/acute 181/mu 182/paragraph 183 + +/periodcentered 184/cedilla 185/onesuperior 186/ordmasculine 187 + +/guillemotright 188/onequarter 189/onehalf 190/threequarters 191/questiondown + +192/Agrave 193/Aacute 194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198 + +/AE 199/Ccedilla 200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204 + +/Igrave 205/Iacute 206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve + +211/Oacute 212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash + +217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn 223 + +/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde 228/adieresis 229 + +/aring 230/ae 231/ccedilla 232/egrave 233/eacute 234/ecircumflex 235/edieresis + +236/igrave 237/iacute 238/icircumflex 239/idieresis 240/eth 241/ntilde 242 + +/ograve 243/oacute 244/ocircumflex 245/otilde 246/odieresis 247/divide 248 + +/oslash 249/ugrave 250/uacute 251/ucircumflex 252/udieresis 253/yacute 254 + +/thorn 255/ydieresis]def currentdict{dup type/operatortype eq{[exch]cvx def}{ + +pop pop}ifelse}forall/initialize{currentdict exch begin begin}bind def + +/terminate{/@FL where not{pop end end}{pop}ifelse}bind def/suspend/terminate + +load def/resume/initialize load def/M/moveto load def end put/Courier findfont + +10 scalefont setfont + + +end /ProcSet defineresource pop + + + + + + +Pscript_Win_Compat dup /initialize get exec + +[ 0 1.000 -1.000 0 0 0 ] false /Pscript_Win_Driver /ProcSet findresource dup /initialize get exec + + + + + +/mysetup [ 0.240 0 0 -0.240 8.880 592.800 ] | + + + + + + +userdict begin /pagesave save def end mysetup concat colspRefresh : 1.000 1.000 1.000 sco 0 0 2550 3300 rf ; + + + + + + +114 70 N M 1 1 rr + +114 70 N M 3000 2250 rr : 1.000 1.000 1.000 sco O ; + +114 70 N M 1 1 rr + +114 70 N M 1 1 rr : 114 70 3000 2250 rc + +114 70 N M 2726 1801 rr : 0.800 1.000 0.800 sco O ; 3 Lw 0 Lc 0 Lj solid 0.800 1.000 0.800 sco K ; + +1901 491 N M -7 1 - -7 0 - -18 0 - -19 1 - -21 1 - -20 2 - -18 4 - -9 3 - -7 4 - -6 5 - -5 5 - -4 6 - -3 8 - -2 9 - -2 9 - -2 22 - 0 23 - 2 23 - 2 23 - 4 20 - 3 9 - 2 8 - 6 14 - 8 14 - 10 11 - 10 11 - 12 10 - 12 8 - 12 7 - 12 5 - 13 5 - 14 3 - 15 2 - 15 1 - 14 -1 - 15 -2 - 13 -3 - 11 -5 - 9 -7 - 8 -9 - 7 -11 - 6 -13 - 6 -12 - 6 -11 - 6 -10 - 6 -7 - 7 -4 - 5 -1 - 5 -1 - 6 1 - 6 2 - 7 1 - 8 1 - 11 1 - 13 0 - 16 -1 - 18 -1 - 18 -1 - 19 -1 - 19 0 - 18 1 - 16 3 - 8 2 - 7 3 - 16 9 - 14 11 - 15 10 - 13 10 - 13 7 - 6 3 - 6 1 - 6 0 - 5 -2 - 5 -3 - 5 -5 - 5 -6 - 5 -8 - 9 -17 - 9 -20 - 7 -20 - 5 -21 - 4 -18 - 1 -9 - 0 -7 - -1 -12 - -3 -11 - -5 -11 - -6 -9 - -9 -9 - -9 -9 - -10 -9 - -12 -10 - -13 -11 - -14 -11 - -16 -12 - -17 -12 - -18 -12 - -19 -9 - -20 -8 - -20 -5 - -11 -1 - -11 -1 - -26 1 - -27 3 - -27 5 - -27 5 - -25 6 - -11 2 - -10 3 - -8 2 - -8 2 - -6 2 - -5 2 - -4 1 - -3 2 - -3 4 - -1 4 - 0 4 - 0 3 - -2 3 - -3 2 - -5 1 - -5 0 - -11 -1 - -6 -1 - -8 -1 - -9 1 - -11 1 - C : 0.502 0.502 0.502 sco O ; + +1893 482 N M -7 1 - -7 0 - -18 1 - -19 1 - -21 1 - -20 2 - -18 4 - -9 3 - -7 4 - -6 5 - -5 5 - -4 6 - -3 8 - -3 9 - -2 9 - -2 22 - 0 23 - 2 23 - 3 23 - 4 20 - 2 9 - 3 8 - 6 14 - 8 14 - 10 11 - 10 11 - 12 10 - 12 8 - 12 7 - 12 5 - 13 4 - 14 3 - 14 2 - 15 1 - 15 -1 - 14 -2 - 13 -3 - 11 -4 - 10 -7 - 8 -9 - 7 -12 - 6 -12 - 6 -12 - 6 -12 - 6 -9 - 6 -7 - 6 -4 - 6 -1 - 5 -1 - 5 1 - 6 2 - 7 1 - 9 1 - 11 1 - 13 0 - 16 -1 - 17 -1 - 19 -1 - 18 -1 - 19 0 - 18 1 - 16 3 - 8 2 - 7 3 - 16 9 - 14 10 - 15 11 - 14 10 - 13 7 - 6 2 - 6 1 - 6 0 - 5 -2 - 5 -3 - 5 -5 - 5 -6 - 5 -7 - 9 -18 - 8 -19 - 7 -21 - 5 -20 - 4 -19 - 1 -8 - 0 -7 - -1 -13 - -3 -11 - -5 -10 - -6 -9 - -8 -9 - -9 -9 - -11 -9 - -11 -10 - -13 -11 - -14 -12 - -16 -12 - -17 -12 - -18 -11 - -19 -9 - -20 -8 - -20 -5 - -11 -1 - -11 -1 - -26 1 - -27 3 - -28 5 - -26 5 - -25 6 - -11 2 - -10 3 - -8 2 - -8 2 - -6 2 - -5 1 - -4 2 - -3 2 - -3 4 - -2 4 - 0 3 - 0 3 - -1 3 - -4 2 - -5 1 - -4 1 - -11 -2 - -6 0 - -8 -1 - -9 0 - -11 1 - C : 0.200 0.200 0.800 sco O ; + +2010 855 N M 62 -99 - 12 Lw 0 Lc 1 Lj solid 0 0.800 0.600 sco K + +2095 773 N M 5 -63 - -53 33 - 48 30 - C : 0 0.800 0.600 sco O ; + +1805 921 N M -11 1 - -14 1 - -15 0 - -16 1 - -16 2 - -14 4 - -12 5 - -4 4 - -4 4 - -3 5 - -3 6 - -3 15 - -2 17 - 0 18 - 1 19 - 3 18 - 3 16 - 4 14 - 5 12 - 6 10 - 7 9 - 8 9 - 18 14 - 19 10 - 10 4 - 11 2 - 11 2 - 12 0 - 12 0 - 10 -2 - 10 -2 - 9 -4 - 7 -5 - 6 -8 - 6 -9 - 5 -10 - 4 -10 - 5 -9 - 4 -8 - 5 -5 - 5 -3 - 4 -2 - 4 0 - 4 1 - 5 1 - 6 1 - 7 2 - 8 0 - 10 0 - 12 -1 - 14 -1 - 14 -1 - 29 0 - 14 1 - 13 2 - 12 4 - 11 7 - 12 8 - 11 9 - 10 7 - 10 6 - 5 2 - 5 1 - 4 -1 - 4 -1 - 4 -2 - 4 -4 - 4 -5 - 4 -6 - 7 -14 - 6 -15 - 6 -17 - 4 -16 - 3 -15 - 1 -12 - -1 -10 - -2 -9 - -4 -8 - -5 -8 - -6 -7 - -8 -7 - -17 -15 - -10 -9 - -11 -9 - -12 -10 - -13 -10 - -14 -8 - -15 -8 - -15 -6 - -16 -4 - -17 -1 - -20 0 - -21 3 - -21 3 - -21 4 - -19 5 - -16 4 - -7 2 - -6 1 - -5 1 - -3 2 - -6 3 - -2 3 - -1 3 - 0 5 - -1 3 - -3 1 - -4 1 - -4 0 - -8 -1 - -5 0 - -6 -1 - -7 0 - -8 1 - C : 0.502 0.502 0.502 sco O ; + +1796 913 N M -11 1 - -13 0 - -15 1 - -16 1 - -16 1 - -14 4 - -12 5 - -5 4 - -4 4 - -3 5 - -2 6 - -4 15 - -1 17 - 0 18 - 1 19 - 2 18 - 3 16 - 4 14 - 5 12 - 6 10 - 8 10 - 8 8 - 9 8 - 9 7 - 10 5 - 9 5 - 10 3 - 11 3 - 23 2 - 22 -2 - 10 -3 - 9 -3 - 7 -5 - 6 -8 - 6 -9 - 5 -10 - 4 -10 - 5 -10 - 4 -7 - 5 -6 - 5 -3 - 4 -1 - 4 0 - 4 0 - 5 1 - 5 2 - 7 1 - 8 0 - 10 0 - 13 -1 - 13 -1 - 14 -1 - 29 0 - 14 1 - 13 2 - 12 5 - 12 7 - 11 8 - 12 9 - 10 7 - 10 6 - 5 2 - 5 1 - 4 -1 - 4 -1 - 4 -3 - 4 -4 - 4 -4 - 3 -6 - 8 -14 - 6 -16 - 5 -16 - 4 -17 - 3 -14 - 1 -13 - -1 -10 - -2 -9 - -4 -8 - -5 -7 - -6 -7 - -7 -8 - -17 -15 - -10 -8 - -11 -10 - -12 -10 - -14 -9 - -14 -9 - -14 -8 - -15 -6 - -16 -4 - -17 -1 - -20 1 - -21 2 - -21 4 - -21 4 - -19 5 - -16 4 - -7 2 - -6 1 - -5 1 - -3 2 - -6 3 - -2 3 - -1 3 - 0 5 - -1 2 - -3 2 - -4 1 - -4 0 - -8 -1 - -5 -1 - -6 0 - -7 0 - -9 1 - C : 0.200 0.200 0.800 sco O ; + +1826 1255 N M 67 -96 - 0 0.800 0.600 sco K + +1915 1178 N M 8 -63 - -55 30 - 47 33 - C : 0 0.800 0.600 sco O ; + +1663 1307 N M -7 1 - -10 0 - -10 1 - -10 0 - -11 2 - -9 2 - -8 4 - -6 5 - -3 7 - -3 10 - -1 11 - 0 13 - 1 12 - 2 12 - 2 11 - 2 9 - 3 8 - 4 7 - 11 12 - 12 9 - 13 7 - 14 4 - 15 1 - 15 -1 - 6 -2 - 6 -2 - 5 -4 - 4 -5 - 4 -6 - 3 -6 - 3 -7 - 3 -6 - 3 -5 - 3 -4 - 3 -2 - 3 -1 - 6 0 - 6 2 - 5 1 - 5 0 - 7 0 - 8 -1 - 19 -1 - 19 0 - 10 1 - 8 1 - 8 3 - 8 5 - 15 11 - 7 5 - 6 4 - 6 2 - 6 -1 - 5 -5 - 5 -7 - 5 -9 - 5 -11 - 4 -11 - 2 -11 - 2 -10 - 1 -8 - -1 -7 - -1 -6 - -6 -10 - -9 -9 - -12 -10 - -14 -12 - -16 -13 - -10 -6 - -9 -5 - -11 -4 - -10 -3 - -11 -1 - -14 0 - -14 2 - -14 2 - -14 3 - -12 3 - -11 3 - -9 2 - -6 2 - -3 2 - -2 2 - 0 2 - 0 4 - -1 1 - -2 1 - -5 1 - -6 -1 - -7 0 - -4 0 - -6 0 - C : 0.502 0.502 0.502 sco O ; + +1655 1299 N M -7 1 - -10 0 - -10 0 - -10 1 - -11 1 - -9 2 - -8 4 - -6 5 - -4 8 - -2 10 - -1 11 - 0 12 - 1 13 - 1 12 - 3 11 - 2 9 - 3 8 - 4 6 - 11 12 - 12 10 - 12 7 - 14 4 - 16 1 - 15 -1 - 6 -2 - 6 -2 - 5 -4 - 4 -5 - 7 -13 - 3 -6 - 3 -6 - 3 -5 - 3 -4 - 3 -2 - 3 -1 - 5 0 - 7 2 - 5 1 - 5 0 - 7 0 - 8 -1 - 19 -1 - 19 0 - 18 2 - 8 3 - 8 5 - 15 11 - 7 5 - 6 3 - 6 2 - 6 -1 - 5 -4 - 5 -7 - 5 -9 - 4 -11 - 7 -22 - 1 -10 - 1 -8 - -1 -7 - -1 -6 - -6 -10 - -9 -10 - -11 -10 - -14 -12 - -16 -13 - -10 -6 - -9 -5 - -11 -4 - -10 -2 - -12 -1 - -13 0 - -14 2 - -14 2 - -14 3 - -13 3 - -10 3 - -9 2 - -6 2 - -3 2 - -2 2 - 0 2 - 0 4 - -1 1 - -2 1 - -5 1 - -6 -1 - -7 -1 - -4 1 - -6 0 - C : 0.200 0.200 0.800 sco O ; + +1611 1566 N M 85 -81 - 0 0.800 0.600 sco K + +1714 1508 N M 21 -59 - -60 18 - 39 41 - C : 0 0.800 0.600 sco O ; + +1410 1556 N M -4 1 - -6 0 - -13 1 - -12 2 - -5 2 - -4 3 - -2 5 - -1 6 - -1 15 - 1 15 - 2 7 - 1 6 - 5 9 - 6 7 - 8 6 - 8 4 - 8 3 - 10 1 - 9 -1 - 8 -3 - 3 -2 - 3 -3 - 4 -8 - 4 -8 - 2 -3 - 2 -2 - 3 -2 - 4 0 - 4 1 - 6 1 - 10 0 - 11 -1 - 12 0 - 11 1 - 5 2 - 5 3 - 10 7 - 4 3 - 5 2 - 3 1 - 4 -1 - 3 -3 - 3 -4 - 3 -5 - 3 -7 - 4 -14 - 1 -6 - 0 -5 - -1 -8 - -4 -7 - -5 -6 - -7 -6 - -9 -7 - -11 -8 - -11 -7 - -7 -2 - -6 -2 - -7 -1 - -9 1 - -17 2 - -9 2 - -8 2 - -7 1 - -5 1 - -4 1 - -2 2 - -1 1 - 0 1 - -1 3 - -1 1 - -3 1 - -3 -1 - -5 0 - -7 0 - C : 0.502 0.502 0.502 sco O ; + +1402 1548 N M -4 1 - -6 0 - -13 1 - -7 0 - -6 2 - -4 2 - -4 3 - -2 5 - -2 6 - -1 7 - 0 7 - 2 16 - 1 6 - 2 6 - 4 9 - 7 8 - 7 6 - 8 4 - 9 2 - 10 1 - 9 -1 - 8 -2 - 3 -2 - 2 -4 - 4 -7 - 4 -8 - 2 -4 - 2 -2 - 4 -2 - 4 1 - 4 0 - 6 1 - 4 0 - 5 0 - 12 -1 - 12 0 - 11 1 - 5 2 - 5 3 - 9 7 - 5 3 - 4 2 - 4 2 - 3 -1 - 3 -3 - 4 -4 - 3 -6 - 2 -6 - 4 -14 - 2 -6 - 0 -5 - -1 -8 - -4 -7 - -6 -6 - -7 -6 - -9 -8 - -10 -8 - -12 -7 - -6 -2 - -7 -2 - -7 -1 - -8 1 - -18 2 - -9 2 - -8 2 - -7 2 - -5 1 - -3 1 - -2 2 - -1 1 - -1 1 - 0 3 - -1 1 - -3 1 - -4 -1 - -5 0 - -6 0 - C : 0.200 0.200 0.800 sco O ; + +1190 1427 N M 83 83 - 0 0.800 0.600 sco K + +1250 1528 N M 60 20 - -19 -60 - -41 40 - C : 0 0.800 0.600 sco O ; + +693 492 N M -7 1 - -7 0 - -18 1 - -19 1 - -21 1 - -20 2 - -18 4 - -8 3 - -7 4 - -6 5 - -5 5 - -4 7 - -3 8 - -3 9 - -2 9 - -2 22 - 0 24 - 2 24 - 3 23 - 4 21 - 2 9 - 3 8 - 6 15 - 8 13 - 9 13 - 11 11 - 11 9 - 13 9 - 12 6 - 12 6 - 13 5 - 13 3 - 15 2 - 15 1 - 15 -1 - 14 -2 - 13 -3 - 11 -5 - 9 -7 - 8 -9 - 7 -12 - 7 -13 - 5 -12 - 6 -12 - 6 -10 - 7 -7 - 6 -4 - 6 -1 - 5 -1 - 5 1 - 6 2 - 7 1 - 8 1 - 11 1 - 13 0 - 16 -1 - 18 -1 - 18 -1 - 19 -1 - 19 0 - 18 1 - 16 3 - 8 2 - 7 4 - 16 8 - 14 11 - 15 11 - 13 10 - 7 4 - 6 4 - 6 2 - 6 1 - 6 0 - 5 -2 - 5 -3 - 5 -5 - 5 -7 - 5 -7 - 9 -18 - 9 -20 - 7 -21 - 5 -21 - 4 -19 - 1 -8 - 0 -8 - -1 -13 - -3 -11 - -5 -10 - -6 -10 - -9 -9 - -9 -9 - -10 -10 - -12 -10 - -13 -11 - -14 -12 - -16 -12 - -17 -12 - -18 -12 - -19 -10 - -20 -8 - -20 -5 - -11 -1 - -11 -1 - -25 1 - -27 4 - -28 4 - -27 6 - -24 6 - -11 2 - -10 3 - -9 2 - -8 2 - -6 2 - -5 2 - -4 2 - -2 1 - -4 4 - -1 4 - 0 4 - 0 3 - -1 3 - -4 2 - -5 1 - -5 1 - -11 -2 - -6 0 - -8 -1 - -9 0 - -11 1 - C : 0.502 0.502 0.502 sco O ; + +685 484 N M -7 1 - -7 0 - -18 0 - -19 1 - -21 1 - -20 2 - -18 5 - -9 3 - -7 4 - -6 4 - -5 6 - -4 7 - -3 8 - -3 9 - -1 9 - -3 22 - 1 24 - 1 24 - 3 23 - 4 21 - 3 9 - 2 8 - 6 15 - 8 13 - 10 12 - 10 11 - 12 10 - 12 8 - 12 7 - 12 6 - 13 5 - 14 3 - 15 2 - 15 1 - 14 -1 - 15 -2 - 13 -3 - 11 -5 - 9 -7 - 8 -10 - 7 -11 - 6 -13 - 6 -13 - 6 -11 - 6 -10 - 6 -7 - 6 -4 - 6 -2 - 5 0 - 5 1 - 6 1 - 7 2 - 9 1 - 11 1 - 13 0 - 16 -1 - 17 -1 - 19 -1 - 18 -1 - 19 0 - 18 1 - 16 3 - 8 2 - 7 4 - 16 8 - 14 11 - 15 11 - 14 10 - 13 7 - 6 3 - 6 1 - 6 0 - 5 -2 - 5 -3 - 5 -5 - 5 -7 - 5 -7 - 9 -18 - 8 -20 - 7 -21 - 5 -21 - 4 -19 - 1 -9 - 0 -7 - -1 -13 - -3 -11 - -5 -11 - -6 -9 - -8 -10 - -9 -9 - -10 -9 - -12 -10 - -13 -11 - -14 -12 - -16 -12 - -17 -13 - -18 -11 - -19 -10 - -20 -8 - -20 -5 - -11 -1 - -11 -1 - -26 1 - -27 3 - -28 5 - -26 5 - -25 6 - -11 2 - -10 3 - -8 2 - -8 2 - -6 2 - -5 2 - -4 2 - -3 2 - -3 4 - -1 4 - 0 4 - 0 3 - -2 3 - -3 2 - -5 1 - -5 0 - -11 -1 - -6 -1 - -8 -1 - -9 1 - -11 1 - C : 0.200 0.200 0.800 sco O ; + +873 919 N M -10 1 - -13 0 - -15 0 - -15 1 - -15 2 - -13 3 - -12 5 - -4 4 - -4 4 - -3 5 - -2 6 - -4 14 - -1 16 - 0 17 - 1 18 - 2 17 - 3 16 - 4 13 - 5 11 - 5 10 - 7 9 - 8 8 - 18 13 - 18 9 - 10 3 - 10 3 - 22 2 - 21 -2 - 10 -3 - 8 -3 - 7 -5 - 6 -7 - 5 -9 - 5 -9 - 4 -9 - 5 -9 - 4 -7 - 5 -5 - 4 -3 - 4 -2 - 4 0 - 4 1 - 4 1 - 5 1 - 7 2 - 8 0 - 10 0 - 12 -1 - 13 -1 - 13 -1 - 28 0 - 13 1 - 12 2 - 12 4 - 11 6 - 11 8 - 11 8 - 10 7 - 10 6 - 9 2 - 4 0 - 4 -1 - 4 -2 - 3 -4 - 8 -10 - 6 -13 - 7 -15 - 5 -16 - 4 -15 - 2 -14 - 1 -12 - -1 -10 - -2 -8 - -4 -8 - -4 -7 - -6 -7 - -7 -7 - -16 -14 - -10 -8 - -10 -9 - -12 -9 - -13 -9 - -13 -9 - -14 -7 - -15 -6 - -15 -4 - -16 -1 - -19 1 - -20 2 - -21 4 - -20 4 - -18 4 - -16 4 - -6 2 - -6 1 - -5 1 - -3 1 - -5 3 - -3 3 - 0 3 - 0 5 - -1 2 - -3 2 - -7 1 - -8 -1 - -5 -1 - -6 0 - -7 0 - -8 1 - C : 0.502 0.502 0.502 sco O ; + +865 910 N M -11 1 - -12 1 - -15 0 - -15 1 - -15 2 - -13 3 - -12 5 - -4 4 - -4 4 - -3 5 - -2 6 - -4 13 - -1 17 - 0 17 - 1 18 - 2 17 - 3 15 - 4 13 - 5 11 - 5 10 - 7 9 - 8 8 - 18 14 - 18 9 - 9 3 - 10 3 - 22 2 - 22 -2 - 9 -3 - 9 -3 - 7 -5 - 6 -7 - 5 -9 - 5 -9 - 4 -10 - 4 -9 - 4 -7 - 5 -5 - 5 -3 - 4 -1 - 4 0 - 4 0 - 4 1 - 5 2 - 7 1 - 8 0 - 10 0 - 11 -1 - 13 -1 - 14 -1 - 28 0 - 13 1 - 12 2 - 12 4 - 11 7 - 11 8 - 11 8 - 10 7 - 9 6 - 9 2 - 4 0 - 4 -1 - 4 -2 - 4 -4 - 4 -5 - 3 -5 - 7 -14 - 6 -15 - 6 -15 - 4 -16 - 2 -14 - 1 -12 - -1 -9 - -2 -9 - -4 -8 - -4 -7 - -6 -6 - -7 -7 - -17 -14 - -9 -8 - -11 -9 - -11 -10 - -13 -9 - -13 -8 - -15 -7 - -14 -6 - -15 -4 - -17 -1 - -19 0 - -20 2 - -20 4 - -20 4 - -18 4 - -16 4 - -6 2 - -6 1 - -5 1 - -3 2 - -5 3 - -3 3 - 0 3 - 0 5 - -1 2 - -3 1 - -4 1 - -3 0 - -8 -1 - -5 0 - -6 -1 - -7 0 - -8 1 - C : 0.200 0.200 0.800 sco O ; + +828 722 N M 72 115 - 0 0.800 0.600 sco K + +874 851 N M 54 32 - -6 -62 - -48 30 - C : 0 0.800 0.600 sco O ; + +1099 1307 N M -7 1 - -9 0 - -10 0 - -10 1 - -11 1 - -9 2 - -8 4 - -6 5 - -4 8 - -2 9 - -1 12 - 0 12 - 1 12 - 1 12 - 3 11 - 2 9 - 3 8 - 4 6 - 11 12 - 12 9 - 12 7 - 14 4 - 15 1 - 15 -1 - 13 -4 - 5 -3 - 4 -5 - 7 -13 - 5 -12 - 4 -5 - 3 -4 - 3 -2 - 3 -1 - 5 0 - 7 2 - 4 1 - 6 0 - 7 0 - 8 -1 - 18 -1 - 19 0 - 10 1 - 8 1 - 8 3 - 8 4 - 8 5 - 8 6 - 7 5 - 6 4 - 6 2 - 6 -1 - 5 -4 - 5 -7 - 5 -9 - 4 -11 - 7 -22 - 1 -10 - 1 -8 - -1 -6 - -1 -6 - -6 -10 - -9 -10 - -11 -10 - -14 -12 - -17 -12 - -9 -6 - -10 -5 - -10 -4 - -11 -3 - -11 -1 - -14 0 - -14 2 - -14 2 - -13 3 - -13 3 - -11 3 - -8 2 - -6 2 - -3 2 - -2 2 - 0 2 - 0 4 - -1 1 - -2 1 - -5 1 - -6 -1 - -7 -1 - -5 1 - -6 0 - C : 0.502 0.502 0.502 sco O ; + +1091 1299 N M -7 1 - -9 0 - -10 0 - -11 0 - -10 2 - -10 2 - -7 4 - -6 5 - -4 7 - -2 10 - -1 11 - 0 12 - 0 12 - 2 12 - 2 11 - 3 9 - 3 8 - 4 6 - 10 12 - 12 10 - 13 7 - 14 4 - 15 1 - 15 -1 - 6 -2 - 6 -2 - 5 -4 - 4 -5 - 7 -13 - 3 -6 - 3 -6 - 3 -5 - 3 -4 - 3 -2 - 3 -1 - 6 0 - 7 2 - 4 1 - 6 0 - 7 0 - 8 -1 - 18 0 - 19 -1 - 10 1 - 8 1 - 8 3 - 8 5 - 15 11 - 7 5 - 6 3 - 6 2 - 6 -1 - 6 -4 - 5 -7 - 5 -9 - 4 -10 - 4 -11 - 3 -11 - 1 -10 - 1 -8 - -1 -7 - -1 -6 - -6 -10 - -9 -9 - -12 -10 - -14 -12 - -16 -13 - -10 -6 - -9 -5 - -11 -4 - -10 -2 - -11 -1 - -14 0 - -14 2 - -14 2 - -14 3 - -12 3 - -11 3 - -9 2 - -5 2 - -4 1 - -1 2 - -1 2 - 0 4 - -1 2 - -2 1 - -5 0 - -6 0 - -7 -1 - -4 0 - -6 1 - C : 0.200 0.200 0.800 sco O ; + +988 1085 N M 73 116 - 0 0.800 0.600 sco K + +1034 1214 N M 55 32 - -7 -62 - -48 30 - C : 0 0.800 0.600 sco O ; : 114 70 3000 2250 rc 0 0.400 0 sco %%IncludeFont: Helvetica-Bold + +(F0) cvn + +0.964 + + (Helvetica-Bold) cvn /Type1 + +T + +(Helvetica-Bold) cvn + +mF + +(F0_83) cvn + +F0 + +83 + +xF + +F0_83 + +Ji + +-302.300 545 825 sR + +0.074 0 (C)A + +0.287 0 (o)A + +0.852 0 (a)A + +-0.287 0 (r)A + +-0.148 0 (s)A + +0.852 0 (e)A + +0.287 0 (n)A + +-0.074 0 (i)A + +-0.361 0 32 0.287 0 (ng )D + +-0.361 0 (P)A + +1.287 0 (h)A + +-0.148 0 (as)A + +0.852 0 (e)A + +eR + +; + +948 1648 N M 1227 151 rr : 114 70 3000 2250 rc 0 0.400 0 sco (F0_100) cvn + +F0 + +100 + +xF + +F0_100 + +Ji + +979 1664 M + +0.200 0 (I)A + +-0.100 0 (n)A + +-0.800 0 (i)A + +-0.300 0 (t)A + +0.200 0 (i)A + +0.400 0 (a)A + +1.000 0 32 -0.800 0 (l )D + +0.300 0 (P)A + +-0.600 0 (a)A + +0.100 0 (r)A + +0.700 0 (t)A + +-0.800 0 (i)A + +0.700 0 (t)A + +-0.800 0 (i)A + +-0.100 0 (on)A + +0.200 0 (i)A + +-0.700 0 32 -0.100 0 (ng )D + +0.300 0 (P)A + +-0.100 0 (h)A + +0.400 0 (a)A + +-0.600 0 (s)A + +0.400 0 (e)A + +; : 114 70 3000 2250 rc 0 0.400 0 sco F0_100 + +Ji + +-60.400 2049 1326 sR + +-0.200 0 (R)A + +0.400 0 (e)A + +-0.300 0 (f)A + +0.200 0 (i)A + +-0.100 0 (n)A + +0.400 0 (e)A + +0.100 0 (m)A + +-0.600 0 (e)A + +-0.100 0 (n)A + +-1.500 0 32 0.700 0 (t )D + +0.300 0 (P)A + +-0.100 0 (h)A + +0.400 0 (a)A + +-0.600 0 (s)A + +0.400 0 (e)A + +eR + +; + +N 1425 1541.500 M 3 1 rr : 1.000 0 0 sco O ; + +N 1423 1542.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1422 1543.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1423 1544.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1424 1545.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1425 1546.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1426 1547.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1427 1548.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1428 1549.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1429 1550.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1430 1551.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1431 1552.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1433 1553.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1434 1554.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1435 1555.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1436 1556.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1437 1557.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1438 1558.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1439 1559.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1441 1560.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1442 1561.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1443 1562.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1444 1563.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1445 1564.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1446 1565.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1447 1566.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1448 1567.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1449 1568.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1449 1569.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1450 1570.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1450 1571.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1450 1572.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1450 1573.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1450 1574.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1450 1575.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1449 1576.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1449 1577.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1449 1578.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1449 1579.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1449 1580.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1448 1581.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1448 1582.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1448 1583.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1448 1584.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1448 1585.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1448 1586.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1449 1587.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1450 1588.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1449 1589.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1450 1590.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1451 1591.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1451 1592.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1452 1593.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1453 1594.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1453 1595.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1454 1596.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1455 1597.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1456 1598.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1457 1599.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1458 1600.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1459 1601.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1460 1602.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1461 1603.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1462 1604.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1464 1605.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1465 1606.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1466 1607.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1467 1608.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1469 1609.500 M 3 1 rr : 1.000 0 0 sco O ; + +N 1470 1610.500 M 2 1 rr : 1.000 0 0 sco O ; + +N 1690 1287.500 M 2 1 rr : 0 0 0 sco O ; + +N 1690 1288.500 M 3 1 rr : 0 0 0 sco O ; + +N 1689 1289.500 M 5 1 rr : 0 0 0 sco O ; + +N 1689 1290.500 M 6 1 rr : 0 0 0 sco O ; + +N 1688 1291.500 M 9 1 rr : 0 0 0 sco O ; + +N 1689 1292.500 M 9 1 rr : 0 0 0 sco O ; + +N 1690 1293.500 M 9 1 rr : 0 0 0 sco O ; + +N 1691 1294.500 M 10 1 rr : 0 0 0 sco O ; + +N 1692 1295.500 M 10 1 rr : 0 0 0 sco O ; + +N 1694 1296.500 M 9 1 rr : 0 0 0 sco O ; + +N 1695 1297.500 M 10 1 rr : 0 0 0 sco O ; + +N 1696 1298.500 M 10 1 rr : 0 0 0 sco O ; + +N 1698 1299.500 M 9 1 rr : 0 0 0 sco O ; + +N 1699 1300.500 M 9 1 rr : 0 0 0 sco O ; + +N 1700 1301.500 M 10 1 rr : 0 0 0 sco O ; + +N 1702 1302.500 M 9 1 rr : 0 0 0 sco O ; + +N 1703 1303.500 M 9 1 rr : 0 0 0 sco O ; + +N 1704 1304.500 M 9 1 rr : 0 0 0 sco O ; + +N 1705 1305.500 M 9 1 rr : 0 0 0 sco O ; + +N 1707 1306.500 M 8 1 rr : 0 0 0 sco O ; + +N 1708 1307.500 M 8 1 rr : 0 0 0 sco O ; + +N 1709 1308.500 M 8 1 rr : 0 0 0 sco O ; + +N 1710 1309.500 M 8 1 rr : 0 0 0 sco O ; + +N 1711 1310.500 M 8 1 rr : 0 0 0 sco O ; + +N 1712 1311.500 M 8 1 rr : 0 0 0 sco O ; + +N 1713 1312.500 M 8 1 rr : 0 0 0 sco O ; + +N 1714 1313.500 M 9 1 rr : 0 0 0 sco O ; + +N 1715 1314.500 M 9 1 rr : 0 0 0 sco O ; + +N 1716 1315.500 M 9 1 rr : 0 0 0 sco O ; + +N 1717 1316.500 M 9 1 rr : 0 0 0 sco O ; + +N 1718 1317.500 M 9 1 rr : 0 0 0 sco O ; + +N 1720 1318.500 M 8 1 rr : 0 0 0 sco O ; + +N 1721 1319.500 M 8 1 rr : 0 0 0 sco O ; + +N 1722 1320.500 M 8 1 rr : 0 0 0 sco O ; + +N 1723 1321.500 M 7 1 rr : 0 0 0 sco O ; + +N 1724 1322.500 M 7 1 rr : 0 0 0 sco O ; + +N 1725 1323.500 M 7 1 rr : 0 0 0 sco O ; + +N 1725 1324.500 M 8 1 rr : 0 0 0 sco O ; + +N 1726 1325.500 M 7 1 rr : 0 0 0 sco O ; + +N 1727 1326.500 M 7 1 rr : 0 0 0 sco O ; + +N 1728 1327.500 M 7 1 rr : 0 0 0 sco O ; + +N 1729 1328.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1329.500 M 7 1 rr : 0 0 0 sco O ; + +N 1730 1330.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1331.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1332.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1333.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1334.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1335.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1336.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1337.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1338.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1339.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1340.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1341.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1342.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1343.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1344.500 M 7 1 rr : 0 0 0 sco O ; + +N 1731 1345.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1346.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1347.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1348.500 M 6 1 rr : 0 0 0 sco O ; + +N 1731 1349.500 M 6 1 rr : 0 0 0 sco O ; + +N 1730 1350.500 M 7 1 rr : 0 0 0 sco O ; + +N 1730 1351.500 M 6 1 rr : 0 0 0 sco O ; + +N 1730 1352.500 M 6 1 rr : 0 0 0 sco O ; + +N 1730 1353.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1354.500 M 7 1 rr : 0 0 0 sco O ; + +N 1729 1355.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1356.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1357.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1358.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1359.500 M 6 1 rr : 0 0 0 sco O ; + +N 1729 1360.500 M 7 1 rr : 0 0 0 sco O ; + +N 1729 1361.500 M 7 1 rr : 0 0 0 sco O ; + +N 1730 1362.500 M 6 1 rr : 0 0 0 sco O ; + +N 1730 1363.500 M 7 1 rr : 0 0 0 sco O ; + +N 1731 1364.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1365.500 M 6 1 rr : 0 0 0 sco O ; + +N 1732 1366.500 M 6 1 rr : 0 0 0 sco O ; + +N 1733 1367.500 M 6 1 rr : 0 0 0 sco O ; + +N 1733 1368.500 M 7 1 rr : 0 0 0 sco O ; + +N 1733 1369.500 M 8 1 rr : 0 0 0 sco O ; + +N 1734 1370.500 M 8 1 rr : 0 0 0 sco O ; + +N 1735 1371.500 M 8 1 rr : 0 0 0 sco O ; + +N 1736 1372.500 M 8 1 rr : 0 0 0 sco O ; + +N 1737 1373.500 M 8 1 rr : 0 0 0 sco O ; + +N 1738 1374.500 M 9 1 rr : 0 0 0 sco O ; + +N 1739 1375.500 M 9 1 rr : 0 0 0 sco O ; + +N 1740 1376.500 M 9 1 rr : 0 0 0 sco O ; + +N 1741 1377.500 M 9 1 rr : 0 0 0 sco O ; + +N 1742 1378.500 M 9 1 rr : 0 0 0 sco O ; + +N 1744 1379.500 M 8 1 rr : 0 0 0 sco O ; + +N 1745 1380.500 M 8 1 rr : 0 0 0 sco O ; + +N 1746 1381.500 M 8 1 rr : 0 0 0 sco O ; + +N 1747 1382.500 M 8 1 rr : 0 0 0 sco O ; + +N 1748 1383.500 M 8 1 rr : 0 0 0 sco O ; + +N 1749 1384.500 M 8 1 rr : 0 0 0 sco O ; + +N 1750 1385.500 M 8 1 rr : 0 0 0 sco O ; + +N 1751 1386.500 M 8 1 rr : 0 0 0 sco O ; + +N 1752 1387.500 M 8 1 rr : 0 0 0 sco O ; + +N 1753 1388.500 M 8 1 rr : 0 0 0 sco O ; + +N 1754 1389.500 M 9 1 rr : 0 0 0 sco O ; + +N 1755 1390.500 M 9 1 rr : 0 0 0 sco O ; + +N 1756 1391.500 M 9 1 rr : 0 0 0 sco O ; + +N 1757 1392.500 M 9 1 rr : 0 0 0 sco O ; + +N 1758 1393.500 M 9 1 rr : 0 0 0 sco O ; + +N 1760 1394.500 M 6 1 rr : 0 0 0 sco O ; + +N 1761 1395.500 M 4 1 rr : 0 0 0 sco O ; + +N 1762 1396.500 M 2 1 rr : 0 0 0 sco O ; + +N 1726 1278.500 M 5 1 rr : 1.000 0 0 sco O ; + +N 1724 1279.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1725 1280.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1725 1281.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1726 1282.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1726 1283.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1727 1284.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1728 1285.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1729 1286.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1730 1287.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1730 1288.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1731 1289.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1732 1290.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1733 1291.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1733 1292.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1734 1293.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1735 1294.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1735 1295.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1736 1296.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1737 1297.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1737 1298.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1738 1299.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1738 1300.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1739 1301.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1739 1302.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1740 1303.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1740 1304.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1741 1305.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1741 1306.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1742 1307.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1742 1308.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1742 1309.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1743 1310.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1311.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1312.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1313.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1314.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1315.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1316.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1317.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1743 1318.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1742 1319.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1742 1320.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1742 1321.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1742 1322.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1741 1323.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1741 1324.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1740 1325.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1740 1326.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1738 1327.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1738 1328.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1737 1329.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1736 1330.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1736 1331.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1735 1332.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1734 1333.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1734 1334.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1733 1335.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1733 1336.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1732 1337.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1732 1338.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1731 1339.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1730 1340.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1730 1341.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1729 1342.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1729 1343.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1728 1344.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1728 1345.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1727 1346.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1726 1347.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1726 1348.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1725 1349.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1724 1350.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1724 1351.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1723 1352.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1722 1353.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1722 1354.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1721 1355.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1721 1356.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1720 1357.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1720 1358.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1719 1359.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1719 1360.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1719 1361.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1719 1362.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1363.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1364.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1365.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1366.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1367.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1368.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1369.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1370.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1371.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1372.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1718 1373.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1719 1374.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1719 1375.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1719 1376.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1720 1377.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1720 1378.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1721 1379.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1721 1380.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1722 1381.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1722 1382.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1723 1383.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1723 1384.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1724 1385.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1724 1386.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1725 1387.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1726 1388.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1726 1389.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1727 1390.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1728 1391.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1729 1392.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1729 1393.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1730 1394.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1731 1395.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1731 1396.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1731 1397.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1732 1398.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1732 1399.500 M 3 1 rr : 1.000 0 0 sco O ; + +N 1905 881.500 M 4 1 rr : 0 0 0 sco O ; + +N 1903 882.500 M 6 1 rr : 0 0 0 sco O ; + +N 1904 883.500 M 6 1 rr : 0 0 0 sco O ; + +N 1904 884.500 M 6 1 rr : 0 0 0 sco O ; + +N 1905 885.500 M 6 1 rr : 0 0 0 sco O ; + +N 1905 886.500 M 7 1 rr : 0 0 0 sco O ; + +N 1905 887.500 M 7 1 rr : 0 0 0 sco O ; + +N 1906 888.500 M 7 1 rr : 0 0 0 sco O ; + +N 1907 889.500 M 7 1 rr : 0 0 0 sco O ; + +N 1907 890.500 M 8 1 rr : 0 0 0 sco O ; + +N 1908 891.500 M 7 1 rr : 0 0 0 sco O ; + +N 1909 892.500 M 7 1 rr : 0 0 0 sco O ; + +N 1910 893.500 M 7 1 rr : 0 0 0 sco O ; + +N 1910 894.500 M 8 1 rr : 0 0 0 sco O ; + +N 1911 895.500 M 7 1 rr : 0 0 0 sco O ; + +N 1912 896.500 M 7 1 rr : 0 0 0 sco O ; + +N 1913 897.500 M 7 1 rr : 0 0 0 sco O ; + +N 1913 898.500 M 7 1 rr : 0 0 0 sco O ; + +N 1914 899.500 M 7 1 rr : 0 0 0 sco O ; + +N 1915 900.500 M 7 1 rr : 0 0 0 sco O ; + +N 1915 901.500 M 8 1 rr : 0 0 0 sco O ; + +N 1916 902.500 M 7 1 rr : 0 0 0 sco O ; + +N 1917 903.500 M 7 1 rr : 0 0 0 sco O ; + +N 1918 904.500 M 7 1 rr : 0 0 0 sco O ; + +N 1918 905.500 M 7 1 rr : 0 0 0 sco O ; + +N 1919 906.500 M 7 1 rr : 0 0 0 sco O ; + +N 1920 907.500 M 7 1 rr : 0 0 0 sco O ; + +N 1920 908.500 M 7 1 rr : 0 0 0 sco O ; + +N 1921 909.500 M 7 1 rr : 0 0 0 sco O ; + +N 1922 910.500 M 6 1 rr : 0 0 0 sco O ; + +N 1922 911.500 M 7 1 rr : 0 0 0 sco O ; + +N 1923 912.500 M 6 1 rr : 0 0 0 sco O ; + +N 1923 913.500 M 7 1 rr : 0 0 0 sco O ; + +N 1924 914.500 M 6 1 rr : 0 0 0 sco O ; + +N 1924 915.500 M 7 1 rr : 0 0 0 sco O ; + +N 1925 916.500 M 6 1 rr : 0 0 0 sco O ; + +N 1925 917.500 M 7 1 rr : 0 0 0 sco O ; + +N 1926 918.500 M 6 1 rr : 0 0 0 sco O ; + +N 1926 919.500 M 7 1 rr : 0 0 0 sco O ; + +N 1927 920.500 M 6 1 rr : 0 0 0 sco O ; + +N 1927 921.500 M 6 1 rr : 0 0 0 sco O ; + +N 1927 922.500 M 7 1 rr : 0 0 0 sco O ; + +N 1928 923.500 M 6 1 rr : 0 0 0 sco O ; + +N 1928 924.500 M 7 1 rr : 0 0 0 sco O ; + +N 1929 925.500 M 6 1 rr : 0 0 0 sco O ; + +N 1929 926.500 M 6 1 rr : 0 0 0 sco O ; + +N 1929 927.500 M 7 1 rr : 0 0 0 sco O ; + +N 1930 928.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 929.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 930.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 931.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 932.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 933.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 934.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 935.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 936.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 937.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 938.500 M 6 1 rr : 0 0 0 sco O ; + +N 1930 939.500 M 6 1 rr : 0 0 0 sco O ; + +N 1929 940.500 M 6 1 rr : 0 0 0 sco O ; + +N 1929 941.500 M 6 1 rr : 0 0 0 sco O ; + +N 1929 942.500 M 6 1 rr : 0 0 0 sco O ; + +N 1929 943.500 M 6 1 rr : 0 0 0 sco O ; + +N 1928 944.500 M 6 1 rr : 0 0 0 sco O ; + +N 1928 945.500 M 6 1 rr : 0 0 0 sco O ; + +N 1928 946.500 M 6 1 rr : 0 0 0 sco O ; + +N 1927 947.500 M 7 1 rr : 0 0 0 sco O ; + +N 1927 948.500 M 6 1 rr : 0 0 0 sco O ; + +N 1926 949.500 M 7 1 rr : 0 0 0 sco O ; + +N 1926 950.500 M 6 1 rr : 0 0 0 sco O ; + +N 1925 951.500 M 7 1 rr : 0 0 0 sco O ; + +N 1925 952.500 M 6 1 rr : 0 0 0 sco O ; + +N 1924 953.500 M 7 1 rr : 0 0 0 sco O ; + +N 1924 954.500 M 6 1 rr : 0 0 0 sco O ; + +N 1924 955.500 M 6 1 rr : 0 0 0 sco O ; + +N 1923 956.500 M 7 1 rr : 0 0 0 sco O ; + +N 1923 957.500 M 6 1 rr : 0 0 0 sco O ; + +N 1922 958.500 M 7 1 rr : 0 0 0 sco O ; + +N 1921 959.500 M 7 1 rr : 0 0 0 sco O ; + +N 1921 960.500 M 7 1 rr : 0 0 0 sco O ; + +N 1920 961.500 M 7 1 rr : 0 0 0 sco O ; + +N 1920 962.500 M 6 1 rr : 0 0 0 sco O ; + +N 1919 963.500 M 7 1 rr : 0 0 0 sco O ; + +N 1918 964.500 M 7 1 rr : 0 0 0 sco O ; + +N 1918 965.500 M 7 1 rr : 0 0 0 sco O ; + +N 1917 966.500 M 7 1 rr : 0 0 0 sco O ; + +N 1916 967.500 M 7 1 rr : 0 0 0 sco O ; + +N 1916 968.500 M 7 1 rr : 0 0 0 sco O ; + +N 1915 969.500 M 7 1 rr : 0 0 0 sco O ; + +N 1914 970.500 M 7 1 rr : 0 0 0 sco O ; + +N 1913 971.500 M 8 1 rr : 0 0 0 sco O ; + +N 1913 972.500 M 7 1 rr : 0 0 0 sco O ; + +N 1912 973.500 M 7 1 rr : 0 0 0 sco O ; + +N 1911 974.500 M 7 1 rr : 0 0 0 sco O ; + +N 1911 975.500 M 7 1 rr : 0 0 0 sco O ; + +N 1910 976.500 M 7 1 rr : 0 0 0 sco O ; + +N 1910 977.500 M 6 1 rr : 0 0 0 sco O ; + +N 1909 978.500 M 7 1 rr : 0 0 0 sco O ; + +N 1908 979.500 M 7 1 rr : 0 0 0 sco O ; + +N 1908 980.500 M 7 1 rr : 0 0 0 sco O ; + +N 1907 981.500 M 7 1 rr : 0 0 0 sco O ; + +N 1907 982.500 M 6 1 rr : 0 0 0 sco O ; + +N 1906 983.500 M 7 1 rr : 0 0 0 sco O ; + +N 1905 984.500 M 7 1 rr : 0 0 0 sco O ; + +N 1905 985.500 M 7 1 rr : 0 0 0 sco O ; + +N 1904 986.500 M 7 1 rr : 0 0 0 sco O ; + +N 1903 987.500 M 7 1 rr : 0 0 0 sco O ; + +N 1903 988.500 M 7 1 rr : 0 0 0 sco O ; + +N 1902 989.500 M 7 1 rr : 0 0 0 sco O ; + +N 1901 990.500 M 7 1 rr : 0 0 0 sco O ; + +N 1901 991.500 M 7 1 rr : 0 0 0 sco O ; + +N 1900 992.500 M 7 1 rr : 0 0 0 sco O ; + +N 1900 993.500 M 6 1 rr : 0 0 0 sco O ; + +N 1899 994.500 M 7 1 rr : 0 0 0 sco O ; + +N 1899 995.500 M 6 1 rr : 0 0 0 sco O ; + +N 1898 996.500 M 7 1 rr : 0 0 0 sco O ; + +N 1898 997.500 M 6 1 rr : 0 0 0 sco O ; + +N 1897 998.500 M 7 1 rr : 0 0 0 sco O ; + +N 1897 999.500 M 6 1 rr : 0 0 0 sco O ; + +N 1896 1000.500 M 7 1 rr : 0 0 0 sco O ; + +N 1896 1001.500 M 6 1 rr : 0 0 0 sco O ; + +N 1895 1002.500 M 7 1 rr : 0 0 0 sco O ; + +N 1895 1003.500 M 6 1 rr : 0 0 0 sco O ; + +N 1895 1004.500 M 6 1 rr : 0 0 0 sco O ; + +N 1894 1005.500 M 7 1 rr : 0 0 0 sco O ; + +N 1894 1006.500 M 6 1 rr : 0 0 0 sco O ; + +N 1894 1007.500 M 6 1 rr : 0 0 0 sco O ; + +N 1894 1008.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1009.500 M 7 1 rr : 0 0 0 sco O ; + +N 1893 1010.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1011.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1012.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1013.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1014.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1015.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1016.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1017.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1018.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1019.500 M 6 1 rr : 0 0 0 sco O ; + +N 1893 1020.500 M 7 1 rr : 0 0 0 sco O ; + +N 1894 1021.500 M 6 1 rr : 0 0 0 sco O ; + +N 1894 1022.500 M 6 1 rr : 0 0 0 sco O ; + +N 1894 1023.500 M 6 1 rr : 0 0 0 sco O ; + +N 1894 1024.500 M 7 1 rr : 0 0 0 sco O ; + +N 1895 1025.500 M 6 1 rr : 0 0 0 sco O ; + +N 1895 1026.500 M 6 1 rr : 0 0 0 sco O ; + +N 1895 1027.500 M 6 1 rr : 0 0 0 sco O ; + +N 1895 1028.500 M 7 1 rr : 0 0 0 sco O ; + +N 1896 1029.500 M 6 1 rr : 0 0 0 sco O ; + +N 1896 1030.500 M 7 1 rr : 0 0 0 sco O ; + +N 1897 1031.500 M 6 1 rr : 0 0 0 sco O ; + +N 1897 1032.500 M 7 1 rr : 0 0 0 sco O ; + +N 1898 1033.500 M 7 1 rr : 0 0 0 sco O ; + +N 1898 1034.500 M 7 1 rr : 0 0 0 sco O ; + +N 1899 1035.500 M 7 1 rr : 0 0 0 sco O ; + +N 1900 1036.500 M 6 1 rr : 0 0 0 sco O ; + +N 1900 1037.500 M 7 1 rr : 0 0 0 sco O ; + +N 1901 1038.500 M 6 1 rr : 0 0 0 sco O ; + +N 1901 1039.500 M 7 1 rr : 0 0 0 sco O ; + +N 1902 1040.500 M 7 1 rr : 0 0 0 sco O ; + +N 1902 1041.500 M 7 1 rr : 0 0 0 sco O ; + +N 1903 1042.500 M 7 1 rr : 0 0 0 sco O ; + +N 1904 1043.500 M 7 1 rr : 0 0 0 sco O ; + +N 1904 1044.500 M 7 1 rr : 0 0 0 sco O ; + +N 1905 1045.500 M 7 1 rr : 0 0 0 sco O ; + +N 1906 1046.500 M 7 1 rr : 0 0 0 sco O ; + +N 1906 1047.500 M 7 1 rr : 0 0 0 sco O ; + +N 1907 1048.500 M 7 1 rr : 0 0 0 sco O ; + +N 1908 1049.500 M 7 1 rr : 0 0 0 sco O ; + +N 1908 1050.500 M 7 1 rr : 0 0 0 sco O ; + +N 1909 1051.500 M 7 1 rr : 0 0 0 sco O ; + +N 1910 1052.500 M 7 1 rr : 0 0 0 sco O ; + +N 1910 1053.500 M 7 1 rr : 0 0 0 sco O ; + +N 1911 1054.500 M 7 1 rr : 0 0 0 sco O ; + +N 1912 1055.500 M 6 1 rr : 0 0 0 sco O ; + +N 1912 1056.500 M 7 1 rr : 0 0 0 sco O ; + +N 1913 1057.500 M 7 1 rr : 0 0 0 sco O ; + +N 1913 1058.500 M 8 1 rr : 0 0 0 sco O ; + +N 1914 1059.500 M 7 1 rr : 0 0 0 sco O ; + +N 1915 1060.500 M 7 1 rr : 0 0 0 sco O ; + +N 1915 1061.500 M 7 1 rr : 0 0 0 sco O ; + +N 1916 1062.500 M 2 1 rr : 0 0 0 sco O ; + +N 1871 885.500 M 2 1 rr : 1.000 0 0 sco O ; + +N 1870 886.500 M 4 1 rr : 1.000 0 0 sco O ; + +N 1869 887.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1868 888.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1869 889.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1870 890.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1871 891.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1872 892.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1873 893.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1874 894.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1875 895.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1876 896.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1877 897.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1878 898.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1879 899.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1880 900.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1881 901.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1882 902.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1883 903.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1884 904.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1885 905.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1886 906.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1886 907.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1887 908.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1888 909.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1889 910.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1890 911.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1891 912.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1892 913.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1892 914.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1893 915.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1894 916.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1895 917.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1896 918.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1896 919.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1897 920.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1898 921.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1898 922.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1899 923.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1899 924.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1900 925.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1900 926.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1901 927.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1901 928.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1902 929.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1902 930.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1903 931.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1903 932.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1904 933.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1904 934.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1905 935.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1905 936.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1906 937.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1906 938.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1907 939.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1907 940.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1908 941.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1908 942.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1909 943.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1909 944.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1910 945.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1910 946.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1911 947.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1911 948.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1912 949.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1912 950.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1913 951.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1913 952.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1914 953.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1914 954.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1915 955.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1915 956.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1916 957.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1916 958.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1917 959.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1917 960.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1918 961.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1918 962.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1919 963.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1919 964.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1919 965.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1920 966.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1920 967.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1921 968.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1921 969.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1922 970.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1922 971.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1923 972.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1924 973.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1924 974.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1925 975.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1925 976.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1926 977.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1926 978.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1927 979.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1928 980.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1929 981.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1929 982.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1930 983.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1931 984.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 1932 985.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1933 986.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1934 987.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1935 988.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1936 989.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1938 990.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1939 991.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1940 992.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1942 993.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1943 994.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 1945 995.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1946 996.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1947 997.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 1949 998.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1950 999.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1951 1000.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1951 1001.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1952 1002.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1953 1003.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1953 1004.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1954 1005.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1006.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1007.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1008.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1955 1009.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1010.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1011.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1012.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1013.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1014.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1015.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1956 1016.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1017.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1018.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1019.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1020.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1021.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1022.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1023.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1024.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1025.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1026.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1027.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1028.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1029.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1030.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1031.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1032.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1033.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1034.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1035.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1036.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1037.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1038.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1956 1039.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1040.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1955 1041.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1042.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1043.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1044.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1045.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1046.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1047.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1048.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1049.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1050.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1051.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1052.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1955 1053.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1054.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 1954 1055.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1056.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1057.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1058.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1059.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1060.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1954 1061.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 1996 458.500 M 3 1 rr : 0 0 0 sco O ; + +N 1994 459.500 M 5 1 rr : 0 0 0 sco O ; + +N 1993 460.500 M 7 1 rr : 0 0 0 sco O ; + +N 1994 461.500 M 7 1 rr : 0 0 0 sco O ; + +N 1994 462.500 M 8 1 rr : 0 0 0 sco O ; + +N 1995 463.500 M 8 1 rr : 0 0 0 sco O ; + +N 1996 464.500 M 8 1 rr : 0 0 0 sco O ; + +N 1997 465.500 M 9 1 rr : 0 0 0 sco O ; + +N 1998 466.500 M 9 1 rr : 0 0 0 sco O ; + +N 1999 467.500 M 9 1 rr : 0 0 0 sco O ; + +N 2000 468.500 M 9 1 rr : 0 0 0 sco O ; + +N 2001 469.500 M 9 1 rr : 0 0 0 sco O ; + +N 2003 470.500 M 9 1 rr : 0 0 0 sco O ; + +N 2004 471.500 M 9 1 rr : 0 0 0 sco O ; + +N 2005 472.500 M 9 1 rr : 0 0 0 sco O ; + +N 2006 473.500 M 9 1 rr : 0 0 0 sco O ; + +N 2007 474.500 M 9 1 rr : 0 0 0 sco O ; + +N 2009 475.500 M 8 1 rr : 0 0 0 sco O ; + +N 2010 476.500 M 8 1 rr : 0 0 0 sco O ; + +N 2011 477.500 M 8 1 rr : 0 0 0 sco O ; + +N 2012 478.500 M 8 1 rr : 0 0 0 sco O ; + +N 2013 479.500 M 8 1 rr : 0 0 0 sco O ; + +N 2014 480.500 M 7 1 rr : 0 0 0 sco O ; + +N 2015 481.500 M 7 1 rr : 0 0 0 sco O ; + +N 2016 482.500 M 7 1 rr : 0 0 0 sco O ; + +N 2016 483.500 M 8 1 rr : 0 0 0 sco O ; + +N 2017 484.500 M 8 1 rr : 0 0 0 sco O ; + +N 2018 485.500 M 8 1 rr : 0 0 0 sco O ; + +N 2019 486.500 M 8 1 rr : 0 0 0 sco O ; + +N 2020 487.500 M 8 1 rr : 0 0 0 sco O ; + +N 2021 488.500 M 7 1 rr : 0 0 0 sco O ; + +N 2022 489.500 M 7 1 rr : 0 0 0 sco O ; + +N 2023 490.500 M 7 1 rr : 0 0 0 sco O ; + +N 2023 491.500 M 8 1 rr : 0 0 0 sco O ; + +N 2024 492.500 M 8 1 rr : 0 0 0 sco O ; + +N 2025 493.500 M 7 1 rr : 0 0 0 sco O ; + +N 2026 494.500 M 7 1 rr : 0 0 0 sco O ; + +N 2027 495.500 M 7 1 rr : 0 0 0 sco O ; + +N 2027 496.500 M 8 1 rr : 0 0 0 sco O ; + +N 2028 497.500 M 7 1 rr : 0 0 0 sco O ; + +N 2029 498.500 M 7 1 rr : 0 0 0 sco O ; + +N 2030 499.500 M 7 1 rr : 0 0 0 sco O ; + +N 2030 500.500 M 8 1 rr : 0 0 0 sco O ; + +N 2031 501.500 M 7 1 rr : 0 0 0 sco O ; + +N 2032 502.500 M 7 1 rr : 0 0 0 sco O ; + +N 2033 503.500 M 6 1 rr : 0 0 0 sco O ; + +N 2033 504.500 M 7 1 rr : 0 0 0 sco O ; + +N 2034 505.500 M 6 1 rr : 0 0 0 sco O ; + +N 2034 506.500 M 7 1 rr : 0 0 0 sco O ; + +N 2035 507.500 M 7 1 rr : 0 0 0 sco O ; + +N 2035 508.500 M 7 1 rr : 0 0 0 sco O ; + +N 2036 509.500 M 7 1 rr : 0 0 0 sco O ; + +N 2037 510.500 M 6 1 rr : 0 0 0 sco O ; + +N 2037 511.500 M 7 1 rr : 0 0 0 sco O ; + +N 2038 512.500 M 6 1 rr : 0 0 0 sco O ; + +N 2038 513.500 M 7 1 rr : 0 0 0 sco O ; + +N 2039 514.500 M 6 1 rr : 0 0 0 sco O ; + +N 2039 515.500 M 7 1 rr : 0 0 0 sco O ; + +N 2040 516.500 M 6 1 rr : 0 0 0 sco O ; + +N 2040 517.500 M 7 1 rr : 0 0 0 sco O ; + +N 2041 518.500 M 6 1 rr : 0 0 0 sco O ; + +N 2041 519.500 M 7 1 rr : 0 0 0 sco O ; + +N 2042 520.500 M 6 1 rr : 0 0 0 sco O ; + +N 2042 521.500 M 7 1 rr : 0 0 0 sco O ; + +N 2043 522.500 M 6 1 rr : 0 0 0 sco O ; + +N 2043 523.500 M 7 1 rr : 0 0 0 sco O ; + +N 2044 524.500 M 6 1 rr : 0 0 0 sco O ; + +N 2044 525.500 M 7 1 rr : 0 0 0 sco O ; + +N 2045 526.500 M 6 1 rr : 0 0 0 sco O ; + +N 2045 527.500 M 7 1 rr : 0 0 0 sco O ; + +N 2046 528.500 M 6 1 rr : 0 0 0 sco O ; + +N 2046 529.500 M 7 1 rr : 0 0 0 sco O ; + +N 2047 530.500 M 6 1 rr : 0 0 0 sco O ; + +N 2047 531.500 M 7 1 rr : 0 0 0 sco O ; + +N 2048 532.500 M 6 1 rr : 0 0 0 sco O ; + +N 2048 533.500 M 7 1 rr : 0 0 0 sco O ; + +N 2049 534.500 M 6 1 rr : 0 0 0 sco O ; + +N 2049 535.500 M 7 1 rr : 0 0 0 sco O ; + +N 2050 536.500 M 6 1 rr : 0 0 0 sco O ; + +N 2050 537.500 M 7 1 rr : 0 0 0 sco O ; + +N 2051 538.500 M 6 1 rr : 0 0 0 sco O ; + +N 2051 539.500 M 7 1 rr : 0 0 0 sco O ; + +N 2052 540.500 M 6 1 rr : 0 0 0 sco O ; + +N 2052 541.500 M 7 1 rr : 0 0 0 sco O ; + +N 2053 542.500 M 6 1 rr : 0 0 0 sco O ; + +N 2053 543.500 M 7 1 rr : 0 0 0 sco O ; + +N 2054 544.500 M 6 1 rr : 0 0 0 sco O ; + +N 2054 545.500 M 7 1 rr : 0 0 0 sco O ; + +N 2055 546.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 547.500 M 6 1 rr : 0 0 0 sco O ; + +N 2055 548.500 M 7 1 rr : 0 0 0 sco O ; + +N 2056 549.500 M 6 1 rr : 0 0 0 sco O ; + +N 2056 550.500 M 7 1 rr : 0 0 0 sco O ; + +N 2057 551.500 M 6 1 rr : 0 0 0 sco O ; + +N 2057 552.500 M 7 1 rr : 0 0 0 sco O ; + +N 2058 553.500 M 6 1 rr : 0 0 0 sco O ; + +N 2058 554.500 M 7 1 rr : 0 0 0 sco O ; + +N 2059 555.500 M 6 1 rr : 0 0 0 sco O ; + +N 2059 556.500 M 6 1 rr : 0 0 0 sco O ; + +N 2059 557.500 M 7 1 rr : 0 0 0 sco O ; + +N 2060 558.500 M 7 1 rr : 0 0 0 sco O ; + +N 2060 559.500 M 7 1 rr : 0 0 0 sco O ; + +N 2061 560.500 M 7 1 rr : 0 0 0 sco O ; + +N 2062 561.500 M 6 1 rr : 0 0 0 sco O ; + +N 2062 562.500 M 7 1 rr : 0 0 0 sco O ; + +N 2063 563.500 M 7 1 rr : 0 0 0 sco O ; + +N 2063 564.500 M 7 1 rr : 0 0 0 sco O ; + +N 2064 565.500 M 7 1 rr : 0 0 0 sco O ; + +N 2065 566.500 M 7 1 rr : 0 0 0 sco O ; + +N 2065 567.500 M 7 1 rr : 0 0 0 sco O ; + +N 2066 568.500 M 7 1 rr : 0 0 0 sco O ; + +N 2067 569.500 M 6 1 rr : 0 0 0 sco O ; + +N 2067 570.500 M 7 1 rr : 0 0 0 sco O ; + +N 2068 571.500 M 7 1 rr : 0 0 0 sco O ; + +N 2068 572.500 M 7 1 rr : 0 0 0 sco O ; + +N 2069 573.500 M 7 1 rr : 0 0 0 sco O ; + +N 2070 574.500 M 7 1 rr : 0 0 0 sco O ; + +N 2070 575.500 M 7 1 rr : 0 0 0 sco O ; + +N 2071 576.500 M 7 1 rr : 0 0 0 sco O ; + +N 2072 577.500 M 8 1 rr : 0 0 0 sco O ; + +N 2072 578.500 M 9 1 rr : 0 0 0 sco O ; + +N 2073 579.500 M 9 1 rr : 0 0 0 sco O ; + +N 2074 580.500 M 10 1 rr : 0 0 0 sco O ; + +N 2075 581.500 M 10 1 rr : 0 0 0 sco O ; + +N 2077 582.500 M 10 1 rr : 0 0 0 sco O ; + +N 2078 583.500 M 11 1 rr : 0 0 0 sco O ; + +N 2079 584.500 M 11 1 rr : 0 0 0 sco O ; + +N 2081 585.500 M 11 1 rr : 0 0 0 sco O ; + +N 2082 586.500 M 11 1 rr : 0 0 0 sco O ; + +N 2084 587.500 M 10 1 rr : 0 0 0 sco O ; + +N 2086 588.500 M 10 1 rr : 0 0 0 sco O ; + +N 2087 589.500 M 10 1 rr : 0 0 0 sco O ; + +N 2089 590.500 M 9 1 rr : 0 0 0 sco O ; + +N 2090 591.500 M 10 1 rr : 0 0 0 sco O ; + +N 2091 592.500 M 10 1 rr : 0 0 0 sco O ; + +N 2093 593.500 M 9 1 rr : 0 0 0 sco O ; + +N 2094 594.500 M 9 1 rr : 0 0 0 sco O ; + +N 2095 595.500 M 9 1 rr : 0 0 0 sco O ; + +N 2097 596.500 M 8 1 rr : 0 0 0 sco O ; + +N 2098 597.500 M 7 1 rr : 0 0 0 sco O ; + +N 2099 598.500 M 7 1 rr : 0 0 0 sco O ; + +N 2100 599.500 M 7 1 rr : 0 0 0 sco O ; + +N 2100 600.500 M 7 1 rr : 0 0 0 sco O ; + +N 2101 601.500 M 7 1 rr : 0 0 0 sco O ; + +N 2102 602.500 M 6 1 rr : 0 0 0 sco O ; + +N 2102 603.500 M 7 1 rr : 0 0 0 sco O ; + +N 2103 604.500 M 6 1 rr : 0 0 0 sco O ; + +N 2103 605.500 M 7 1 rr : 0 0 0 sco O ; + +N 2104 606.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 607.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 608.500 M 7 1 rr : 0 0 0 sco O ; + +N 2105 609.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 610.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 611.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 612.500 M 7 1 rr : 0 0 0 sco O ; + +N 2106 613.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 614.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 615.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 616.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 617.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 618.500 M 7 1 rr : 0 0 0 sco O ; + +N 2107 619.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 620.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 621.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 622.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 623.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 624.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 625.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 626.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 627.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 628.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 629.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 630.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 631.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 632.500 M 6 1 rr : 0 0 0 sco O ; + +N 2107 633.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 634.500 M 7 1 rr : 0 0 0 sco O ; + +N 2106 635.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 636.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 637.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 638.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 639.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 640.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 641.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 642.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 643.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 644.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 645.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 646.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 647.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 648.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 649.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 650.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 651.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 652.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 653.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 654.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 655.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 656.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 657.500 M 6 1 rr : 0 0 0 sco O ; + +N 2106 658.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 659.500 M 7 1 rr : 0 0 0 sco O ; + +N 2105 660.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 661.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 662.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 663.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 664.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 665.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 666.500 M 6 1 rr : 0 0 0 sco O ; + +N 2105 667.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 668.500 M 7 1 rr : 0 0 0 sco O ; + +N 2104 669.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 670.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 671.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 672.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 673.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 674.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 675.500 M 6 1 rr : 0 0 0 sco O ; + +N 2104 676.500 M 6 1 rr : 0 0 0 sco O ; + +N 2046 440.500 M 3 1 rr : 1.000 0 0 sco O ; + +N 2044 441.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2043 442.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2044 443.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2045 444.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2045 445.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2046 446.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2047 447.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2048 448.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2049 449.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2049 450.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2050 451.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2051 452.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2052 453.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2053 454.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2053 455.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2054 456.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2055 457.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2056 458.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2056 459.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2057 460.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2058 461.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2059 462.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2059 463.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2060 464.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2061 465.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2062 466.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2062 467.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2063 468.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2064 469.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2064 470.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2065 471.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2066 472.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2067 473.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2067 474.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2068 475.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2069 476.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2069 477.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2070 478.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2071 479.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2071 480.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2072 481.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2073 482.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2074 483.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2074 484.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2075 485.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2076 486.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2076 487.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2077 488.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2078 489.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2078 490.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2079 491.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2079 492.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2080 493.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2081 494.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2081 495.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2082 496.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2082 497.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2082 498.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2083 499.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2083 500.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2083 501.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2084 502.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2084 503.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2084 504.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2084 505.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2085 506.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2085 507.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2085 508.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2086 509.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 510.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 511.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 512.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2087 513.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 514.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 515.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 516.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 517.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 518.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 519.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 520.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 521.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 522.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 523.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 524.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 525.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 526.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 527.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 528.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 529.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 530.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 531.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 532.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 533.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 534.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 535.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2087 536.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 537.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2086 538.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 539.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 540.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 541.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 542.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 543.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2086 544.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2085 545.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2085 546.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2085 547.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2084 548.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2084 549.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2084 550.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2084 551.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2084 552.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2083 553.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2083 554.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2083 555.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2082 556.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2082 557.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2081 558.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2080 559.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2080 560.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2079 561.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2077 562.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2076 563.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 2074 564.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 2072 565.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2071 566.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2069 567.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2068 568.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2066 569.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2064 570.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2063 571.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2061 572.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2060 573.500 M 11 1 rr : 1.000 0 0 sco O ; + +N 2059 574.500 M 10 1 rr : 1.000 0 0 sco O ; + +N 2058 575.500 M 9 1 rr : 1.000 0 0 sco O ; + +N 2058 576.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2057 577.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2056 578.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2055 579.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2054 580.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2053 581.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2052 582.500 M 8 1 rr : 1.000 0 0 sco O ; + +N 2052 583.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2051 584.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2051 585.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2050 586.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2049 587.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2049 588.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2049 589.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 590.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2048 591.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 592.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 593.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 594.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2047 595.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2047 596.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2047 597.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2047 598.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2047 599.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2047 600.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 601.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 602.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 603.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 604.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 605.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2048 606.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2049 607.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2049 608.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2049 609.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2049 610.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2050 611.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2050 612.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2050 613.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2050 614.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2051 615.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2051 616.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2051 617.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2052 618.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2052 619.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2052 620.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2053 621.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2053 622.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2053 623.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2054 624.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2054 625.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2054 626.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2055 627.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2055 628.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2055 629.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2056 630.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2056 631.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2056 632.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2057 633.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2057 634.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2058 635.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2058 636.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2059 637.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2059 638.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2060 639.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2060 640.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2060 641.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2061 642.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2061 643.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2062 644.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2062 645.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2062 646.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2063 647.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2063 648.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2064 649.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2064 650.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2064 651.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2065 652.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2065 653.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2066 654.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2066 655.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2066 656.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2067 657.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2067 658.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2068 659.500 M 6 1 rr : 1.000 0 0 sco O ; + +N 2068 660.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2068 661.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2069 662.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2069 663.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2070 664.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2070 665.500 M 7 1 rr : 1.000 0 0 sco O ; + +N 2071 666.500 M 2 1 rr : 1.000 0 0 sco O ; + +164 95 N M 2601 271 rr : 114 70 3000 2250 rc 0.647 0 0.129 sco F0_100 + +Ji + +201 111 M + +-0.300 0 (M)A + +-0.100 0 (u)A + +0.200 0 (l)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.800 0 (l)A + +0.400 0 (eve)A + +1.000 0 32 -0.800 0 (l )D + +-0.100 0 (p)A + +-0.600 0 (a)A + +0.100 0 (r)A + +0.700 0 (t)A + +-0.800 0 (i)A + +0.700 0 (t)A + +-0.800 0 (i)A + +-0.100 0 (on)A + +0.200 0 (i)A + +-0.700 0 32 -0.100 0 (ng )D + +0.400 0 (a)A + +0.200 0 (l)A + +-0.100 0 (g)A + +-1.100 0 (o)A + +1.100 0 (r)A + +-0.800 0 (i)A + +-0.300 0 (t)A + +-0.100 0 (h)A + +0.100 0 (m)A + +-0.200 0 32 0.400 0 (s c)D + +-1.100 0 (o)A + +1.100 0 (m)A + +-1.100 0 (p)A + +-0.100 0 (u)A + +0.700 0 (t)A + +0.800 0 32 -0.600 0 (e )D + +-1.200 0 32 0.400 0 (a )D + +-0.100 0 (p)A + +0.400 0 (a)A + +0.100 0 (r)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.300 0 (t)A + +0.200 0 (i)A + +-0.100 0 (on)A + +; : 114 70 3000 2250 rc 0.647 0 0.129 sco F0_100 + +Ji + +273 231 M + +0.400 0 (a)A + +0.500 0 32 -0.300 0 (t t)D + +-0.100 0 (h)A + +-1.200 0 32 0.400 0 (e c)D + +-0.100 0 (o)A + +0.400 0 (a)A + +0.100 0 (r)A + +-0.600 0 (s)A + +0.400 0 (es)A + +0.500 0 32 -0.300 0 (t )D + +-0.100 0 (g)A + +0.100 0 (r)A + +0.400 0 (a)A + +-1.100 0 (p)A + +0.300 0 32 -0.100 0 (h )D + +0.400 0 (a)A + +-0.700 0 32 -0.100 0 (nd )D + +0.700 0 (t)A + +-1.100 0 (h)A + +0.400 0 (e)A + +0.300 0 32 -0.100 0 (n )D + +0.100 0 (r)A + +-0.600 0 (e)A + +0.700 0 (f)A + +-0.800 0 (i)A + +-0.100 0 (n)A + +-0.200 0 32 0.400 0 (e )D + +-0.300 0 (t)A + +-0.100 0 (h)A + +-1.200 0 32 0.400 0 (e s)D + +-0.100 0 (o)A + +0.200 0 (l)A + +-1.100 0 (u)A + +0.700 0 (t)A + +-0.800 0 (i)A + +-0.100 0 (on)A + +0.700 0 (!)A + +; + +LH + +pagesave restore + + + + + + + +/Pscript_Win_Driver /ProcSet findresource dup /terminate get exec + +Pscript_Win_Compat dup /terminate get exec + + + +restore gr +% +% End Imported PIC File: slide8.eps +% +/Helvetica-Bold findfont 300.00 scalefont setfont +14550 7514 m +gs 1 -1 sc (\(b\)) col-1 show gr +/Helvetica-Bold findfont 300.00 scalefont setfont +5100 5864 m +gs 1 -1 sc (\(a\)) col-1 show gr +$F2psEnd +restore +%%EndDocument + @endspecial 678 2789 a Fy(Figure)e(1)p FL(:)26 b Fx(\(a\))18 +b(T)-8 b(r)o(aditional)18 b(par)s(titioning)g(algor)q(ithms)o(.)k +(\(b\))c(Multile)n(v)n(el)h(par)s(titioning)f(algor)q(ithms)o(.)100 +2982 y FL(The)h(adv)n(antages)g(of)j Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)24 b FL(compared)19 b(to)h(other)f(similar)i +(packages)e(are)h(the)g(follo)n(wing:)88 3167 y Fw(+)42 +b FC(Pr)o(o)o(vides)19 b(high)i(quality)f(partitions!)208 +3277 y FL(Experiments)j(on)i(a)h(lar)o(ge)f(number)e(of)j(graphs)e +(arising)h(in)g(v)n(arious)g(domains)f(including)g(\002nite)i(element)f +(methods,)g(linear)208 3386 y(programming,)g(VLSI,)i(and)g +(transportation)e(sho)n(w)h(that)k Fz(M)l FG(E)-17 b +Fz(T)g FG(I)p Fz(S)31 b FL(produces)26 b(partitions)g(that)i(are)f +(consistently)f(better)h(than)208 3496 y(those)g(produced)f(by)h(other) +g(widely)g(used)h(algorithms.)47 b(The)27 b(partitions)g(produced)e(by) +30 b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)32 b FL(are)c(consistently)f +(10\045)g(to)208 3606 y(50\045)19 b(better)h(than)g(those)g(produced)e +(by)h(spectral)h(partitioning)f(algorithms)g([1)o(,)h(4].)88 +3790 y Fw(+)42 b FC(It)20 b(is)h(extr)o(emely)e(fast!)208 +3900 y FL(Experiments)d(on)i(a)g(wide)g(range)f(of)h(graphs)f(has)i +(sho)n(wn)e(that)j Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)23 +b FL(is)c(one)e(to)i(tw)o(o)f(orders)f(of)h(magnitude)e(f)o(aster)j +(than)e(other)208 4010 y(widely)h(used)h(partitioning)e(algorithms.)24 +b(Figure)18 b(2)i(sho)n(ws)f(the)g(amount)f(of)h(time)g(required)e(to)j +(partition)e(a)i(v)n(ariety)e(of)h(graphs)208 4119 y(in)h(256)g(parts)h +(for)f(tw)o(o)g(dif)n(ferent)f(architectures,)g(an)i(R10000-based)d +(SGI)j(Challenge)f(and)g(a)h(Pentium)f(Pro-based)f(personal)208 +4229 y(computer)-5 b(.)30 b(Graphs)21 b(containing)g(up)h(to)g(four)f +(million)h(v)o(ertices)g(can)g(be)g(partitioned)f(in)i(256)e(parts)h +(in)h(well)g(under)e(a)h(minute)208 4338 y(on)g(today')-5 +b(s)22 b(scienti\002c)h(w)o(orkstations.)33 b(The)22 +b(run)g(time)h(of)i Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)27 +b FL(is)d(comparable)c(to)j(\(or)g(e)n(v)o(en)f(smaller)g(than\))g(the) +h(run)f(time)208 4448 y(of)d(some)h(geometric)f(partitioning)f +(algorithms)h(that)i(often)e(produce)f(much)h(w)o(orse)i(partitions.)88 +4633 y Fw(+)42 b FC(Pr)o(o)o(vides)19 b(lo)o(w)h(\002ll)i(orderings!) +208 4742 y FL(The)29 b(\002ll-reducing)f(orderings)g(produced)f(by)32 +b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)34 b FL(are)c(substantially)f +(better)g(than)h(those)f(produced)f(by)h(other)g(widely)208 +4852 y(used)18 b(algorithms)g(including)g(multiple)g(minimum)g(de)o +(gree.)23 b(F)o(or)18 b(man)o(y)g(classes)j(of)d(problems)g(arising)h +(in)g(scienti\002c)g(compu-)208 4962 y(tations)k(and)g(linear)g +(programming,)f Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)27 +b FL(is)e(able)e(to)g(reduce)g(the)g(storage)f(and)h(computational)e +(requirements)g(of)j(sparse)208 5071 y(matrix)e(f)o(actorization)f +(methods)g(by)h(up)h(to)g(an)f(order)g(of)g(magnitude.)31 +b(Moreo)o(v)o(er)m(,)20 b(unlik)o(e)i(multiple)g(minimum)f(de)o(gree,)h +(the)208 5181 y(elimination)f(trees)h(produced)e(by)k +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)27 b FL(are)22 b(suited)g(for)g +(parallel)g(direct)f(f)o(actorization.)30 b(Furthermore,)20 +b(as)j(Figure)f(2)g(illus-)208 5290 y(trates,)g Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)24 b FL(is)d(able)e(to)h(compute)f(these) +h(ordering)e(v)o(ery)g(f)o(ast.)26 b(Matrices)20 b(with)g(o)o(v)o(er)e +(tw)o(o)i(hundred)e(thousand)g(ro)n(ws)i(can)g(be)208 +5400 y(reordered)d(in)k(just)f(a)h(fe)n(w)f(seconds)g(on)g(current)e +(generation)h(w)o(orkstations)g(and)g(PCs.)1929 5649 +y(4)p eop +%%Page: 5 5 +5 4 bop 690 3717 a @beginspecial 0 @llx 0 @lly 716 @urx +1056 @ury 3024 @rwi @setspecial +%%BeginDocument: ./figures/slides.eps +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-30.0 1113.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +n -1000 19537 m -1000 -1000 l 13423 -1000 l 13423 19537 l cp clip + 0.06000 0.06000 sc +% Polyline +% +% Begin Imported EPS File: slide1.eps +% +n gs +525 973 tr +16.646067 -16.638623 sc +0 -523 tr +-40 -50 tr +sa +n 40 50 m 752 50 l 752 573 l 40 573 l cp clip +countdictstack +mark +/showpage {} def +% EPS file follows: + + + + + + + + + + + + + + + +/defineresource where{pop}{userdict begin/defineresource{userdict/Resources 2 + +copy known{get begin}{15 dict dup begin put}ifelse exch readonly exch + +currentdict 1 index known not{dup 30 dict def}if load 3 -1 roll 2 index put + +end}bind readonly def/findresource{userdict/Resources get exch get exch get} + +bind readonly def/resourceforall{pop pop pop pop}bind readonly def + +/resourcestatus{userdict/Resources 2 copy known{get exch 2 copy known{get exch + +known{0 -1 true}{pop pop false}ifelse}{pop pop pop false}ifelse}{pop pop false + +}ifelse}bind readonly def end}ifelse + + + +/Pscript_Win_Driver 200 dict dup begin + + +/FatalErrorIf{{initgraphics findfont exch scalefont setfont counttomark 3 div + +cvi{moveto show}repeat showpage quit}{cleartomark}ifelse}bind def + + +/VM? {vmstatus exch sub exch pop gt { [ + +(This job requires more memory than is available in this printer.) 100 500 + +(Try one or more of the following, and then print again:) 100 485 + +(In the PostScript dialog box, click Optimize For Portability.) 115 470 + +(In the Device Options dialog box, make sure the Available Printer Memory is accurate.) 115 455 + +(Reduce the number of fonts in the document.) 115 440 + +(Print the document in parts.) 115 425 + +12 /Times-Roman showpage + +(%%[ PrinterError: Low Printer VM ]%%) = + +true FatalErrorIf}if} bind def + + +/|/def load def/,/load load |/~/exch , |/?/ifelse , |/!/pop , |/`/begin , |/^ + +/index , |/@/dup , |/+/translate , |/$/roll , |/U/userdict , |/M/moveto , |/- + +/rlineto , |/&/currentdict , |/:/gsave , |/;/grestore , |/F/false , |/T/true , + +|/N/newpath , |/E/end , |/Ac/arc , |/An/arcn , |/A/ashow , |/D/awidthshow , | + +/C/closepath , |/V/div , |/O/eofill , |/L/fill , |/I/lineto , |/-C/rcurveto , + +|/-M/rmoveto , |/+S/scale , |/Ji/setfont , |/Lc/setlinecap , |/Lj/setlinejoin + +, |/Lw/setlinewidth , |/S/show , |/LH/showpage , |/K/stroke , |/W/widthshow , + +|/R/rotate , |/b{bind |}bind |/bd{bind |}bind |/xd{~ |}bd/ld{, |}bd/lw/Lw ld + +/lc/Lc ld/lj/Lj ld/sg/setgray ld/L2? F/languagelevel where{! languagelevel 2 + +ge{! T}if}if |/g{@ not{U/DefIf_save save put}if U/DefIf_bool 2 ^ put}b + +/DefIf_El{if U/DefIf_bool get not @{U/DefIf_save get restore}if}b/e{DefIf_El ! + +}b/self & |/reinitialize{[/TextInit/GraphInit/UtilsInit counttomark{@ where{ + +self eq}{F}?{cvx exec}{!}?}repeat cleartomark}b/initialize{`{/ADO_mxRot ~ | + +/TextInitialised? F | reinitialize E}{U/Pscript_Win_Data 200 dict @ ` put + +/ADO_mxRot ~ |/TextInitialised? F | reinitialize}?}b/terminate{!{& self eq{ + +exit}{E}?}loop E}b/suspend/terminate , |/resume{` Pscript_Win_Data `}b/snap{ + +transform 0.25 sub round 0.25 add ~ 0.25 sub round 0.25 add ~ itransform}b + +/dsnap{dtransform round ~ round ~ idtransform}b<04>cvn{}|/setjn{{statusdict + +/jobname known{statusdict/jobname 3 -1 $ put}if}stopped cleartomark}b/solid{[] + +0 setdash}b/setdsh{0 setdash}b/colspRefresh{}b/rp{4 2 $ M 1 ^ 0 - 0 ~ - neg 0 + +-}b/rr{1 ^ 0 - 0 ~ - neg 0 - C}b + + + +L2? not g{/rf{N rp L}b/fx{1 1 dtransform @ 0 ge{1 sub 1}{1 add -0.25}? 3 -1 $ + +@ 0 ge{1 sub 1}{1 add -0.25}? 3 1 $ 4 1 $ idtransform 4 -2 $ idtransform}b/BZ{ + +4 -2 $ snap + +S fx rf}b/rs{N rp C K}b/rc{N rp clip N}b/sg{setgray}b/sco{ + +setrgbcolor}b/sgco{{sg}{sco}?}b}e + + + +L2? g{/colspA/DeviceGray |/colspABC/DeviceRGB |/setAorABC{{colspA}{colspABC}? + +setcolorspace}b/rf/rectfill , |/fx{1 1 dtransform @ 0 ge{1 sub 0.5}{1 add -0.5 + +}? 3 -1 $ @ 0 ge{1 sub 0.5}{1 add -0.5}? 3 1 $ 4 1 $ idtransform 4 -2 $ + +idtransform}b/BZ{4 -2 $ snap + +S fx rf}b/rs/rectstroke , |/rc/rectclip , |/sg + +{@ @ setcolor}b/sco{setcolor}b/colspRefresh{colspABC setcolorspace}b/sgco{{sg + +}{sco}?}b/UtilsInit{F setglobal}b/definecolorrendering{/ColorRendering + +defineresource !}b/findcolorrendering{@/ColorRendering resourcestatus{! ! + +/ColorRendering findresource T}{! F}?}b/selectcolorrendering{@/ColorRendering + +resourcestatus{! !/ColorRendering}{!/DefaultColorRendering/ColorRendering}? + +findresource setcolorrendering}b}e + + + +/bullets{{/bullet}repeat}b/ANSIEncoding[/grave/acute/circumflex/tilde/macron + +/breve/dotaccent/dieresis/ring/cedilla/hungarumlaut/ogonek/caron/dotlessi 18 + +bullets StandardEncoding 32 95 getinterval aload ! 3 bullets/quotesinglbase + +/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron + +/guilsinglleft/OE 4 bullets/quoteleft/quoteright/quotedblleft/quotedblright + +/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe 2 bullets + +/Ydieresis/space/exclamdown/cent/sterling/currency/yen/brokenbar/section + +/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered + +/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph + +/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter + +/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis + +/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute + +/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis + +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls + +/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute + +/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve + +/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex + +/udieresis/yacute/thorn/ydieresis]| ANSIEncoding @ 39/quotesingle put 96/grave + +put/ANSIEncodingOld ANSIEncoding 256 array copy | ANSIEncodingOld @[138 153 + +154 169 172 174 177 178 179 181 185 188 189 190 208 215 221 222 240 247 253 + +254]{/bullet put @}forall 166/bar put 176/ring put + + + +/TextInit{TextInitialised? not{/Pscript_Windows_Font & |/TextInitialised? T | + +/fM[1 0 0 -1 0 0]|/mFM matrix |/iMat[1 0 0.212557 neg 1 0 0]|}if}b/xUP null | + +/yUP null |/uW null |/xSP null |/ySP null |/sW null |/copyfont{1 ^ length add + +dict `{1 ^/FID ne{|}{! !}?}forall & E}b/rF{3 copyfont @ `/Encoding + +ANSIEncoding &/CharStrings known{CharStrings/Eth known not{! ANSIEncodingOld} + +if}if | E}b/mF{findfont ~{@/Encoding get @ StandardEncoding eq{! T}{{ + +ISOLatin1Encoding}stopped{! F}{eq}?{T}{@ ` T 32 1 127{Encoding 1 ^ get + +StandardEncoding 3 -1 $ get eq and}for E}?}?}{F}?{rF}{3 copyfont}? ` + +/OrigFontType ~ |/OrigFontName ~ | & E 2 ^ ~ definefont fM 5 4 -1 $ put fM 4 0 + +put fM makefont Pscript_Windows_Font 3 1 $ put}b/xF{scalefont + +Pscript_Windows_Font 3 1 $ put}b/xMF{mFM astore makefont Pscript_Windows_Font + +3 1 $ put}b/xF2/scalefont , |/xMF2{mFM astore makefont}b/sLT{: Lw -M + +currentpoint snap M 0 - 0 Lc K ;}b/sSU{N/uW ~ |/yUP ~ |/xUP ~ |}b/sU{xUP yUP + +uW sLT}b/sST{N/sW ~ |/ySP ~ |/xSP ~ |}b/sT{xSP ySP sW sLT}b/sR{: + R 0 0 M}b + +/sRxy{: matrix astore concat 0 0 M}b/eR/; , | + + + +/mBF{@ 4 copyfont `/FontName ~ |/OrigFontType ~ |/OrigFontName ~ | 0 + +FontMatrix idtransform ! &/PaintType known{PaintType 0 eq{/PaintType 2 | + +/StrokeWidth ~ |}{PaintType 1 eq PaintType 2 eq or PaintType 3 eq or & + +/StrokeWidth known and{StrokeWidth add/StrokeWidth ~ |}{!}?}?}{!}? @ & E + +definefont Pscript_Windows_Font 3 1 $ put}b/xBF{Pscript_Windows_Font ` 1 ^ + +/FontName get 1 ^ scalefont 3 1 $ scalefont 2 copy ~ | ~ ! | E}b/xMBF{mFM + +astore Pscript_Windows_Font ` 1 ^/FontName get 1 ^ makefont 3 1 $ makefont 2 + +copy ~ | ~ ! | E}b/xBF2{/sB0 ~ mBF/sB1 sB0 3 -1 $ xBF sB1}b/xMBF2{/sB0 ~ mBF + +mFM astore/sB1 sB0 3 -1 $ xMBF sB1}b/sB{: Pscript_Windows_Font currentfont get + +Ji @ S ; S}b/asB{: Pscript_Windows_Font currentfont get Ji 3 copy A ; A}b/wsB{ + +: Pscript_Windows_Font currentfont get Ji 4 copy W ; W}b/awsB{: + +Pscript_Windows_Font currentfont get Ji 6 copy D ; D}b/sBT3{: @ S ; 1 1 -M S}b + +/asBT3{: 3 copy A ; 1 1 -M A}b/wsBT3{: 4 copy W ; 1 1 -M W}b/awsBT3{: 6 copy D + +; 1 1 -M D}b/mIF{iMat 4 3 -1 $ put 2 copyfont `/OrigFontType ~ |/OrigFontName + +~ | @ & E definefont iMat makefont Pscript_Windows_Font 3 1 $ put}b + + + +/SavedCTM null |/CTMsave{/SavedCTM SavedCTM currentmatrix |}b/CTMrestore{ + +SavedCTM setmatrix}b/mp null |/ADO_mxRot null |/GDIHMatrix null | + +/GDIHPatternDict 22 dict | GDIHPatternDict `/PatternType 1 |/PaintType 2 | + +/Reps L2?{1}{5}? |/XStep 8 Reps mul |/YStep XStep |/BBox[0 0 XStep YStep]| + +/TilingType 1 |/PaintProc{` 1 Lw[]0 setdash PaintData , exec E}b/FGnd null | + +/BGnd null |/HS_Horizontal{horiz}b/HS_Vertical{vert}b/HS_FDiagonal{fdiag}b + +/HS_BDiagonal{biag}b/HS_Cross{horiz vert}b/HS_DiagCross{fdiag biag}b/MaxXYStep + +XStep YStep gt{XStep}{YStep}? |/horiz{Reps{0 4 M XStep 0 - 0 8 +}repeat 0 -8 + +Reps mul + K}b/vert{Reps{4 0 M 0 YStep - 8 0 +}repeat 0 -8 Reps mul + K}b/biag + +{Reps{0 0 M MaxXYStep @ - 0 YStep neg M MaxXYStep @ - 0 8 +}repeat 0 -8 Reps + +mul + 0 YStep M 8 8 - K}b/fdiag{Reps{0 0 M MaxXYStep @ neg - 0 YStep M + +MaxXYStep @ neg - 0 8 +}repeat 0 -8 Reps mul + MaxXYStep @ M 8 -8 - K}b E + +/makehatch{GDIHPatternDict/PaintData 3 -1 $ put CTMsave GDIHMatrix setmatrix + +GDIHPatternDict matrix mp CTMrestore ~ U ~ 2 ^ put}b/h0{/h0/HS_Horizontal + +makehatch}b/h1{/h1/HS_Vertical makehatch}b/h2{/h2/HS_FDiagonal makehatch}b/h3{ + +/h3/HS_BDiagonal makehatch}b/h4{/h4/HS_Cross makehatch}b/h5{/h5/HS_DiagCross + +makehatch}b/GDIBWPatternDict 17 dict @ `/PatternType 1 |/PaintType L2?{1}{2}? + +|/RepsV L2?{1}{6}? |/RepsH L2?{1}{5}? |/BBox[0 0 RepsH 1]|/TilingType 1 | + +/XStep 1 |/YStep 1 |/Height 8 RepsV mul |/Width 8 |/mx[Width 0 0 Height neg 0 + +Height]|/FGnd null |/BGnd null |/SetBGndFGnd L2?{{BGnd null ne{BGnd aload ! + +sgco BBox aload ! 2 ^ sub ~ 3 ^ sub ~ rf}if FGnd null ne{FGnd aload ! sgco}if} + +}{{}}? b/PaintProc{` SetBGndFGnd RepsH{Width Height F mx PaintData imagemask + +Width 0 +}repeat E}b E |/GDIBWPatternMx null |/pfprep{save 4 1 $ + +/PatternOfTheDay 4 1 $ GDIBWPatternDict `/PaintData ~ |/BGnd ~ |/FGnd ~ | E + +CTMsave GDIBWPatternMx setmatrix GDIBWPatternDict matrix mp CTMrestore ~ !}b + +/hrf null |/prf{pfprep ~ 6 1 $ 5 hrf restore}b/GraphInit{GDIHMatrix null eq{ + +/SavedCTM matrix | : ADO_mxRot concat 0 0 snap + : 0.48 @ GDIHPatternDict ` + +YStep mul ~ XStep mul ~ dsnap YStep V ~ XStep V ~ E +S/GDIHMatrix matrix + +currentmatrix readonly | ; : 0.24 -0.24 +S GDIBWPatternDict ` Width Height E + +dsnap +S/GDIBWPatternMx matrix currentmatrix readonly | ; ;}if}b/cirp{360 0 An + +C}b/ellp{CTMsave + +S 0.5 0 M 0 0 0.5 360 0 An C CTMrestore}b/rrp{/rad ~ |/y2 + +~ |/x2 ~ |/y1 ~ |/x1 ~ | x2 x1 add 2 V y1 M x1 y1 x1 y2 rad arct x1 y2 x2 y2 + +rad arct x2 y2 x2 y1 rad arct x2 y1 x1 y1 rad arct C}b/RRp{CTMsave + +S/dyS ~ + +|/dxS ~ | dxS 2 V 0 M 0 0 0 dyS 0.5 arct 0 dyS dxS dyS 0.5 arct dxS dyS dxS 0 + +0.5 arct dxS 0 0 0 0.5 arct C CTMrestore}b + + + +L2? not g{/arct{arcto ! ! ! !}b/GDIpattfill{@ ` BGnd null ne PaintType 2 eq + +and{: BGnd aload ! sgco fEOFill{O}{L}? ; FGnd aload ! U/fGray 2 ^ put{2}{4}? + +-1 $}if E @ patterncalc : 4 ^/PaintType get 2 eq{fGray{6 -1 $ sg}{8 -3 $ sco}? + +}if fEOFill{eoclip}{clip}? N patternfill ; N}b/hrf{/fGray 1 ^ 6 eq | -4 $ N rp + +C/fEOFill F | GDIpattfill}b/hfMain{/fEOFill ~ |/fGray ~ | GDIpattfill}b/hf{T + +hfMain}b/hfW{F hfMain}b/hs{currentpoint strokepath M hfW}b/pfMain{/fEOFill ~ | + +pfprep GDIpattfill restore N}b/pf{T pfMain}b/pfW{F pfMain}b/ps{currentpoint + +strokepath M pfW}b/mpstr 1 string |/mp{~ @ length 12 add dict copy ` + +/PatternCTM matrix currentmatrix |/PatternMatrix ~ |/PatWidth XStep mpstr + +length mul |/PatHeight YStep |/FontType 3 |/Encoding 256 array | 3 string 0 1 + +255{Encoding ~ @ 3 ^ cvs cvn put}for !/FontMatrix matrix |/FontBBox BBox | + +/BuildChar{! @ ` XStep 0 FontBBox aload ! setcachedevice/PaintProc , E : exec + +;}b & E ~ @ 3 -1 $ definefont}b/patterncalc{` : PatternCTM setmatrix + +PatternMatrix concat BBox aload ! ! ! + pathbbox ; PatHeight V ceiling 4 1 $ + +PatWidth V ceiling 4 1 $ PatHeight V floor 4 1 $ PatWidth V floor 4 1 $ 2 ^ + +sub cvi abs ~ 3 ^ sub cvi abs ~ 4 2 $ PatHeight mul ~ PatWidth mul ~ E}b + +/patternfill{5 -1 $ @ ` Ji PatternCTM setmatrix PatternMatrix concat 0 2 ^ 2 ^ + +M 0 1 mpstr length 1 sub{1 ^ mpstr 3 1 $ put}for ! 2 ^{currentpoint 5 ^{mpstr + +S}repeat YStep add M}repeat ! ! ! ! E}b}e + + + +L2? g{/mp/makepattern , |/hrf{6 eq setAorABC setpattern rectfill}b/hf{ + +setAorABC setpattern O}b/hfW{setAorABC setpattern L}b/hs{setAorABC setpattern + +K}b/pf{pfprep setpattern O restore N}b/pfW{pfprep setpattern L restore N}b/ps{ + +pfprep setpattern K restore N}b}e + + + +/iw 0 |/ih 0 |/im_save 0 |/s 0 |/polarity 0 |/smoothflag 0 |/mystring 0 |/bpc + +0 |/setup1asciiproc{[currentfile mystring/readhexstring cvx/! cvx]cvx bind}b + +/setup1binaryproc{[currentfile mystring/readstring cvx/! cvx]cvx bind}b + +/setup2asciiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}b + +/setup2binaryproc{currentfile/RunLengthDecode filter}b/mycolorspace{colspABC}| + +/myimagedict{/myimagedict 10 dict | myimagedict @ `/ImageType 1 | + +/MultipleDataSource F | E}b/imageprocarray[/setup1binaryproc/setup1asciiproc + +/setup2binaryproc/setup2asciiproc/setup1binarydecodeproc/setup1asciidecodeproc + +]|/L2Polarity{{[1 0]}{[0 1]}?}b/Q{/im_save save | imageprocarray ~ get/s ~ , | + +L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring ~ + +string |/bpc ~ |/ih ~ |/iw ~ |}b/X{/im_save save | imageprocarray ~ get/s ~ , + +| L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring + +~ string |/bpc ~ |/ih ~ |/iw ~ |}b/Z{im_save restore}b/Y{sgco myimagedict @ ` + +/Width iw |/Height ih |/Decode polarity |/ImageMatrix[iw 0 0 ih 0 0]| + +/DataSource s |/BitsPerComponent 1 |/Interpolate smoothflag | E imagemask}b + + + +L2? not g{/setup2asciiproc{[/Level2ImagesError , aload ! T FatalErrorIf}b + +/setup2binaryproc/setup2asciiproc , |/L2Polarity{}|/Y{sgco iw ih polarity[iw 0 + +0 ih 0 0]s imagemask}b}e + + + +L2? not g{/testsystemdict{where{systemdict eq{T}{F}?}{F}?}b/c 1 |/colorimage + +where{! T}{F}?{/c 0 statusdict `/processcolors where{! ! processcolors}{ + +/deviceinfo where{! deviceinfo/Colors known{!{deviceinfo/Colors get}}if}if}? E + +| c 0 ne{/colorimage testsystemdict/setcolortransfer testsystemdict + +/currentcolortransfer testsystemdict/currentcmykcolor testsystemdict and and + +and not{/c 0 |}if}if}if c @ 1 ne ~ @ 3 ne ~ 4 ne and and{/c 0 |}if c 1 eq g{ + +/expandbw{expandfactor mul round cvi bwclut ~ get 255 V}b/doclutimage{!/bwclut + +~ | bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/expandfactor ~ |[/expandbw ,/exec , @ + +currenttransfer ~]cvx bind settransfer iw ih bpc[iw 0 0 ih 0 0]s image}b}e c @ + +3 eq ~ 4 eq or g{/nullproc{{}}|/concatutil{/exec , 7 -1 $/exec ,}b/defsubclut{ + +1 add getinterval |}b/spconcattransfer{/Dclut ~ |/Cclut ~ |/Bclut ~ |/Aclut ~ + +|/ncompute ~ , | currentcolortransfer[{Aclut ncompute}concatutil]cvx[{Bclut + +ncompute}concatutil]cvx[{Cclut ncompute}concatutil]cvx[{Dclut ncompute} + +concatutil]cvx setcolortransfer}b/setuprgbcluts{/bit3x rgbclut length 3 sub | + +/bit1x bit3x 3 idiv |/rclut rgbclut |/gclut rclut 1 bit3x defsubclut/bclut + +rclut 2 bit3x defsubclut}b}e c 3 eq g{/3compute{~ bit3x mul round cvi get 255 + +V}b/doclutimage{/rgbclut ~ | ! setuprgbcluts/3compute rclut gclut bclut @ + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @]cvx nullproc nullproc + +T 3 colorimage}b}e c 4 eq g{/ftoint{1 ~ sub 255 mul round cvi}b/stuffclut{ + +cmykindex 3 -1 $ put}b/4compute{~ bit4x mul round cvi get 255 V}b + +/invalidcolortable? T |/computecmykclut{setuprgbcluts/bit4x rgbclut length 3 + +idiv 4 mul 4 sub |/cmykclut bit4x 4 add string |/cclut cmykclut |/mclut cclut + +1 bit4x defsubclut/yclut cclut 2 bit4x defsubclut/kclut cclut 3 bit4x + +defsubclut/cmykindex 0 | 0 1 bit1x{@/cmykindex ~ bit1x ~ sub 4 mul | 3 mul @ + +rclut ~ get 255 V ~ @ gclut ~ get 255 V ~ bclut ~ get 255 V setrgbcolor + +currentcmykcolor ftoint kclut stuffclut ftoint yclut stuffclut ftoint mclut + +stuffclut ftoint cclut stuffclut}for}b/doclutimage{/rgbclut ~ | ! + +invalidcolortable?{computecmykclut}if/4compute cclut mclut yclut kclut + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @ @]cvx nullproc + +nullproc nullproc T 4 colorimage}b}e c 0 eq g{/a{3 mul 3 getinterval + +putinterval ~ 3 add ~ 3 copy}b/8lookup/a , |/4lookup{/byte 1 ^ | -4 bitshift a + +byte 15 and a}b/2lookup{/byte 1 ^ | -6 bitshift a byte -4 bitshift 3 and a + +byte -2 bitshift 3 and a byte 3 and a}b/colorexpand{mystringexp 0 rgbclut 3 + +copy 7 -1 $/mylookup , forall ! ! ! ! !}b/createexpandstr{/mystringexp ~ + +mystring length mul string |}b/doclutimage{/rgbclut ~ | !/mylookup bpc 8 eq{3 + +createexpandstr/8lookup}{bpc 4 eq{6 createexpandstr/4lookup}{12 + +createexpandstr/2lookup}?}? , | iw ih bpc[iw 0 0 ih 0 0][s/exec ,/colorexpand + +,/exec ,]cvx F 3 colorimage}b}e/colorimage where{! T}{F}? g{/do24image{iw ih 8 + +[iw 0 0 ih 0 0]s F 3 colorimage}b}DefIf_El{/rgbtogray{/str ~ |/len str length + +|/smlen len 3 idiv |/rstr str |/gstr str 1 len 1 sub getinterval |/bstr str 2 + +len 2 sub getinterval | str @ 0 1 smlen 1 sub{@ 3 mul rstr 1 ^ get 0.3 mul + +gstr 2 ^ get 0.59 mul add bstr 3 -1 $ get 0.11 mul add round cvi put @}for ! 0 + +smlen getinterval}b/do24image{iw ih 8[iw 0 0 ih 0 0][s/exec ,/rgbtogray ,/exec + +,]cvx bind image}b}e/doNimage{bpc 24 eq{do24image}{iw ih bpc[iw 0 0 ih 0 0]s + +image}?}b}e + + + +L2? g{/doclutimage{/rgbclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[ + +/Indexed colspABC hival rgbclut]setcolorspace myimagedict @ `/Width iw | + +/Height ih |/Decode[0 hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s | + +/BitsPerComponent bpc |/Interpolate smoothflag | E image}b/doCMYKclutimage{ + +/CMYKclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[/Indexed/DeviceCMYK + +hival CMYKclut]setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 + +hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent bpc | + +/Interpolate smoothflag | E image}b/doNimage{bpc 24 eq{colspABC}{colspA}? + +setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode bpc 24 eq{[0 1 0 1 + +0 1]}{[0 1]}? |/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent + +bpc 24 eq{8}{bpc}? |/Interpolate smoothflag | E image}b/doCMYKimage{ + +/DeviceCMYK setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 1 0 + +1 0 1 0 1]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent 8 | + +/Interpolate smoothflag | E image}b}e + + + +/GreNewFont{10 dict @ 3 1 $ | @ ` 4 1 $/FontType 3 |/FontMatrix ~ |/FontBBox ~ + +|/Encoding 256 array | 0 1 255{Encoding ~/.notdef put}for/CharProcs 257 dict | + +CharProcs/.notdef{}put/Metrics 257 dict | Metrics/.notdef 3 -1 $ put/BuildChar + +{/char ~ |/fontdict ~ |/charname fontdict/Encoding get char get | fontdict + +/Metrics get charname get aload ! setcachedevice fontdict ` Encoding char get + +CharProcs ~ get E exec}| E definefont !}|/AddChar{` Encoding 3 1 $ put + +CharProcs 3 1 $ put Metrics 3 1 $ put E}| + + + +/FEbuf 2 string |/FEglyph 3 string |/FE{(G00)FEglyph copy ! 1 ~{@ 16 lt{ + +/offset 2 store}{/offset 1 store}? @ 16 FEbuf cvrs FEglyph ~ offset ~ + +putinterval 1 ^ ~ FEglyph cvn put}for}bind |/Type1Hdr{11 dict `/FontName ~ | + +/PaintType ~ |/FontType 1 |/FontMatrix[1 3 ^ V 0 0 1 6 ^ V 0 0]| !/Encoding + +256 array 0 1 255{1 ^ ~/.notdef put}for 3 ^ 3 ^ FE | ! !/FontBBox{0 0 0 0}| & + +E currentfile eexec}bind | + + +/pp 1 string |/ss 1 string |/rledecodebinary{/DC 0 |/BC 0 |{DC mystring length + +ge{exit}if currentfile ss readstring ! 0 get/BC ~ | BC 127 le{/BC BC 1 add | + +DC 1 DC BC add 1 sub{mystring ~ currentfile ss readstring ! 0 get put}for}{/BC + +257 BC sub | currentfile ss readstring ! 0 get/pp ~ | DC 1 DC BC add 1 sub{ + +mystring ~ pp put}for}?/DC DC BC add |}loop mystring}b/rledecodeascii{/DC 0 | + +/BC 0 |{DC mystring length ge{exit}if currentfile ss readhexstring ! 0 get/BC + +~ | BC 127 le{/BC BC 1 add | DC 1 DC BC add 1 sub{mystring ~ currentfile ss + +readhexstring ! 0 get put}for}{/BC 257 BC sub | currentfile ss readhexstring ! + +0 get/pp ~ | DC 1 DC BC add 1 sub{mystring ~ pp put}for}?/DC DC BC add |}loop + +mystring}b/setup1asciidecodeproc{[/rledecodeascii cvx]cvx bind}b + +/setup1binarydecodeproc{[/rledecodebinary cvx]cvx bind}b + + +userdict/Pscript_Win_Compat 13 dict dup begin/bd{bind def}bind def/ld{load def + +}bd/CB{pop pop pop pop}bind def/B{pop pop pop pop}bind def/$x matrix def/SS{ + +/pagesave save def}bind def/RS{/pagesave where{pop pagesave restore}{$x matrix + +invertmatrix concat}ifelse}bind def/ANSIVec[0/grave 1/acute 2/circumflex 3 + +/tilde 4/macron 5/breve 6/dotaccent 7/dieresis 8/ring 9/cedilla 10 + +/hungarumlaut 11/ogonek 12/caron 13/dotlessi 39/quotesingle 96/grave 124/bar + +130/quotesinglbase 131/florin 132/quotedblbase 133/ellipsis 134/dagger 135 + +/daggerdbl 136/circumflex 137/perthousand 138/Scaron 139/guilsinglleft 140/OE + +145/quoteleft 146/quoteright 147/quotedblleft 148/quotedblright 149/bullet 150 + +/endash 151/emdash 152/tilde 153/trademark 154/scaron 155/guilsinglright 156 + +/oe 159/Ydieresis 160/space 161/exclamdown 164/currency 165/yen 166/brokenbar + +167/section 168/dieresis 169/copyright 170/ordfeminine 171/guillemotleft 172 + +/logicalnot 173/hyphen 174/registered 175/macron 176/degree 177/plusminus 178 + +/twosuperior 179/threesuperior 180/acute 181/mu 182/paragraph 183 + +/periodcentered 184/cedilla 185/onesuperior 186/ordmasculine 187 + +/guillemotright 188/onequarter 189/onehalf 190/threequarters 191/questiondown + +192/Agrave 193/Aacute 194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198 + +/AE 199/Ccedilla 200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204 + +/Igrave 205/Iacute 206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve + +211/Oacute 212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash + +217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn 223 + +/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde 228/adieresis 229 + +/aring 230/ae 231/ccedilla 232/egrave 233/eacute 234/ecircumflex 235/edieresis + +236/igrave 237/iacute 238/icircumflex 239/idieresis 240/eth 241/ntilde 242 + +/ograve 243/oacute 244/ocircumflex 245/otilde 246/odieresis 247/divide 248 + +/oslash 249/ugrave 250/uacute 251/ucircumflex 252/udieresis 253/yacute 254 + +/thorn 255/ydieresis]def currentdict{dup type/operatortype eq{[exch]cvx def}{ + +pop pop}ifelse}forall/initialize{currentdict exch begin begin}bind def + +/terminate{/@FL where not{pop end end}{pop}ifelse}bind def/suspend/terminate + +load def/resume/initialize load def/M/moveto load def end put/Courier findfont + +10 scalefont setfont + + +end /ProcSet defineresource pop + + + + + + +Pscript_Win_Compat dup /initialize get exec + +[ 0 1.000 -1.000 0 0 0 ] false /Pscript_Win_Driver /ProcSet findresource dup /initialize get exec + + + + + +/mysetup [ 0.240 0 0 -0.240 7.920 592.800 ] | + + + + + + +userdict begin /pagesave save def end mysetup concat colspRefresh : 1.000 1.000 1.000 sco 0 0 2550 3300 rf ; + + + + + + +116 70 N M 1 1 rr + +116 70 N M 3000 2250 rr : 1.000 1.000 1.000 sco O ; + +116 70 N M 1 1 rr + +116 70 N M 1 1 rr + +134 87 N M 2960 2172 rr 11 Lw 0 Lc 0 Lj solid 0 0 0 sco K + +455 462 N M 2600 1570 rr : 1.000 0.800 0.600 sco O ; + +455 462 N M 2600 0 - 4 Lw 1 Lc 1 Lj solid 0 0 0 sco K + +3055 462 N M 0 1570 - 0 0 0 sco K + +3055 2032 N M -2600 0 - 0 0 0 sco K + +455 2032 N M 0 -1570 - 0 0 0 sco K + +455 1963 N M 40 54 rr : 1.000 1.000 0 sco O ; 0 Lc 0 Lj 0 0 0 sco K + +455 1790 N M 54 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 1613 N M 105 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 1440 N M 115 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 1267 N M 202 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 1090 N M 296 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 917 N M 411 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 744 N M 461 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 567 N M 1229 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +455 1877 N M 65 57 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 1703 N M 97 54 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 1527 N M 151 57 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 1353 N M 155 58 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 1180 N M 393 54 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 1003 N M 440 58 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 830 N M 505 58 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 657 N M 808 54 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 480 N M 2351 58 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +455 462 N M 0 1570 - 1 Lc 1 Lj 0 0 0 sco K + +433 2032 N M 22 0 - 0 0 0 sco K + +433 1858 N M 22 0 - 0 0 0 sco K + +433 1682 N M 22 0 - 0 0 0 sco K + +433 1509 N M 22 0 - 0 0 0 sco K + +433 1335 N M 22 0 - 0 0 0 sco K + +433 1159 N M 22 0 - 0 0 0 sco K + +433 985 N M 22 0 - 0 0 0 sco K + +433 812 N M 22 0 - 0 0 0 sco K + +433 635 N M 22 0 - 0 0 0 sco K + +433 462 N M 22 0 - 0 0 0 sco K : 560 170 2116 150 rc 0.502 0 0 sco %%IncludeFont: Helvetica-Bold + +(F0) cvn + +0.931 + + (Helvetica-Bold) cvn /Type1 + +T + +(Helvetica-Bold) cvn + +mF + +(F0_130) cvn + +F0 + +130 + +xF + +F0_130 + +Ji + +581 170 M + +-3.290 0 (M)A + +-0.710 0 (E)A + +3.570 0 (T)A + +-4.140 0 (I)A + +0.290 0 (S)A + +1.060 0 (')A + +3.140 0 32 -3.280 0 (s )D + +0.290 0 (P)A + +2.720 0 (a)A + +0.430 0 (r)A + +-0.290 0 (t)A + +-4.140 0 (i)A + +0.710 0 (t)A + +-4.140 0 (i)A + +0.570 0 (o)A + +-4.430 0 (n)A + +-3.140 0 (i)A + +-4.430 0 (n)A + +-0.710 0 32 0.570 0 (g )D + +-0.710 0 (P)A + +-0.280 0 (e)A + +0.430 0 (r)A + +3.710 0 (f)A + +-0.430 0 (o)A + +0.430 0 (r)A + +3.430 0 (m)A + +2.720 0 (a)A + +-3.430 0 (n)A + +0.140 0 32 -0.280 0 (ce )D + +; : 498 1959 188 55 rc 0 0 0 sco (F0_47) cvn + +F0 + +47 + +xF + +F0_47 + +Ji + +509 1959 M + +-1.132 0 (1)A + +1.934 0 (.)A + +-1.132 0 (57)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 513 1786 187 55 rc 0 0 0 sco F0_47 + +Ji + +523 1786 M + +-1.132 0 (2)A + +1.934 0 (.)A + +-1.132 0 (10)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 563 1610 188 55 rc 0 0 0 sco F0_47 + +Ji + +574 1610 M + +-1.132 0 (4)A + +1.934 0 (.)A + +-1.132 0 (00)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 574 1436 187 55 rc 0 0 0 sco F0_47 + +Ji + +585 1436 M + +-1.132 0 (4)A + +1.934 0 (.)A + +-1.132 0 (42)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 660 1263 188 55 rc 0 0 0 sco F0_47 + +Ji + +671 1263 M + +-1.132 0 (7)A + +1.934 0 (.)A + +-1.132 0 (79)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 754 1086 213 55 rc 0 0 0 sco F0_47 + +Ji + +765 1086 M + +-1.132 0 (11)A + +1.934 0 (.)A + +-1.132 0 (32)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 870 913 212 55 rc 0 0 0 sco F0_47 + +Ji + +880 913 M + +-1.132 0 (15)A + +1.934 0 (.)A + +-1.132 0 (76)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 920 740 213 55 rc 0 0 0 sco F0_47 + +Ji + +931 740 M + +-1.132 0 (17)A + +1.934 0 (.)A + +-1.132 0 (81)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 1688 563 213 55 rc 0 0 0 sco F0_47 + +Ji + +1699 563 M + +-1.132 0 (47)A + +1.934 0 (.)A + +-1.132 0 (34)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 523 1873 188 55 rc 0 0 0 sco F0_47 + +Ji + +534 1873 M + +-1.132 0 (2)A + +1.934 0 (.)A + +-1.132 0 (55)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 556 1700 187 55 rc 0 0 0 sco F0_47 + +Ji + +567 1700 M + +-1.132 0 (3)A + +1.934 0 (.)A + +-1.132 0 (79)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 610 1527 187 55 rc 0 0 0 sco F0_47 + +Ji + +621 1527 M + +-1.132 0 (5)A + +1.934 0 (.)A + +-1.132 0 (87)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 614 1353 187 55 rc 0 0 0 sco F0_47 + +Ji + +624 1353 M + +-1.132 0 (5)A + +1.934 0 (.)A + +-1.132 0 (96)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 852 1177 212 55 rc 0 0 0 sco F0_47 + +Ji + +862 1177 M + +-1.132 0 (15)A + +1.934 0 (.)A + +-1.132 0 (12)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 898 1000 213 55 rc 0 0 0 sco F0_47 + +Ji + +909 1000 M + +-1.132 0 (16)A + +1.934 0 (.)A + +-1.132 0 (95)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 963 827 213 55 rc 0 0 0 sco F0_47 + +Ji + +974 827 M + +-1.132 0 (19)A + +1.934 0 (.)A + +-1.132 0 (40)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 1266 653 213 55 rc 0 0 0 sco F0_47 + +Ji + +1277 653 M + +-1.132 0 (31)A + +1.934 0 (.)A + +-1.132 0 (11)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 2809 480 213 55 rc 0 0 0 sco F0_47 + +Ji + +2820 480 M + +-1.132 0 (90)A + +1.934 0 (.)A + +-1.132 0 (45)A + +-4.132 0 (s)A + +2.868 0 (e)A + +-1.132 0 (c)A + +; : 116 1905 3000 77 rc 0 0 0 sco %%IncludeFont: Helvetica + +(F3) cvn + +0.899 + + (Helvetica) cvn /Type1 + +T + +(Helvetica) cvn + +mF + +(F3_69) cvn + +F3 + +69 + +xF + +F3_69 + +Ji + +188 1905 M + +0.977 0 (B)A + +-0.977 0 (r)A + +-2.364 0 (a)A + +1.500 0 (c)A + +-2.500 0 (k)A + +1.636 0 (2)A + +; : 116 1729 3000 77 rc 0 0 0 sco F3_69 + +Ji + +199 1729 M + +0.318 0 (O)A + +1.500 0 (c)A + +1.636 0 (e)A + +-2.364 0 (an)A + +; : 159 1555 2957 77 rc 0 0 0 sco F3_69 + +Ji + +282 1555 M + +1.636 0 (1)A + +0.636 0 (4)A + +1.636 0 (4)A + +; : 116 1382 3000 77 rc 0 0 0 sco F3_69 + +Ji + +181 1382 M + +-3.477 0 (M)A + +1.636 0 (d)A + +-2.364 0 (ua)A + +-1.318 0 (l)A + +1.636 0 (1)A + +; : 144 1205 2972 77 rc 0 0 0 sco F3_69 + +Ji + +267 1205 M + +0.841 0 (T)A + +-0.977 0 (r)A + +1.636 0 (o)A + +-1.318 0 (ll)A + +; : 137 1032 2979 77 rc 0 0 0 sco F3_69 + +Ji + +260 1032 M + +0.977 0 (A)A + +-2.364 0 (u)A + +-1.182 0 (t)A + +1.636 0 (o)A + +; : 116 859 3000 77 rc 0 0 0 sco F3_69 + +Ji + +181 859 M + +-3.477 0 (M)A + +1.636 0 (d)A + +-2.364 0 (ua)A + +-1.318 0 (l)A + +1.636 0 (2)A + +; : 177 682 2939 77 rc 0 0 0 sco F3_69 + +Ji + +300 682 M + +0.977 0 (B)A + +-1.318 0 (i)A + +1.636 0 (g)A + +; : 116 509 3000 77 rc 0 0 0 sco F3_69 + +Ji + +181 509 M + +-3.477 0 (M)A + +1.636 0 (d)A + +-2.364 0 (ua)A + +-1.318 0 (l)A + +1.636 0 (3)A + +; + +729 2075 N M 2044 133 rr : 1.000 1.000 1.000 sco O ; 0 Lc 0 Lj 0 0 0 sco K + +758 2118 N M 54 54 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K : 729 2097 2048 100 rc 0 0 0 sco (F0_87) cvn + +F0 + +87 + +xF + +F0_87 + +Ji + +837 2097 M + +3.529 0 (M)A + +0.814 0 (I)A + +-0.029 0 (P)A + +2.843 0 32 -1.029 0 (S )D + +-1.814 0 (R)A + +-1.372 0 (100)A + +-2.372 0 (0)A + +-1.372 0 (0)A + +-1.825 0 (@)A + +-1.372 0 (200)A + +3.529 0 (M)A + +-1.814 0 (H)A + +-0.500 0 (z)A + +; + +1818 2118 N M 54 54 rr : 0 0 1.000 sco O ; 0 0 0 sco K : 1789 2097 988 100 rc 0 0 0 sco F0_87 + +Ji + +1897 2097 M + +0.814 0 (I)A + +0.843 0 (n)A + +0.029 0 (t)A + +-1.372 0 (e)A + +1.000 0 32 0.814 0 (l )D + +-1.029 0 (P)A + +-0.029 0 (P)A + +-1.814 0 (R)A + +-2.686 0 (O)A + +-1.825 0 (@)A + +-1.372 0 (200)A + +2.529 0 (M)A + +-0.814 0 (H)A + +-0.500 0 (z)A + +; + +1721 889 N M 350 42 rr : 0.502 0 0 sco O ; + +1721 931 N M 350 69 rr : 0.502 0 0 sco O ; + +1721 1000 N M 350 43 rr : 0.502 0 0 sco O ; + +2071 889 N M 430 77 rr : 0.502 0 0 sco O ; : 1697 889 1319 1131 rc 1.000 1.000 1.000 sco %%IncludeFont: Helvetica-BoldOblique + +(F6) cvn + +0.909 + + (Helvetica-BoldOblique) cvn /Type1 + +T + +(Helvetica-BoldOblique) cvn + +mF + +(F6_66) cvn + +F6 + +66 + +xF + +F6_66 + +Ji + +2121 891 M + +0.348 0 (N)A + +-0.326 0 (u)A + +-0.674 0 (m)A + +0.674 0 (b)A + +-0.696 0 (e)A + +-0.674 0 32 0.326 0 (r )D + +-0.326 0 (o)A + +0.022 0 (f)A + +; + +2071 966 N M 430 77 rr : 0.502 0 0 sco O ; : 1697 889 1319 1131 rc 1.000 1.000 1.000 sco F6_66 + +Ji + +2159 967 M + +-0.022 0 (V)A + +-0.696 0 (e)A + +-0.674 0 (r)A + +0.022 0 (t)A + +0.652 0 (i)A + +0.304 0 (c)A + +-0.696 0 (e)A + +0.304 0 (s)A + +; + +2501 889 N M 431 77 rr : 0.502 0 0 sco O ; : 1697 889 1319 1131 rc 1.000 1.000 1.000 sco F6_66 + +Ji + +2551 891 M + +0.348 0 (N)A + +-0.326 0 (u)A + +-0.674 0 (m)A + +0.674 0 (b)A + +-0.696 0 (e)A + +-0.674 0 32 0.326 0 (r )D + +-0.326 0 (o)A + +0.022 0 (f)A + +; + +2501 966 N M 431 77 rr : 0.502 0 0 sco O ; : 1697 889 1319 1131 rc 1.000 1.000 1.000 sco F6_66 + +Ji + +2618 967 M + +-0.022 0 (E)A + +-0.326 0 (dg)A + +0.304 0 (e)A + +-0.696 0 (s)A + +; + +1721 1047 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1063 N M 350 68 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco (F0_60) cvn + +F0 + +60 + +xF + +F0_60 + +Ji + +1738 1061 M + +0.020 0 (M)A + +-0.660 0 (d)A + +0.340 0 (u)A + +-0.360 0 (a)A + +-0.680 0 (l)A + +-0.360 0 (3)A + +; + +1721 1131 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1047 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1063 N M 430 68 rr : 1.000 1.000 0.800 sco O ; : 2071 1043 430 88 rc 0.004 0 0 sco (F3_60) cvn + +F3 + +60 + +xF + +F3_60 + +Ji + +2219 1065 M + +-0.360 0 (4)A + +0.320 0 (,)A + +-0.360 0 (039)A + +-0.680 0 (,)A + +0.640 0 (1)A + +-0.360 0 (60)A + +; + +2071 1131 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1047 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1063 N M 431 68 rr : 1.000 1.000 0.800 sco O ; : 2501 1043 431 88 rc 0.004 0 0 sco F3_60 + +Ji + +2649 1065 M + +-0.360 0 (8)A + +0.320 0 (,)A + +-0.360 0 (016)A + +-0.680 0 (,)A + +0.640 0 (8)A + +-0.360 0 (48)A + +; + +2501 1131 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1043 N M 350 4 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +1721 1043 N M 350 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2071 1043 N M 4 4 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2071 1043 N M 4 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1697 889 1319 1131 rc + +2071 1043 N M 0 4 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2075 1043 N M 426 4 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2075 1043 N M 426 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2501 1043 N M 5 4 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2501 1043 N M 5 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1697 889 1319 1131 rc + +2501 1043 N M 0 4 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2506 1043 N M 426 4 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2506 1043 N M 426 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +1721 1147 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1163 N M 350 68 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1161 M + +-0.320 0 (B)A + +-0.680 0 (i)A + +0.340 0 (g)A + +; + +1721 1231 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1147 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1163 N M 430 68 rr : 1.000 1.000 0.800 sco O ; : 2071 1147 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2269 1165 M + +-0.360 0 (2)A + +0.640 0 (9)A + +-0.360 0 (5)A + +-0.680 0 (,)A + +-0.360 0 (433)A + +; + +2071 1231 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1147 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1163 N M 431 68 rr : 1.000 1.000 0.800 sco O ; : 2501 1147 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2649 1165 M + +-0.360 0 (7)A + +0.320 0 (,)A + +-0.360 0 (953)A + +-0.680 0 (,)A + +0.640 0 (4)A + +-0.360 0 (53)A + +; + +2501 1231 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1247 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1263 N M 350 68 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1261 M + +0.020 0 (M)A + +-0.660 0 (d)A + +0.340 0 (u)A + +-0.360 0 (a)A + +-0.680 0 (l)A + +-0.360 0 (2)A + +; + +1721 1331 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1247 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1263 N M 430 68 rr : 1.000 1.000 0.800 sco O ; : 2071 1247 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2219 1265 M + +-0.360 0 (1)A + +0.320 0 (,)A + +-0.360 0 (017)A + +-0.680 0 (,)A + +0.640 0 (2)A + +-0.360 0 (53)A + +; + +2071 1331 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1247 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1263 N M 431 68 rr : 1.000 1.000 0.800 sco O ; : 2501 1247 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2649 1265 M + +-0.360 0 (2)A + +0.320 0 (,)A + +-0.360 0 (015)A + +-0.680 0 (,)A + +0.640 0 (7)A + +-0.360 0 (14)A + +; + +2501 1331 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1347 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1363 N M 350 68 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1361 M + +-1.320 0 (A)A + +-0.660 0 (u)A + +0.020 0 (t)A + +0.340 0 (o)A + +; + +1721 1431 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1347 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1363 N M 430 68 rr : 1.000 1.000 0.800 sco O ; : 2071 1347 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2269 1365 M + +-0.360 0 (4)A + +0.640 0 (4)A + +-0.360 0 (8)A + +-0.680 0 (,)A + +-0.360 0 (695)A + +; + +2071 1431 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1347 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1363 N M 431 68 rr : 1.000 1.000 0.800 sco O ; : 2501 1347 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2649 1365 M + +-0.360 0 (3)A + +0.320 0 (,)A + +-0.360 0 (314)A + +-0.680 0 (,)A + +0.640 0 (6)A + +-0.360 0 (11)A + +; + +2501 1431 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1447 N M 350 15 rr : 1.000 1.000 0.800 sco O ; + +1721 1462 N M 350 69 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1461 M + +-0.660 0 (T)A + +-0.340 0 (r)A + +0.340 0 (o)A + +-0.680 0 (l)A + +0.320 0 (l)A + +; + +1721 1531 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1447 N M 430 15 rr : 1.000 1.000 0.800 sco O ; + +2071 1462 N M 430 69 rr : 1.000 1.000 0.800 sco O ; : 2071 1447 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2269 1465 M + +-0.360 0 (2)A + +0.640 0 (1)A + +-0.360 0 (3)A + +-0.680 0 (,)A + +-0.360 0 (453)A + +; + +2071 1531 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1447 N M 431 15 rr : 1.000 1.000 0.800 sco O ; + +2501 1462 N M 431 69 rr : 1.000 1.000 0.800 sco O ; : 2501 1447 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2649 1465 M + +-0.360 0 (5)A + +0.320 0 (,)A + +-0.360 0 (885)A + +-0.680 0 (,)A + +0.640 0 (8)A + +-0.360 0 (29)A + +; + +2501 1531 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1547 N M 350 15 rr : 1.000 1.000 0.800 sco O ; + +1721 1562 N M 350 69 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1561 M + +0.020 0 (M)A + +-0.660 0 (d)A + +0.340 0 (u)A + +-0.360 0 (a)A + +-0.680 0 (l)A + +-0.360 0 (1)A + +; + +1721 1631 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1547 N M 430 15 rr : 1.000 1.000 0.800 sco O ; + +2071 1562 N M 430 69 rr : 1.000 1.000 0.800 sco O ; : 2071 1547 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2269 1565 M + +-0.360 0 (2)A + +0.640 0 (5)A + +-0.360 0 (7)A + +-0.680 0 (,)A + +-0.360 0 (000)A + +; + +2071 1631 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1547 N M 431 15 rr : 1.000 1.000 0.800 sco O ; + +2501 1562 N M 431 69 rr : 1.000 1.000 0.800 sco O ; : 2501 1547 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2699 1565 M + +-0.360 0 (5)A + +0.640 0 (0)A + +-0.360 0 (5)A + +-0.680 0 (,)A + +-0.360 0 (048)A + +; + +2501 1631 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1647 N M 350 15 rr : 1.000 1.000 0.800 sco O ; + +1721 1662 N M 350 69 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1661 M + +-0.360 0 (1)A + +0.640 0 (4)A + +-0.360 0 (4)A + +; + +1721 1731 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1647 N M 430 15 rr : 1.000 1.000 0.800 sco O ; + +2071 1662 N M 430 69 rr : 1.000 1.000 0.800 sco O ; : 2071 1647 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2269 1665 M + +-0.360 0 (1)A + +0.640 0 (4)A + +-0.360 0 (4)A + +-0.680 0 (,)A + +-0.360 0 (649)A + +; + +2071 1731 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1647 N M 431 15 rr : 1.000 1.000 0.800 sco O ; + +2501 1662 N M 431 69 rr : 1.000 1.000 0.800 sco O ; : 2501 1647 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2649 1665 M + +-0.360 0 (1)A + +0.320 0 (,)A + +-0.360 0 (074)A + +-0.680 0 (,)A + +0.640 0 (3)A + +-0.360 0 (93)A + +; + +2501 1731 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1747 N M 350 15 rr : 1.000 1.000 0.800 sco O ; + +1721 1762 N M 350 69 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1761 M + +-0.680 0 (O)A + +-0.360 0 (ce)A + +0.640 0 (a)A + +-0.660 0 (n)A + +; + +1721 1831 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1747 N M 430 15 rr : 1.000 1.000 0.800 sco O ; + +2071 1762 N M 430 69 rr : 1.000 1.000 0.800 sco O ; : 2071 1747 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2269 1765 M + +-0.360 0 (1)A + +0.640 0 (4)A + +-0.360 0 (3)A + +-0.680 0 (,)A + +-0.360 0 (437)A + +; + +2071 1831 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1747 N M 431 15 rr : 1.000 1.000 0.800 sco O ; + +2501 1762 N M 431 69 rr : 1.000 1.000 0.800 sco O ; : 2501 1747 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2699 1765 M + +-0.360 0 (4)A + +0.640 0 (0)A + +-0.360 0 (9)A + +-0.680 0 (,)A + +-0.360 0 (593)A + +; + +2501 1831 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1847 N M 350 15 rr : 1.000 1.000 0.800 sco O ; + +1721 1862 N M 350 69 rr : 1.000 1.000 0.800 sco O ; : 1697 889 1319 1131 rc 0.004 0 0 sco F0_60 + +Ji + +1738 1861 M + +-0.320 0 (B)A + +-0.340 0 (r)A + +-0.360 0 (ack)A + +0.640 0 (2)A + +; + +1721 1931 N M 350 16 rr : 1.000 1.000 0.800 sco O ; + +2071 1847 N M 430 15 rr : 1.000 1.000 0.800 sco O ; + +2071 1862 N M 430 69 rr : 1.000 1.000 0.800 sco O ; : 2071 1847 430 84 rc 0.004 0 0 sco F3_60 + +Ji + +2302 1865 M + +-0.360 0 (6)A + +0.640 0 (2)A + +-0.680 0 (,)A + +-0.360 0 (631)A + +; + +2071 1931 N M 430 16 rr : 1.000 1.000 0.800 sco O ; + +2501 1847 N M 431 15 rr : 1.000 1.000 0.800 sco O ; + +2501 1862 N M 431 69 rr : 1.000 1.000 0.800 sco O ; : 2501 1847 431 84 rc 0.004 0 0 sco F3_60 + +Ji + +2699 1865 M + +-0.360 0 (3)A + +0.640 0 (6)A + +-0.360 0 (6)A + +-0.680 0 (,)A + +-0.360 0 (559)A + +; + +2501 1931 N M 431 16 rr : 1.000 1.000 0.800 sco O ; + +1721 1947 N M 350 5 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +1721 1947 N M 350 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2071 1947 N M 4 5 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2071 1947 N M 4 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1697 889 1319 1131 rc + +2071 1947 N M 0 5 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2075 1947 N M 426 5 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2075 1947 N M 426 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2501 1947 N M 5 5 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2501 1947 N M 5 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1697 889 1319 1131 rc + +2501 1947 N M 0 5 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2506 1947 N M 426 5 rr : 0 0 0 sco O ; : 1697 889 1319 1131 rc + +2506 1947 N M 426 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +LH + +pagesave restore + + + + + + + +/Pscript_Win_Driver /ProcSet findresource dup /terminate get exec + +Pscript_Win_Compat dup /terminate get exec + + +cleartomark +countdictstack exch sub { end } repeat +restore grestore +% +% End Imported PIC File: slide1.eps +% +% Polyline +% +% Begin Imported EPS File: slide2.eps +% +n gs +525 9750 tr +16.980000 -16.972921 sc +0 -517 tr +-39 -55 tr +sa +n 39 55 m 739 55 l 739 572 l 39 572 l cp clip +countdictstack +mark +/showpage {} def +% EPS file follows: + + + + + + + + + + + + + + +/defineresource where{pop}{userdict begin/defineresource{userdict/Resources 2 + +copy known{get begin}{15 dict dup begin put}ifelse exch readonly exch + +currentdict 1 index known not{dup 30 dict def}if load 3 -1 roll 2 index put + +end}bind readonly def/findresource{userdict/Resources get exch get exch get} + +bind readonly def/resourceforall{pop pop pop pop}bind readonly def + +/resourcestatus{userdict/Resources 2 copy known{get exch 2 copy known{get exch + +known{0 -1 true}{pop pop false}ifelse}{pop pop pop false}ifelse}{pop pop false + +}ifelse}bind readonly def end}ifelse + + + +/Pscript_Win_Driver 200 dict dup begin + + +/FatalErrorIf{{initgraphics findfont exch scalefont setfont counttomark 3 div + +cvi{moveto show}repeat showpage quit}{cleartomark}ifelse}bind def + + +/VM? {vmstatus exch sub exch pop gt { [ + +(This job requires more memory than is available in this printer.) 100 500 + +(Try one or more of the following, and then print again:) 100 485 + +(In the PostScript dialog box, click Optimize For Portability.) 115 470 + +(In the Device Options dialog box, make sure the Available Printer Memory is accurate.) 115 455 + +(Reduce the number of fonts in the document.) 115 440 + +(Print the document in parts.) 115 425 + +12 /Times-Roman showpage + +(%%[ PrinterError: Low Printer VM ]%%) = + +true FatalErrorIf}if} bind def + + +/|/def load def/,/load load |/~/exch , |/?/ifelse , |/!/pop , |/`/begin , |/^ + +/index , |/@/dup , |/+/translate , |/$/roll , |/U/userdict , |/M/moveto , |/- + +/rlineto , |/&/currentdict , |/:/gsave , |/;/grestore , |/F/false , |/T/true , + +|/N/newpath , |/E/end , |/Ac/arc , |/An/arcn , |/A/ashow , |/D/awidthshow , | + +/C/closepath , |/V/div , |/O/eofill , |/L/fill , |/I/lineto , |/-C/rcurveto , + +|/-M/rmoveto , |/+S/scale , |/Ji/setfont , |/Lc/setlinecap , |/Lj/setlinejoin + +, |/Lw/setlinewidth , |/S/show , |/LH/showpage , |/K/stroke , |/W/widthshow , + +|/R/rotate , |/b{bind |}bind |/bd{bind |}bind |/xd{~ |}bd/ld{, |}bd/lw/Lw ld + +/lc/Lc ld/lj/Lj ld/sg/setgray ld/L2? F/languagelevel where{! languagelevel 2 + +ge{! T}if}if |/g{@ not{U/DefIf_save save put}if U/DefIf_bool 2 ^ put}b + +/DefIf_El{if U/DefIf_bool get not @{U/DefIf_save get restore}if}b/e{DefIf_El ! + +}b/self & |/reinitialize{[/TextInit/GraphInit/UtilsInit counttomark{@ where{ + +self eq}{F}?{cvx exec}{!}?}repeat cleartomark}b/initialize{`{/ADO_mxRot ~ | + +/TextInitialised? F | reinitialize E}{U/Pscript_Win_Data 200 dict @ ` put + +/ADO_mxRot ~ |/TextInitialised? F | reinitialize}?}b/terminate{!{& self eq{ + +exit}{E}?}loop E}b/suspend/terminate , |/resume{` Pscript_Win_Data `}b/snap{ + +transform 0.25 sub round 0.25 add ~ 0.25 sub round 0.25 add ~ itransform}b + +/dsnap{dtransform round ~ round ~ idtransform}b<04>cvn{}|/setjn{{statusdict + +/jobname known{statusdict/jobname 3 -1 $ put}if}stopped cleartomark}b/solid{[] + +0 setdash}b/setdsh{0 setdash}b/colspRefresh{}b/rp{4 2 $ M 1 ^ 0 - 0 ~ - neg 0 + +-}b/rr{1 ^ 0 - 0 ~ - neg 0 - C}b + + + +L2? not g{/rf{N rp L}b/fx{1 1 dtransform @ 0 ge{1 sub 1}{1 add -0.25}? 3 -1 $ + +@ 0 ge{1 sub 1}{1 add -0.25}? 3 1 $ 4 1 $ idtransform 4 -2 $ idtransform}b/BZ{ + +4 -2 $ snap + +S fx rf}b/rs{N rp C K}b/rc{N rp clip N}b/sg{setgray}b/sco{ + +setrgbcolor}b/sgco{{sg}{sco}?}b}e + + + +L2? g{/colspA/DeviceGray |/colspABC/DeviceRGB |/setAorABC{{colspA}{colspABC}? + +setcolorspace}b/rf/rectfill , |/fx{1 1 dtransform @ 0 ge{1 sub 0.5}{1 add -0.5 + +}? 3 -1 $ @ 0 ge{1 sub 0.5}{1 add -0.5}? 3 1 $ 4 1 $ idtransform 4 -2 $ + +idtransform}b/BZ{4 -2 $ snap + +S fx rf}b/rs/rectstroke , |/rc/rectclip , |/sg + +{@ @ setcolor}b/sco{setcolor}b/colspRefresh{colspABC setcolorspace}b/sgco{{sg + +}{sco}?}b/UtilsInit{F setglobal}b/definecolorrendering{/ColorRendering + +defineresource !}b/findcolorrendering{@/ColorRendering resourcestatus{! ! + +/ColorRendering findresource T}{! F}?}b/selectcolorrendering{@/ColorRendering + +resourcestatus{! !/ColorRendering}{!/DefaultColorRendering/ColorRendering}? + +findresource setcolorrendering}b}e + + + +/bullets{{/bullet}repeat}b/ANSIEncoding[/grave/acute/circumflex/tilde/macron + +/breve/dotaccent/dieresis/ring/cedilla/hungarumlaut/ogonek/caron/dotlessi 18 + +bullets StandardEncoding 32 95 getinterval aload ! 3 bullets/quotesinglbase + +/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron + +/guilsinglleft/OE 4 bullets/quoteleft/quoteright/quotedblleft/quotedblright + +/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe 2 bullets + +/Ydieresis/space/exclamdown/cent/sterling/currency/yen/brokenbar/section + +/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered + +/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph + +/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter + +/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis + +/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute + +/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis + +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls + +/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute + +/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve + +/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex + +/udieresis/yacute/thorn/ydieresis]| ANSIEncoding @ 39/quotesingle put 96/grave + +put/ANSIEncodingOld ANSIEncoding 256 array copy | ANSIEncodingOld @[138 153 + +154 169 172 174 177 178 179 181 185 188 189 190 208 215 221 222 240 247 253 + +254]{/bullet put @}forall 166/bar put 176/ring put + + + +/TextInit{TextInitialised? not{/Pscript_Windows_Font & |/TextInitialised? T | + +/fM[1 0 0 -1 0 0]|/mFM matrix |/iMat[1 0 0.212557 neg 1 0 0]|}if}b/xUP null | + +/yUP null |/uW null |/xSP null |/ySP null |/sW null |/copyfont{1 ^ length add + +dict `{1 ^/FID ne{|}{! !}?}forall & E}b/rF{3 copyfont @ `/Encoding + +ANSIEncoding &/CharStrings known{CharStrings/Eth known not{! ANSIEncodingOld} + +if}if | E}b/mF{findfont ~{@/Encoding get @ StandardEncoding eq{! T}{{ + +ISOLatin1Encoding}stopped{! F}{eq}?{T}{@ ` T 32 1 127{Encoding 1 ^ get + +StandardEncoding 3 -1 $ get eq and}for E}?}?}{F}?{rF}{3 copyfont}? ` + +/OrigFontType ~ |/OrigFontName ~ | & E 2 ^ ~ definefont fM 5 4 -1 $ put fM 4 0 + +put fM makefont Pscript_Windows_Font 3 1 $ put}b/xF{scalefont + +Pscript_Windows_Font 3 1 $ put}b/xMF{mFM astore makefont Pscript_Windows_Font + +3 1 $ put}b/xF2/scalefont , |/xMF2{mFM astore makefont}b/sLT{: Lw -M + +currentpoint snap M 0 - 0 Lc K ;}b/sSU{N/uW ~ |/yUP ~ |/xUP ~ |}b/sU{xUP yUP + +uW sLT}b/sST{N/sW ~ |/ySP ~ |/xSP ~ |}b/sT{xSP ySP sW sLT}b/sR{: + R 0 0 M}b + +/sRxy{: matrix astore concat 0 0 M}b/eR/; , | + + + +/mBF{@ 4 copyfont `/FontName ~ |/OrigFontType ~ |/OrigFontName ~ | 0 + +FontMatrix idtransform ! &/PaintType known{PaintType 0 eq{/PaintType 2 | + +/StrokeWidth ~ |}{PaintType 1 eq PaintType 2 eq or PaintType 3 eq or & + +/StrokeWidth known and{StrokeWidth add/StrokeWidth ~ |}{!}?}?}{!}? @ & E + +definefont Pscript_Windows_Font 3 1 $ put}b/xBF{Pscript_Windows_Font ` 1 ^ + +/FontName get 1 ^ scalefont 3 1 $ scalefont 2 copy ~ | ~ ! | E}b/xMBF{mFM + +astore Pscript_Windows_Font ` 1 ^/FontName get 1 ^ makefont 3 1 $ makefont 2 + +copy ~ | ~ ! | E}b/xBF2{/sB0 ~ mBF/sB1 sB0 3 -1 $ xBF sB1}b/xMBF2{/sB0 ~ mBF + +mFM astore/sB1 sB0 3 -1 $ xMBF sB1}b/sB{: Pscript_Windows_Font currentfont get + +Ji @ S ; S}b/asB{: Pscript_Windows_Font currentfont get Ji 3 copy A ; A}b/wsB{ + +: Pscript_Windows_Font currentfont get Ji 4 copy W ; W}b/awsB{: + +Pscript_Windows_Font currentfont get Ji 6 copy D ; D}b/sBT3{: @ S ; 1 1 -M S}b + +/asBT3{: 3 copy A ; 1 1 -M A}b/wsBT3{: 4 copy W ; 1 1 -M W}b/awsBT3{: 6 copy D + +; 1 1 -M D}b/mIF{iMat 4 3 -1 $ put 2 copyfont `/OrigFontType ~ |/OrigFontName + +~ | @ & E definefont iMat makefont Pscript_Windows_Font 3 1 $ put}b + + + +/SavedCTM null |/CTMsave{/SavedCTM SavedCTM currentmatrix |}b/CTMrestore{ + +SavedCTM setmatrix}b/mp null |/ADO_mxRot null |/GDIHMatrix null | + +/GDIHPatternDict 22 dict | GDIHPatternDict `/PatternType 1 |/PaintType 2 | + +/Reps L2?{1}{5}? |/XStep 8 Reps mul |/YStep XStep |/BBox[0 0 XStep YStep]| + +/TilingType 1 |/PaintProc{` 1 Lw[]0 setdash PaintData , exec E}b/FGnd null | + +/BGnd null |/HS_Horizontal{horiz}b/HS_Vertical{vert}b/HS_FDiagonal{fdiag}b + +/HS_BDiagonal{biag}b/HS_Cross{horiz vert}b/HS_DiagCross{fdiag biag}b/MaxXYStep + +XStep YStep gt{XStep}{YStep}? |/horiz{Reps{0 4 M XStep 0 - 0 8 +}repeat 0 -8 + +Reps mul + K}b/vert{Reps{4 0 M 0 YStep - 8 0 +}repeat 0 -8 Reps mul + K}b/biag + +{Reps{0 0 M MaxXYStep @ - 0 YStep neg M MaxXYStep @ - 0 8 +}repeat 0 -8 Reps + +mul + 0 YStep M 8 8 - K}b/fdiag{Reps{0 0 M MaxXYStep @ neg - 0 YStep M + +MaxXYStep @ neg - 0 8 +}repeat 0 -8 Reps mul + MaxXYStep @ M 8 -8 - K}b E + +/makehatch{GDIHPatternDict/PaintData 3 -1 $ put CTMsave GDIHMatrix setmatrix + +GDIHPatternDict matrix mp CTMrestore ~ U ~ 2 ^ put}b/h0{/h0/HS_Horizontal + +makehatch}b/h1{/h1/HS_Vertical makehatch}b/h2{/h2/HS_FDiagonal makehatch}b/h3{ + +/h3/HS_BDiagonal makehatch}b/h4{/h4/HS_Cross makehatch}b/h5{/h5/HS_DiagCross + +makehatch}b/GDIBWPatternDict 17 dict @ `/PatternType 1 |/PaintType L2?{1}{2}? + +|/RepsV L2?{1}{6}? |/RepsH L2?{1}{5}? |/BBox[0 0 RepsH 1]|/TilingType 1 | + +/XStep 1 |/YStep 1 |/Height 8 RepsV mul |/Width 8 |/mx[Width 0 0 Height neg 0 + +Height]|/FGnd null |/BGnd null |/SetBGndFGnd L2?{{BGnd null ne{BGnd aload ! + +sgco BBox aload ! 2 ^ sub ~ 3 ^ sub ~ rf}if FGnd null ne{FGnd aload ! sgco}if} + +}{{}}? b/PaintProc{` SetBGndFGnd RepsH{Width Height F mx PaintData imagemask + +Width 0 +}repeat E}b E |/GDIBWPatternMx null |/pfprep{save 4 1 $ + +/PatternOfTheDay 4 1 $ GDIBWPatternDict `/PaintData ~ |/BGnd ~ |/FGnd ~ | E + +CTMsave GDIBWPatternMx setmatrix GDIBWPatternDict matrix mp CTMrestore ~ !}b + +/hrf null |/prf{pfprep ~ 6 1 $ 5 hrf restore}b/GraphInit{GDIHMatrix null eq{ + +/SavedCTM matrix | : ADO_mxRot concat 0 0 snap + : 0.48 @ GDIHPatternDict ` + +YStep mul ~ XStep mul ~ dsnap YStep V ~ XStep V ~ E +S/GDIHMatrix matrix + +currentmatrix readonly | ; : 0.24 -0.24 +S GDIBWPatternDict ` Width Height E + +dsnap +S/GDIBWPatternMx matrix currentmatrix readonly | ; ;}if}b/cirp{360 0 An + +C}b/ellp{CTMsave + +S 0.5 0 M 0 0 0.5 360 0 An C CTMrestore}b/rrp{/rad ~ |/y2 + +~ |/x2 ~ |/y1 ~ |/x1 ~ | x2 x1 add 2 V y1 M x1 y1 x1 y2 rad arct x1 y2 x2 y2 + +rad arct x2 y2 x2 y1 rad arct x2 y1 x1 y1 rad arct C}b/RRp{CTMsave + +S/dyS ~ + +|/dxS ~ | dxS 2 V 0 M 0 0 0 dyS 0.5 arct 0 dyS dxS dyS 0.5 arct dxS dyS dxS 0 + +0.5 arct dxS 0 0 0 0.5 arct C CTMrestore}b + + + +L2? not g{/arct{arcto ! ! ! !}b/GDIpattfill{@ ` BGnd null ne PaintType 2 eq + +and{: BGnd aload ! sgco fEOFill{O}{L}? ; FGnd aload ! U/fGray 2 ^ put{2}{4}? + +-1 $}if E @ patterncalc : 4 ^/PaintType get 2 eq{fGray{6 -1 $ sg}{8 -3 $ sco}? + +}if fEOFill{eoclip}{clip}? N patternfill ; N}b/hrf{/fGray 1 ^ 6 eq | -4 $ N rp + +C/fEOFill F | GDIpattfill}b/hfMain{/fEOFill ~ |/fGray ~ | GDIpattfill}b/hf{T + +hfMain}b/hfW{F hfMain}b/hs{currentpoint strokepath M hfW}b/pfMain{/fEOFill ~ | + +pfprep GDIpattfill restore N}b/pf{T pfMain}b/pfW{F pfMain}b/ps{currentpoint + +strokepath M pfW}b/mpstr 1 string |/mp{~ @ length 12 add dict copy ` + +/PatternCTM matrix currentmatrix |/PatternMatrix ~ |/PatWidth XStep mpstr + +length mul |/PatHeight YStep |/FontType 3 |/Encoding 256 array | 3 string 0 1 + +255{Encoding ~ @ 3 ^ cvs cvn put}for !/FontMatrix matrix |/FontBBox BBox | + +/BuildChar{! @ ` XStep 0 FontBBox aload ! setcachedevice/PaintProc , E : exec + +;}b & E ~ @ 3 -1 $ definefont}b/patterncalc{` : PatternCTM setmatrix + +PatternMatrix concat BBox aload ! ! ! + pathbbox ; PatHeight V ceiling 4 1 $ + +PatWidth V ceiling 4 1 $ PatHeight V floor 4 1 $ PatWidth V floor 4 1 $ 2 ^ + +sub cvi abs ~ 3 ^ sub cvi abs ~ 4 2 $ PatHeight mul ~ PatWidth mul ~ E}b + +/patternfill{5 -1 $ @ ` Ji PatternCTM setmatrix PatternMatrix concat 0 2 ^ 2 ^ + +M 0 1 mpstr length 1 sub{1 ^ mpstr 3 1 $ put}for ! 2 ^{currentpoint 5 ^{mpstr + +S}repeat YStep add M}repeat ! ! ! ! E}b}e + + + +L2? g{/mp/makepattern , |/hrf{6 eq setAorABC setpattern rectfill}b/hf{ + +setAorABC setpattern O}b/hfW{setAorABC setpattern L}b/hs{setAorABC setpattern + +K}b/pf{pfprep setpattern O restore N}b/pfW{pfprep setpattern L restore N}b/ps{ + +pfprep setpattern K restore N}b}e + + + +/iw 0 |/ih 0 |/im_save 0 |/s 0 |/polarity 0 |/smoothflag 0 |/mystring 0 |/bpc + +0 |/setup1asciiproc{[currentfile mystring/readhexstring cvx/! cvx]cvx bind}b + +/setup1binaryproc{[currentfile mystring/readstring cvx/! cvx]cvx bind}b + +/setup2asciiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}b + +/setup2binaryproc{currentfile/RunLengthDecode filter}b/mycolorspace{colspABC}| + +/myimagedict{/myimagedict 10 dict | myimagedict @ `/ImageType 1 | + +/MultipleDataSource F | E}b/imageprocarray[/setup1binaryproc/setup1asciiproc + +/setup2binaryproc/setup2asciiproc/setup1binarydecodeproc/setup1asciidecodeproc + +]|/L2Polarity{{[1 0]}{[0 1]}?}b/Q{/im_save save | imageprocarray ~ get/s ~ , | + +L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring ~ + +string |/bpc ~ |/ih ~ |/iw ~ |}b/X{/im_save save | imageprocarray ~ get/s ~ , + +| L2Polarity/polarity ~ |/smoothflag ~ | snap +/dx 2 ^ |/dy 1 ^ | +S/mystring + +~ string |/bpc ~ |/ih ~ |/iw ~ |}b/Z{im_save restore}b/Y{sgco myimagedict @ ` + +/Width iw |/Height ih |/Decode polarity |/ImageMatrix[iw 0 0 ih 0 0]| + +/DataSource s |/BitsPerComponent 1 |/Interpolate smoothflag | E imagemask}b + + + +L2? not g{/setup2asciiproc{[/Level2ImagesError , aload ! T FatalErrorIf}b + +/setup2binaryproc/setup2asciiproc , |/L2Polarity{}|/Y{sgco iw ih polarity[iw 0 + +0 ih 0 0]s imagemask}b}e + + + +L2? not g{/testsystemdict{where{systemdict eq{T}{F}?}{F}?}b/c 1 |/colorimage + +where{! T}{F}?{/c 0 statusdict `/processcolors where{! ! processcolors}{ + +/deviceinfo where{! deviceinfo/Colors known{!{deviceinfo/Colors get}}if}if}? E + +| c 0 ne{/colorimage testsystemdict/setcolortransfer testsystemdict + +/currentcolortransfer testsystemdict/currentcmykcolor testsystemdict and and + +and not{/c 0 |}if}if}if c @ 1 ne ~ @ 3 ne ~ 4 ne and and{/c 0 |}if c 1 eq g{ + +/expandbw{expandfactor mul round cvi bwclut ~ get 255 V}b/doclutimage{!/bwclut + +~ | bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/expandfactor ~ |[/expandbw ,/exec , @ + +currenttransfer ~]cvx bind settransfer iw ih bpc[iw 0 0 ih 0 0]s image}b}e c @ + +3 eq ~ 4 eq or g{/nullproc{{}}|/concatutil{/exec , 7 -1 $/exec ,}b/defsubclut{ + +1 add getinterval |}b/spconcattransfer{/Dclut ~ |/Cclut ~ |/Bclut ~ |/Aclut ~ + +|/ncompute ~ , | currentcolortransfer[{Aclut ncompute}concatutil]cvx[{Bclut + +ncompute}concatutil]cvx[{Cclut ncompute}concatutil]cvx[{Dclut ncompute} + +concatutil]cvx setcolortransfer}b/setuprgbcluts{/bit3x rgbclut length 3 sub | + +/bit1x bit3x 3 idiv |/rclut rgbclut |/gclut rclut 1 bit3x defsubclut/bclut + +rclut 2 bit3x defsubclut}b}e c 3 eq g{/3compute{~ bit3x mul round cvi get 255 + +V}b/doclutimage{/rgbclut ~ | ! setuprgbcluts/3compute rclut gclut bclut @ + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @]cvx nullproc nullproc + +T 3 colorimage}b}e c 4 eq g{/ftoint{1 ~ sub 255 mul round cvi}b/stuffclut{ + +cmykindex 3 -1 $ put}b/4compute{~ bit4x mul round cvi get 255 V}b + +/invalidcolortable? T |/computecmykclut{setuprgbcluts/bit4x rgbclut length 3 + +idiv 4 mul 4 sub |/cmykclut bit4x 4 add string |/cclut cmykclut |/mclut cclut + +1 bit4x defsubclut/yclut cclut 2 bit4x defsubclut/kclut cclut 3 bit4x + +defsubclut/cmykindex 0 | 0 1 bit1x{@/cmykindex ~ bit1x ~ sub 4 mul | 3 mul @ + +rclut ~ get 255 V ~ @ gclut ~ get 255 V ~ bclut ~ get 255 V setrgbcolor + +currentcmykcolor ftoint kclut stuffclut ftoint yclut stuffclut ftoint mclut + +stuffclut ftoint cclut stuffclut}for}b/doclutimage{/rgbclut ~ | ! + +invalidcolortable?{computecmykclut}if/4compute cclut mclut yclut kclut + +spconcattransfer iw ih bpc[iw 0 0 ih 0 0][s/exec ,/@ , @ @]cvx nullproc + +nullproc nullproc T 4 colorimage}b}e c 0 eq g{/a{3 mul 3 getinterval + +putinterval ~ 3 add ~ 3 copy}b/8lookup/a , |/4lookup{/byte 1 ^ | -4 bitshift a + +byte 15 and a}b/2lookup{/byte 1 ^ | -6 bitshift a byte -4 bitshift 3 and a + +byte -2 bitshift 3 and a byte 3 and a}b/colorexpand{mystringexp 0 rgbclut 3 + +copy 7 -1 $/mylookup , forall ! ! ! ! !}b/createexpandstr{/mystringexp ~ + +mystring length mul string |}b/doclutimage{/rgbclut ~ | !/mylookup bpc 8 eq{3 + +createexpandstr/8lookup}{bpc 4 eq{6 createexpandstr/4lookup}{12 + +createexpandstr/2lookup}?}? , | iw ih bpc[iw 0 0 ih 0 0][s/exec ,/colorexpand + +,/exec ,]cvx F 3 colorimage}b}e/colorimage where{! T}{F}? g{/do24image{iw ih 8 + +[iw 0 0 ih 0 0]s F 3 colorimage}b}DefIf_El{/rgbtogray{/str ~ |/len str length + +|/smlen len 3 idiv |/rstr str |/gstr str 1 len 1 sub getinterval |/bstr str 2 + +len 2 sub getinterval | str @ 0 1 smlen 1 sub{@ 3 mul rstr 1 ^ get 0.3 mul + +gstr 2 ^ get 0.59 mul add bstr 3 -1 $ get 0.11 mul add round cvi put @}for ! 0 + +smlen getinterval}b/do24image{iw ih 8[iw 0 0 ih 0 0][s/exec ,/rgbtogray ,/exec + +,]cvx bind image}b}e/doNimage{bpc 24 eq{do24image}{iw ih bpc[iw 0 0 ih 0 0]s + +image}?}b}e + + + +L2? g{/doclutimage{/rgbclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[ + +/Indexed colspABC hival rgbclut]setcolorspace myimagedict @ `/Width iw | + +/Height ih |/Decode[0 hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s | + +/BitsPerComponent bpc |/Interpolate smoothflag | E image}b/doCMYKclutimage{ + +/CMYKclut ~ | ! bpc @ 8 eq{! 255}{4 eq{15}{3}?}?/hival ~ |[/Indexed/DeviceCMYK + +hival CMYKclut]setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 + +hival]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent bpc | + +/Interpolate smoothflag | E image}b/doNimage{bpc 24 eq{colspABC}{colspA}? + +setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode bpc 24 eq{[0 1 0 1 + +0 1]}{[0 1]}? |/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent + +bpc 24 eq{8}{bpc}? |/Interpolate smoothflag | E image}b/doCMYKimage{ + +/DeviceCMYK setcolorspace myimagedict @ `/Width iw |/Height ih |/Decode[0 1 0 + +1 0 1 0 1]|/ImageMatrix[iw 0 0 ih 0 0]|/DataSource s |/BitsPerComponent 8 | + +/Interpolate smoothflag | E image}b}e + + + +/GreNewFont{10 dict @ 3 1 $ | @ ` 4 1 $/FontType 3 |/FontMatrix ~ |/FontBBox ~ + +|/Encoding 256 array | 0 1 255{Encoding ~/.notdef put}for/CharProcs 257 dict | + +CharProcs/.notdef{}put/Metrics 257 dict | Metrics/.notdef 3 -1 $ put/BuildChar + +{/char ~ |/fontdict ~ |/charname fontdict/Encoding get char get | fontdict + +/Metrics get charname get aload ! setcachedevice fontdict ` Encoding char get + +CharProcs ~ get E exec}| E definefont !}|/AddChar{` Encoding 3 1 $ put + +CharProcs 3 1 $ put Metrics 3 1 $ put E}| + + + +/FEbuf 2 string |/FEglyph 3 string |/FE{(G00)FEglyph copy ! 1 ~{@ 16 lt{ + +/offset 2 store}{/offset 1 store}? @ 16 FEbuf cvrs FEglyph ~ offset ~ + +putinterval 1 ^ ~ FEglyph cvn put}for}bind |/Type1Hdr{11 dict `/FontName ~ | + +/PaintType ~ |/FontType 1 |/FontMatrix[1 3 ^ V 0 0 1 6 ^ V 0 0]| !/Encoding + +256 array 0 1 255{1 ^ ~/.notdef put}for 3 ^ 3 ^ FE | ! !/FontBBox{0 0 0 0}| & + +E currentfile eexec}bind | + + +/pp 1 string |/ss 1 string |/rledecodebinary{/DC 0 |/BC 0 |{DC mystring length + +ge{exit}if currentfile ss readstring ! 0 get/BC ~ | BC 127 le{/BC BC 1 add | + +DC 1 DC BC add 1 sub{mystring ~ currentfile ss readstring ! 0 get put}for}{/BC + +257 BC sub | currentfile ss readstring ! 0 get/pp ~ | DC 1 DC BC add 1 sub{ + +mystring ~ pp put}for}?/DC DC BC add |}loop mystring}b/rledecodeascii{/DC 0 | + +/BC 0 |{DC mystring length ge{exit}if currentfile ss readhexstring ! 0 get/BC + +~ | BC 127 le{/BC BC 1 add | DC 1 DC BC add 1 sub{mystring ~ currentfile ss + +readhexstring ! 0 get put}for}{/BC 257 BC sub | currentfile ss readhexstring ! + +0 get/pp ~ | DC 1 DC BC add 1 sub{mystring ~ pp put}for}?/DC DC BC add |}loop + +mystring}b/setup1asciidecodeproc{[/rledecodeascii cvx]cvx bind}b + +/setup1binarydecodeproc{[/rledecodebinary cvx]cvx bind}b + + +userdict/Pscript_Win_Compat 13 dict dup begin/bd{bind def}bind def/ld{load def + +}bd/CB{pop pop pop pop}bind def/B{pop pop pop pop}bind def/$x matrix def/SS{ + +/pagesave save def}bind def/RS{/pagesave where{pop pagesave restore}{$x matrix + +invertmatrix concat}ifelse}bind def/ANSIVec[0/grave 1/acute 2/circumflex 3 + +/tilde 4/macron 5/breve 6/dotaccent 7/dieresis 8/ring 9/cedilla 10 + +/hungarumlaut 11/ogonek 12/caron 13/dotlessi 39/quotesingle 96/grave 124/bar + +130/quotesinglbase 131/florin 132/quotedblbase 133/ellipsis 134/dagger 135 + +/daggerdbl 136/circumflex 137/perthousand 138/Scaron 139/guilsinglleft 140/OE + +145/quoteleft 146/quoteright 147/quotedblleft 148/quotedblright 149/bullet 150 + +/endash 151/emdash 152/tilde 153/trademark 154/scaron 155/guilsinglright 156 + +/oe 159/Ydieresis 160/space 161/exclamdown 164/currency 165/yen 166/brokenbar + +167/section 168/dieresis 169/copyright 170/ordfeminine 171/guillemotleft 172 + +/logicalnot 173/hyphen 174/registered 175/macron 176/degree 177/plusminus 178 + +/twosuperior 179/threesuperior 180/acute 181/mu 182/paragraph 183 + +/periodcentered 184/cedilla 185/onesuperior 186/ordmasculine 187 + +/guillemotright 188/onequarter 189/onehalf 190/threequarters 191/questiondown + +192/Agrave 193/Aacute 194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198 + +/AE 199/Ccedilla 200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204 + +/Igrave 205/Iacute 206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve + +211/Oacute 212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash + +217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn 223 + +/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde 228/adieresis 229 + +/aring 230/ae 231/ccedilla 232/egrave 233/eacute 234/ecircumflex 235/edieresis + +236/igrave 237/iacute 238/icircumflex 239/idieresis 240/eth 241/ntilde 242 + +/ograve 243/oacute 244/ocircumflex 245/otilde 246/odieresis 247/divide 248 + +/oslash 249/ugrave 250/uacute 251/ucircumflex 252/udieresis 253/yacute 254 + +/thorn 255/ydieresis]def currentdict{dup type/operatortype eq{[exch]cvx def}{ + +pop pop}ifelse}forall/initialize{currentdict exch begin begin}bind def + +/terminate{/@FL where not{pop end end}{pop}ifelse}bind def/suspend/terminate + +load def/resume/initialize load def/M/moveto load def end put/Courier findfont + +10 scalefont setfont + + +end /ProcSet defineresource pop + + + + + + +Pscript_Win_Compat dup /initialize get exec + +[ 0 1.000 -1.000 0 0 0 ] false /Pscript_Win_Driver /ProcSet findresource dup /initialize get exec + + + + + +/mysetup [ 0.240 0 0 -0.240 7.920 592.800 ] | + + + + + + +userdict begin /pagesave save def end mysetup concat colspRefresh : 1.000 1.000 1.000 sco 0 0 2550 3300 rf ; + + + + + + +116 70 N M 1 1 rr + +116 70 N M 3000 2250 rr : 1.000 1.000 1.000 sco O ; + +116 70 N M 1 1 rr + +116 70 N M 1 1 rr + +133 87 N M 2904 2146 rr 10 Lw 0 Lc 0 Lj solid 0 0 0 sco K + +579 456 N M 2416 1561 rr : 1.000 0.800 0.600 sco O ; + +579 456 N M 2416 0 - 3 Lw 1 Lc 1 Lj solid 0 0 0 sco K + +2995 456 N M 0 1561 - 0 0 0 sco K + +2995 2017 N M -2416 0 - 0 0 0 sco K + +579 2017 N M 0 -1561 - 0 0 0 sco K + +579 1947 N M 73 56 rr : 1.000 1.000 0 sco O ; 0 Lc 0 Lj 0 0 0 sco K + +579 1774 N M 177 55 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 1600 N M 215 55 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 1426 N M 274 56 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 1252 N M 285 56 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 1082 N M 319 55 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 908 N M 476 56 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 734 N M 845 56 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 560 N M 1074 56 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K + +579 1864 N M 121 52 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 1690 N M 319 52 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 1516 N M 274 53 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 1343 N M 330 52 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 1169 N M 532 55 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 998 N M 528 52 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 824 N M 911 53 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 651 N M 1617 52 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 477 N M 1968 52 rr : 0 0 1.000 sco O ; 0 0 0 sco K + +579 456 N M 0 1561 - 1 Lc 1 Lj 0 0 0 sco K + +558 2017 N M 21 0 - 0 0 0 sco K + +558 1843 N M 21 0 - 0 0 0 sco K + +558 1669 N M 21 0 - 0 0 0 sco K + +558 1495 N M 21 0 - 0 0 0 sco K + +558 1322 N M 21 0 - 0 0 0 sco K + +558 1151 N M 21 0 - 0 0 0 sco K + +558 977 N M 21 0 - 0 0 0 sco K + +558 804 N M 21 0 - 0 0 0 sco K + +558 630 N M 21 0 - 0 0 0 sco K + +558 456 N M 21 0 - 0 0 0 sco K : 610 167 1954 149 rc 0.502 0 0 sco %%IncludeFont: Helvetica-Bold + +(F0) cvn + +0.930 + + (Helvetica-Bold) cvn /Type1 + +T + +(Helvetica-Bold) cvn + +mF + +(F0_129) cvn + +F0 + +129 + +xF + +F0_129 + +Ji + +634 167 M + +0.543 0 (M)A + +0.957 0 (E)A + +1.181 0 (T)A + +-4.862 0 (I)A + +0.957 0 (S)A + +0.298 0 (')A + +-2.138 0 32 1.276 0 (s )D + +0.638 0 (O)A + +-1.181 0 (r)A + +1.181 0 (d)A + +1.276 0 (e)A + +-2.181 0 (r)A + +-0.862 0 (i)A + +-2.043 0 32 1.181 0 (ng )D + +0.957 0 (P)A + +1.276 0 (e)A + +-2.181 0 (r)A + +-0.957 0 (f)A + +1.181 0 (o)A + +-1.181 0 (r)A + +0.319 0 (m)A + +1.276 0 (a)A + +1.181 0 (n)A + +-3.138 0 32 1.276 0 (ce )D + +; : 655 1947 181 53 rc 0 0 0 sco (F0_45) cvn + +F0 + +45 + +xF + +F0_45 + +Ji + +665 1947 M + +-1.020 0 (0)A + +1.490 0 (.)A + +-0.020 0 (9)A + +-1.020 0 (0)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 759 1774 181 53 rc 0 0 0 sco F0_45 + +Ji + +770 1774 M + +-1.020 0 (2)A + +1.490 0 (.)A + +-0.020 0 (1)A + +-1.020 0 (9)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 798 1600 180 53 rc 0 0 0 sco F0_45 + +Ji + +808 1600 M + +-1.020 0 (2)A + +1.490 0 (.)A + +-0.020 0 (6)A + +-1.020 0 (7)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 857 1426 181 53 rc 0 0 0 sco F0_45 + +Ji + +867 1426 M + +-1.020 0 (3)A + +1.490 0 (.)A + +-0.020 0 (4)A + +-1.020 0 (3)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 867 1252 181 53 rc 0 0 0 sco F0_45 + +Ji + +878 1252 M + +-1.020 0 (3)A + +1.490 0 (.)A + +-0.020 0 (5)A + +-1.020 0 (5)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 902 1078 181 53 rc 0 0 0 sco F0_45 + +Ji + +912 1078 M + +-1.020 0 (3)A + +1.490 0 (.)A + +-0.020 0 (9)A + +-1.020 0 (6)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 1058 904 181 53 rc 0 0 0 sco F0_45 + +Ji + +1069 904 M + +-1.020 0 (5)A + +1.490 0 (.)A + +-0.020 0 (9)A + +-1.020 0 (0)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 1427 731 205 53 rc 0 0 0 sco F0_45 + +Ji + +1437 731 M + +-1.020 0 (1)A + +-0.020 0 (0)A + +1.490 0 (.)A + +-1.020 0 (51)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 1657 557 205 53 rc 0 0 0 sco F0_45 + +Ji + +1667 557 M + +-1.020 0 (1)A + +-0.020 0 (3)A + +1.490 0 (.)A + +-1.020 0 (34)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 704 1861 181 53 rc 0 0 0 sco F0_45 + +Ji + +714 1861 M + +-1.020 0 (1)A + +1.490 0 (.)A + +-0.020 0 (5)A + +-1.020 0 (2)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 902 1687 181 53 rc 0 0 0 sco F0_45 + +Ji + +912 1687 M + +-1.020 0 (3)A + +1.490 0 (.)A + +-0.020 0 (9)A + +-1.020 0 (5)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 857 1513 181 53 rc 0 0 0 sco F0_45 + +Ji + +867 1513 M + +-1.020 0 (3)A + +1.490 0 (.)A + +-0.020 0 (4)A + +-1.020 0 (2)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 912 1339 181 53 rc 0 0 0 sco F0_45 + +Ji + +923 1339 M + +-1.020 0 (4)A + +1.490 0 (.)A + +-0.020 0 (1)A + +-1.020 0 (0)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 1114 1169 181 53 rc 0 0 0 sco F0_45 + +Ji + +1124 1169 M + +-1.020 0 (6)A + +1.490 0 (.)A + +-0.020 0 (5)A + +-1.020 0 (9)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 1111 995 180 53 rc 0 0 0 sco F0_45 + +Ji + +1121 995 M + +-1.020 0 (6)A + +1.490 0 (.)A + +-0.020 0 (5)A + +-1.020 0 (5)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 1493 821 205 53 rc 0 0 0 sco F0_45 + +Ji + +1504 821 M + +-1.020 0 (1)A + +-0.020 0 (1)A + +1.490 0 (.)A + +-1.020 0 (32)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 2199 647 205 53 rc 0 0 0 sco F0_45 + +Ji + +2209 647 M + +-1.020 0 (2)A + +-0.020 0 (0)A + +1.490 0 (.)A + +-1.020 0 (07)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 2550 473 205 53 rc 0 0 0 sco F0_45 + +Ji + +2561 473 M + +-1.020 0 (2)A + +-0.020 0 (4)A + +1.490 0 (.)A + +-1.020 0 (43)A + +-4.020 0 (s)A + +2.980 0 (e)A + +-1.020 0 (c)A + +; : 217 1892 2841 74 rc 0 0 0 sco %%IncludeFont: Helvetica + +(F3) cvn + +0.909 + + (Helvetica) cvn /Type1 + +T + +(Helvetica) cvn + +mF + +(F3_66) cvn + +F3 + +66 + +xF + +F3_66 + +Ji + +335 1892 M + +2.652 0 (I)A + +-1.696 0 (n)A + +1.304 0 (p)A + +-0.978 0 (r)A + +1.304 0 (o1)A + +; : 116 1718 2942 74 rc 0 0 0 sco F3_66 + +Ji + +179 1718 M + +0.978 0 (B)A + +1.348 0 (C)A + +0.978 0 (SS)A + +1.674 0 (T)A + +0.978 0 (K)A + +2.304 0 (3)A + +1.304 0 (0)A + +; : 116 1544 2942 74 rc 0 0 0 sco F3_66 + +Ji + +179 1544 M + +0.978 0 (B)A + +1.348 0 (C)A + +0.978 0 (SS)A + +1.674 0 (T)A + +0.978 0 (K)A + +2.304 0 (3)A + +1.304 0 (2)A + +; : 116 1370 2942 74 rc 0 0 0 sco F3_66 + +Ji + +179 1370 M + +0.978 0 (B)A + +1.348 0 (C)A + +0.978 0 (SS)A + +1.674 0 (T)A + +0.978 0 (K)A + +2.304 0 (3)A + +1.304 0 (1)A + +; : 172 1196 2886 74 rc 0 0 0 sco F3_66 + +Ji + +290 1196 M + +0.978 0 (P)A + +1.348 0 (D)A + +0.978 0 (S)A + +-0.978 0 (-)A + +1.304 0 (20)A + +; : 196 1026 2862 74 rc 0 0 0 sco F3_66 + +Ji + +314 1026 M + +0.978 0 (KE)A + +-1.652 0 (N)A + +1.304 0 (18)A + +; : 148 852 2910 74 rc 0 0 0 sco F3_66 + +Ji + +266 852 M + +1.674 0 (F)A + +0.652 0 (O)A + +1.348 0 (R)A + +0.674 0 (T)A + +2.304 0 (1)A + +1.304 0 (7)A + +; : 280 678 2778 74 rc 0 0 0 sco F3_66 + +Ji + +398 678 M + +1.674 0 (T)A + +-0.978 0 (r)A + +1.304 0 (o)A + +-0.652 0 (ll)A + +; : 214 505 2844 74 rc 0 0 0 sco F3_66 + +Ji + +332 505 M + +0.652 0 (O)A + +2.000 0 (c)A + +1.304 0 (e)A + +-1.696 0 (an)A + +; + +784 2059 N M 1971 128 rr : 1.000 1.000 1.000 sco O ; 0 Lc 0 Lj 0 0 0 sco K + +812 2100 N M 52 53 rr : 1.000 1.000 0 sco O ; 0 0 0 sco K : 785 2080 1974 96 rc 0 0 0 sco (F0_83) cvn + +F0 + +83 + +xF + +F0_83 + +Ji + +888 2080 M + +3.861 0 (M)A + +0.926 0 (I)A + +0.287 0 32 0.639 0 (PS )D + +-0.926 0 (R)A + +-1.148 0 (1)A + +-0.148 0 (0)A + +-1.148 0 (000)A + +-0.925 0 (@)A + +-1.148 0 (2)A + +-0.148 0 (0)A + +-1.148 0 (0)A + +3.861 0 (M)A + +-0.926 0 (H)A + +0.500 0 (z)A + +; + +1834 2100 N M 52 53 rr : 0 0 1.000 sco O ; 0 0 0 sco K : 1807 2080 952 96 rc 0 0 0 sco F0_83 + +Ji + +1910 2080 M + +0.926 0 (I)A + +2.287 0 (n)A + +-0.639 0 (t)A + +-0.148 0 (e)A + +0.926 0 (l )A + +0.639 0 (PP)A + +-0.926 0 (R)A + +-2.574 0 (O)A + +-0.925 0 (@)A + +-1.148 0 (2)A + +-0.148 0 (0)A + +-1.148 0 (0)A + +3.861 0 (M)A + +-0.926 0 (H)A + +0.500 0 (z)A + +; + +1538 1010 N M 320 38 rr : 0.502 0 0 sco O ; + +1538 1048 N M 320 61 rr : 0.502 0 0 sco O ; + +1538 1109 N M 320 37 rr : 0.502 0 0 sco O ; + +1858 1010 N M 361 68 rr : 0.502 0 0 sco O ; : 1516 1010 1425 985 rc 1.000 1.000 1.000 sco %%IncludeFont: Helvetica-BoldOblique + +(F6) cvn + +0.915 + + (Helvetica-BoldOblique) cvn /Type1 + +T + +(Helvetica-BoldOblique) cvn + +mF + +(F6_59) cvn + +F6 + +59 + +xF + +F6_59 + +Ji + +1888 1011 M + +0.402 0 (N)A + +0.951 0 (u)A + +1.549 0 (m)A + +0.951 0 (b)A + +0.196 0 (e)A + +0.549 0 32 0.049 0 (r )D + +0.951 0 (o)A + +0.353 0 (f)A + +; + +1858 1078 N M 361 68 rr : 0.502 0 0 sco O ; : 1516 1010 1425 985 rc 1.000 1.000 1.000 sco F6_59 + +Ji + +1922 1080 M + +0.647 0 (V)A + +0.196 0 (e)A + +0.049 0 (r)A + +1.353 0 (t)A + +0.598 0 (i)A + +0.196 0 (ce)A + +1.196 0 (s)A + +; + +2219 1010 N M 362 68 rr : 0.502 0 0 sco O ; : 1516 1010 1425 985 rc 1.000 1.000 1.000 sco F6_59 + +Ji + +2250 1011 M + +0.402 0 (N)A + +0.951 0 (u)A + +1.549 0 (m)A + +0.951 0 (b)A + +0.196 0 (e)A + +0.549 0 32 0.049 0 (r )D + +0.951 0 (o)A + +0.353 0 (f)A + +; + +2219 1078 N M 362 68 rr : 0.502 0 0 sco O ; : 1516 1010 1425 985 rc 1.000 1.000 1.000 sco F6_59 + +Ji + +2311 1080 M + +0.647 0 (E)A + +0.951 0 (dg)A + +0.196 0 (es)A + +; + +2581 1010 N M 360 68 rr : 0.502 0 0 sco O ; : 1516 1010 1425 985 rc 1.000 1.000 1.000 sco F6_59 + +Ji + +2620 1011 M + +1.098 0 (O)A + +0.951 0 (p)A + +0.196 0 (e)A + +0.049 0 (r)A + +1.196 0 (a)A + +0.353 0 (t)A + +0.598 0 (i)A + +0.951 0 (o)A + +-0.049 0 (n)A + +; + +2581 1078 N M 360 68 rr : 0.502 0 0 sco O ; : 1516 1010 1425 985 rc 1.000 1.000 1.000 sco F6_59 + +Ji + +2675 1080 M + +0.402 0 (C)A + +0.951 0 (oun)A + +0.353 0 (t)A + +; + +1538 1151 N M 320 13 rr : 1.000 1.000 0.800 sco O ; + +1538 1164 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1516 1010 1425 985 rc 0.004 0 0 sco (F0_53) cvn + +F0 + +53 + +xF + +F0_53 + +Ji + +1554 1163 M + +0.766 0 (O)A + +0.532 0 (c)A + +1.532 0 (e)A + +0.532 0 (a)A + +0.617 0 (n)A + +; + +1538 1225 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1151 N M 361 13 rr : 1.000 1.000 0.800 sco O ; + +1858 1164 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1146 361 79 rc 0.004 0 0 sco (F3_53) cvn + +F3 + +53 + +xF + +F3_53 + +Ji + +2007 1166 M + +0.532 0 (1)A + +1.532 0 (4)A + +0.532 0 (3)A + +0.266 0 (,)A + +0.532 0 (43)A + +1.532 0 (7)A + +; + +1858 1225 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1151 N M 362 13 rr : 1.000 1.000 0.800 sco O ; + +2219 1164 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1146 362 79 rc 0.004 0 0 sco F3_53 + +Ji + +2369 1166 M + +0.532 0 (4)A + +1.532 0 (0)A + +0.532 0 (9)A + +0.266 0 (,)A + +0.532 0 (59)A + +1.532 0 (3)A + +; + +2219 1225 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1151 N M 360 13 rr : 1.000 1.000 0.800 sco O ; + +2581 1164 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1146 360 79 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1166 M + +0.532 0 (1)A + +1.266 0 (.)A + +0.532 0 (26e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (8)A + +; + +2581 1225 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1146 N M 320 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +1538 1146 N M 320 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +1858 1146 N M 4 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +1858 1146 N M 4 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1516 1010 1425 985 rc + +1858 1146 N M 0 5 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +1862 1146 N M 357 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +1862 1146 N M 357 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2219 1146 N M 5 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2219 1146 N M 5 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1516 1010 1425 985 rc + +2219 1146 N M 0 5 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2224 1146 N M 357 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2224 1146 N M 357 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2581 1146 N M 5 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2581 1146 N M 5 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1516 1010 1425 985 rc + +2581 1146 N M 0 5 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2586 1146 N M 355 5 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2586 1146 N M 355 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +1538 1239 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1253 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1516 1010 1425 985 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1251 M + +0.617 0 (T)A + +0.383 0 (r)A + +1.617 0 (o)A + +0.266 0 (ll)A + +; + +1538 1314 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1239 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1253 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1239 361 75 rc 0.004 0 0 sco F3_53 + +Ji + +2007 1255 M + +0.532 0 (2)A + +1.532 0 (1)A + +0.532 0 (3)A + +0.266 0 (,)A + +0.532 0 (45)A + +1.532 0 (3)A + +; + +1858 1314 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1239 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1253 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1239 362 75 rc 0.004 0 0 sco F3_53 + +Ji + +2323 1255 M + +0.532 0 (5)A + +1.266 0 (,)A + +0.532 0 (885)A + +0.266 0 (,)A + +1.532 0 (8)A + +0.532 0 (29)A + +; + +2219 1314 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1239 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1253 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1239 360 75 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1255 M + +0.532 0 (5)A + +1.266 0 (.)A + +0.532 0 (53e)A + +1.048 0 (+)A + +0.532 0 (1)A + +1.532 0 (0)A + +; + +2581 1314 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1328 N M 320 13 rr : 1.000 1.000 0.800 sco O ; + +1538 1341 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1516 1010 1425 985 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1340 M + +0.617 0 (F)A + +1.617 0 (o)A + +0.383 0 (r)A + +0.351 0 (t)A + +0.532 0 (17)A + +; + +1538 1402 N M 320 15 rr : 1.000 1.000 0.800 sco O ; + +1858 1328 N M 361 13 rr : 1.000 1.000 0.800 sco O ; + +1858 1341 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1328 361 74 rc 0.004 0 0 sco F3_53 + +Ji + +2037 1344 M + +0.532 0 (8)A + +1.532 0 (6)A + +0.266 0 (,)A + +0.532 0 (650)A + +; + +1858 1402 N M 361 15 rr : 1.000 1.000 0.800 sco O ; + +2219 1328 N M 362 13 rr : 1.000 1.000 0.800 sco O ; + +2219 1341 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1328 362 74 rc 0.004 0 0 sco F3_53 + +Ji + +2369 1344 M + +0.532 0 (2)A + +1.532 0 (4)A + +0.532 0 (7)A + +0.266 0 (,)A + +0.532 0 (42)A + +1.532 0 (4)A + +; + +2219 1402 N M 362 15 rr : 1.000 1.000 0.800 sco O ; + +2581 1328 N M 360 13 rr : 1.000 1.000 0.800 sco O ; + +2581 1341 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1328 360 74 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1344 M + +0.532 0 (8)A + +1.266 0 (.)A + +0.532 0 (05e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (6)A + +; + +2581 1402 N M 360 15 rr : 1.000 1.000 0.800 sco O ; + +1538 1417 N M 320 13 rr : 1.000 1.000 0.800 sco O ; + +1538 1430 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1516 1010 1425 985 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1429 M + +0.734 0 (K)A + +0.532 0 (e)A + +1.617 0 (n)A + +0.532 0 (1)A + +1.532 0 (8)A + +; + +1538 1491 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1417 N M 361 13 rr : 1.000 1.000 0.800 sco O ; + +1858 1430 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1417 361 74 rc 0.004 0 0 sco F3_53 + +Ji + +2007 1432 M + +0.532 0 (1)A + +1.532 0 (0)A + +0.532 0 (5)A + +0.266 0 (,)A + +0.532 0 (12)A + +1.532 0 (7)A + +; + +1858 1491 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1417 N M 362 13 rr : 1.000 1.000 0.800 sco O ; + +2219 1430 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1417 362 74 rc 0.004 0 0 sco F3_53 + +Ji + +2369 1432 M + +0.532 0 (2)A + +1.532 0 (5)A + +0.532 0 (2)A + +0.266 0 (,)A + +0.532 0 (07)A + +1.532 0 (2)A + +; + +2219 1491 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1417 N M 360 13 rr : 1.000 1.000 0.800 sco O ; + +2581 1430 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1417 360 74 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1432 M + +0.532 0 (2)A + +1.266 0 (.)A + +0.532 0 (85e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (8)A + +; + +2581 1491 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1505 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1519 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1516 1010 1425 985 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1517 M + +0.649 0 (P)A + +0.734 0 (D)A + +0.649 0 (S)A + +1.351 0 (-)A + +0.532 0 (20)A + +; + +1538 1580 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1505 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1519 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1505 361 75 rc 0.004 0 0 sco F3_53 + +Ji + +2037 1521 M + +0.532 0 (3)A + +1.532 0 (3)A + +0.266 0 (,)A + +0.532 0 (798)A + +; + +1858 1580 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1505 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1519 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1505 362 75 rc 0.004 0 0 sco F3_53 + +Ji + +2369 1521 M + +0.532 0 (1)A + +1.532 0 (4)A + +0.532 0 (3)A + +0.266 0 (,)A + +0.532 0 (16)A + +1.532 0 (1)A + +; + +2219 1580 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1505 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1519 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1505 360 75 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1521 M + +0.532 0 (3)A + +1.266 0 (.)A + +0.532 0 (82e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (9)A + +; + +2581 1580 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1594 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1608 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1538 1594 320 75 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1606 M + +0.734 0 (BC)A + +0.649 0 (S)A + +1.649 0 (S)A + +0.617 0 (T)A + +0.734 0 (K)A + +0.532 0 (3)A + +1.532 0 (1)A + +; + +1538 1669 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1594 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1608 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1594 361 75 rc 0.004 0 0 sco F3_53 + +Ji + +2037 1610 M + +0.532 0 (3)A + +1.532 0 (5)A + +0.266 0 (,)A + +0.532 0 (588)A + +; + +1858 1669 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1594 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1608 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1594 362 75 rc 0.004 0 0 sco F3_53 + +Ji + +2369 1610 M + +0.532 0 (5)A + +1.532 0 (7)A + +0.532 0 (2)A + +0.266 0 (,)A + +0.532 0 (91)A + +1.532 0 (4)A + +; + +2219 1669 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1594 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1608 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1594 360 75 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1610 M + +0.532 0 (1)A + +1.266 0 (.)A + +0.532 0 (16e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (9)A + +; + +2581 1669 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1683 N M 320 13 rr : 1.000 1.000 0.800 sco O ; + +1538 1696 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1538 1683 320 74 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1695 M + +0.734 0 (BC)A + +0.649 0 (S)A + +1.649 0 (S)A + +0.617 0 (T)A + +0.734 0 (K)A + +0.532 0 (3)A + +1.532 0 (2)A + +; + +1538 1757 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1683 N M 361 13 rr : 1.000 1.000 0.800 sco O ; + +1858 1696 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1683 361 74 rc 0.004 0 0 sco F3_53 + +Ji + +2037 1698 M + +0.532 0 (4)A + +1.532 0 (4)A + +0.266 0 (,)A + +0.532 0 (609)A + +; + +1858 1757 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1683 N M 362 13 rr : 1.000 1.000 0.800 sco O ; + +2219 1696 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1683 362 74 rc 0.004 0 0 sco F3_53 + +Ji + +2369 1698 M + +0.532 0 (9)A + +1.532 0 (8)A + +0.532 0 (5)A + +0.266 0 (,)A + +0.532 0 (04)A + +1.532 0 (6)A + +; + +2219 1757 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1683 N M 360 13 rr : 1.000 1.000 0.800 sco O ; + +2581 1696 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1683 360 74 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1698 M + +0.532 0 (1)A + +1.266 0 (.)A + +0.532 0 (32e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (9)A + +; + +2581 1757 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1771 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1785 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1538 1771 320 75 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1784 M + +0.734 0 (BC)A + +0.649 0 (S)A + +1.649 0 (S)A + +0.617 0 (T)A + +0.734 0 (K)A + +0.532 0 (3)A + +1.532 0 (0)A + +; + +1538 1846 N M 320 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1771 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +1858 1785 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1771 361 75 rc 0.004 0 0 sco F3_53 + +Ji + +2037 1787 M + +0.532 0 (2)A + +1.532 0 (8)A + +0.266 0 (,)A + +0.532 0 (294)A + +; + +1858 1846 N M 361 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1771 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2219 1785 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1771 362 75 rc 0.004 0 0 sco F3_53 + +Ji + +2323 1787 M + +0.532 0 (1)A + +1.266 0 (,)A + +0.532 0 (007)A + +0.266 0 (,)A + +1.532 0 (2)A + +0.532 0 (84)A + +; + +2219 1846 N M 362 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1771 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +2581 1785 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1771 360 75 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1787 M + +0.532 0 (1)A + +1.266 0 (.)A + +0.532 0 (17e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (9)A + +; + +2581 1846 N M 360 14 rr : 1.000 1.000 0.800 sco O ; + +1538 1860 N M 320 16 rr : 1.000 1.000 0.800 sco O ; + +1538 1876 N M 320 61 rr : 1.000 1.000 0.800 sco O ; : 1516 1010 1425 985 rc 0.004 0 0 sco F0_53 + +Ji + +1554 1874 M + +0.266 0 (I)A + +0.617 0 (n)A + +1.617 0 (p)A + +0.383 0 (r)A + +0.617 0 (o)A + +0.532 0 (1)A + +; + +1538 1937 N M 320 17 rr : 1.000 1.000 0.800 sco O ; + +1858 1860 N M 361 16 rr : 1.000 1.000 0.800 sco O ; + +1858 1876 N M 361 61 rr : 1.000 1.000 0.800 sco O ; : 1858 1860 361 77 rc 0.004 0 0 sco F3_53 + +Ji + +2037 1878 M + +0.532 0 (4)A + +1.532 0 (6)A + +0.266 0 (,)A + +0.532 0 (949)A + +; + +1858 1937 N M 361 17 rr : 1.000 1.000 0.800 sco O ; + +2219 1860 N M 362 16 rr : 1.000 1.000 0.800 sco O ; + +2219 1876 N M 362 61 rr : 1.000 1.000 0.800 sco O ; : 2219 1860 362 77 rc 0.004 0 0 sco F3_53 + +Ji + +2323 1878 M + +0.532 0 (1)A + +1.266 0 (,)A + +0.532 0 (117)A + +0.266 0 (,)A + +1.532 0 (8)A + +0.532 0 (09)A + +; + +2219 1937 N M 362 17 rr : 1.000 1.000 0.800 sco O ; + +2581 1860 N M 360 16 rr : 1.000 1.000 0.800 sco O ; + +2581 1876 N M 360 61 rr : 1.000 1.000 0.800 sco O ; : 2581 1860 360 77 rc 0.004 0 0 sco F3_53 + +Ji + +2699 1878 M + +0.532 0 (1)A + +1.266 0 (.)A + +0.532 0 (24e)A + +1.048 0 (+)A + +0.532 0 (0)A + +1.532 0 (9)A + +; + +2581 1937 N M 360 17 rr : 1.000 1.000 0.800 sco O ; + +1538 1954 N M 320 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +1538 1954 N M 320 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +1858 1954 N M 4 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +1858 1954 N M 4 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1516 1010 1425 985 rc + +1858 1954 N M 0 4 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +1862 1954 N M 357 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +1862 1954 N M 357 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2219 1954 N M 5 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2219 1954 N M 5 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1516 1010 1425 985 rc + +2219 1954 N M 0 4 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2224 1954 N M 357 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2224 1954 N M 357 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2581 1954 N M 5 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2581 1954 N M 5 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; : 1516 1010 1425 985 rc + +2581 1954 N M 0 4 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +2586 1954 N M 355 4 rr : 0 0 0 sco O ; : 1516 1010 1425 985 rc + +2586 1954 N M 355 0 - 1 Lw 1 Lc 1 Lj solid 0 0 0 sco K ; + +LH + +pagesave restore + + + + + + + +/Pscript_Win_Driver /ProcSet findresource dup /terminate get exec + +Pscript_Win_Compat dup /terminate get exec + + +cleartomark +countdictstack exch sub { end } repeat +restore grestore +% +% End Imported PIC File: slide2.eps +% +$F2psEnd +rs +%%EndDocument + @endspecial 0 3899 a Fy(Figure)19 b(2)p FL(:)28 b Fx(The)19 +b(amount)g(of)h(time)g(required)f(b)o(y)i(M)l Fv(E)-17 +b Fx(T)g Fv(I)p Fx(S)23 b(to)d(par)s(tition)f(v)n(ar)q(ious)h(g)o(r)o +(aphs)f(in)h(256)g(par)s(ts)f(and)h(the)f(amount)g(of)h(time)g +(required)e(b)o(y)k(M)l Fv(E)-17 b Fx(T)g Fv(I)p Fx(S)0 +3999 y(to)19 b(compute)f(\002ll-reducing)g(order)q(ings)f(f)n(or)i(v)n +(ar)q(ious)f(sparse)h(matr)q(ices)o(.)100 4183 y FL(The)i(rest)h(of)f +(this)i(manual)d(is)j(or)o(ganized)c(as)j(follo)n(ws:)28 +b(Section)21 b(4)h(describes)f(the)h(user)f(interf)o(ace)g(to)h(the)f +(stand-alone)f(programs)0 4292 y(pro)o(vided)i(by)k Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)r FL(.)26 b(Section)e(5)g(describes)g +(the)g(stand-alone)f(library)g(that)i(implements)e(the)h(v)n(arious)f +(algorithms)g(implemented)0 4402 y(in)f Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)r FL(.)23 b(Finally)-5 b(,)19 b(Section)h(6)g +(describes)g(the)g(system)g(requirements)f(for)g(the)j +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)25 b FL(package.)1929 +5649 y(5)p eop +%%Page: 6 6 +6 5 bop 0 85 a FD(3)116 b(What)31 b(is)h(Ne)n(w)h(in)g(This)f(V)-6 +b(er)n(sion)0 261 y FL(The)19 b(latest)i(v)o(ersion)d(of)j +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)24 b FL(contains)19 +b(a)h(number)d(of)i(changes)g(o)o(v)o(er)f(the)i(pre)n(vious)e(major)g +(release)i(\(v)o(ersion)e(3.0\).)23 b(Most)d(of)f(these)0 +370 y(changes)h(are)g(concentrated)e(on)i(the)h(graph)e(and)h(mesh)g +(partitioning)f(routines)h(and)g(the)o(y)f(mar)o(ginally)g(af)n(fect)h +(the)g(sparse)h(matrix)f(re-)0 480 y(ordering)c(routines.)23 +b(T)-7 b(able)18 b(1)h(describes)e(which)h(programs)e(and)i(routines)f +(of)j Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)21 b +FL(ha)n(v)o(e)d(been)f(changed)g(and)g(the)i(ne)n(w)f(routines)0 +590 y(in)k Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)p +FL(.)29 b(In)20 b(the)g(rest)g(of)g(this)h(section)f(we)g(brie\003y)g +(describe)f(some)h(of)g(the)h(major)e(changes.)0 799 +y FB(Multi-Constraint)24 b(P)n(ar)r(titioning)100 b Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)26 b FL(no)n(w)c(includes)f(partitioning) +f(routines)h(that)h(can)g(be)g(used)g(to)g(partition)f(a)i(graph)d(in)0 +908 y(the)e(presence)e(of)h(multiple)g(balancing)f(constraints.)24 +b(The)17 b(idea)g(is)i(that)e(each)g(v)o(erte)o(x)g(has)g(a)h(v)o +(ector)f(of)g(weights)g(of)h(size)g Ft(m)23 b FL(associated)0 +1018 y(with)g(it,)i(and)d(the)h(objecti)n(v)o(e)f(of)h(the)g +(partitioning)e(algorithm)h(is)i(to)f(minimize)g(the)g(edgecut)f +(subject)h(to)g(the)g(constraints)g(that)g(each)0 1128 +y(one)i(of)g(the)h Ft(m)31 b FL(weights)25 b(is)i(equally)e(distrib)n +(uted)f(among)g(the)i(domains.)40 b(F)o(or)25 b(e)o(xample,)h(if)f(the) +h(\002rst)g(weight)f(corresponds)f(to)i(the)0 1237 y(amount)c(of)i +(computation)d(and)i(the)g(second)g(weight)g(corresponds)f(to)h(the)h +(amount)e(of)i(storage)e(required)g(for)h(each)g(element,)h(then)0 +1347 y(the)19 b(partitioning)f(computed)f(by)i(the)g(ne)n(w)g +(algorithms)f(will)i(balance)e(both)h(the)g(computation)e(performed)g +(in)i(each)g(domain)f(as)i(well)0 1456 y(as)f(the)e(amount)g(of)g +(memory)f(that)i(it)h(requires.)k(Also,)18 b(multi-phase)f +(\(multi-physics\))e(computations)h(can)h(use)h(the)g(ne)n(w)g +(partitioning)0 1566 y(algorithm)28 b(to)i(simultaneously)e(balance)h +(the)h(computations)e(performed)f(in)j(each)f(phase.)53 +b(The)30 b(multi-constraint)e(partitioning)0 1675 y(algorithms)19 +b(and)h(their)f(applications)g(are)i(further)d(described)h(in)i([6)o +(].)100 1785 y(The)46 b(multi-constraint)f(partitioning)g(algorithm)h +(is)i(implemented)d(by)h(the)h Fz(METIS)p 2781 1785 25 +4 v 31 w(mCP)m(ar)s(tGr)o(aphRecursiv)n(e)g FL(and)0 +1895 y Fz(METIS)p 258 1895 V 31 w(mCP)m(ar)s(tGr)o(aphKw)o(a)n(y)25 +b FL(routines)g(that)h(are)g(based)g(on)f(the)h(multile)n(v)o(el)f +(recursi)n(v)o(e)f(bisection)h(and)g(the)h(multile)n(v)o(el)f +Ft(k)5 b FL(-w)o(ay)0 2004 y(partitioning)21 b(paradigms,)i(respecti)n +(v)o(ely)-5 b(.)32 b(Also,)24 b(the)g Fz(pmetis)g FL(and)f(the)g +Fz(kmetis)h FL(programs)d(ha)n(v)o(e)i(been)g(o)o(v)o(erloaded)d(to)j +(in)m(v)n(ok)o(e)g(the)0 2114 y(multi-constraint)h(partitioner)g(when)i +(the)g(input)f(graph)g(contains)g(multiple)g(v)o(erte)o(x)g(weights)h +(\(Section)f(4.5.1)g(describes)g(ho)n(w)h(the)0 2223 +y(format)19 b(of)h(the)g(input)g(graph)e(\002le)j(has)g(been)e(e)o +(xtended)f(to)j(allo)n(w)f(you)f(to)i(specify)e(multiple)h(v)o(erte)o +(x)e(weights\).)0 2433 y FB(Minimizing)25 b(the)g(T)-7 +b(otal)25 b(Comm)n(unication)f(V)-7 b(olume)99 b FL(The)22 +b(objecti)n(v)o(e)f(of)i(the)f(traditional)f(graph)g(partitioning)g +(problem)g(is)0 2542 y(to)f(compute)e(a)i(balanced)e +Ft(k)5 b FL(-w)o(ay)19 b(partitioning)f(such)h(that)h(the)g(number)d +(of)j(edges)f(\(or)g(in)h(the)f(case)h(of)g(weighted)e(graphs)h(the)g +(sum)h(of)0 2652 y(their)f(weights\))g(that)h(straddle)f(dif)n(ferent)f +(partitions)h(is)i(minimized.)i(When)d(partitioning)d(is)k(used)e(to)h +(distrib)n(ute)f(a)h(graph)e(or)i(a)g(mesh)0 2761 y(among)f(the)i +(processors)f(of)h(a)g(parallel)f(computer)m(,)f(the)i(objecti)n(v)o(e) +e(of)i(minimizing)e(the)i(edgecut)f(is)h(only)f(an)h(approximation)d +(of)j(the)0 2871 y(true)j(communication)e(cost)i(resulting)g(from)f +(the)i(partitioning.)36 b(Despite)24 b(that,)i(for)d(a)i(wide)g(range)e +(of)h(problems,)g(by)g(minimizing)0 2981 y(the)c(edgecut,)f(the)h +(partitioning)e(algorithms)h(also)i(minimize)e(the)h(communication)e +(cost)i(reasonably)f(well.)100 3090 y(Ho)n(we)n(v)o(er)m(,)29 +b(there)f(are)h(cases)h(in)f(which)f(a)i(partitioning)d(algorithm)g +(can)i(signi\002cantly)f(reduce)g(the)h(communication)d(cost)j(by)0 +3200 y(directly)24 b(minimizing)f(this)j(objecti)n(v)o(e)d(\(as)i +(opposed)e(to)i(the)g(edgecut\).)39 b Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)29 b FL(no)n(w)c(pro)o(vides)e(the)i +Fz(METIS)p 3238 3200 V 30 w(P)m(ar)s(tGr)o(aphVKw)o(a)n(y)0 +3309 y FL(and)32 b Fz(METIS)p 411 3309 V 30 w(WP)m(ar)s(tGr)o(aphVKw)o +(a)n(y)h FL(routines)e(that)h(directly)g(minimize)f(the)h +(communication)d(cost)k(as)g(de\002ned)e(by)g(the)h(total)0 +3419 y(communication)16 b(v)n(olume)i(resulted)g(by)h(the)g +(partitioning)e(\(see)i(Section)g(5.3)f(for)g(a)i(precise)e +(de\002nition)g(of)h(this)g(objecti)n(v)o(e)f(function\).)0 +3529 y(Note)24 b(that)g(for)f(these)h(routines)f(to)g(pro)o(vide)f +(meaningful)g(partitionings,)g(the)i(connecti)n(vity)e(of)h(the)h +(graph)f(should)f(re\003ect)i(the)g(true)0 3638 y(information)18 +b(e)o(xchange)g(requirements)g(of)i(the)g(underlying)e(computation.)0 +3847 y FB(Minimizing)28 b(the)g(Maxim)n(um)h(Connectivity)f(of)g(the)h +(Subdomains)99 b FL(The)25 b(communication)d(cost)k(resulting)e(from)h +(a)h Ft(k)5 b FL(-)0 3957 y(w)o(ay)23 b(partitioning)e(in)j(general)e +(depends)g(on)g(the)i(follo)n(wing)d(f)o(actors:)31 b(\(i\))23 +b(the)g(total)h(communication)c(v)n(olume,)j(\(ii\))g(the)g(maximum)0 +4067 y(amount)e(of)i(data)f(that)h(an)o(y)f(particular)f(processor)g +(needs)h(to)h(send)g(and)f(recei)n(v)o(e;)h(and)f(\(iii\))g(the)h +(number)e(of)h(messages)h(a)g(processor)0 4176 y(needs)f(to)h(send)g +(and)f(recei)n(v)o(e.)31 b(The)23 b(partitioning)d(routines)i(in)h +(earlier)f(v)o(ersions)g(of)i Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)27 b FL(concentrated)21 b(only)h(on)g(the)h(\002rst)g(f)o +(actor)0 4286 y(\(by)30 b(minimizing)f(the)h(edgecut\).)54 +b(In)30 b(this)h(release,)k Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)35 b FL(also)c(pro)o(vides)d(support)i(for)f(minimizing)g +(the)i(third)f(f)o(actor)f(\(which)0 4395 y(essentially)21 +b(reduces)f(the)h(number)e(of)h(startups\))g(and)h(indirectly)e(\(up)h +(to)h(a)g(point\))f(reduces)g(the)h(second)f(f)o(actor)-5 +b(.)26 b(Experiments)19 b(ha)n(v)o(e)0 4505 y(sho)n(wn)26 +b(that)h(for)f(most)h(graphs)e(corresponding)e(to)k(\002nite)g(element) +f(meshes,)i(the)f(ne)n(w)g(release)f(of)j Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)31 b FL(is)d(able)e(to)h(reduce)f(the)0 +4614 y(maximum)i(\(and)g(total\))h(number)f(of)h(adjacent)f(subdomains) +g(considerably\227especially)e(when)j(the)g(graph)f(is)i(partitioned)e +(in)h(a)0 4724 y(relati)n(v)o(ely)18 b(lar)o(ge)g(number)f(of)i +(partitions)f(\()p Fs(e)o(.g)o FL(.,)h(greater)f(than)h(30\).)24 +b(F)o(or)19 b(most)g(3D)g(\002nite)g(elements)g(graphs,)f(the)h +(maximum)e(number)0 4834 y(of)j(subdomains)e(for)i(a)h(50-w)o(ay)d +(partition)i(has)g(been)f(reduced)g(from)g(around)f(25)i(to)h(around)d +(16.)100 4943 y(This)66 b(enhancement)d(is)j(pro)o(vided)e(as)i(a)g +(re\002nement)e(option)h(for)g(both)g(the)h Fz(METIS)p +3041 4943 V 30 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)g FL(and)0 +5053 y Fz(METIS)p 258 5053 V 31 w(P)m(ar)s(tGr)o(aphVKw)o(a)n(y)20 +b FL(routines,)f(and)h(is)h(the)f(def)o(ault)g(option)f(of)g +Fz(kmetis)i FL(and)f Fz(METIS)p 2822 5053 V 30 w(P)m(ar)s(tGr)o(aphKw)o +(a)n(y)p FL(.)0 5262 y FB(Reducing)28 b(the)h(Number)g(of)f +(Non-Contiguous)e(Subdomains)99 b FL(A)26 b Ft(k)5 b +FL(-w)o(ay)25 b(partitioning)f(of)h(a)h(contiguous)e(graph)g(can)0 +5372 y(often)h(lead)g(to)h(some)f(subdomains)f(being)g(assigned)h +(non-contiguous)d(portions)i(of)i(the)f(graph.)40 b(F)o(or)25 +b(man)o(y)f(problems,)h(the)h(non-)1929 5649 y(6)p eop +%%Page: 7 7 +7 6 bop 120 100 3661 17 v 120 199 a Fr(Chang)q(es)28 +b(in)i(M)-6 b Fq(E)-21 b Fr(T)g Fq(I)o Fr(S)r(')-6 b(s)33 +b(stand-alone)c(pr)n(ograms)p 120 257 V 120 357 a Fz(pmetis)1016 +b FL(It)24 b(has)f(been)g(o)o(v)o(er)n(-loaded)d(to)j(in)m(v)n(ok)o(e)f +(the)i(multi-constraint)d(partitioning)g(algo-)1380 457 +y(rithm)f(when)f(the)h(graph)f(contains)h(multiple)f(v)o(erte)o(x)g +(weights.)120 643 y Fz(kmetis)1020 b FL(It)24 b(has)f(been)g(o)o(v)o +(er)n(-loaded)d(to)j(in)m(v)n(ok)o(e)f(the)i(multi-constraint)d +(partitioning)g(algo-)1380 742 y(rithm)f(when)f(the)h(graph)f(contains) +h(multiple)f(v)o(erte)o(x)g(weights.)1380 842 y(The)k(partitioning)e +(algorithm)h(has)h(been)f(modi\002ed)g(to)i(also)f(minimize)f(the)h +(con-)1380 941 y(necti)n(vity)c(of)h(the)g(subdomains.)1380 +1041 y(A)f(pre-)e(and)g(post-re\002nement)f(step)i(is)h(applied)e(that) +i(tries)f(to)g(reduce)f(the)h(number)1380 1141 y(of)i(non-contiguous)c +(subdomains.)120 1327 y Fz(par)s(tnmesh)120 1426 y(par)s(tdmesh)1380 +1327 y FL(The)23 b(partitioning)e(algorithm)h(has)h(been)f(modi\002ed)g +(to)i(also)f(minimize)f(the)h(con-)1380 1426 y(necti)n(vity)c(of)h(the) +g(subdomains.)p 120 1469 V 120 1768 V 120 1868 a Fr(Chang)q(es)28 +b(in)i(M)-6 b Fq(E)-21 b Fr(T)g Fq(I)o Fr(S)r(lib')-6 +b(s)32 b(r)n(outines)p 120 1926 V 120 2025 a Fz(METIS)p +378 2025 25 4 v 31 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)120 +2125 y(METIS)p 378 2125 V 31 w(WP)m(ar)s(tGr)o(aphKw)o(a)n(y)1380 +2025 y FL(A)19 b(ne)n(w)f(re\002nement)f(algorithm)f(has)j(been)e +(added)h(that)g(also)g(minimizes)g(the)g(con-)1380 2125 +y(necti)n(vity)j(of)i(the)f(subdomains.)30 b(This)22 +b(ne)n(w)h(algorithm)d(has)j(been)f(made)g(the)g(de-)1380 +2225 y(f)o(ault)e(option.)1380 2324 y(A)f(pre-)e(and)g +(post-re\002nement)f(step)i(is)h(applied)e(that)i(tries)f(to)g(reduce)f +(the)h(number)1380 2424 y(of)i(non-contiguous)c(subdomains.)120 +2611 y Fz(METIS)p 378 2611 V 31 w(P)m(ar)s(tGr)o(aphVKw)o(a)n(y)120 +2710 y(METIS)p 378 2710 V 31 w(WP)m(ar)s(tGr)o(aphVKw)o(a)n(y)1380 +2611 y FL(This)28 b(is)h(a)f(ne)n(w)g(set)g(of)g(routines)f(that)h +(compute)e(a)j Ft(k)5 b FL(-w)o(ay)27 b(partitioning)f(whose)1380 +2710 y(objecti)n(v)o(e)19 b(is)i(to)f(minimize)g(the)g(total)g +(communication)e(v)n(olume.)120 2898 y Fz(METIS)p 378 +2898 V 31 w(mCP)m(ar)s(tGr)o(aphRecursiv)n(e)120 2997 +y(METIS)p 378 2997 V 31 w(mCP)m(ar)s(tGr)o(aphKw)o(a)n(y)1380 +2898 y FL(This)h(is)h(a)f(ne)n(w)g(set)h(of)e(routines)g(that)h +(compute)f(a)h Ft(k)5 b FL(-w)o(ay)19 b(partitioning)e(subject)h(to) +1380 2997 y(multiple)i(balancing)e(constraints.)p 120 +3040 3661 17 v 1105 3276 a Fy(T)-5 b(ab)o(le)18 b(1)p +FL(:)26 b Fx(Summar)r(y)18 b(of)h(the)f(changes)h(in)h(M)l +Fv(E)-17 b Fx(T)g Fv(I)p Fx(S)22 b(and)f(M)l Fv(E)-17 +b Fx(T)g Fv(I)p Fx(S)r(lib.)0 3459 y FL(contiguity)23 +b(is)j(a)f(result)g(of)g(the)g(underlying)d(geometry)h(and)i(often)f +(leads)h(to)g(better)g(quality)f(partitions.)38 b(Ne)n(v)o(ertheless,) +25 b(there)g(are)0 3569 y(cases)32 b(in)g(which)e(the)i(partitioning)d +(algorithm)h(is)i(fooled)e(and)h(breaks)f(certain)h(domains.)59 +b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)36 b FL(no)n(w)31 +b(pro)o(vides)e(support)h(for)0 3678 y(eliminating)19 +b(such)h(spurious)f(non-contiguous)d(subdomains.)100 +3788 y(This)j(support)f(is)i(pro)o(vided)c(as)k(a)f(def)o(ault)g +(option)f(for)g(both)g(the)h Fz(METIS)p 2213 3788 25 +4 v 31 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)g FL(and)g Fz(METIS)p +3238 3788 V 30 w(P)m(ar)s(tGr)o(aphVKw)o(a)n(y)0 3898 +y FL(routines,)g(and)h(the)g Fz(kmetis)g FL(program.)1929 +5649 y(7)p eop +%%Page: 8 8 +8 7 bop 0 85 a FD(4)119 b(M)-6 b FA(E)-23 b FD(T)g FA(I)p +FD(S)s(')-7 b(s)31 b(Stand-Alone)g(Pr)n(ograms)2 261 +y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)32 b FL(pro)o(vides)27 +b(a)h(v)n(ariety)f(of)h(programs)e(that)i(can)g(be)g(used)g(to)g +(partition)f(graphs,)h(partition)f(meshes,)j(compute)d(\002ll-reducing) +0 370 y(orderings)21 b(of)i(sparse)h(matrices,)f(as)h(well)g(as)g +(programs)d(to)j(con)m(v)o(ert)d(meshes)i(into)g(graphs)f(appropriate)f +(for)j Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r FL(')-5 +b(s)26 b(graph)c(parti-)0 480 y(tioning)d(programs.)100 +590 y(The)j(rest)h(of)f(this)h(section)f(pro)o(vides)e(detailed)i +(descriptions)f(about)h(the)g(functionality)f(of)h(these)g(programs,)f +(ho)n(w)h(to)h(use)f(them,)0 699 y(the)e(format)f(of)h(the)g(input)g +(\002les)h(required)d(by)i(them,)g(and)f(the)i(format)e(of)h(the)g +(produced)d(output)i(\002les.)0 927 y Fr(4.1)100 b(Graph)27 +b(P)m(ar)r(titioning)g(Pr)n(ograms)2 1086 y Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)30 b FL(pro)o(vides)25 b(tw)o(o)h(programs)e +Fp(pmetis)i FL(and)g Fp(kmetis)f FL(for)h(partitioning)e(an)i +(unstructured)d(graph)i(into)h Ft(k)32 b FL(equal)25 +b(size)i(parts.)0 1196 y(The)c(partitioning)f(algorithm)h(used)g(by)h +Fp(pmetis)f FL(is)i(based)e(on)g(multile)n(v)o(el)g(recursi)n(v)o(e)g +(bisection)g(described)f(in)i([8)o(],)h(whereas)f(the)0 +1305 y(partitioning)j(algorithm)h(used)h(by)f Fp(kmetis)h +FL(is)h(based)f(on)g(multile)n(v)o(el)f Ft(k)5 b FL(-w)o(ay)29 +b(partitioning)e(described)h(in)h([7)o(].)52 b(Both)29 +b(of)g(these)0 1415 y(programs)24 b(are)i(able)g(to)g(produce)e(high)h +(quality)g(partitions.)41 b(Ho)n(we)n(v)o(er)m(,)26 b(depending)d(on)i +(the)h(application,)g(one)f(program)f(may)i(be)0 1524 +y(preferable)16 b(than)i(the)g(other)-5 b(.)23 b(In)18 +b(general,)f Fp(kmetis)h FL(is)h(preferred)c(when)j(it)g(is)h +(necessary)f(to)g(partition)f(graphs)g(into)g(more)g(than)h(eight)0 +1634 y(partitions.)37 b(F)o(or)25 b(such)f(cases,)i Fp(kmetis)e +FL(is)i(considerably)c(f)o(aster)j(than)f Fp(pmetis)p +FL(.)38 b(On)24 b(the)h(other)f(hand,)g Fp(pmetis)g FL(is)i(preferable) +0 1744 y(for)20 b(partitioning)e(a)i(graph)f(into)h(a)h(small)f(number) +f(of)h(partitions.)100 1853 y(Both)g Fp(pmetis)f FL(and)h +Fp(kmetis)g FL(are)g(in)m(v)n(ok)o(ed)e(by)i(pro)o(viding)d(tw)o(o)k +(ar)o(guments)d(at)j(the)f(command)e(line)i(as)h(follo)n(ws:)257 +2046 y FB(pmetis)124 b Fs(Gr)o(aphF)l(ile)f(Nparts)257 +2155 y FB(kmetis)129 b Fs(Gr)o(aphF)l(ile)123 b(Nparts)100 +2348 y FL(The)30 b(\002rst)h(ar)o(gument)e Fs(Gr)o(aphF)l(ile)p +FL(,)j(is)f(the)g(name)f(of)g(the)h(\002le)g(that)g(stores)g(the)f +(graph)f(\(whose)h(format)g(is)h(described)f(in)g(Sec-)0 +2458 y(tion)19 b(4.5.1\),)f(while)i(the)f(second)g(ar)o(gument)e +Fs(Nparts)p FL(,)j(is)h(the)e(number)f(of)h(partitions)g(that)h(is)g +(desired.)k(Both)c Fp(pmetis)f FL(and)g Fp(kmetis)0 2567 +y FL(can)i(partition)g(a)h(graph)e(into)h(an)g(arbitrary)f(number)g(of) +h(partitions.)28 b(Upon)21 b(successful)g(e)o(x)o(ecution,)e(both)i +(programs)f(display)h(statis-)0 2677 y(tics)i(re)o(garding)c(the)j +(quality)f(of)h(the)g(computed)e(partitioning)f(and)j(the)g(amount)e +(of)i(time)g(tak)o(en)g(to)g(perform)e(the)i(partitioning.)28 +b(The)0 2786 y(actual)20 b(partitioning)e(is)j(stored)f(in)g(a)h +(\002le)g(named)e Fo(GraphF)m(ile.part.Nparts)p FL(,)f(whose)i(format)f +(is)j(described)c(in)j(Section)f(4.6.1.)100 2896 y(Figure)k(3)h(sho)n +(ws)g(the)g(output)f(of)g Fp(pmetis)h FL(and)f Fp(kmetis)h +FL(for)f(partitioning)f(a)i(graph)f(into)h(100)f(parts.)39 +b(From)24 b(this)i(\002gure)e(we)0 3006 y(see)19 b(that)g(both)e +(programs)g(initially)h(print)g(information)e(about)i(the)g(graph,)f +(such)i(as)g(its)g(name,)f(the)h(number)d(of)j(v)o(ertices)f(\()p +Fs(#V)-9 b(ertices)p FL(\),)0 3115 y(the)22 b(number)f(of)h(edges)g(\() +p Fs(#Edg)o(es)p FL(\),)f(and)g(also)i(the)f(number)f(of)h(desired)f +(partitions)h(\()p Fs(#P)-7 b(arts)p FL(\).)30 b(Ne)o(xt,)23 +b(the)o(y)e(print)h(some)g(information)0 3225 y(re)o(garding)h(the)j +(quality)f(of)h(the)g(partitioning.)40 b(Speci\002cally)-5 +b(,)26 b(the)o(y)g(report)e(the)i(number)f(of)g(edges)h(being)f(cut)h +(\()p Fs(Edg)o(e-Cut)p FL(\))e(by)i(the)0 3334 y(partitioning,)j(as)g +(well)g(as)h(the)e(balance)g(of)h(the)f(partitioning)1841 +3304 y Fn(1)1875 3334 y FL(.)51 b(Finally)-5 b(,)30 b(both)d +Fp(pmetis)i FL(and)f Fp(kmetis)g FL(sho)n(w)g(the)h(time)g(tak)o(en)0 +3444 y(by)e(the)g(v)n(arious)f(phases)h(of)g(the)g(algorithm.)44 +b(All)27 b(times)h(are)f(in)g(seconds.)45 b(F)o(or)27 +b(this)g(particular)f(e)o(xample,)h Fp(pmetis)g FL(required)e(a)0 +3553 y(total)g(of)g(17.070)d(seconds,)j(of)g(which)f(13.850)f(seconds)h +(w)o(as)i(tak)o(en)e(by)h(the)g(partitioning)e(algorithm)g(itself,)j +(and)f(the)f(rest)i(w)o(as)f(to)0 3663 y(read)d(the)g(graph)f(itself.) +31 b(Similarly)-5 b(,)22 b Fp(kmetis)g FL(required)e(a)j(total)f(of)g +(6.790)e(seconds,)i(of)g(which)g(3.570)e(seconds)i(w)o(as)h(tak)o(en)f +(by)g(the)0 3773 y(partitioning)e(algorithm)g(itself.)31 +b(As)23 b(you)e(can)h(see)g(from)f(this)i(e)o(xample,)d +Fp(kmetis)i FL(is)h(considerably)c(f)o(aster)j(than)g +Fp(pmetis)p FL(,)f(and)h(it)0 3882 y(produces)c(a)j(partitioning)d +(that)j(is)g(slightly)f(better)f(than)h(that)g(produced)e(by)i +Fp(pmetis)p FL(.)100 3992 y(Figure)e(4)g(sho)n(ws)h(the)f(output)g(of)g +Fp(pmetis)g FL(and)g Fp(kmetis)g FL(for)g(partitioning)f(a)i(graph)e +(into)h(16)g(parts)h(subject)f(to)h(three)f(balancing)0 +4101 y(constraints.)41 b(Both)26 b Fp(pmetis)f FL(and)h +Fp(kmetis)f FL(ha)n(v)o(e)g(been)g Fs(o)o(ver)n(-loaded)f +FL(to)i(in)m(v)n(ok)o(e)f(the)h(multi-constraint)e(partitioning)g +(routines)0 4211 y(whene)n(v)o(er)c(the)i(input)g(graph)e(\002le)j +(speci\002es)g(more)e(that)h(one)g(set)h(of)f(v)o(erte)o(x)f(weights.) +30 b(Comparing)21 b(the)h(output)f(of)g(Figure)h(4)g(to)g(that)0 +4321 y(of)c(Figure)f(3)h(we)g(see)h(that)f(when)f Fp(pmetis)h +FL(and)f Fp(kmetis)h FL(operate)e(in)j(the)f(multi-constraint)d(mode)i +(the)o(y)h(display)f(some)h(additional)0 4430 y(information)d(re)o +(garding)g(the)j(number)e(of)i(constraints)f(and)h(also)g(the)g +(balance)f(of)g(the)h(computed)e(partitioning)g(with)i(respect)g(to)g +(each)0 4540 y(one)j(of)h(these)g(constraints.)28 b(In)22 +b(this)g(e)o(xample,)f Fp(pmetis)g FL(w)o(as)h(able)g(to)g(balance)f +(the)g(three)h(constraints)f(within)g(1\045,)h(3\045,)g(and)g(2\045,)0 +4649 y(respecti)n(v)o(ely)-5 b(.)22 b(Note)c(that)g(for)g +(multi-constraint)e(partitioning,)g(for)h(small)i(number)d(of)i +(partitions)f Fp(pmetis)h FL(outperforms)d Fp(kmetis)0 +4759 y FL(in)20 b(terms)h(of)f(partitioning)e(quality)-5 +b(.)24 b(Ho)n(we)n(v)o(er)m(,)18 b(for)i(lar)o(ger)f(number)f(of)i +(partitions)g Fp(kmetis)g FL(achie)n(v)o(es)f(better)h(quality)f(and)h +(is)h(more)0 4869 y(rob)n(ust)f(in)g(simultaneously)f(balancing)f(the)i +(v)n(arious)f(constraints.)p 0 5031 1560 4 v 87 5091 +a Fm(1)120 5115 y FF(F)o(or)d(a)h Fk(k)k FF(w)o(ay)c(partition)j(of)c +(a)h(graph)h(with)f Fk(n)j FF(v)o(ertices,)f(let)e Fk(m)k +FF(be)c(the)g(size)h(of)f(the)g(lar)o(gest)h(part)g(produced)g(by)f +(the)h Fk(k)5 b FF(-w)o(ay)17 b(partitioning)j(algorithm.)j(The)16 +b(balance)0 5194 y(of)i(the)h(partitioning)i(is)d(de\002ned)h(as)f +Fk(k)5 b(m)t Fl(=)t Fk(n)s FF(,)17 b(and)i(is)f(essentially)j(the)d +(load)h(imbalance)i(induced)f(by)e(non-equal)i(partitions.)26 +b Fj(pmetis)17 b FF(produces)i(partitions)i(that)e(are)0 +5273 y(perfectly)h(balanced)g(at)d(each)i(bisection)g(le)n(v)o(el,)g +(ho)n(we)n(v)o(er)m(,)g(some)e(small)h(load)g(imbalance)i(may)d(result) +h(due)g(to)g(the)f(log)12 b Fk(k)22 b FF(le)n(v)o(els)d(of)e(recursi)n +(v)o(e)i(bisection.)24 b(In)17 b(general,)0 5352 y(the)g(load)g +(imbalance)h(is)e(less)h(than)f(1\045.)21 b Fj(kmetis)15 +b FF(produces)i(partitions)i(that)e(are)f(not)h(perfectly)i(balanced,)f +(b)o(ut)e(the)h(algorithm)h(limits)f(the)g(load)g(imbalance)h(to)f +(3\045.)1929 5649 y FL(8)p eop +%%Page: 9 9 +9 8 bop 478 90 a Fi(')p 478 2466 7 2214 v 478 2635 a(&)3415 +90 y($)p 3415 2466 V 3415 2635 a(\045)p 648 2635 2605 +7 v 648 90 V 590 159 a Fj(prompt\045)39 b(pmetis)f(brack2.graph)h(100) +590 237 y(******************************************)o(*******)o +(******)o(*******)o(*******)o(*)669 316 y(METIS)h(4.0)119 +b(Copyright)38 b(1998,)h(Regents)g(of)h(the)f(University)f(of)i +(Minnesota)590 474 y(Graph)f(Information)f +(--------------------------------------------)o(-------)669 +553 y(Name:)i(brack2.graph,)d(#Vertices:)i(62631,)g(#Edges:)g(366559,)f +(#Parts:)h(100)590 711 y(Recursive)f(Partitioning...)g +(-------------------------------------------)669 790 +y(100-way)h(Edge-Cut:)118 b(37494,)39 b(Balance:)79 b(1.00)590 +947 y(Timing)39 b(Information)f +(-------------------------------------------)o(-------)669 +1026 y(I/O:)1155 b(0.820)669 1105 y(Partitioning:)795 +b(6.110)119 b(\(PMETIS)39 b(time\))669 1184 y(Total:)1075 +b(6.940)590 1263 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)590 1421 y(prompt\045)39 +b(kmetis)f(brack2.graph)h(100)590 1499 y +(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 1578 y(METIS)h(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +1736 y(Graph)f(Information)f +(--------------------------------------------)o(-------)669 +1815 y(Name:)i(brack2.graph,)d(#Vertices:)i(62631,)g(#Edges:)g(366559,) +f(#Parts:)h(100)590 1973 y(K-way)g(Partitioning...)e +(-----------------------------------------------)669 +2052 y(100-way)i(Edge-Cut:)118 b(37310,)39 b(Balance:)79 +b(1.03)590 2209 y(Timing)39 b(Information)f +(-------------------------------------------)o(-------)669 +2288 y(I/O:)1155 b(0.820)669 2367 y(Partitioning:)795 +b(1.750)119 b(\(KMETIS)39 b(time\))669 2446 y(Total:)1075 +b(2.570)590 2525 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)546 2871 y +Fy(Figure)18 b(3)p FL(:)25 b Fx(Output)19 b(of)f Fp(pmetis)g +Fx(and)h Fp(kmetis)e Fx(f)n(or)i(g)o(r)o(aph)g Fh(br)o(ac)n(k2.g)o(r)o +(aph)g Fx(and)f(a)h(100-w)o(a)n(y)g(par)s(tition.)0 3055 +y Fr(4.2)100 b(Mesh)28 b(P)m(ar)r(titioning)g(Pr)n(ograms)2 +3214 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)34 b FL(pro)o(vides)28 +b(tw)o(o)i(programs)d Fp(partnmesh)i FL(and)g Fp(partdmesh)f +FL(for)h(partitioning)f(meshes)h(\()p Fs(e)o(.g)o FL(.,)j(those)d +(arising)h(in)f(\002nite)0 3324 y(element)20 b(or)g(\002nite)g(v)n +(olume)g(methods\))e(into)j Ft(k)k FL(equal)20 b(size)h(parts.)k(These) +20 b(programs)f(tak)o(e)h(as)h(input)f(the)g(element)g(node)f(array)h +(of)g(the)0 3434 y(mesh)i(and)f(compute)f(a)j(partitioning)c(for)j +(both)f(its)h(elements)g(and)f(its)i(nodes.)31 b Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)26 b FL(currently)21 b(supports)f(four)h +(dif)n(ferent)f(types)i(of)0 3543 y(mesh)e(elements)g(which)g(are)g +(triangles,)f(tetrahedra,)g(he)o(xahedra)e(\(bricks\),)i(and)h +(quadrilaterals.)100 3653 y(These)j(programs)f(\002rst)j(con)m(v)o(ert) +c(the)j(mesh)g(into)f(a)h(graph,)f(and)h(then)f(use)h +Fp(kmetis)f FL(to)h(partition)f(this)h(graph.)34 b(The)24 +b(dif)n(ference)0 3762 y(between)g(these)h(tw)o(o)g(programs)e(is)j +(that)f Fp(partnmesh)f FL(con)m(v)o(erts)f(the)i(mesh)g(into)f(a)i +(nodal)e(graph)f(\()p Fs(i.e)p FL(.,)j(each)e(node)g(of)h(the)g(mesh)0 +3872 y(becomes)17 b(a)h(v)o(erte)o(x)f(of)g(the)h(graph\),)e(whereas)i +Fp(partdmesh)f FL(con)m(v)o(erts)f(the)i(mesh)f(into)h(a)g(dual)g +(graph)e(\()p Fs(i.e)o FL(.,)j(each)e(element)h(becomes)0 +3981 y(a)f(v)o(erte)o(x)f(of)h(the)g(graph\).)22 b(In)17 +b(the)g(case)g(of)g Fp(partnmesh)p FL(,)g(the)g(partitioning)e(of)i +(the)g(nodal)f(graph)f(is)j(used)f(to)g(deri)n(v)o(e)f(a)i +(partitioning)d(of)0 4091 y(the)h(elements.)23 b(In)16 +b(the)g(case)g(of)f Fp(partdmesh)p FL(,)h(the)g(partitioning)e(of)h +(the)h(dual)f(graph)g(is)i(used)e(to)h(deri)n(v)o(e)f(a)h(partitioning) +e(of)i(the)g(nodes.)0 4201 y(Both)21 b(of)f(these)h(programs)e(produce) +f(partitioning)h(of)h(comparable)f(quality)-5 b(,)19 +b(with)i Fp(partnmesh)e FL(being)h(considerably)e(f)o(aster)j(than)0 +4310 y Fp(partdmesh)p FL(.)41 b(Ho)n(we)n(v)o(er)m(,)25 +b(in)h(some)g(cases,)h Fp(partnmesh)e FL(may)g(produce)f(partitions)h +(that)h(ha)n(v)o(e)g(higher)e(load)h(imbalance)g(than)0 +4420 y Fp(partdmesh)p FL(.)100 4529 y(Both)20 b Fp(partnmesh)f +FL(and)h Fp(partdmesh)f FL(are)h(in)m(v)n(ok)o(ed)e(by)i(pro)o(viding)d +(tw)o(o)k(ar)o(guments)d(at)j(the)f(command)e(line)i(as)h(follo)n(ws:) +257 4722 y FB(par)r(tnmesh)124 b Fs(MeshF)l(ile)g(Nparts)257 +4832 y FB(par)r(tdmesh)g Fs(MeshF)l(ile)g(Nparts)100 +5024 y FL(The)15 b(\002rst)i(ar)o(gument)c Fs(MeshF)l(ile)p +FL(,)k(is)g(the)f(name)f(of)g(the)h(\002le)h(that)e(stores)i(the)e +(mesh)h(\(whose)f(format)g(is)i(described)d(in)i(Section)g(4.5.2\),)0 +5134 y(while)h(the)f(second)g(ar)o(gument)e Fs(Nparts)p +FL(,)j(is)h(the)e(number)f(of)h(partitions)g(that)g(is)i(desired.)23 +b(Both)16 b Fp(partnmesh)g FL(and)f Fp(partdmesh)h FL(can)0 +5243 y(partition)24 b(a)i(mesh)f(into)g(an)g(arbitrary)e(number)h(of)h +(partitions.)39 b(Upon)24 b(successful)h(e)o(x)o(ecution,)f(both)g +(programs)f(display)i(statistics)0 5353 y(re)o(garding)h(the)j(quality) +g(of)g(the)g(computed)e(partitioning)g(and)i(the)g(amount)f(of)h(time)g +(tak)o(en)g(to)h(perform)d(the)i(partitioning.)50 b(The)1929 +5649 y(9)p eop +%%Page: 10 10 +10 9 bop 478 90 a Fi(')p 478 2624 7 2372 v 478 2793 a(&)3415 +90 y($)p 3415 2624 V 3415 2793 a(\045)p 648 2793 2605 +7 v 648 90 V 590 159 a Fj(prompt\045)39 b(pmetis)f(m14.graph3)h(16)590 +237 y(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 316 y(METIS)h(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +474 y(Graph)f(Information)f +(--------------------------------------------)o(-------)669 +553 y(Name:)i(m14.graph3,)e(#Vertices:)g(214765,)h(#Edges:)g(1679018,)f +(#Parts:)h(16)669 632 y(Balancing)g(Constraints:)f(3)590 +790 y(Recursive)g(Partitioning...)g +(-------------------------------------------)669 868 +y(16-way)h(Edge-Cut:)119 b(74454,)39 b(Balance:)78 b(1.01)h(1.03)g +(1.02)590 1026 y(Timing)39 b(Information)f +(-------------------------------------------)o(-------)669 +1105 y(I/O:)1155 b(4.310)669 1184 y(Partitioning:)756 +b(28.410)118 b(\(PMETIS)39 b(time\))669 1263 y(Total:)1036 +b(32.830)590 1342 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)590 1499 y(prompt\045)39 +b(kmetis)f(m14.graph3)h(16)590 1578 y +(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 1657 y(METIS)h(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +1815 y(Graph)f(Information)f +(--------------------------------------------)o(-------)669 +1894 y(Name:)i(m14.graph3,)e(#Vertices:)g(214765,)h(#Edges:)g(1679018,) +f(#Parts:)h(16)669 1973 y(Balancing)g(Constraints:)f(3)590 +2130 y(K-way)h(Partitioning...)e +(-----------------------------------------------)669 +2209 y(16-way)i(Edge-Cut:)119 b(71410,)39 b(Balance:)78 +b(1.04)h(1.04)g(1.04)590 2367 y(Timing)39 b(Information)f +(-------------------------------------------)o(-------)669 +2446 y(I/O:)1155 b(4.020)669 2525 y(Partitioning:)795 +b(7.430)119 b(\(KMETIS)39 b(time\))669 2604 y(Total:)1036 +b(11.550)590 2682 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)172 3028 y +Fy(Figure)18 b(4)p FL(:)26 b Fx(Output)18 b(of)h Fp(pmetis)f +Fx(and)g Fp(kmetis)g Fx(f)n(or)h(a)f(m)o(ulti-constr)o(aint)h(g)o(r)o +(aph)f(with)h(three)g(constr)o(aints)f(and)h(a)f(16-w)o(a)n(y)h(par)s +(tition.)0 3213 y FL(actual)f(partitioning)f(is)j(stored)e(in)h(tw)o(o) +g(\002les)g(named:)24 b Fo(MeshF)m(ile.npart.Nparts)18 +b FL(which)g(stores)h(the)f(partitioning)f(of)h(the)h(nodes,)f(and)0 +3322 y Fo(MeshF)m(ile.epart.Nparts)j FL(which)f(stores)i(the)f +(partitioning)f(of)h(the)g(elements.)28 b(The)21 b(format)f(of)i(the)f +(partitioning)e(\002les)k(is)f(described)0 3432 y(in)e(Section)g +(4.6.1.)100 3541 y(Figure)d(5)g(sho)n(ws)h(the)g(output)e(of)h +Fp(partnmesh)g FL(and)g Fp(partdmesh)f FL(for)h(partitioning)f(a)i +(mesh)f(with)h(tetrahedron)d(elements)j(into)0 3651 y(100)h(parts.)25 +b(From)20 b(this)h(\002gure)e(we)i(see)f(that)h(both)e(programs)f +(initially)j(print)e(information)f(about)h(the)h(mesh,)g(such)g(as)h +(its)g(name,)f(the)0 3761 y(number)d(of)i(elements)f(\()p +Fs(#Elements)p FL(\),)g(the)h(number)e(of)h(nodes)g(\()p +Fs(#Nodes)p FL(\),)g(and)g(the)h(type)g(of)f(elements)h(\()p +Fs(e)o(.g)n FL(.,)h Fs(TET)p FL(\).)e(Ne)o(xt,)h(the)o(y)f(print)0 +3870 y(some)27 b(information)d(re)o(garding)g(the)j(quality)f(of)h(the) +f(partitioning.)43 b(Speci\002cally)-5 b(,)28 b(the)o(y)e(report)g(the) +h(number)e(of)h(edges)h(being)f(cut)0 3980 y(\()p Fs(Edg)o(e-Cut)p +FL(\))21 b(by)h(the)h(partitioning)1017 3950 y Fn(2)1050 +3980 y FL(,)h(as)g(well)f(as)h(the)e(balance)g(of)h(the)g +(partitioning.)31 b(F)o(or)22 b(both)g Fp(partnmesh)g +FL(and)g Fp(partdmesh)p FL(,)0 4089 y(the)h(balance)e(is)j(computed)c +(with)j(respect)f(to)h(the)f(number)f(of)h(elements.)32 +b(The)22 b(balance)g(with)g(respect)h(to)f(the)h(number)e(of)h(nodes)g +(is)0 4199 y(not)e(sho)n(wn,)f(b)n(ut)h(it)h(is)g(in)g(general)e +(similar)h(to)g(the)h(element)e(balance.)100 4309 y(Finally)-5 +b(,)20 b(both)h Fp(partnmesh)f FL(and)g Fp(partdmesh)g +FL(sho)n(w)h(the)g(time)h(that)f(w)o(as)h(tak)o(en)e(by)h(the)g(v)n +(arious)f(phases)h(of)g(the)g(algorithm.)0 4418 y(All)k(times)h(are)e +(in)h(seconds.)38 b(In)25 b(this)g(particular)f(e)o(xample,)g(it)h +(took)f Fp(partnmesh)g FL(23.370)f(seconds)h(to)h(partition)e(the)i +(mesh)g(into)0 4528 y(100)17 b(parts.)25 b(Note)18 b(that)g(this)h +(time)f(includes)g(the)g(time)g(required)f(both)g(to)i(construct)e(the) +h(nodal)f(graph)g(and)h(to)g(partition)g(it.)25 b(Similarly)-5 +b(,)0 4637 y(it)24 b(took)f Fp(partdmesh)g FL(74.560)e(seconds)i(to)h +(partition)e(the)i(same)g(mesh.)35 b(Again,)23 b(this)h(time)g +(includes)f(the)g(time)h(required)e(both)g(to)0 4747 +y(construct)j(the)h(dual)g(graph)e(and)i(to)g(partition)f(it.)43 +b(As)27 b(you)f(can)f(see)i(from)e(this)i(e)o(xample,)f +Fp(partnmesh)f FL(is)i(considerably)c(f)o(aster)0 4857 +y(than)g Fp(partdmesh)p FL(.)32 b(This)23 b(is)h(because)e(of)h(tw)o(o) +g(reasons:)31 b(\(i\))23 b(the)g(time)g(required)e(to)i(construct)f +(the)h(nodal)f(graph)g(is)i(smaller)f(than)0 4966 y(the)d(time)h +(required)d(to)i(construct)f(the)i(dual)e(graph;)g(\(ii\))h(the)h +(nodal)e(graph)g(is)i(smaller)f(than)g(the)g(dual)g(graph.)p +0 5129 1560 4 v 87 5189 a Fm(2)120 5213 y FF(The)15 b(edgecut)j(that)f +(is)f(reported)i(by)e Fj(partnmesh)e FF(is)h(that)i(of)f(the)h(nodal)g +(graph,)f(whereas)h(the)g(edgecut)h(reported)f(by)f Fj(partdmesh)e +FF(is)i(that)h(of)f(the)g(dual)h(graph.)0 5292 y(These)g(tw)o(o)h +(edgecuts)h(cannot)f(be)g(compared)g(with)g(each)g(other)m(,)g(as)f +(the)o(y)h(correspond)h(to)e(partitionings)k(of)16 b(tw)o(o)i(totally)h +(dif)n(ferent)h(graphs.)1908 5649 y FL(10)p eop +%%Page: 11 11 +11 10 bop -18 83 a FB(Note)41 b FL(If)23 b(you)g(need)h(to)g(compute)e +(multiple)h(partitionings)g(of)g(the)h(same)g(mesh,)h(it)g(may)e(be)h +(preferable)e(to)i(\002rst)h(use)f(one)f(of)208 193 y(the)18 +b(mesh)f(con)m(v)o(ersion)f(programs)g(described)h(in)h(Section)f(4.4)h +(to)g(\002rst)h(con)m(v)o(ert)d(the)i(mesh)g(into)f(a)i(graph,)e(and)g +(then)h(use)208 302 y Fp(kmetis)h FL(to)i(partition)e(it.)25 +b(By)c(doing)e(this,)h(you)g(pay)f(the)h(cost)h(of)f(con)m(v)o(erting)d +(the)j(mesh)g(into)g(a)h(graph)e(only)g(once.)478 555 +y Fi(')p 478 2772 7 2054 v 478 2941 a(&)3415 555 y($)p +3415 2772 V 3415 2941 a(\045)p 648 2941 2605 7 v 648 +555 V 590 622 a Fj(prompt\045)39 b(partnmesh)f(144.mesh)h(100)590 +701 y(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 780 y(METIS)h(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +938 y(Mesh)f(Information)f +(---------------------------------------------)o(-------)669 +1016 y(Name:)i(144.mesh,)e(#Elements:)g(905410,)h(#Nodes:)g(144649,)g +(Etype:)g(TET)590 1174 y(Partitioning)f(Nodal)h(Graph...)g +(-----------------------------------------)669 1253 y(100-way)g +(Edge-Cut:)79 b(105207,)38 b(Balance:)79 b(1.03)590 1411 +y(Timing)39 b(Information)f +(-------------------------------------------)o(-------)669 +1490 y(I/O:)1116 b(13.210)669 1569 y(Partitioning:)795 +b(7.950)590 1647 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)590 1805 y(prompt\045)39 +b(partdmesh)f(144.mesh)h(100)590 1884 y +(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 1963 y(METIS)h(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +2121 y(Mesh)f(Information)f +(---------------------------------------------)o(-------)669 +2199 y(Name:)i(144.mesh,)e(#Elements:)g(905410,)h(#Nodes:)g(144649,)g +(Etype:)g(TET)590 2357 y(Partitioning)f(Dual)h(Graph...)g +(------------------------------------------)669 2436 +y(100-way)g(Edge-Cut:)118 b(52474,)39 b(Balance:)79 b(1.03)590 +2594 y(Timing)39 b(Information)f +(-------------------------------------------)o(-------)669 +2673 y(I/O:)1116 b(11.540)669 2752 y(Partitioning:)756 +b(28.220)590 2830 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)447 3176 y +Fy(Figure)18 b(5)p FL(:)25 b Fx(Output)19 b(of)f Fp(partnmesh)f +Fx(and)i Fp(partdmesh)e Fx(f)n(or)i(mesh)f Fh(144.mesh)h +Fx(and)g(a)f(100-w)o(a)n(y)h(par)s(tition.)0 3491 y Fr(4.3)100 +b(Spar)o(se)29 b(Matrix)f(Reor)n(dering)f(Pr)n(ograms)102 +3647 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)27 b FL(pro)o(vides)20 +b(tw)o(o)j(programs)e Fp(oemetis)h FL(and)g Fp(onmetis)g +FL(for)g(computing)e(\002ll-reducing)h(orderings)g(of)h(sparse)h +(matrices.)0 3756 y(Both)d(of)f(these)h(programs)d(use)j(multile)n(v)o +(el)e(nested)i(dissection)f(to)h(compute)e(a)i(\002ll-reducing)d +(ordering)g([8].)25 b(The)19 b(nested)g(dissection)0 +3866 y(paradigm)k(is)j(based)f(on)f(computing)f(a)i(v)o(erte)o +(x-separator)d(for)i(the)h(the)g(graph)e(corresponding)f(to)j(the)g +(matrix.)39 b(The)24 b(nodes)g(in)i(the)0 3975 y(separator)18 +b(are)i(mo)o(v)o(ed)d(to)j(the)f(end)g(of)h(the)f(matrix,)g(and)g(a)h +(similar)f(process)g(is)i(applied)d(recursi)n(v)o(ely)g(for)h(each)g +(one)g(of)g(the)h(other)e(tw)o(o)0 4085 y(parts.)100 +4195 y(Ev)o(en)j(though)f(both)h(programs)f(are)i(based)g(on)g(multile) +n(v)o(el)f(nested)h(dissection,)f(the)o(y)h(dif)n(fer)f(on)g(ho)n(w)h +(the)o(y)f(compute)g(the)h(v)o(erte)o(x)0 4304 y(separators.)38 +b(The)24 b Fp(oemetis)g FL(program)f(\002nds)i(a)g(v)o(erte)o(x)e +(separator)h(by)g(\002rst)h(computing)e(an)i(edge)f(separator)f(using)h +(a)i(multile)n(v)o(el)0 4414 y(algorithm,)f(whereas)f(the)h +Fp(onmetis)g FL(program)e(uses)j(the)f(multile)n(v)o(el)f(paradigm)f +(to)i(directly)g(\002nd)g(a)g(v)o(erte)o(x)f(separator)-5 +b(.)39 b(The)25 b(or)n(-)0 4523 y(derings)20 b(produced)f(by)i +Fp(onmetis)f FL(generally)g(incur)g(less)j(\002ll)f(than)f(those)g +(produced)d(by)j Fp(oemetis)p FL(.)28 b(In)20 b(particular)m(,)g(for)h +(matrices)0 4633 y(arising)g(in)g(linear)g(programming)d(problems)i +(the)h(orderings)f(computed)f(by)i Fp(onmetis)f FL(are)h +(signi\002cantly)g(better)g(than)g(those)g(pro-)0 4742 +y(duced)f(by)g Fp(oemetis)p FL(.)26 b(Furthermore,)18 +b Fp(onmetis)i FL(utilizes)i(compression)d(techniques)g(to)i(reduce)f +(the)g(size)i(of)e(the)h(graph)f(prior)f(to)0 4852 y(computing)f(the)j +(ordering.)j(Sparse)c(matrices)g(arising)g(in)h(man)o(y)e(application)g +(domains)h(are)g(such)g(that)h(certain)f(ro)n(ws)g(of)h(the)f(matrix)0 +4962 y(ha)n(v)o(e)27 b(the)g(same)g(sparsity)g(pattern.)45 +b(Such)27 b(matrices)g(can)g(be)g(represented)e(by)i(a)h(much)e +(smaller)h(graph)f(in)h(which)g(all)g(ro)n(ws)g(with)0 +5071 y(identical)d(sparsity)g(pattern)g(are)g(represented)f(by)h(just)h +(a)g(single)g(v)o(erte)o(x)e(whose)h(weight)g(is)h(equal)f(to)h(the)f +(number)f(of)h(ro)n(ws.)38 b(Such)0 5181 y(compression)21 +b(techniques)g(can)h(signi\002cantly)g(reduce)f(the)i(size)g(of)g(the)f +(graph,)g(whene)n(v)o(er)e(applicable,)i(and)g(substantially)g(reduce)0 +5290 y(the)k(amount)f(of)g(time)i(required)d(by)h Fp(onmetis)p +FL(.)42 b(Ho)n(we)n(v)o(er)m(,)25 b(when)h(there)f(is)i(no)f(reduction) +e(in)i(graph)e(size,)k Fp(oemetis)e FL(is)h(about)0 5400 +y(20\045)19 b(to)h(30\045)f(f)o(aster)g(than)g Fp(onmetis)p +FL(.)24 b(Furthermore,)17 b(for)i(lar)o(ge)f(matrices)h(arising)g(in)h +(three-dimensional)c(problems,)i(the)h(quality)1908 5649 +y(11)p eop +%%Page: 12 12 +12 11 bop 478 7 a Fi(')p 478 2541 7 2372 v 478 2710 a(&)3415 +7 y($)p 3415 2541 V 3415 2710 a(\045)p 648 2710 2605 +7 v 648 7 V 590 76 a Fj(prompt\045)39 b(oemetis)f(bcsstk31.graph)590 +154 y(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 233 y(METIS)i(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +391 y(Graph)f(Information)f +(--------------------------------------------)o(-------)669 +470 y(Name:)i(bcsstk31.graph,)d(#Vertices:)h(35588,)h(#Edges:)g(572914) +590 628 y(Edge-Based)f(Ordering...)g +(----------------------------------------------)669 707 +y(Nonzeros:)h(4693428,)158 b(Operation)39 b(Count:)g(1.4356e+09)590 +864 y(Timing)g(Information)f +(-------------------------------------------)o(-------)669 +943 y(I/O:)1155 b(1.160)669 1022 y(Ordering:)955 b(7.380)119 +b(\(OEMETIS)39 b(time\))669 1101 y(Symbolic)g(Factorization:)396 +b(0.440)669 1180 y(Total:)1075 b(8.980)590 1259 y +(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)590 1416 y(prompt\045)39 b(onmetis)f +(bcsstk31.graph)590 1495 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)669 1574 y(METIS)i(4.0)119 +b(Copyright)38 b(1998,)h(Regents)g(of)h(the)f(University)f(of)i +(Minnesota)590 1732 y(Graph)f(Information)f +(--------------------------------------------)o(-------)669 +1811 y(Name:)i(bcsstk31.graph,)d(#Vertices:)h(35588,)h(#Edges:)g +(572914)590 1968 y(Node-Based)f(Ordering...)g +(----------------------------------------------)669 2047 +y(Nonzeros:)h(4330669,)158 b(Operation)39 b(Count:)g(1.1564e+09)590 +2205 y(Timing)g(Information)f +(-------------------------------------------)o(-------)669 +2284 y(I/O:)1155 b(1.080)669 2363 y(Ordering:)955 b(4.540)119 +b(\(ONMETIS)39 b(time\))669 2442 y(Symbolic)g(Factorization:)396 +b(0.440)669 2521 y(Total:)1075 b(6.060)590 2599 y +(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)826 2945 y Fy(Figure)18 b(6)p +FL(:)25 b Fx(Output)19 b(of)f Fp(oemetis)g Fx(and)g Fp(onmetis)g +Fx(f)n(or)g(g)o(r)o(aph)h Fh(bcsstk31.g)o(r)o(aph)q Fx(.)0 +3130 y FL(of)h(orderings)e(produced)g(by)i(the)g(tw)o(o)g(algorithms)f +(is)i(quite)f(similar)-5 b(.)100 3239 y(Both)20 b Fp(oemetis)f +FL(and)h Fp(onmetis)f FL(are)i(in)m(v)n(ok)o(ed)d(by)i(pro)o(viding)d +(one)j(ar)o(gument)e(at)i(the)g(command)f(line)h(as)h(follo)n(ws:)257 +3432 y FB(oemetis)124 b Fs(Gr)o(aphF)l(ile)257 3541 y +FB(onmetis)119 b Fs(Gr)o(aphF)l(ile)100 3734 y FL(The)23 +b(only)f(ar)o(gument)f(of)i(these)h(programs)d Fs(Gr)o(aphF)l(ile)p +FL(,)i(is)i(the)e(name)g(of)g(the)g(\002le)h(that)g(stores)g(the)f +(sparse)g(matrix)g(in)h(the)f(graph)0 3844 y(format)g(described)g(in)h +(Section)f(4.5.1.)35 b(Upon)24 b(successful)f(e)o(x)o(ecution,)g(both)g +(programs)f(display)i(statistics)h(re)o(garding)c(the)j(quality)0 +3953 y(of)19 b(the)f(computed)f(orderings)g(and)h(the)h(amount)e(of)i +(time)g(tak)o(en)f(to)h(perform)e(the)i(ordering.)j(The)d(actual)f +(ordering)f(is)i(stored)g(in)g(a)g(\002le)0 4063 y(named)g +Fo(GraphF)m(ile.iperm)p FL(,)g(whose)h(format)f(is)i(described)e(in)i +(Section)e(4.6.2.)100 4172 y(Figure)i(6)g(sho)n(ws)h(the)g(output)e(of) +h Fp(oemetis)g FL(and)g Fp(onmetis)g FL(for)g(computing)f(a)i +(\002ll-reducing)d(ordering)h(of)h(a)h(sample)f(matrix.)0 +4282 y(From)i(this)h(\002gure)f(we)h(see)g(that)f(both)g(programs)f +(initially)h(print)g(information)e(about)i(the)g(graph,)g(such)h(as)g +(its)g(name,)g(the)f(number)0 4392 y(of)e(v)o(ertices)g(\()p +Fs(#V)-9 b(ertices)p FL(\),)20 b(and)g(the)i(number)d(of)i(edges)g(\()p +Fs(#Edg)o(es)p FL(\).)26 b(Ne)o(xt,)21 b(the)o(y)f(print)g(some)h +(information)e(re)o(garding)f(the)k(quality)e(of)0 4501 +y(the)f(ordering.)k(Speci\002cally)-5 b(,)18 b(the)o(y)g(report)g(the)h +(number)f(of)g(non-zeros)f(that)j(are)f(required)e(in)i(the)g(lo)n(wer) +g(triangular)f(matrix,)g(and)h(the)0 4611 y(number)e(of)i(operations)e +(\()p Fs(OPC)p FL(\))i(required)e(to)i(f)o(actor)f(the)h(matrix)g +(using)f(Cholesk)o(y)g(f)o(actorization.)23 b(Note)c(that)g(number)e +(of)h(nonzeros)0 4720 y(includes)26 b(both)g(the)i(original)d +(non-zeros)g(and)i(the)g(ne)n(w)g(non-zeros)e(due)h(to)h(the)g(\002ll.) +46 b(Finally)-5 b(,)28 b(both)f Fp(oemetis)f FL(and)g +Fp(onmetis)0 4830 y FL(sho)n(w)h(the)g(time)h(that)f(w)o(as)h(tak)o(en) +f(by)g(the)g(v)n(arious)g(phases)g(of)g(the)g(algorithm.)45 +b(All)28 b(times)g(are)f(in)g(seconds.)46 b(F)o(or)27 +b(this)h(particular)0 4940 y(e)o(xample,)e Fp(oemetis)f +FL(tak)o(es)i(a)f(total)g(of)g(23.290)e(seconds,)j(of)f(which)f(17.760) +f(seconds)i(w)o(as)h(tak)o(en)e(by)h(the)g(ordering)e(algorithm)0 +5049 y(itself.)41 b(F)o(or)25 b(the)g(same)h(e)o(xample)e +Fp(onmetis)g FL(tak)o(es)i(a)f(total)h(of)f(17.340)e(seconds,)j(of)f +(which)g(11.810)e(seconds)i(w)o(as)h(tak)o(en)f(by)g(the)0 +5159 y(partitioning)d(algorithm)h(itself.)38 b(Note)24 +b(that)g(in)h(this)g(case)f Fp(onmetis)g FL(is)h(f)o(aster)f(than)g +Fp(oemetis)p FL(,)g(because)g Fp(onmetis)g FL(w)o(as)h(able)0 +5268 y(to)20 b(compress)g(the)g(matrix.)k(Also)d(note)e(that)i(the)f +(quality)f(of)h(the)g(\002ll-reducing)e(ordering)g(produced)g(by)i +Fp(onmetis)f FL(is)i(signi\002cantly)0 5378 y(better)j(than)g(that)g +(produced)e(by)i Fp(oemetis)p FL(.)37 b(In)24 b(f)o(act,)i(the)e +(ordering)e(produced)g(by)i Fp(onmetis)g FL(results)h(in)f(8\045)h(fe)n +(wer)f(non-zeros)1908 5649 y(12)p eop +%%Page: 13 13 +13 12 bop 0 83 a FL(and)20 b(20\045)g(fe)n(wer)f(operations.)0 +314 y Fr(4.4)100 b(A)m(uxiliar)q(y)28 b(Pr)n(ograms)0 +470 y FB(4.4.1)84 b(Mesh)23 b(T)-7 b(o)23 b(Graph)f(Con)m(ver)o(sion) +478 593 y Fi(')p 478 2809 7 2054 v 478 2979 a(&)3415 +593 y($)p 3415 2809 V 3415 2979 a(\045)p 648 2979 2605 +7 v 648 593 V 590 660 a Fj(prompt\045)39 b(mesh2nodal)f(144.mesh)590 +739 y(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 818 y(METIS)i(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +975 y(Mesh)f(Information)f +(---------------------------------------------)o(-------)669 +1054 y(Name:)i(144.mesh,)e(#Elements:)g(905410,)h(#Nodes:)g(144649,)g +(Etype:)g(TET)590 1212 y(Forming)g(Nodal)g(Graph...)f +(----------------------------------------------)669 1291 +y(Nodal)i(Information:)e(#Vertices:)g(144649,)h(#Edges:)g(1074393)590 +1449 y(Timing)g(Information)f +(-------------------------------------------)o(-------)669 +1527 y(I/O:)1116 b(15.290)669 1606 y(Nodal)40 b(Creation:)715 +b(3.030)590 1685 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)590 1843 y(prompt\045)39 +b(mesh2dual)f(144.mesh)590 1922 y +(******************************************)o(*******)o(******)o +(*******)o(*******)o(*)669 2001 y(METIS)i(4.0)119 b(Copyright)38 +b(1998,)h(Regents)g(of)h(the)f(University)f(of)i(Minnesota)590 +2158 y(Mesh)f(Information)f +(---------------------------------------------)o(-------)669 +2237 y(Name:)i(144.mesh,)e(#Elements:)g(905410,)h(#Nodes:)g(144649,)g +(Etype:)g(TET)590 2395 y(Forming)g(Dual)g(Graph...)f +(-----------------------------------------------)669 +2474 y(Dual)i(Information:)e(#Vertices:)g(905410,)h(#Edges:)g(1786484) +590 2632 y(Timing)g(Information)f +(-------------------------------------------)o(-------)669 +2710 y(I/O:)1116 b(19.200)669 2789 y(Dual)40 b(Creation:)716 +b(10.880)590 2868 y(******************************************)o +(*******)o(******)o(*******)o(*******)o(*)785 3214 y +Fy(Figure)18 b(7)p FL(:)25 b Fx(Output)19 b(of)g Fp(mesh2nodal)e +Fx(and)h Fp(mesh2dual)f Fx(f)n(or)i(mesh)f Fh(144.mesh)q +Fx(.)102 3408 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)27 +b FL(pro)o(vides)21 b(tw)o(o)j(programs)d Fp(mesh2nodal)h +FL(and)g Fp(mesh2dual)g FL(for)h(con)m(v)o(erting)d(a)j(mesh)g(into)g +(the)g(graph)f(format)g(used)0 3518 y(by)i Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)r FL(.)24 b(In)e(particular)m(,)f +Fp(mesh2nodal)g FL(con)m(v)o(erts)g(the)h(element)g(node)f(array)g(of)h +(a)h(mesh)f(into)g(a)h(nodal)e(graph;)h Fs(i.e)p FL(.,)h(each)f(node)0 +3627 y(of)30 b(the)f(mesh)h(corresponds)e(to)i(a)g(v)o(erte)o(x)e(in)i +(the)g(graph)e(and)i(tw)o(o)g(v)o(ertices)f(are)h(connected)e(by)h(an)h +(edge)f(if)h(the)g(corresponding)0 3737 y(nodes)c(are)h(connected)d(by) +j(lines)g(in)g(the)f(mesh.)45 b(Similarly)-5 b(,)27 b +Fp(mesh2dual)f FL(con)m(v)o(erts)e(the)j(element)f(node)g(array)g(of)g +(a)h(mesh)g(into)0 3847 y(a)g(dual)f(graph;)i Fs(i.e)p +FL(.,)g(each)e(element)g(of)g(the)h(mesh)f(corresponds)f(to)h(a)h(v)o +(erte)o(x)e(in)i(the)f(graph)f(and)h(tw)o(o)h(v)o(ertices)f(are)h +(connected)d(if)0 3956 y(the)c(corresponding)d(elements)j(in)h(the)f +(mesh)h(share)f(a)h(f)o(ace.)k(These)c(mesh-to-graph)c(con)m(v)o +(ersion)g(programs)i(support)g(meshes)h(with)0 4066 y(triangular)m(,)e +(tetrahedra,)g(and)i(he)o(xahedra)e(\(bricks\))h(elements.)100 +4175 y(Both)h Fp(mesh2nodal)f FL(and)g Fp(mesh2dual)g +FL(are)i(in)m(v)n(ok)o(ed)d(by)i(pro)o(viding)d(one)j(ar)o(gument)e(at) +i(the)h(command)d(line)i(as)h(follo)n(ws:)257 4349 y +FB(mesh2nodal)124 b Fs(MeshF)l(ile)257 4459 y FB(mesh2dual)175 +b Fs(MeshF)l(ile)100 4633 y FL(The)30 b(only)h(ar)o(gument)d(of)j +(these)g(programs)e Fs(MeshF)l(ile)p FL(,)34 b(is)e(the)f(name)g(of)f +(the)h(\002le)h(that)f(stores)g(the)h(mesh)e(\(whose)h(format)f(is)0 +4742 y(described)15 b(in)h(Section)g(4.5.2\).)22 b(Upon)15 +b(successful)h(e)o(x)o(ecution,)f(both)g(programs)g(display)g +(information)f(about)h(the)h(generated)f(graphs,)0 4852 +y(and)k(the)h(amount)f(of)g(time)h(tak)o(en)g(to)g(perform)e(the)i(con) +m(v)o(ersion.)i(The)e(actual)f(graph)g(is)i(stored)e(in)h(a)g(\002le)h +(named:)j Fo(MeshF)m(ile.ngraph)0 4962 y FL(in)g(the)g(case)g(of)f +Fp(mesh2nodal)f FL(and)i Fo(MeshF)m(ile.dgraph)e FL(in)i(the)g(case)g +(of)f Fp(mesh2dual)p FL(.)35 b(The)23 b(format)f(of)i(these)g(graph)e +(\002les)j(are)0 5071 y(compatible)19 b(with)j Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)25 b FL(and)19 b(is)i(described)e(in)i +(Section)e(4.5.1.)100 5181 y(Figure)e(7)g(sho)n(ws)h(the)g(output)e(of) +i Fp(mesh2nodal)e FL(and)h Fp(mesh2dual)g FL(for)g(generating)f(the)h +(nodal)g(and)g(dual)h(graphs)e(of)i(a)g(sample)0 5290 +y(mesh.)30 b(Note)22 b(that)g(the)g(sizes)h(of)e(the)h(generated)e +(graphs)h(are)h(dif)n(ferent,)e(as)j(the)f(dual)f(graph)g(is)i(lar)o +(ger)d(than)i(the)g(nodal)f(graph.)28 b(Also)0 5400 y(note)20 +b(that)g(generating)e(the)i(nodal)g(graph)e(is)k(considerably)c(f)o +(aster)i(than)g(generating)e(the)i(dual)g(graph.)1908 +5649 y(13)p eop +%%Page: 14 14 +14 13 bop 0 83 a FB(4.4.2)84 b(Graph)22 b(Chec)n(ker)2 +209 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)25 b FL(pro)o(vide)18 +b(a)j(program)d(called)j Fp(graphchk)e FL(to)i(check)f(whether)f(or)h +(not)g(the)h(format)e(of)h(a)h(graph)e(is)j(appropriate)c(for)i(use)g +(with)2 319 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r +FL(.)24 b(This)e(program)e(should)h(be)h(used)g(whene)n(v)o(er)e(there) +i(is)h(an)o(y)e(doubt)f(about)i(the)g(format)f(of)g(an)o(y)h(graph)e +(\002le.)31 b(It)23 b(is)g(in)m(v)n(ok)o(ed)d(by)0 428 +y(pro)o(viding)d(one)j(ar)o(gument)e(at)j(the)f(command)e(line)i(as)h +(follo)n(ws:)257 621 y FB(graphc)o(hk)124 b Fs(Gr)o(aphF)l(ile)0 +814 y FL(where)20 b Fs(Gr)o(aphF)l(ile)f FL(is)i(the)f(name)g(of)g(the) +g(\002le)h(that)f(stores)g(the)h(graph.)1908 5649 y(14)p +eop +%%Page: 15 15 +15 14 bop 0 83 a Fr(4.5)100 b(Input)27 b(File)h(Formats)0 +242 y FL(The)d(v)n(arious)f(programs)g(in)k Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)29 b FL(require)24 b(as)i(input)f(either)g(a)h +(\002le)g(storing)f(a)h(graph)e(or)h(a)h(\002le)g(storing)e(a)i(mesh.) +40 b(The)26 b(format)e(of)0 352 y(these)c(\002les)i(are)e(described)f +(in)h(the)g(follo)n(wing)f(sections.)0 561 y FB(4.5.1)84 +b(Graph)22 b(File)0 687 y FL(The)j(primary)f(input)g(of)i(the)f +(partitioning)e(and)i(\002ll-reducing)f(ordering)f(programs)g(in)28 +b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)30 b FL(is)c(the)f(graph)f(to)i +(be)f(partitioned)f(or)0 797 y(ordered.)f(This)d(graph)f(is)i(stored)f +(in)g(a)h(\002le)g(and)e(is)j(supplied)d(to)h(the)g(v)n(arious)f +(programs)g(as)i(one)e(of)h(the)g(command)f(line)h(parameters.)100 +907 y(A)i(graph)h Ft(G)32 b FM(D)26 b Fu(.)r Ft(V)8 b +Fu(;)20 b Ft(E)7 b Fu(/)24 b FL(with)e Ft(n)k FL(v)o(ertices)c(and)f +Ft(m)28 b FL(edges)22 b(is)h(stored)f(in)g(a)h(plain)f(te)o(xt)g +(\002le)h(that)f(contains)f Ft(n)j FM(C)19 b FL(1)k(lines)f(\(e)o +(xcluding)0 1016 y(comment)i(lines\).)40 b(The)25 b(\002rst)h(line)f +(contains)g(information)e(about)h(the)h(size)h(and)f(the)g(type)g(of)g +(the)g(graph,)g(while)g(the)g(remaining)f Ft(n)0 1126 +y FL(lines)d(contain)e(information)f(for)h(each)h(v)o(erte)o(x)f(of)j +Ft(G)5 b FL(.)25 b(An)o(y)19 b(line)i(that)f(starts)h(with)f(`\045')h +(is)g(a)f(comment)f(line)h(and)g(is)h(skipped.)100 1235 +y(The)g(\002rst)h(line)f(contains)g(either)g(tw)o(o)h(\()p +Ft(n)s FL(,)g Ft(m)5 b FL(\),)21 b(three)g(\()p Ft(n)s +FL(,)h Ft(m)5 b FL(,)22 b Fs(fmt)p FL(\),)g(or)f(four)f(\()p +Ft(n)s FL(,)i Ft(m)5 b FL(,)22 b Fs(fmt)p FL(,)g Fs(ncon)p +FL(\))e(inte)o(gers.)28 b(The)21 b(\002rst)h(tw)o(o)f(inte)o(gers)0 +1345 y(\()p Ft(n)s FL(,)f Ft(m)5 b FL(\))19 b(are)g(the)g(number)e(of)i +(v)o(ertices)f(and)h(the)g(number)e(of)i(edges,)g(respecti)n(v)o(ely)-5 +b(.)22 b(Note)d(that)h(in)f(determining)e(the)i(number)e(of)i(edges)0 +1455 y Ft(m)5 b FL(,)26 b(an)e(edge)g(between)g(an)o(y)f(pair)h(of)h(v) +o(ertices)f Fu(v)k FL(and)c Ft(u)29 b FL(is)d(counted)d +FC(only)h(once)g FL(and)g(not)g(twice)h(\()p Fs(i.e)p +FL(.,)g(we)g(do)f(not)g(count)g(the)g(edge)0 1564 y Fu(.v)s(;)14 +b Ft(u)t Fu(/)22 b FL(separately)e(from)g Fu(.)p Ft(u)t +Fu(;)14 b(v)s(/)p FL(\).)28 b(F)o(or)20 b(e)o(xample,)f(the)i(graph)f +(in)h(Figure)f(8)g(contains)h(11)f(v)o(ertices.)26 b(The)21 +b(third)f(inte)o(ger)f(\()p Fs(fmt)p FL(\))i(is)h(used)0 +1674 y(to)h(specify)g(whether)f(or)h(not)g(the)g(graph)f(has)i(weights) +f(associated)g(with)g(its)h(v)o(ertices,)g(its)g(edges,)f(or)g(both.)33 +b(T)-7 b(able)24 b(2)f(describes)g(the)0 1783 y(possible)i(v)n(alues)g +(of)h Fs(fmt)g FL(and)f(their)g(meaning.)40 b(Note)25 +b(that)h(if)g(the)g(graph)e(is)i(unweighted)e(\()p Fs(i.e)o +FL(.,)j(all)f(v)o(ertices)f(and)g(edges)h(ha)n(v)o(e)f(the)0 +1893 y(same)d(weight\),)f(then)h(the)f Fs(fmt)j FL(parameter)d(can)g +(be)h(omitted.)29 b(Finally)-5 b(,)22 b(the)g(fourth)e(inte)o(ger)h(\() +p Fs(ncon)p FL(\))f(is)j(used)e(to)h(specify)g(the)f(number)0 +2003 y(of)e(weights)g(associated)f(with)i(each)e(v)o(erte)o(x)g(of)g +(the)h(graph.)24 b(The)18 b(v)n(alue)h(of)f(this)i(parameter)d +(determines)h(whether)g(or)h(not)i Fz(M)l FG(E)-17 b +Fz(T)g FG(I)p Fz(S)23 b FL(will)0 2112 y(use)e(the)f(multi-constraint)e +(partitioning)h(algorithms)g(described)g(in)i(Section)f(3.)26 +b(If)20 b(the)g(v)o(ertices)g(of)g(the)h(graph)e(ha)n(v)o(e)h(no)g +(weights)g(or)0 2222 y(only)h(a)h(single)f(weight,)g(then)g(the)h +Fs(ncon)f FL(parameter)f(can)h(be)g(omitted.)29 b(Ho)n(we)n(v)o(er)m(,) +19 b(if)j Fs(ncon)f FL(is)h(greater)f(than)g(0,)h(then)f(the)g(\002le)i +(should)0 2331 y(contain)18 b(the)h(required)f(v)o(erte)o(x)g(weights)h +(and)f(the)h Fs(fmt)h FL(parameter)e(should)g(be)h(set)h(appropriately) +d(\()p Fs(i.e)o FL(.,)j(it)f(should)g(be)g(set)h(to)f(either)g(10)0 +2441 y(or)h(11\).)p 590 2625 2721 4 v 588 2725 4 100 +v 640 2695 a Fs(fmt)p 794 2725 V 99 w FL(Meaning)p 3309 +2725 V 590 2728 2721 4 v 588 2828 4 100 v 672 2798 a(0)p +794 2828 V 131 w(The)g(graph)f(has)h(no)g(weights)g(associated)g(with)h +(either)e(the)i(edges)e(or)h(the)g(v)o(ertices)p 3309 +2828 V 590 2831 2721 4 v 588 2930 4 100 v 672 2901 a(1)p +794 2930 V 131 w(The)g(graph)f(has)h(weights)g(associated)g(with)h(the) +f(edges)p 3309 2930 V 590 2934 2721 4 v 588 3033 4 100 +v 651 3004 a(10)p 794 3033 V 110 w(The)g(graph)f(has)h(weights)g +(associated)g(with)h(the)f(v)o(ertices)p 3309 3033 V +590 3037 2721 4 v 588 3136 4 100 v 651 3106 a(11)p 794 +3136 V 110 w(The)g(graph)f(has)h(weights)g(associated)g(with)h(both)e +(the)h(edges)g(&)g(v)o(ertices)p 3309 3136 V 590 3140 +2721 4 v 776 3292 a Fy(T)-5 b(ab)o(le)17 b(2)p FL(:)26 +b Fx(The)18 b(v)n(ar)q(ious)h(possib)o(le)f(v)n(alues)h(f)n(or)g(the)f +Fh(fmt)h Fx(par)o(ameter)e(and)i(their)f(meaning.)100 +3571 y FL(The)f(remaining)g Ft(n)22 b FL(lines)c(store)h(information)c +(about)j(the)g(actual)g(structure)f(of)h(the)g(graph.)23 +b(In)18 b(particular)m(,)f(the)g Ft(i)9 b FL(th)18 b(line)g(\(e)o +(xcluding)0 3680 y(comment)25 b(lines\))h(contains)f(information)f +(that)i(is)h(rele)n(v)n(ant)e(to)h(the)f Ft(i)9 b FL(th)26 +b(v)o(erte)o(x.)41 b(Depending)24 b(on)i(the)g(v)n(alue)f(of)h(the)g +Fs(fmt)h FL(and)f Fs(ncon)0 3790 y FL(parameters,)d(the)h(information)e +(stored)h(at)h(each)g(line)g(is)h(some)n(what)e(dif)n(ferent.)34 +b(In)23 b(the)h(most)g(general)f(form)g(\(when)g Fs(fmt)h(=)h(11)e +FL(and)0 3899 y Fs(ncon)c Fu(>)i Fs(1)p FL(\))f(each)f(line)i(will)g +(ha)n(v)o(e)e(the)h(follo)n(wing)f(structure:)1225 4100 +y Fu(w)1286 4112 y Fn(1)1322 4100 y Fu(;)14 b(w)1424 +4112 y Fn(2)1460 4100 y Fu(;)g(:)g(:)g(:)f(w)1672 4112 +y Ff(n)r(c)q(o)q(n)1806 4100 y Fu(;)38 b(v)1911 4112 +y Fn(1)1947 4100 y Fu(;)14 b Ft(e)2025 4112 y Fn(1)2061 +4100 y Fu(;)g(v)2142 4112 y Fn(2)2178 4100 y Fu(;)g Ft(e)2256 +4112 y Fn(2)2292 4100 y Fu(;)g(:)g(:)g(:)f(;)h(v)2524 +4112 y Ff(k)2561 4100 y Fu(;)g Ft(e)2639 4112 y Ff(k)0 +4301 y FL(where)20 b Fu(w)285 4313 y Fn(1)321 4301 y +Fu(;)14 b(w)423 4313 y Fn(2)459 4301 y Fu(;)g(:)g(:)g(:)f(;)h(w)712 +4313 y Ff(n)r(c)q(o)q(n)869 4301 y FL(are)21 b(the)g +Fs(ncon)f FL(v)o(erte)o(x)f(weights)i(associated)g(with)g(this)h(v)o +(erte)o(x,)d Fu(v)2765 4313 y Fn(1)2801 4301 y Fu(;)14 +b(v)2882 4313 y Fn(2)2919 4301 y Fu(;)g(:)g(:)g(:)f(;)h(v)3151 +4313 y Ff(k)3210 4301 y FL(are)20 b(the)i(v)o(ertices)e(adja-)0 +4411 y(cent)h(to)f(this)h(v)o(erte)o(x,)f(and)g Ft(e)812 +4423 y Fn(1)847 4411 y Fu(;)14 b Ft(e)925 4423 y Fn(2)961 +4411 y Fu(;)g(:)g(:)g(:)f(;)h Ft(e)1190 4423 y Ff(k)1248 +4411 y FL(are)20 b(the)h(weights)f(of)h(these)g(edges.)k(In)c(the)f +(remaining)f(of)i(this)g(section)f(we)h(illustrate)g(this)0 +4520 y(format)e(by)h(a)h(sequence)e(of)h(e)o(xamples.)k(Note)d(that)f +(the)g(v)o(ertices)g(are)g(numbered)e(starting)i(from)g(1)g(\(not)g +(from)f(0)h(as)h(is)h(often)d(done)g(in)0 4630 y(C\).)j(Furthermore,)d +(the)i(v)o(erte)o(x-weights)e(must)i(be)h(inte)o(gers)e(greater)h(or)g +(equal)g(to)g(0,)h(whereas)f(the)g(edge-weights)f(must)h(be)g(strictly) +0 4740 y(greater)e(than)h(0.)100 4849 y(The)k(simplest)g(format)g(for)f +(a)i(graph)g Ft(G)30 b FL(is)25 b(when)f(the)h(weight)e(of)i(all)f(v)o +(ertices)g(and)g(the)h(weight)f(of)g(all)h(the)f(edges)g(is)h(the)g +(same.)0 4959 y(This)20 b(format)f(is)j(illustrated)d(in)i(Figure)e +(8\(a\).)24 b(Note,)c(the)h(optional)d Fs(fmt)23 b FL(parameter)18 +b(is)k(skipped)d(in)h(this)h(case.)100 5068 y(Ho)n(we)n(v)o(er)m(,)30 +b(there)g(are)g(cases)h(in)f(which)g(the)g(edges)g(in)i +Ft(G)k FL(ha)n(v)o(e)30 b(dif)n(ferent)e(weights.)55 +b(This)30 b(is)i(accommodated)27 b(as)k(sho)n(wn)e(in)0 +5178 y(Figure)21 b(8\(b\).)30 b(No)n(w)-5 b(,)22 b(the)g(adjacenc)o(y)f +(list)i(of)f(each)f(v)o(erte)o(x)g(contains)h(the)g(weight)f(of)h(the)g +(edges)g(in)g(addition)f(to)i(the)f(v)o(ertices)f(that)i(is)0 +5288 y(connected)18 b(with.)25 b(If)20 b Fu(v)25 b FL(has)20 +b Ft(k)26 b FL(v)o(ertices)19 b(adjacent)g(to)i(it,)f(then)g(the)g +(line)g(for)g Fu(v)k FL(in)c(the)g(graph)f(\002le)i(contains)e(2)f +FM(\003)g Ft(k)26 b FL(numbers,)18 b(each)i(pair)0 5397 +y(of)j(numbers)f(stores)i(the)f(v)o(erte)o(x)f(that)i +Fu(v)k FL(is)c(connected)e(to,)i(and)f(the)h(weight)f(of)g(the)g(edge.) +35 b(Note)23 b(that)h(the)f Fs(fmt)j FL(parameter)c(is)i(equal)1908 +5649 y(15)p eop +%%Page: 16 16 +16 15 bop 600 3819 a @beginspecial 0 @llx 0 @lly 673 +@urx 952 @ury 3240 @rwi @setspecial +%%BeginDocument: ./figures/graph00.eps +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-8.0 955.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/reencdict 12 dict def /ReEncode { reencdict begin +/newcodesandnames exch def /newfontname exch def /basefontname exch def +/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def +basefontdict { exch dup /FID ne { dup /Encoding eq +{ exch dup length array copy newfont 3 1 roll put } +{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall +newfont /FontName newfontname put newcodesandnames aload pop +128 1 255 { newfont /Encoding get exch /.notdef put } for +newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat +newfontname newfont definefont pop end } def +/isovec [ +8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde +8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis +8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron +8#220 /dotlessi 8#230 /oe 8#231 /OE +8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling +8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis +8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot +8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus +8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph +8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine +8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf +8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute +8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring +8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute +8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute +8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve +8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply +8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex +8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave +8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring +8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute +8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute +8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve +8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide +8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex +8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def +/Times-BoldItalic /Times-BoldItalic-iso isovec ReEncode +/Times-Roman /Times-Roman-iso isovec ReEncode +/Helvetica-Bold /Helvetica-Bold-iso isovec ReEncode +/Courier /Courier-iso isovec ReEncode +/Helvetica /Helvetica-iso isovec ReEncode +/Times-Bold /Times-Bold-iso isovec ReEncode +/Helvetica-BoldOblique /Helvetica-BoldOblique-iso isovec ReEncode + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +n -1000 16912 m -1000 -1000 l 12337 -1000 l 12337 16912 l cp clip + 0.06000 0.06000 sc +% Polyline +7.500 slw +n 826 3151 m 2026 2026 l gs col-1 s gr +% Polyline +n 901 3151 m 2926 2926 l gs col-1 s gr +% Polyline +n 2926 2926 m 2026 2026 l gs col-1 s gr +% Polyline +n 901 1276 m 1951 526 l gs col-1 s gr +% Polyline +n 1951 526 m 3226 1126 l gs col-1 s gr +% Polyline +n 1951 526 m 2026 2026 l gs col-1 s gr +% Polyline +n 2026 2026 m 976 1276 l gs col-1 s gr +% Polyline +n 3226 1126 m 2926 2926 l gs col-1 s gr +% Polyline +n 2926 2926 m 3976 2401 l gs col-1 s gr +% Polyline +n 3976 2401 m 3226 1126 l gs col-1 s gr +% Polyline +n 901 1276 m 826 3151 l gs col-1 s gr +% Polyline +n 7352 11402 m 8552 10277 l gs col-1 s gr +% Polyline +n 7427 11402 m 9452 11177 l gs col-1 s gr +% Polyline +n 9452 11177 m 8552 10277 l gs col-1 s gr +% Polyline +n 7427 9527 m 8477 8777 l gs col-1 s gr +% Polyline +n 8477 8777 m 9752 9377 l gs col-1 s gr +% Polyline +n 8477 8777 m 8552 10277 l gs col-1 s gr +% Polyline +n 8552 10277 m 7502 9527 l gs col-1 s gr +% Polyline +n 9752 9377 m 9452 11177 l gs col-1 s gr +% Polyline +n 9452 11177 m 10502 10652 l gs col-1 s gr +% Polyline +n 10502 10652 m 9752 9377 l gs col-1 s gr +% Polyline +n 7427 9527 m 7352 11402 l gs col-1 s gr +% Polyline +n 7126 3152 m 8326 2027 l gs col-1 s gr +% Polyline +n 7201 3152 m 9226 2927 l gs col-1 s gr +% Polyline +n 9226 2927 m 8326 2027 l gs col-1 s gr +% Polyline +n 7201 1277 m 8251 527 l gs col-1 s gr +% Polyline +n 8251 527 m 9526 1127 l gs col-1 s gr +% Polyline +n 8251 527 m 8326 2027 l gs col-1 s gr +% Polyline +n 8326 2027 m 7276 1277 l gs col-1 s gr +% Polyline +n 9526 1127 m 9226 2927 l gs col-1 s gr +% Polyline +n 9226 2927 m 10276 2402 l gs col-1 s gr +% Polyline +n 10276 2402 m 9526 1127 l gs col-1 s gr +% Polyline +n 7201 1277 m 7126 3152 l gs col-1 s gr +% Polyline +n 977 11252 m 2177 10127 l gs col-1 s gr +% Polyline +n 1052 11252 m 3077 11027 l gs col-1 s gr +% Polyline +n 3077 11027 m 2177 10127 l gs col-1 s gr +% Polyline +n 1052 9377 m 2102 8627 l gs col-1 s gr +% Polyline +n 2102 8627 m 3377 9227 l gs col-1 s gr +% Polyline +n 2102 8627 m 2177 10127 l gs col-1 s gr +% Polyline +n 2177 10127 m 1127 9377 l gs col-1 s gr +% Polyline +n 3377 9227 m 3077 11027 l gs col-1 s gr +% Polyline +n 3077 11027 m 4127 10502 l gs col-1 s gr +% Polyline +n 4127 10502 m 3377 9227 l gs col-1 s gr +% Polyline +n 1052 9377 m 977 11252 l gs col-1 s gr +% Ellipse +n 2008 2008 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 901 1276 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 1933 508 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 3208 1108 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 2908 2908 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 3958 2383 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 808 3133 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 8534 10259 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 7427 9527 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 8459 8759 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 9734 9359 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 9434 11159 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 10484 10634 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 7334 11384 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 8308 2009 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 7201 1277 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 8233 509 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 9508 1109 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 9208 2909 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 10258 2384 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 7108 3134 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 2159 10109 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 1052 9377 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 2084 8609 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 3359 9209 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 3059 11009 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 4109 10484 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +% Ellipse +n 959 11234 168 168 0 360 DrawEllipse gs col7 1.00 shd ef gr gs col-1 s gr + +/Helvetica-iso ff 210.00 scf sf +1951 2101 m +gs 1 -1 sc (3) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +2851 3001 m +gs 1 -1 sc (4) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +1876 601 m +gs 1 -1 sc (5) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +3151 1201 m +gs 1 -1 sc (6) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +751 3226 m +gs 1 -1 sc (2) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +3901 2476 m +gs 1 -1 sc (7) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +863 1351 m +gs 1 -1 sc (1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 4727 m +gs 1 -1 sc (7 11) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 4997 m +gs 1 -1 sc (5 3 2) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 5267 m +gs 1 -1 sc (1 3 4) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 5807 m +gs 1 -1 sc (2 3 6 7) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 6077 m +gs 1 -1 sc (1 3 6) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 6347 m +gs 1 -1 sc (5 4 7) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 6617 m +gs 1 -1 sc (6 4) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1202 5537 m +gs 1 -1 sc (5 4 2 1) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +8477 10352 m +gs 1 -1 sc (3) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +9377 11252 m +gs 1 -1 sc (4) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +8402 8852 m +gs 1 -1 sc (5) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +9677 9452 m +gs 1 -1 sc (6) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +7277 11477 m +gs 1 -1 sc (2) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +10427 10727 m +gs 1 -1 sc (7) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +7389 9602 m +gs 1 -1 sc (1) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +8251 2102 m +gs 1 -1 sc (3) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +9151 3002 m +gs 1 -1 sc (4) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +8176 602 m +gs 1 -1 sc (5) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +9451 1202 m +gs 1 -1 sc (6) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +7051 3227 m +gs 1 -1 sc (2) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +10201 2477 m +gs 1 -1 sc (7) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +7163 1352 m +gs 1 -1 sc (1) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +7651 827 m +gs 1 -1 sc (1) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +8926 752 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +8401 1352 m +gs 1 -1 sc (3) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +7801 1577 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +7726 2477 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +8176 3002 m +gs 1 -1 sc (1) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +8776 2402 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +9226 2027 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +9676 2627 m +gs 1 -1 sc (5) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +9976 1727 m +gs 1 -1 sc (6) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +6976 2177 m +gs 1 -1 sc (1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 4728 m +gs 1 -1 sc (7 11 1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 4998 m +gs 1 -1 sc (5 1 3 2 2 1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 5268 m +gs 1 -1 sc (1 1 3 2 4 1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 5538 m +gs 1 -1 sc (5 3 4 2 2 2 1 2) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 5808 m +gs 1 -1 sc (2 1 3 2 6 2 7 5) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 6078 m +gs 1 -1 sc (1 1 3 3 6 2) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 6348 m +gs 1 -1 sc (5 2 4 2 7 6) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7502 6618 m +gs 1 -1 sc (6 6 4 5) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +2102 10202 m +gs 1 -1 sc (3) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +3002 11102 m +gs 1 -1 sc (4) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +2027 8702 m +gs 1 -1 sc (5) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +3302 9302 m +gs 1 -1 sc (6) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +902 11327 m +gs 1 -1 sc (2) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +4052 10577 m +gs 1 -1 sc (7) col-1 sh gr +/Helvetica-iso ff 210.00 scf sf +1014 9452 m +gs 1 -1 sc (1) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +1502 8927 m +gs 1 -1 sc (1) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +2777 8852 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +2252 9452 m +gs 1 -1 sc (3) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +1652 9677 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +1577 10577 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +2027 11102 m +gs 1 -1 sc (1) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +2627 10502 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +3077 10127 m +gs 1 -1 sc (2) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +3527 10727 m +gs 1 -1 sc (5) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +3827 9827 m +gs 1 -1 sc (6) col-1 sh gr +/Times-Bold-iso ff 210.00 scf sf +827 10277 m +gs 1 -1 sc (1) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +750 9150 m +gs 1 -1 sc ([4]) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +600 11025 m +gs 1 -1 sc ([2]) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +1950 8325 m +gs 1 -1 sc ([1]) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +3300 8925 m +gs 1 -1 sc ([6]) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +2325 9900 m +gs 1 -1 sc ([5]) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +2925 11400 m +gs 1 -1 sc ([3]) col-1 sh gr +/Helvetica-BoldOblique-iso ff 210.00 scf sf +4350 10500 m +gs 1 -1 sc ([2]) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 12828 m +gs 1 -1 sc (7 11 11) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 13098 m +gs 1 -1 sc (4 5 1 3 2 2 1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 13368 m +gs 1 -1 sc (2 1 1 3 2 4 1) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 13638 m +gs 1 -1 sc (5 5 3 4 2 2 2 1 2) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 13908 m +gs 1 -1 sc (3 2 1 3 2 6 2 7 5) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 14178 m +gs 1 -1 sc (1 1 1 3 3 6 2) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 14448 m +gs 1 -1 sc (6 5 2 4 2 7 6) col-1 sh gr +/Courier-iso ff 210.00 scf sf +1353 14718 m +gs 1 -1 sc (2 6 6 4 5) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 12978 m +gs 1 -1 sc (7 11 10 3) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 13248 m +gs 1 -1 sc (1 2 0 5 3 2) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 13518 m +gs 1 -1 sc (0 2 2 1 3 4) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 14058 m +gs 1 -1 sc (2 2 3 2 3 6 7) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 14328 m +gs 1 -1 sc (1 1 1 1 3 6) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 14598 m +gs 1 -1 sc (2 2 1 5 4 7) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 14868 m +gs 1 -1 sc (1 2 1 6 4) col-1 sh gr +/Courier-iso ff 210.00 scf sf +7728 13788 m +gs 1 -1 sc (4 1 1 5 4 2 1) col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +1501 7351 m +gs 1 -1 sc (\(a\)) dup sw pop neg 0 rm col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +1801 7351 m +gs 1 -1 sc (Unweighted Graph) col-1 sh gr +% Polyline +n 301 3826 m 4351 3826 l gs col-1 s gr +/Times-Roman-iso ff 180.00 scf sf +600 4350 m +gs 1 -1 sc (Graph File:) col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +1052 15377 m +gs 1 -1 sc (\(c\)) dup sw pop neg 0 rm col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +1352 15377 m +gs 1 -1 sc (Weighted Graph) col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +1352 15647 m +gs 1 -1 sc (Weights both on vertices and edges) col-1 sh gr +% Polyline +n 452 11927 m 4652 11927 l gs col-1 s gr +/Times-Roman-iso ff 180.00 scf sf +751 12451 m +gs 1 -1 sc (Graph File:) col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8026 7276 m +gs 1 -1 sc (\(b\)) dup sw pop neg 0 rm col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8326 7276 m +gs 1 -1 sc (Weighted Graph) col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8326 7546 m +gs 1 -1 sc (Weights on edges) col-1 sh gr +% Polyline +n 6827 12077 m 10877 12077 l gs col-1 s gr +% Polyline +n 6601 3827 m 10726 3827 l gs col-1 s gr +% Polyline +n 6450 8100 m 11325 8100 l 11325 15900 l 6450 15900 l cp gs col0 s gr +% Polyline +n 150 8100 m 5025 8100 l 5025 15900 l 150 15900 l cp gs col0 s gr +% Polyline +n 150 75 m 5025 75 l 5025 7875 l 150 7875 l cp gs col0 s gr +% Polyline +n 6450 75 m 11325 75 l 11325 7875 l 6450 7875 l cp gs col0 s gr +/Times-BoldItalic-iso ff 210.00 scf sf +6600 11100 m +gs 1 -1 sc ([0, 2, 2]) col0 sh gr +/Times-BoldItalic-iso ff 210.00 scf sf +7050 9225 m +gs 1 -1 sc ([1, 2, 0]) col0 sh gr +/Times-BoldItalic-iso ff 210.00 scf sf +8175 8475 m +gs 1 -1 sc ([1, 1, 1]) col0 sh gr +/Times-BoldItalic-iso ff 210.00 scf sf +9525 9075 m +gs 1 -1 sc ([2, 2, 1]) col0 sh gr +/Times-BoldItalic-iso ff 210.00 scf sf +8700 10050 m +gs 1 -1 sc ([4, 1, 1]) col0 sh gr +/Times-BoldItalic-iso ff 210.00 scf sf +10425 10350 m +gs 1 -1 sc ([1, 2, 1]) col0 sh gr +/Times-BoldItalic-iso ff 210.00 scf sf +9225 11550 m +gs 1 -1 sc ([2, 2, 3]) col0 sh gr +/Times-Roman-iso ff 180.00 scf sf +7126 12601 m +gs 1 -1 sc (Graph File:) col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8027 15602 m +gs 1 -1 sc (\(d\)) dup sw pop neg 0 rm col-1 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8327 15602 m +gs 1 -1 sc (Multi-Constraint Graph) col-1 sh gr +/Times-Roman-iso ff 180.00 scf sf +6900 4351 m +gs 1 -1 sc (Graph File:) col-1 sh gr +$F2psEnd +rs +%%EndDocument + @endspecial 1168 4002 a Fy(Figure)18 b(8)p FL(:)25 b +Fx(Stor)o(age)19 b(f)n(or)r(mat)f(f)n(or)g(v)n(ar)q(ious)h(type)g(of)f +(g)o(r)o(aphs)o(.)0 4186 y FL(to)i(1,)g(indicating)f(the)h(f)o(act)h +(that)h Ft(G)k FL(has)20 b(weights)g(on)g(the)g(edges.)100 +4296 y(In)e(addition)g(to)h(ha)n(ving)f(weights)g(on)h(the)g(edges,)f +(weights)h(on)f(the)h(v)o(ertices)g(are)f(also)i(allo)n(wed,)e(as)h +(illustrated)g(in)g(Figure)f(8\(c\).)24 b(In)0 4406 y(this)f(case,)h +(the)f(v)n(alue)f(of)g Fs(fmt)j FL(is)f(equal)e(to)h(11,)g(and)f(each)g +(line)h(of)g(the)f(graph)g(\002le)h(\002rst)h(stores)f(the)g(weight)f +(of)g(the)h(v)o(erte)o(x,)f(and)g(then)0 4515 y(the)e(weighted)f +(adjacenc)o(y)g(list.)100 4625 y(Finally)-5 b(,)22 b(Figure)h(8\(d\))f +(illustrates)h(the)g(format)f(of)h(the)g(input)f(\002le)h(when)g(the)g +(v)o(ertices)f(of)h(the)g(graph)e(contain)h(multiple)h(weights)0 +4734 y(\(3)h(in)g(this)g(e)o(xample\).)34 b(In)24 b(this)g(case,)h(the) +f(v)n(alue)f(of)g Fs(fmt)i FL(is)g(equal)e(to)h(10)f(\(we)h(do)g(not)f +(ha)n(v)o(e)g(weights)h(associated)g(with)g(the)g(edges\),)0 +4844 y(and)e(the)g(v)n(alue)f(of)h Fs(ncon)f FL(is)i(equal)e(to)i(3)f +(\(since)g(we)g(ha)n(v)o(e)g(three)f(sets)i(of)f(v)o(erte)o +(x-weights\).)28 b(Each)22 b(line)g(of)g(the)g(graph)e(\002le)j(stores) +g(the)0 4954 y(three)d(weights)g(of)g(the)g(v)o(ertices)g(follo)n(wed)e +(by)i(the)g(adjacenc)o(y)f(list.)0 5163 y FB(4.5.2)84 +b(Mesh)23 b(File)0 5289 y FL(The)h(primary)g(input)g(of)g(the)h(mesh)f +(partitioning)f(programs)g(in)k Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)29 b FL(is)c(the)g(mesh)g(to)g(be)f(partitioned.)37 +b(This)25 b(mesh)g(is)g(stored)f(in)0 5399 y(a)f(\002le)h(in)f(the)g +(form)f(of)h(the)g(element)g(node)f(array)-5 b(.)32 b(A)23 +b(mesh)g(with)g Ft(n)k FL(elements)c(is)h(stored)e(in)h(a)h(plain)e(te) +o(xt)h(\002le)h(that)f(contains)f Ft(n)i FM(C)c FL(1)1908 +5649 y(16)p eop +%%Page: 17 17 +17 16 bop 0 83 a FL(lines.)30 b(The)22 b(\002rst)g(line)g(contains)f +(information)f(about)g(the)i(size)h(and)e(the)h(type)f(of)h(the)f +(mesh,)h(while)g(the)g(remaining)e Ft(n)25 b FL(lines)e(contain)0 +193 y(the)d(nodes)g(that)g(mak)o(e)g(up)f(each)h(element.)100 +302 y(The)i(\002rst)h(line)f(contains)g(tw)o(o)g(inte)o(gers.)31 +b(The)22 b(\002rst)h(inte)o(ger)e(is)i(the)g(number)d(of)i(elements)g +Ft(n)k FL(in)d(the)f(mesh.)31 b(The)22 b(second)g(inte)o(ger)0 +412 y Fs(etype)e FL(is)h(used)f(to)g(denote)f(the)h(type)f(of)h +(elements)g(that)g(the)g(mesh)g(is)h(made)e(of)n(f.)25 +b Fs(Etype)19 b FL(can)h(either)g(tak)o(e)g(the)g(v)n(alues)f(of)h(1,)g +(2,)g(3,)g(or)g(4,)0 521 y(indicating)f(that)h(the)g(mesh)g(consists)h +(of)f(either)g(triangles,)f(tetrahedra,)g(he)o(xahedra)e(\(bricks\),)i +(or)h(quadrilaterals,)e(respecti)n(v)o(ely)-5 b(.)100 +631 y(After)21 b(the)g(\002rst)h(line,)f(the)h(remaining)d +Ft(n)25 b FL(lines)d(store)f(the)g(element)g(node)f(array)-5 +b(.)27 b(In)21 b(particular)f(for)h(element)e Ft(i)9 +b FL(,)22 b(line)e Ft(i)28 b FM(C)19 b FL(1)i(stores)0 +741 y(the)j(nodes)g(that)g(this)h(element)f(is)h(made)e(of)n(f.)37 +b(Depending)22 b(on)i Fs(etype)p FL(,)h(each)f(line)g(can)g(either)g +(ha)n(v)o(e)g(three)f(inte)o(gers)h(\(in)g(the)g(case)h(of)0 +850 y(triangles\),)e(four)g(inte)o(gers)g(\(in)g(the)g(case)h(of)g +(tetrahedra)e(and)h(quadrilaterals\),)f(or)h(eight)h(inte)o(gers)e +(\(in)i(the)f(case)h(of)g(he)o(xahedra\).)32 b(In)0 960 +y(the)22 b(case)g(of)g(triangles)f(and)g(tetrahedra,)g(the)h(ordering)d +(of)j(the)g(nodes)f(for)g(each)h(element)f(does)h(not)f(matter)-5 +b(.)30 b(Ho)n(we)n(v)o(er)m(,)20 b(in)i(the)g(case)0 +1069 y(of)f(he)o(xahedra)e(and)i(quadrilaterals,)f(the)i(nodes)e(for)h +(each)g(element)g(should)g(be)g(ordered)f(according)f(to)j(the)f +(numbering)e(illustrated)0 1179 y(in)h(Figure)g(9\(b\).)k(Note)c(that)g +(the)g(node)f(numbering)f(starts)j(from)e(1.)100 1289 +y(Figure)h(9)h(illustrates)h(this)g(format)e(for)g(a)i(small)f(mesh)g +(with)g(triangular)f(elements.)27 b(Note)21 b(that)h(the)f +Fs(etype)g FL(\002eld)g(of)g(the)g(mesh)g(\002le)0 1398 +y(is)g(set)g(to)f(1)h(indicating)e(that)h(the)g(mesh)g(consists)h(of)f +(triangular)e(elements.)750 2599 y @beginspecial 0 @llx +0 @lly 469 @urx 215 @ury 2880 @rwi @setspecial +%%BeginDocument: ./figures/meshformat.eps +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {} def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-32.0 264.0 translate +1 -1 scale + +/clp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/l {lineto} bind def +/m {moveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit + 0.06000 0.06000 sc +/Times-Roman findfont 180.00 scalefont setfont +750 2850 m +gs 1 -1 sc (Mesh File:) col-1 show gr +/Helvetica-Bold findfont 210.00 scalefont setfont +1650 4350 m +gs 1 -1 sc (\(a\) Sample Mesh File) dup stringwidth pop 2 div neg 0 rmoveto col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +4350 2566 m +gs 1 -1 sc (2) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +5430 2700 m +gs 1 -1 sc (3) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +1605 2288 m +gs 1 -1 sc (1) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +1597 1268 m +gs 1 -1 sc (6) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +2183 1860 m +gs 1 -1 sc (3) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +2145 952 m +gs 1 -1 sc (5) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +1043 930 m +gs 1 -1 sc (4) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +6053 2310 m +gs 1 -1 sc (4) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +8228 2385 m +gs 1 -1 sc (4) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +7050 1441 m +gs 1 -1 sc (2) col-1 show gr +/Helvetica-Bold findfont 210.00 scalefont setfont +6450 3375 m +gs 1 -1 sc (\(b\) Ordering of nodes) dup stringwidth pop 2 div neg 0 rmoveto col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +7043 2378 m +gs 1 -1 sc (1) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +8205 1425 m +gs 1 -1 sc (3) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +4958 1312 m +gs 1 -1 sc (5) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +4350 1650 m +gs 1 -1 sc (6) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +5468 1800 m +gs 1 -1 sc (7) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +6030 1379 m +gs 1 -1 sc (8) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +4943 2228 m +gs 1 -1 sc (1) col-1 show gr +/Helvetica findfont 180.00 scalefont setfont +1050 1875 m +gs 1 -1 sc (2) col-1 show gr +/Courier findfont 180.00 scalefont setfont +1725 3900 m +gs 1 -1 sc (5 6 3) col-1 show gr +7.500 slw +% Polyline +n 1200 900 m 1200 1800 l 2100 1800 l 2100 900 l 1200 900 l gs col-1 s gr +% Polyline +n 1200 900 m 2100 1800 l gs col-1 s gr +% Polyline +n 1650 1350 m 1200 1800 l gs col-1 s gr +/Courier findfont 180.00 scalefont setfont +1725 3690 m +gs 1 -1 sc (4 5 6) col-1 show gr +/Courier findfont 180.00 scalefont setfont +1725 2850 m +gs 1 -1 sc (5 1) col-1 show gr +/Courier findfont 180.00 scalefont setfont +1725 3060 m +gs 1 -1 sc (1 2 3) col-1 show gr +/Courier findfont 180.00 scalefont setfont +1725 3270 m +gs 1 -1 sc (2 4 6) col-1 show gr +/Courier findfont 180.00 scalefont setfont +1725 3480 m +gs 1 -1 sc (2 6 3) col-1 show gr +% Polyline +n 2100 900 m 1650 1350 l gs col-1 s gr +% Polyline +n 5100 1335 m 4500 1635 l gs col-1 s gr +% Polyline +n 6000 1335 m 5400 1635 l gs col-1 s gr +% Polyline +n 5100 2235 m 4500 2535 l gs col-1 s gr +% Polyline +n 6000 2235 m 5400 2535 l gs col-1 s gr +% Polyline +n 4500 1635 m 5400 1635 l 5400 2535 l 4500 2535 l clp gs col-1 s gr +% Polyline +n 1200 1800 m 1650 2400 l gs col-1 s gr +% Polyline +n 2100 1800 m 1650 2400 l gs col-1 s gr +% Polyline +n 600 2550 m 2550 2550 l gs col-1 s gr +% Polyline +n 7200 1500 m 8100 1500 l 8100 2400 l 7200 2400 l clp gs col-1 s gr +% Polyline +n 5100 1335 m 6000 1335 l 6000 2235 l 5100 2235 l clp gs col-1 s gr +$F2psEnd +restore +%%EndDocument + @endspecial 180 2782 a Fy(Figure)g(9)p FL(:)25 b Fx(\(a\))19 +b(The)f(\002le)h(that)f(stores)h(the)f(mesh.)23 b(\(b\))18 +b(The)g(order)q(ing)g(of)h(the)f(nodes)h(in)g(the)f(case)h(of)g(he)n +(xahedr)o(a)f(and)g(quadr)q(ilater)o(als)o(.)0 3093 y +Fr(4.6)100 b(Output)27 b(File)h(Formats)0 3252 y FL(The)h(output)f(of)k +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)33 b FL(is)e(either)e(a)h +(partition)e(or)i(an)f(ordering)e(\002le,)33 b(depending)27 +b(on)i(whether)h Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)34 +b FL(is)c(used)g(for)f(graph/mesh)0 3362 y(partitioning)18 +b(or)i(for)g(sparse)g(matrix)f(ordering.)k(The)d(format)f(of)h(these)g +(\002les)i(are)e(described)f(in)h(the)g(follo)n(wing)f(sections.)0 +3571 y FB(4.6.1)84 b(P)n(ar)r(tition)22 b(File)0 3697 +y FL(The)28 b(partition)g(\002le)i(of)e(a)h(graph)f(with)h +Ft(n)j FL(v)o(ertices)d(consists)g(of)f Ft(n)33 b FL(lines)c(with)g(a)g +(single)g(number)e(per)h(line.)51 b(The)28 b Ft(i)9 b +FL(th)28 b(line)h(of)g(the)0 3807 y(\002le)d(contains)e(the)h +(partition)e(number)g(that)i(the)f Ft(i)9 b FL(th)25 +b(v)o(erte)o(x)e(belongs)h(to.)39 b(P)o(artition)24 b(numbers)f(start)j +(from)e(0)g(up)h(to)g(the)g(number)e(of)0 3916 y(partitions)c(minus)h +(one.)0 4126 y FB(4.6.2)84 b(Or)n(dering)23 b(File)0 +4252 y FL(The)28 b(ordering)f(\002le)j(of)e(a)h(graph)f(with)h +Ft(n)j FL(v)o(ertices)d(consists)g(of)f Ft(n)33 b FL(lines)c(with)g(a)g +(single)g(number)e(per)h(line.)51 b(The)28 b Ft(i)9 b +FL(th)28 b(line)h(of)g(the)0 4361 y(ordering)18 b(\002le)j(contains)e +(the)i(ne)n(w)f(order)e(of)i(the)g Ft(i)9 b FL(th)20 +b(v)o(erte)o(x)e(of)i(the)g(graph.)k(The)c(numbering)d(in)k(the)f +(ordering)e(\002le)j(starts)g(from)e(0.)100 4471 y(Note)g(that)g(the)g +(ordering)d(\002le)k(stores)f(what)g(is)h(referred)d(to)i(as)h(the)f +(the)g(in)m(v)o(erse)f(permutation)e(v)o(ector)i Fs(iperm)h +FL(of)g(the)g(ordering.)j(Let)8 4581 y Ft(A)g FL(be)e(a)g(matrix)f(and) +g(let)29 b Ft(A)779 4550 y Fe(0)820 4581 y FL(be)20 b(the)f(reordered)f +(matrix.)24 b(The)19 b(in)m(v)o(erse)g(permutation)f(v)o(ector)g(maps)i +(the)f Ft(i)9 b FL(th)19 b(ro)n(w)h(\(column\))d(of)28 +b Ft(A)22 b FL(into)0 4690 y(the)e Fs(iperm)p FM(T)o +Ft(i)9 b FM(U)19 b FL(ro)n(w)h(\(column\))e(of)28 b Ft(A)1046 +4660 y Fe(0)1067 4690 y FL(.)1908 5649 y(17)p eop +%%Page: 18 18 +18 17 bop 0 85 a FD(5)119 b(M)-6 b FA(E)-23 b FD(T)g +FA(I)p FD(S)s(')-7 b(s)31 b(Librar)q(y)h(Interface)0 +261 y FL(The)17 b(v)n(arious)g(programs)f(pro)o(vided)f(in)20 +b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)22 b FL(can)c(also)g(be)f +(directly)g(accessed)h(from)f(a)h(C)g(or)g(F)o(ortran)e(program)g(by)h +(using)g(the)h(stand-)0 370 y(alone)27 b(library)h Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)p FL(.)49 b(Furthermore,)29 +b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)30 b FL(e)o(xtends)d(the)g +(functionality)e(pro)o(vided)g(by)k Fz(M)l FG(E)-17 b +Fz(T)g FG(I)p Fz(S)r FL(')-5 b(s)30 b(stand-alone)25 +b(programs)0 480 y(in)h(tw)o(o)h(dif)n(ferent)d(w)o(ays.)43 +b(First,)29 b(it)d(allo)n(ws)h(the)f(user)g(to)g(alter)h(the)f(beha)n +(vior)e(of)i(the)g(v)n(arious)f(algorithms)g(in)k Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)r FL(,)28 b(and)d(second)2 +590 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)31 b +FL(pro)o(vides)26 b(additional)g(routines)h(that)g(can)h(be)f(used)g +(to)h(partition)f(graphs)f(into)i(unequal-size)d(partitions)i(and)g +(compute)0 699 y(partitionings)19 b(that)h(directly)f(minimize)h(the)g +(total)g(communication)d(v)n(olume.)100 809 y(In)24 b(the)g(rest)g(of)g +(this)h(section)f(we)h(describe)e(the)h(interf)o(ace)f(to)i(the)f +(routines)f(in)k Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)27 +b FL(by)d(\002rst)h(describing)d(the)j(v)n(arious)e(data)0 +918 y(structures)e(used)h(to)g(pass)g(information)e(into)h(and)h(get)f +(information)f(out)h(of)h(the)g(routines,)f(follo)n(wed)f(by)i(a)g +(detailed)f(description)g(of)0 1028 y(the)f(calling)g(sequence)f(of)h +(the)g(v)n(arious)f(routines.)0 1255 y Fr(5.1)100 b(Graph)27 +b(Data)i(Structure)0 1415 y FL(All)24 b(of)f(the)h(graph)e +(partitioning)f(and)i(sparse)h(matrix)f(ordering)e(routines)h(in)k +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)27 b FL(tak)o(e)c(as)h +(input)f(the)h(adjacenc)o(y)d(structure)i(of)0 1524 y(the)d(graph)f +(and)h(the)g(weights)g(of)g(the)g(v)o(ertices)g(and)f(edges)h(\(if)g +(an)o(y\).)100 1634 y(The)25 b(adjacenc)o(y)e(structure)h(of)h(the)h +(graph)e(is)i(stored)f(using)f(the)i(compressed)d(storage)i(format)f +(\(CSR\).)i(The)f(CSR)i(format)d(is)i(a)0 1744 y(widely)e(used)h +(scheme)g(for)f(storing)g(sparse)h(graphs.)38 b(In)24 +b(this)i(format)e(the)g(adjacenc)o(y)g(structure)g(of)g(a)h(graph)f +(with)h Ft(n)k FL(v)o(ertices)24 b(and)0 1853 y Ft(m)k +FL(edges)22 b(is)h(represented)e(using)h(tw)o(o)g(arrays)g +Fp(xadj)h FL(and)e Fp(adjncy)p FL(.)32 b(The)22 b Fp(xadj)g +FL(array)f(is)j(of)e(size)h Ft(n)g FM(C)d FL(1)j(whereas)f(the)g +Fp(adjncy)0 1963 y FL(array)d(is)i(of)f(size)h(2)p Ft(m)k +FL(\(this)c(is)g(because)e(for)h(each)g(edge)f(between)h(v)o(ertices)f +Fu(v)25 b FL(and)19 b Ft(u)25 b FL(we)c(actually)e(store)h(both)g +Fu(.v)s(;)14 b Ft(u)t Fu(/)21 b FL(and)f Fu(.)p Ft(u)t +Fu(;)14 b(v)s(/)p FL(\).)100 2072 y(The)21 b(adjacenc)o(y)e(structure)i +(of)g(the)g(graph)f(is)j(stored)e(as)h(follo)n(ws.)28 +b(Assuming)21 b(that)g(v)o(erte)o(x)f(numbering)f(starts)j(from)e(0)i +(\(C)g(style\),)0 2182 y(then)32 b(the)g(adjacenc)o(y)f(list)j(of)e(v)o +(erte)o(x)e Ft(i)42 b FL(is)33 b(stored)f(in)h(array)e +Fp(adjncy)h FL(starting)g(at)h(inde)o(x)e Fp(xadj[)o +Ft(i)9 b Fp(])32 b FL(and)g(ending)f(at)i(\(b)n(ut)f(not)0 +2292 y(including\))17 b(inde)o(x)g Fp(xadj[)o Ft(i)22 +b FM(C)14 b FL(1)p Fp(])k FL(\()p Fs(i.e)o FL(.,)h Fp(adjncy[xadj[)o +Ft(i)9 b Fp(]])17 b FL(through)g(and)h(including)f Fp(adjncy[xadj[)o +Ft(i)j FM(C)14 b FL(1)p Fp(]-1])p FL(\).)23 b(That)0 +2401 y(is,)h(for)e(each)h(v)o(erte)o(x)d Ft(i)9 b FL(,)24 +b(its)g(adjacenc)o(y)d(list)j(is)g(stored)e(in)h(consecuti)n(v)o(e)e +(locations)h(in)h(the)g(array)f Fp(adjncy)p FL(,)h(and)f(the)h(array)f +Fp(xadj)h FL(is)0 2511 y(used)i(to)h(point)f(to)h(where)f(it)h(be)o +(gins)f(and)g(where)g(it)h(ends.)41 b(Figure)25 b(10\(b\))f +(illustrates)i(the)g(CSR)h(format)d(for)h(the)h(15-v)o(erte)o(x)d +(graph)0 2620 y(sho)n(wn)c(in)i(Figure)e(10\(a\).)450 +3789 y @beginspecial 0 @llx 0 @lly 506 @urx 180 @ury +3600 @rwi @setspecial +%%BeginDocument: ./figures/csr.eps +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {} def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-8.0 206.0 translate +1 -1 scale + +/clp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/l {lineto} bind def +/m {moveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit + 0.06000 0.06000 sc +/Times-Roman findfont 150.00 scalefont setfont +4725 2850 m +gs 1 -1 sc (3) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4500 2850 m +gs 1 -1 sc (12) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4350 2850 m +gs 1 -1 sc (8) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4200 2850 m +gs 1 -1 sc (6) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4875 2850 m +gs 1 -1 sc (7) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +5550 2850 m +gs 1 -1 sc (8) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +5400 2850 m +gs 1 -1 sc (4) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +5175 2850 m +gs 1 -1 sc (13) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +5025 2850 m +gs 1 -1 sc (9) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4050 2850 m +gs 1 -1 sc (2) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2700 2850 m +gs 1 -1 sc (9) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2250 2850 m +gs 1 -1 sc (4) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2100 2850 m +gs 1 -1 sc (2) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1050 2850 m +gs 1 -1 sc (5) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2550 2850 m +gs 1 -1 sc (3) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3825 2850 m +gs 1 -1 sc (11) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3675 2850 m +gs 1 -1 sc (7) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3525 2850 m +gs 1 -1 sc (5) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3375 2850 m +gs 1 -1 sc (1) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2400 2850 m +gs 1 -1 sc (8) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +5700 2850 m +gs 1 -1 sc (14) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +8100 2850 m +gs 1 -1 sc (9) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +7875 2850 m +gs 1 -1 sc (14) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +7650 2850 m +gs 1 -1 sc (12) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +7500 2850 m +gs 1 -1 sc (8) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +8250 2850 m +gs 1 -1 sc (13) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +600 2850 m +gs 1 -1 sc (adjncy) dup stringwidth pop neg 0 rmoveto col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +600 2550 m +gs 1 -1 sc (xadj) dup stringwidth pop neg 0 rmoveto col-1 show gr +/Helvetica-Bold findfont 210.00 scalefont setfont +3900 3375 m +gs 1 -1 sc (\(b CSR format) dup stringwidth pop 2 div neg 0 rmoveto col-1 show gr +/Helvetica-Bold findfont 210.00 scalefont setfont +3900 1500 m +gs 1 -1 sc (\(a\) A sample graph) dup stringwidth pop 2 div neg 0 rmoveto col-1 show gr +7.500 slw +% Polyline +n 150 2250 m 8550 2250 l 8550 3000 l 150 3000 l clp gs col-1 s gr +/Times-Roman findfont 150.00 scalefont setfont +7275 2850 m +gs 1 -1 sc (13) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +5925 2850 m +gs 1 -1 sc (5) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3150 2850 m +gs 1 -1 sc (10) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3000 2850 m +gs 1 -1 sc (6) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2850 2850 m +gs 1 -1 sc (0) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +6075 2850 m +gs 1 -1 sc (11) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +7050 2850 m +gs 1 -1 sc (11) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +6900 2850 m +gs 1 -1 sc (7) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +6675 2850 m +gs 1 -1 sc (12) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +6450 2850 m +gs 1 -1 sc (10) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +6300 2850 m +gs 1 -1 sc (6) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1950 2850 m +gs 1 -1 sc (7) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4350 1125 m +gs 1 -1 sc (14) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4050 1125 m +gs 1 -1 sc (13) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3750 1125 m +gs 1 -1 sc (12) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3450 1125 m +gs 1 -1 sc (11) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3225 525 m +gs 1 -1 sc (0) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4425 525 m +gs 1 -1 sc (4) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4125 525 m +gs 1 -1 sc (3) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3825 525 m +gs 1 -1 sc (2) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3525 525 m +gs 1 -1 sc (1) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3150 1125 m +gs 1 -1 sc (10) col-1 show gr +% Polyline +n 4200 525 m 4200 1125 l gs col-1 s gr +% Polyline +n 3900 525 m 3900 1125 l gs col-1 s gr +% Polyline +n 3600 525 m 3600 1125 l gs col-1 s gr +% Polyline +n 3300 525 m 4500 525 l 4500 1125 l 3300 1125 l 3300 525 l gs col-1 s gr +% Polyline +n 3300 825 m 4500 825 l gs col-1 s gr +/Times-Roman findfont 150.00 scalefont setfont +4425 825 m +gs 1 -1 sc (9) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +4125 825 m +gs 1 -1 sc (8) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3825 825 m +gs 1 -1 sc (7) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3525 825 m +gs 1 -1 sc (6) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3225 825 m +gs 1 -1 sc (5) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +900 2550 m +gs 1 -1 sc (0) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3975 2550 m +gs 1 -1 sc (44) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3750 2550 m +gs 1 -1 sc (42) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3525 2550 m +gs 1 -1 sc (39) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3300 2550 m +gs 1 -1 sc (36) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +900 2850 m +gs 1 -1 sc (1) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1800 2850 m +gs 1 -1 sc (3) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1650 2850 m +gs 1 -1 sc (1) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1500 2850 m +gs 1 -1 sc (6) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1350 2850 m +gs 1 -1 sc (2) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1200 2850 m +gs 1 -1 sc (0) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +3075 2550 m +gs 1 -1 sc (33) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1500 2550 m +gs 1 -1 sc (11) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1350 2550 m +gs 1 -1 sc (8) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1200 2550 m +gs 1 -1 sc (5) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1050 2550 m +gs 1 -1 sc (2) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1725 2550 m +gs 1 -1 sc (13) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2850 2550 m +gs 1 -1 sc (31) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2625 2550 m +gs 1 -1 sc (28) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2400 2550 m +gs 1 -1 sc (24) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +2175 2550 m +gs 1 -1 sc (20) col-1 show gr +/Times-Roman findfont 150.00 scalefont setfont +1950 2550 m +gs 1 -1 sc (16) col-1 show gr +$F2psEnd +restore +%%EndDocument + @endspecial 920 3971 a Fy(Figure)f(10)p FL(:)25 b Fx(An)20 +b(e)n(xample)e(of)g(the)h(CSR)h(f)n(or)r(mat)d(f)n(or)i(stor)q(ing)f +(sparse)g(g)o(r)o(aphs)o(.)100 4164 y FL(The)h(weights)h(of)g(the)g(v)o +(ertices)g(\(if)g(an)o(y\))f(are)h(stored)f(in)h(an)g(additional)f +(array)g(called)h Fp(vwgt)p FL(.)25 b(If)20 b Fs(ncon)f +FL(is)i(the)f(number)e(of)i(weights)0 4274 y(associated)h(with)h(each)f +(v)o(erte)o(x,)f(the)i(array)f Fp(vwgt)g FL(contains)g +Ft(n)h FM(\003)e Fs(ncon)h FL(elements)g(\(recall)g(that)g +Ft(n)26 b FL(is)c(the)g(number)e(of)h(v)o(ertices\).)28 +b(The)0 4383 y(weights)e(of)h(the)e Ft(i)9 b FL(th)26 +b(v)o(erte)o(x)g(are)g(stored)g(in)h Fs(ncon)e FL(consecuti)n(v)o(e)g +(entries)h(starting)h(at)g(location)e Fp(vwgt[)o Ft(i)31 +b FM(\003)23 b Fd(ncon)p Fp(])p FL(.)44 b(Note)27 b(that)f(if)0 +4493 y(each)d(v)o(erte)o(x)g(has)h(only)f(a)h(single)f(weight,)h(then)g +Fp(vwgt)f FL(will)i(contain)d Ft(n)28 b FL(elements,)c(and)f +Fp(vwgt[)o Ft(i)9 b Fp(])23 b FL(will)h(store)g(the)g(weight)f(of)h +(the)-1 4603 y Ft(i)9 b FL(th)21 b(v)o(erte)o(x.)26 b(The)21 +b(v)o(erte)o(x-weights)d(must)j(be)g(inte)o(gers)f(greater)h(or)f +(equal)h(to)g(zero.)27 b(If)21 b(all)h(the)f(v)o(ertices)f(of)h(the)g +(graph)f(ha)n(v)o(e)g(the)h(same)0 4712 y(weight)f(\()p +Fs(i.e)o FL(.,)g(the)h(graph)d(is)j(unweighted\),)d(then)i(the)g +Fp(vwgt)g FL(can)g(be)g(set)h(to)f(NULL.)100 4822 y(The)c(weights)h(of) +g(the)h(edges)e(\(if)h(an)o(y\))f(are)i(stored)e(in)h(an)h(additional)d +(array)i(called)g Fp(adjwgt)p FL(.)23 b(This)17 b(array)g(contains)f(2) +p Ft(m)22 b FL(elements,)0 4931 y(and)j(the)g(weight)g(of)g(edge)g +Fp(adjncy[)14 b Ft(j)9 b Fp(])23 b FL(is)j(stored)f(at)h(location)e +Fp(adjwgt[)14 b Ft(j)9 b Fp(])p FL(.)39 b(The)25 b(edge-weights)e(must) +j(be)f(inte)o(gers)g(greater)0 5041 y(than)c(zero.)27 +b(If)21 b(all)h(the)f(edges)f(of)h(the)g(graph)f(ha)n(v)o(e)h(the)g +(same)g(weight)g(\()p Fs(i.e)o FL(.,)h(the)f(graph)f(is)i +(unweighted\),)c(then)j(the)g Fp(adjwgt)g FL(can)g(be)0 +5150 y(set)g(to)f(NULL.)100 5260 y(All)26 b(of)f(these)h(four)e(arrays) +h(\()p Fs(xadj)p FL(,)g Fs(adjncy)p FL(,)h Fs(vwgt)p +FL(,)h(and)e Fs(adjwgt)p FL(\))f(are)i(de\002ned)e(in)k +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)29 b FL(to)c(be)h(of)f(of)g +(type)g Fp(idxtype)p FL(.)40 b(By)0 5370 y(def)o(ault)27 +b Fp(idxtype)g FL(is)h(set)h(to)e(be)h(equi)n(v)n(alent)e(to)i(type)f +Fp(int)g FL(\()p Fs(i.e)p FL(.,)i(the)f(inte)o(ger)e(datatype)h(of)g +(C\).)h(Ho)n(we)n(v)o(er)m(,)f Fp(idxtype)g FL(can)h(be)1908 +5649 y(18)p eop +%%Page: 19 19 +19 18 bop 0 83 a FL(made)18 b(to)h(be)f(equi)n(v)n(alent)f(to)i(a)g +Fp(short)49 b(int)19 b FL(for)f(certain)g(architectures)f(that)i(use)g +(64-bit)f(inte)o(gers)g(by)g(def)o(ault.)24 b(The)18 +b(con)m(v)o(ersion)e(of)0 193 y Fp(idxtype)j FL(from)f +Fp(int)i FL(to)f Fp(short)g FL(can)h(be)f(done)g(by)g(modifying)e(the)i +(\002le)h Fp(Lib/struct.h)e FL(\(instructions)g(are)i(included)e +(there\).)0 302 y(The)i(same)g Fp(idxtype)g FL(is)h(used)f(for)f(the)h +(arrays)g(that)g(are)g(used)g(to)h(store)f(the)g(computed)e(partition)h +(and)h(permutation)e(v)o(ector)-5 b(.)0 530 y Fr(5.2)100 +b(Mesh)28 b(Data)h(Structure)0 689 y FL(All)21 b(of)e(the)h(mesh)g +(partitioning)e(and)h(mesh)h(con)m(v)o(ersion)d(routines)i(in)k +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)23 b FL(tak)o(e)d(as)g +(input)g(the)g(element)f(node)g(array)g(of)h(a)g(mesh.)0 +799 y(This)e(element)f(node)g(array)g(is)i(stored)e(using)h(an)f(array) +g(called)h Fp(elmnts)p FL(.)24 b(F)o(or)17 b(a)h(mesh)g(with)g +Ft(n)k FL(elements)17 b(and)h Ft(k)23 b FL(nodes)17 b(per)g(element,)0 +908 y(the)k(size)i(of)e(the)g Fp(elmnts)g FL(array)g(is)h +Ft(n)h FM(\003)c Ft(k)5 b FL(.)29 b(Note)22 b(that)f(since)h(the)f +(supported)f(elements)h(in)j Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)25 b FL(are)d(only)e(triangles,)h(tetrahedra,)0 +1018 y(he)o(xahedra,)c(and)j(quadrilaterals,)e(the)j(possible)f(v)n +(alues)f(for)h Ft(k)25 b FL(are)c(3,)f(4,)g(8,)g(and)f(4,)h(respecti)n +(v)o(ely)-5 b(.)100 1127 y(The)21 b(element)g(node)g(array)g(of)h(the)f +(mesh)h(is)h(stored)e(in)h Fp(elmnts)f FL(as)i(follo)n(ws.)29 +b(Assuming)22 b(that)g(the)f(element)h(numbering)d(starts)0 +1237 y(from)e(0)i(\(C)f(style\),)h(then)f(the)g Ft(k)24 +b FL(nodes)17 b(that)i(mak)o(e)f(up)f(element)g Ft(i)28 +b FL(are)18 b(stored)g(in)g(array)f Fp(elmnts)h FL(starting)g(at)h +(inde)o(x)d Ft(i)k FM(\003)11 b Ft(k)24 b FL(and)18 b(ending)0 +1347 y(\(b)n(ut)23 b(not)h(including\))d(inde)o(x)i Fu(.)o +Ft(i)29 b FM(C)21 b FL(1)p Fu(/)f FM(\003)i Ft(k)5 b +FL(.)36 b(As)24 b(it)g(w)o(as)h(the)f(case)g(with)g(the)f(format)g(of)g +(the)h(mesh)f(\002le)i(described)d(in)i(Section)f(4.5.2,)0 +1456 y(the)d(ordering)e(of)h(the)h(nodes)f(is)i(not)f(important)e(for)h +(triangle)g(and)h(tetrahedra)e(elements.)25 b(Ho)n(we)n(v)o(er)m(,)17 +b(in)k(the)e(case)i(of)e(he)o(xahedra,)f(the)0 1566 y(nodes)h(for)h +(each)g(element)f(must)i(be)f(ordered)e(according)g(to)j(the)f +(numbering)d(illustrated)j(in)g(Figure)g(9\(b\).)100 +1675 y(The)h(array)g(that)h(describes)f(the)g(element)h(node)e(array)h +(of)g(the)h(mesh)g(is)g(de\002ned)f(in)j Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)r(lib)25 b FL(to)d(be)f(of)h(type)f +Fp(idxtype)p FL(,)g(which)0 1785 y(by)f(def)o(ault)f(is)i(equi)n(v)n +(alent)e(to)h Fp(int)g FL(\()p Fs(i.e)p FL(.,)g(inte)o(gers\).)0 +2012 y Fr(5.3)100 b(P)m(ar)r(titioning)27 b(Objectives)0 +2172 y FL(The)d(partitioning)e(algorithms)h(in)j Fz(M)l +FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)27 b FL(can)d(be)g(used)g(to)g +(compute)e(a)j(balanced)e Ft(k)5 b FL(-w)o(ay)23 b(partitioning)f(that) +i(minimizes)g(either)0 2281 y(the)g(number)d(of)j(edges)f(that)g +(straddle)g(partitions)g(\()p Fs(edg)o(ecut)p FL(\))f(or)h(the)h(total) +g(communication)c(v)n(olume)j(\()p Fs(totalv)p FL(\).)34 +b(In)23 b(the)h(rest)g(of)f(this)0 2391 y(section)d(we)h(brie\003y)e +(describe)g(these)i(tw)o(o)f(objecti)n(v)o(es)f(and)h(pro)o(vide)e +(some)i(suggestions)f(on)h(when)g(the)o(y)f(should)g(be)h(used.)0 +2600 y FB(Minimizing)j(the)h(Edg)q(e-Cut)99 b FL(Consider)20 +b(a)i(graph)g Ft(G)30 b FM(D)25 b Fu(.)r Ft(V)8 b Fu(;)20 +b Ft(E)7 b Fu(/)p FL(,)22 b(and)f(let)29 b Ft(P)f FL(be)21 +b(a)h(v)o(ector)e(of)h(size)h FM(j)r Ft(V)13 b FM(j)21 +b FL(such)g(that)29 b Ft(P)6 b FM(T)o Ft(i)j FM(U)21 +b FL(stores)0 2710 y(the)f(number)f(of)h(the)g(partition)g(that)g(v)o +(erte)o(x)e Ft(i)29 b FL(belongs)19 b(to.)26 b(The)20 +b Fs(edg)o(ecut)f FL(of)h(this)h(partitioning)d(is)k(de\002ned)d(as)i +(the)f(number)f(of)h(edges)0 2819 y(that)d(straddle)f(partitions.)23 +b(That)16 b(is,)i(the)e(number)f(of)i(edges)f Fu(.v)s(;)e +Ft(u)t Fu(/)k FL(for)e(which)23 b Ft(P)6 b FM(T)p Fu(v)s +FM(U)24 b(6)r(D)30 b Ft(P)6 b FM(T)p Ft(u)t FM(U)p FL(.)24 +b(If)17 b(the)f(graph)g(has)g(weights)h(associated)0 +2929 y(with)j(the)h(edges,)e(then)h(the)g(edgecut)f(is)i(de\002ned)e +(as)i(the)f(sum)h(of)e(the)i(weight)e(of)h(these)h(straddling)e(edges.) +0 3138 y FB(Minimizing)26 b(the)h(T)-7 b(otal)28 b(Comm)n(unication)e +(V)-7 b(olume)99 b FL(Consider)23 b(a)i(graph)f Ft(G)36 +b FM(D)30 b Fu(.)r Ft(V)8 b Fu(;)20 b Ft(E)7 b Fu(/)p +FL(,)26 b(and)d(let)32 b Ft(P)f FL(be)25 b(a)f(v)o(ector)f(of)h(size)0 +3248 y FM(j)r Ft(V)12 b FM(j)20 b FL(such)f(that)26 b +Ft(P)6 b FM(T)o Ft(i)j FM(U)19 b FL(stores)g(the)g(number)f(of)g(the)h +(partition)f(that)i(v)o(erte)o(x)c Ft(i)28 b FL(belongs)18 +b(to.)25 b(Let)c Ft(V)2726 3260 y Ff(b)2786 3248 y FM(\032)k +Ft(V)32 b FL(be)19 b(the)g(subset)g(of)g(interf)o(ace)f(\(or)0 +3357 y(boarder\))i(v)o(ertices.)32 b(That)23 b(is,)h(each)e(v)o(erte)o +(x)g Fu(v)31 b FM(2)f Ft(V)1497 3369 y Ff(b)1557 3357 +y FL(is)24 b(connected)d(to)h(at)i(least)f(one)f(v)o(erte)o(x)f(that)i +(belongs)f(to)h(a)g(dif)n(ferent)e(partition.)0 3467 +y(F)o(or)h(each)g(v)o(erte)o(x)e Fu(v)31 b FM(2)e Ft(V)740 +3479 y Ff(b)799 3467 y FL(let)g Ft(N)8 b(a)t(d)k(j)d +FM(T)p Fu(v)s FM(U)22 b FL(be)g(the)g(number)e(of)i(domains)f(other)h +(than)28 b Ft(P)6 b FM(T)p Fu(v)s FM(U)24 b FL(that)e(the)g(v)o +(ertices)g(adjacent)f(to)i Fu(v)j FL(belong)0 3577 y(to.)f(The)20 +b Fs(totalv)g FL(of)g(this)g(partitioning)f(is)i(de\002ned)e(as:)1561 +3778 y Fs(totalv)j FM(D)1873 3699 y Fc(X)1861 3872 y +Fg(v)s Fe(2)r Ff(V)1974 3882 y Fa(b)2023 3778 y Ft(N)8 +b(a)t(d)k(j)d FM(T)p Fu(v)s FM(U)p Fu(:)1463 b FL(\(1\))0 +4048 y(Equation)19 b(1)i(corresponds)e(to)i(the)g(total)g +(communication)d(v)n(olume)i(incurred)f(by)h(the)h(partitioning)e +(because)h(each)h(interf)o(ace)f(v)o(erte)o(x)0 4158 +y Fu(v)25 b FL(needs)19 b(to)i(be)f(sent)g(to)h(all)f(of)g(its)28 +b Ft(N)8 b(a)t(d)k(j)d FM(T)p Fu(v)s FM(U)19 b FL(partitions.)100 +4267 y(The)k(abo)o(v)o(e)e(model)i(can)g(be)g(e)o(xtended)e(to)j +(instances)f(in)h(which)e(the)i(amount)e(of)h(data)g(that)g(needs)g(to) +h(be)f(sent)h(for)e(each)h(node)g(is)0 4377 y(dif)n(ferent.)g(In)c +(particular)m(,)f(if)i Fu(w)907 4389 y Fg(v)964 4377 +y FL(is)h(the)e(amount)f(of)h(data)h(that)f(needs)g(to)h(be)f(sent)h +(for)f(v)o(erte)o(x)f Fu(v)s FL(,)j(then)e(Equation)e(1)j(can)f(be)h +(re-written)0 4487 y(as:)1512 4596 y Fs(totalv)i FM(D)1824 +4517 y Fc(X)1812 4691 y Fg(v)s Fe(2)r Ff(V)1925 4701 +y Fa(b)1967 4596 y Fu(w)2028 4608 y Fg(v)2072 4596 y +Ft(N)8 b(a)t(d)k(j)d FM(T)p Fu(v)s FM(U)p Fu(:)1414 b +FL(\(2\))2 4835 y Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)24 +b FL(supports)19 b(this)j(weighted)d(totalv)h(model)g(by)g(using)h(an)f +(array)g(called)g Fp(vsize)g FL(such)h(that)g(the)f(amount)f(of)i(data) +f(that)h(needs)0 4944 y(to)h(be)f(sent)h(due)f(to)h(the)f +Ft(i)9 b FL(th)21 b(v)o(erte)o(x)f(is)j(stored)e(in)h +Fp(vsize[)o Ft(i)9 b Fp(])p FL(.)28 b(Note)22 b(that)f(the)h(amount)e +(of)i(data)f(that)h(needs)f(to)h(be)g(sent)g(is)g(dif)n(ferent)0 +5054 y(from)j(the)g Fs(weight)h FL(of)f(the)h(v)o(erte)o(x.)39 +b(The)25 b(former)g(corresponds)e(to)j(communication)c(cost)k(whereas)f +(the)h(later)g(corresponds)d(to)j(the)0 5164 y(computational)18 +b(cost.)100 5273 y(Note)j(that)h(for)f(partitioning)e(algorithms)h(to)i +(correctly)e(minimize)h(the)h(totalv)-5 b(,)20 b(the)i(graph)e(should)h +(re\003ect)g(the)h(true)f(information)0 5383 y(e)o(xchange)c +(requirements)g(of)i(the)g(underlying)e(computations.)23 +b(F)o(or)18 b(instance,)h(the)h(dual)e(graph)g(of)h(a)h(\002nite)f +(element)g(mesh)g(does)g(not)1908 5649 y(19)p eop +%%Page: 20 20 +20 19 bop 0 83 a FL(correctly)19 b(model)g(the)h(underlying)e +(communication,)f(whereas)j(the)g(nodal)f(graph)g(does.)0 +292 y FB(Whic)o(h)h(one)e(is)i(Better?)99 b FL(When)17 +b(partitioning)d(is)k(used)f(to)g(distrib)n(ute)f(a)h(graph)e(or)i(a)g +(mesh)g(among)e(the)i(processors)e(of)i(a)g(parallel)0 +402 y(computer)m(,)24 b(the)i(edgecut)e(is)i(only)e(an)i(approximation) +c(of)j(the)g(true)g(communication)e(cost)i(resulting)g(from)f(the)h +(partitioning.)39 b(On)0 511 y(the)25 b(other)e(hand,)i(by)f +(minimizing)f(the)h(totalv)g(we)h(can)g(directly)e(minimize)h(the)h(o)o +(v)o(erall)e(communication)e(cost.)39 b(Despite)24 b(of)h(that,)0 +621 y(for)i(man)o(y)f(graphs)h(the)g(solutions)g(obtained)f(by)h +(minimizing)f(the)i(edgecut)e(or)h(minimizing)f(the)i(totalv)-5 +b(,)28 b(are)g(comparable.)44 b(This)0 731 y(is)27 b(especially)g(true) +f(for)g(graphs)f(corresponding)e(to)k(well-shaped)e(\002nite)i(element) +f(meshes.)43 b(This)27 b(is)h(because)d(for)h(these)h(graphs,)0 +840 y(the)e(de)o(grees)f(of)g(the)h(v)n(arious)f(v)o(ertices)h(are)g +(similar)g(and)f(the)h(objecti)n(v)o(es)f(of)h(minimizing)e(the)i +(edgecut)f(or)g(the)h(totalv)g(beha)n(v)o(e)f(the)0 950 +y(same.)38 b(On)25 b(the)g(other)e(hand,)i(if)g(the)f(v)o(erte)o(x)f +(de)o(grees)h(v)n(ary)f(signi\002cantly)h(\()p Fs(e)o(.g)o +FL(.,)h(graphs)f(corresponding)d(to)k(linear)f(programming)0 +1059 y(matrices\),)19 b(then)h(by)g(minimizing)f(the)h(totalv)g(we)g +(can)g(obtain)g(a)g(signi\002cant)g(reduction)e(in)j(the)f(total)g +(communication)d(v)n(olume.)100 1169 y(In)j(terms)i(of)e(the)i(amount)d +(of)i(time)g(required)f(by)g(these)i(tw)o(o)f(partitioning)e(objecti)n +(v)o(es,)h(minimizing)g(the)h(edgecut)f(is)i(f)o(aster)f(than)0 +1279 y(minimizing)28 b(the)h(totalv)-5 b(.)52 b(F)o(or)29 +b(this)h(reason,)h(the)f(totalv)f(objecti)n(v)o(e)f(should)g(be)i(used) +f(only)g(for)f(problems)g(in)i(which)f(it)h(actually)0 +1388 y(reduces)19 b(the)i(o)o(v)o(erall)d(communication)g(v)n(olume.) +1908 5649 y(20)p eop +%%Page: 21 21 +21 20 bop 0 83 a Fr(5.4)100 b(Graph)27 b(P)m(ar)r(titioning)g(Routines) +0 240 y FB(METIS)p 258 240 25 4 v 31 w(P)n(ar)r(tGraphRecur)o(sive)20 +b FL(\(int)g(*n,)g(idxtype)f(*xadj,)g(idxtype)f(*adjnc)o(y)-5 +b(,)18 b(idxtype)h(*vwgt,)g(idxtype)g(*adjwgt,)g(int)h(*wgt\003ag,)1105 +350 y(int)h(*num\003ag,)d(int)i(*nparts,)f(int)h(*options,)f(int)h +(*edgecut,)f(idxtype)f(*part\))0 587 y FB(Description)208 +697 y FL(It)23 b(is)i(used)e(to)h(partition)f(a)h(graph)e(into)h +Ft(k)29 b FL(equal-size)23 b(parts)g(using)g(multile)n(v)o(el)g +(recursi)n(v)o(e)f(bisection.)35 b(It)23 b(pro)o(vides)f(the)i(func-) +208 806 y(tionality)c(of)i(the)f Fp(pmetis)g FL(program.)27 +b(The)21 b(objecti)n(v)o(e)f(of)i(the)f(partitioning)f(is)i(to)g +(minimize)e(the)i(edgecut)e(\(as)i(described)e(in)208 +916 y(Section)f(5.3\).)0 1087 y FB(P)n(arameter)o(s)208 +1202 y FC(n)327 b FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h +(graph.)208 1314 y FC(xadj,)e(adjncy)581 1423 y FL(The)h(adjacenc)o(y)e +(structure)i(of)g(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.) +208 1535 y FC(vwgt,)f(adjwgt)581 1645 y FL(Information)f(about)h(the)h +(weights)g(of)g(the)g(v)o(ertices)g(and)f(edges)h(as)h(described)e(in)h +(Section)g(5.1.)208 1783 y FC(wgt\003ag)113 b FL(Used)21 +b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 1921 y(0)83 b(No)20 b(weights)g(\(vwgts)g(and)f(adjwgt)h +(are)g(NULL\))581 2045 y(1)83 b(W)-7 b(eights)21 b(on)e(the)h(edges)g +(only)g(\(vwgts)f(=)i(NULL\))581 2168 y(2)83 b(W)-7 b(eights)21 +b(on)e(the)h(v)o(ertices)g(only)g(\(adjwgt)f(=)i(NULL\))581 +2292 y(3)83 b(W)-7 b(eights)21 b(both)e(on)h(v)o(ertices)f(and)h +(edges.)208 2430 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g +(which)g(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f +(structure)g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 +2540 y FL(can)20 b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:) +581 2678 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g +(starts)h(from)e(0)581 2802 y(1)83 b(F)o(ortran-style)18 +b(numbering)g(is)j(assumed)e(that)i(starts)g(from)e(1)208 +2940 y FC(nparts)142 b FL(The)20 b(number)e(of)i(parts)g(to)h +(partition)e(the)h(graph.)208 3078 y FC(options)114 b +FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o(gers)e(that)h(is)i(used) +e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f(phases)h(of)g(the)g +(algorithm.)581 3187 y(If)j Fs(options[0]=0)e FL(then)h(def)o(ault)g(v) +n(alues)g(are)h(used.)34 b(If)24 b Fs(options[0]=1)p +FL(,)f(then)g(the)g(remaining)f(four)h(elements)g(of)581 +3297 y Fs(options)c FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +3435 y(options[1])108 b(Determines)20 b(matching)e(type.)25 +b(Possible)20 b(v)n(alues)g(are:)1033 3559 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 3683 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 3806 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 3930 y(Experiments)f(has)h +(sho)n(wn)g(that)g(both)f(HEM)h(and)g(SHEM)g(perform)f(quite)g(well.) +581 4054 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used)g +(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 +4178 y(1)83 b(Re)o(gion)19 b(Gro)n(wing)g(\(Def)o(ault\))581 +4302 y(options[3])108 b(Determines)20 b(the)g(algorithm)f(used)g(for)h +(re\002nement.)k(Possible)c(v)n(alues)g(are:)1033 4425 +y(1)83 b(Early-Exit)18 b(Boundary)h(FM)h(re\002nement)f(\(Def)o(ault\)) +581 4549 y(options[4])108 b(Used)21 b(for)e(deb)n(ugging)f(purposes.)23 +b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o(ault\).)208 +4687 y FC(edgecut)100 b FL(Upon)19 b(successful)h(completion,)e(this)j +(v)n(ariable)e(stores)i(the)f(number)e(of)i(edges)g(that)g(are)g(cut)h +(by)e(the)i(partition.)208 4825 y FC(part)220 b FL(This)18 +b(is)h(a)f(v)o(ector)e(of)i(size)g Fs(n)g FL(that)g(upon)e(successful)h +(completion)f(stores)i(the)g(partition)f(v)o(ector)f(of)h(the)h(graph.) +23 b(The)581 4935 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i +(from)e(either)h(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)0 5106 y FB(Note)208 5216 y FL(This)d(function)f +(should)h(be)g(used)g(to)h(partition)f(a)g(graph)g(into)g(a)h(small)g +(number)e(of)h(partitions)g(\(less)h(than)f(8\).)23 b(If)17 +b(a)g(lar)o(ge)e(number)208 5325 y(of)k(partitions)h(is)h(desired,)e +(the)h Fz(METIS)p 1369 5325 V 31 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)g +FL(should)f(be)i(used)e(instead,)h(as)h(it)g(is)g(signi\002cantly)e(f)o +(aster)-5 b(.)1908 5649 y(21)p eop +%%Page: 22 22 +22 21 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(P)n(ar)r(tGraphKwa)n(y) +20 b FL(\(int)g(*n,)f(idxtype)g(*xadj,)g(idxtype)g(*adjnc)o(y)-5 +b(,)18 b(idxtype)g(*vwgt,)i(idxtype)e(*adjwgt,)h(int)i(*wgt\003ag,)925 +193 y(int)f(*num\003ag,)e(int)j(*nparts,)e(int)h(*options,)f(int)h +(*edgecut,)e(idxtype)h(*part\))0 380 y FB(Description)208 +490 y FL(It)32 b(is)i(used)e(to)g(partition)g(a)g(graph)f(into)i +Ft(k)k FL(equal-size)32 b(parts)g(using)g(the)h(multile)n(v)o(el)e +Ft(k)5 b FL(-w)o(ay)32 b(partitioning)e(algorithm.)60 +b(It)208 600 y(pro)o(vides)17 b(the)j(functionality)e(of)h(the)h +Fp(kmetis)f FL(program.)j(The)e(objecti)n(v)o(e)e(of)h(the)h +(partitioning)e(is)i(to)g(minimize)f(the)h(edgecut)208 +709 y(\(as)g(described)f(in)h(Section)g(5.3\).)0 869 +y FB(P)n(arameter)o(s)208 973 y FC(n)327 b FL(The)20 +b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 1074 +y FC(xadj,)e(adjncy)581 1183 y FL(The)h(adjacenc)o(y)e(structure)i(of)g +(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.)208 +1284 y FC(vwgt,)f(adjwgt)581 1394 y FL(Information)f(about)h(the)h +(weights)g(of)g(the)g(v)o(ertices)g(and)f(edges)h(as)h(described)e(in)h +(Section)g(5.1.)208 1521 y FC(wgt\003ag)113 b FL(Used)21 +b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 1648 y(0)83 b(No)20 b(weights)g(\(vwgts)g(and)f(adjwgt)h +(are)g(NULL\))581 1766 y(1)83 b(W)-7 b(eights)21 b(on)e(the)h(edges)g +(only)g(\(vwgts)f(=)i(NULL\))581 1884 y(2)83 b(W)-7 b(eights)21 +b(on)e(the)h(v)o(ertices)g(only)g(\(adjwgt)f(=)i(NULL\))581 +2003 y(3)83 b(W)-7 b(eights)21 b(both)e(on)h(v)o(ertices)f(and)h +(edges.)208 2129 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g +(which)g(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f +(structure)g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 +2239 y FL(can)20 b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:) +581 2366 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g +(starts)h(from)e(0)581 2484 y(1)83 b(F)o(ortran-style)18 +b(numbering)g(is)j(assumed)e(that)i(starts)g(from)e(1)208 +2611 y FC(nparts)142 b FL(The)20 b(number)e(of)i(parts)g(to)h +(partition)e(the)h(graph.)208 2738 y FC(options)114 b +FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o(gers)e(that)h(is)i(used) +e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f(phases)h(of)g(the)g +(algorithm.)581 2848 y(If)j Fs(options[0]=0)e FL(then)h(def)o(ault)g(v) +n(alues)g(are)h(used.)34 b(If)24 b Fs(options[0]=1)p +FL(,)f(then)g(the)g(remaining)f(four)h(elements)g(of)581 +2957 y Fs(options)c FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +3084 y(options[1])108 b(Determines)20 b(the)g(matching)f(type.)24 +b(Possible)d(v)n(alues)e(are:)1033 3203 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 3321 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 3439 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 3557 y(Experiments)f(has)h +(sho)n(wn)g(that)g(both)f(HEM)h(and)g(SHEM)g(perform)f(quite)g(well.) +581 3676 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used)g +(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 +3794 y(1)83 b(Multile)n(v)o(el)19 b(recursi)n(v)o(e)g(bisection)g +(\(Def)o(ault\))581 3912 y(options[3])108 b(Determines)20 +b(the)g(algorithm)f(used)g(for)h(re\002nement.)k(Possible)c(v)n(alues)g +(are:)1033 4030 y(1)83 b(Random)19 b(boundary)e(re\002nement)1033 +4149 y(2)83 b(Greedy)19 b(boundary)e(re\002nement)1033 +4267 y(3)83 b(Random)19 b(boundary)e(re\002nement)i(that)h(also)h +(minimizes)f(the)g(connecti)n(vity)e(among)h(the)h(sub-)1158 +4377 y(domains)f(\(Def)o(ault\))581 4495 y(options[4])108 +b(Used)21 b(for)e(deb)n(ugging)f(purposes.)23 b(Al)o(w)o(ays)e(set)g +(it)g(to)f(0)h(\(Def)o(ault\).)208 4622 y FC(edgecut)100 +b FL(Upon)19 b(successful)h(completion,)e(this)j(v)n(ariable)e(stores)i +(the)f(number)e(of)i(edges)g(that)g(are)g(cut)h(by)e(the)i(partition.) +208 4749 y FC(part)220 b FL(This)18 b(is)h(a)f(v)o(ector)e(of)i(size)g +Fs(n)g FL(that)g(upon)e(successful)h(completion)f(stores)i(the)g +(partition)f(v)o(ector)f(of)h(the)h(graph.)23 b(The)581 +4858 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i(from)e(either)h +(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)0 5019 y FB(Note)208 5128 y FL(This)24 +b(function)f(should)g(be)i(used)f(to)h(partition)e(a)i(graph)e(into)h +(a)h(lar)o(ge)f(number)e(of)j(partitions)e(\(greater)g(than)h(8\).)38 +b(If)24 b(a)h(small)208 5238 y(number)17 b(of)i(partitions)g(is)h +(desired,)f(the)g Fz(METIS)p 1639 5238 V 31 w(P)m(ar)s(tGr)o +(aphRecursiv)n(e)g FL(should)g(be)g(used)g(instead,)g(as)h(it)g +(produces)e(some-)208 5347 y(what)i(better)f(partitions.)1908 +5649 y(22)p eop +%%Page: 23 23 +23 22 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(P)n(ar)r(tGraphVKwa)n(y) +20 b FL(\(int)g(*n,)g(idxtype)e(*xadj,)h(idxtype)g(*adjnc)o(y)-5 +b(,)18 b(idxtype)h(*vwgt,)g(idxtype)g(*vsize,)g(int)i(*wgt\003ag,)980 +193 y(int)f(*num\003ag,)f(int)h(*nparts,)f(int)h(*options,)f(int)h(*v)n +(olume,)f(idxtype)g(*part\))0 452 y FB(Description)208 +561 y FL(It)28 b(is)h(used)f(to)h(partition)e(a)i(graph)e(into)h +Ft(k)33 b FL(equal-size)28 b(parts)g(using)g(the)g(multile)n(v)o(el)f +Ft(k)5 b FL(-w)o(ay)28 b(partitioning)e(algorithm.)48 +b(The)208 671 y(objecti)n(v)o(e)18 b(of)i(the)g(partitioning)f(is)i(to) +f(minimize)g(the)g(total)g(communication)d(v)n(olume)j(\(as)g +(described)f(in)h(Section)g(5.3\).)0 847 y FB(P)n(arameter)o(s)208 +966 y FC(n)327 b FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h +(graph.)208 1083 y FC(xadj,)e(adjncy)581 1193 y FL(The)h(adjacenc)o(y)e +(structure)i(of)g(the)g(graph)f(as)i(described)d(in)j(Sections)f(5.1)f +(and)h(5.3.)208 1309 y FC(vwgt,)f(vsize)581 1419 y FL(Information)h +(about)j(the)g(weights)g(of)g(the)g(v)o(ertices)f(related)h(to)g(the)g +(computation)e(and)i(communication)d(as)k(de-)581 1529 +y(scribed)c(in)g(Section)g(5.1.)208 1671 y FC(wgt\003ag)113 +b FL(Used)21 b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 1814 y(0)83 b(No)20 b(weights)g(\(vwgts)g(and)f(vsize)i +(are)f(NULL\))581 1940 y(1)83 b(Communication)18 b(weights)i(only)f +(\(vwgts)h(=)g(NULL\))581 2067 y(2)83 b(Computation)18 +b(weights)i(only)f(\(vsize)h(=)h(NULL\))581 2193 y(3)83 +b(Both)20 b(communication)d(and)j(computation)e(weights.)208 +2335 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 2445 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +2588 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 2714 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 2857 y FC(nparts)142 +b FL(The)20 b(number)e(of)i(parts)g(to)h(partition)e(the)h(graph.)208 +3000 y FC(options)114 b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o +(gers)e(that)h(is)i(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n +(arious)f(phases)h(of)g(the)g(algorithm.)581 3109 y(If)j +Fs(options[0]=0)e FL(then)h(def)o(ault)g(v)n(alues)g(are)h(used.)34 +b(If)24 b Fs(options[0]=1)p FL(,)f(then)g(the)g(remaining)f(four)h +(elements)g(of)581 3219 y Fs(options)c FL(are)i(interpreted)d(as)j +(follo)n(ws:)581 3362 y(options[1])108 b(Determines)20 +b(the)g(matching)f(type.)24 b(Possible)d(v)n(alues)e(are:)1033 +3488 y(1)83 b(Random)19 b(Matching)g(\(RM\))1033 3614 +y(2)83 b(Hea)n(vy-Edge)18 b(Matching)h(\(HEM\))1033 3740 +y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f(Matching)h(\(SHEM\))h(\(Def)o +(ault\))1033 3866 y(Experiments)f(has)h(sho)n(wn)g(that)g(both)f(HEM)h +(and)g(SHEM)g(perform)f(quite)g(well.)581 3993 y(options[2])108 +b(Determines)20 b(the)g(algorithm)f(used)g(during)g(initial)i +(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 4119 +y(1)83 b(Multile)n(v)o(el)19 b(recursi)n(v)o(e)g(bisection)g(\(Def)o +(ault\))581 4245 y(options[3])108 b(Determines)20 b(the)g(algorithm)f +(used)g(for)h(re\002nement.)k(Possible)c(v)n(alues)g(are:)1033 +4371 y(1)83 b(Random)19 b(boundary)e(re\002nement)i(\(Def)o(ault\))1033 +4497 y(3)83 b(Random)19 b(boundary)e(re\002nement)i(that)h(also)h +(minimizes)f(the)g(connecti)n(vity)e(among)h(the)h(sub-)1158 +4607 y(domains)581 4733 y(options[4])108 b(Used)21 b(for)e(deb)n +(ugging)f(purposes.)23 b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o +(ault\).)208 4876 y FC(v)o(olume)115 b FL(Upon)28 b(successful)h +(completion,)g(this)g(v)n(ariable)f(stores)h(the)g(total)g +(communication)d(v)n(olume)h(requires)h(by)h(the)581 +4986 y(partition.)208 5128 y FC(part)220 b FL(This)18 +b(is)h(a)f(v)o(ector)e(of)i(size)g Fs(n)g FL(that)g(upon)e(successful)h +(completion)f(stores)i(the)g(partition)f(v)o(ector)f(of)h(the)h(graph.) +23 b(The)581 5238 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i +(from)e(either)h(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)1908 5649 y(23)p eop +%%Page: 24 24 +24 23 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(mCP)n(ar)r(tGraphRecur)o +(sive)20 b FL(\(int)g(*n,)f(int)i(*ncon,)d(idxtype)h(*xadj,)g(idxtype)g +(*adjnc)o(y)-5 b(,)18 b(idxtype)g(*vwgt,)i(idxtype)e(*adjwgt,)1239 +193 y(int)i(*wgt\003ag,)f(int)i(*num\003ag,)d(int)i(*nparts,)f(int)i +(*options,)d(int)j(*edgecut,)d(idxtype)h(*part\))0 447 +y FB(Description)208 557 y FL(It)g(is)h(used)f(to)h(partition)e(a)h +(graph)f(into)h Ft(k)25 b FL(parts)19 b(such)g(that)g(multiple)g +(balancing)e(constraints)i(are)g(satis\002ed.)25 b(It)20 +b(uses)g(the)f(multi-)208 666 y(constraint)h(multile)n(v)o(el)h +(recursi)n(v)o(e)f(bisection)h(algorithm.)27 b(It)22 +b(pro)o(vides)e(the)h(functionality)f(of)h(the)h Fp(pmetis)f +FL(program)e(when)208 776 y(it)g(is)g(used)g(to)f(compute)f(a)i +(multi-constraint)e(partitioning.)22 b(The)d(objecti)n(v)o(e)e(of)h +(the)h(partitioning)d(is)k(to)e(minimize)g(the)h(edgecut)208 +885 y(\(as)h(described)f(in)h(Section)g(5.3\).)0 1060 +y FB(P)n(arameter)o(s)208 1179 y FC(n)327 b FL(The)20 +b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 1321 +y FC(ncon)202 b FL(The)20 b(number)e(of)i(constraints.)25 +b(This)20 b(should)f(be)h(greater)f(than)h(one)g(and)f(smaller)i(than)e +(15.)208 1436 y FC(xadj,)g(adjncy)581 1546 y FL(The)h(adjacenc)o(y)e +(structure)i(of)g(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.) +208 1662 y FC(vwgt,)f(adjwgt)581 1771 y FL(Information)k(about)h(the)h +(weights)g(of)g(the)h(v)o(ertices)e(and)h(edges)g(as)h(described)e(in)h +(Section)g(5.1.)40 b(Note)25 b(that)h(the)581 1881 y(weight)20 +b(v)o(ector)f(must)h(be)g(supplied)f(and)h(it)h(should)e(be)h(of)g +(size)h Fz(n*ncon)p FL(.)208 2023 y FC(wgt\003ag)113 +b FL(Used)21 b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 2164 y(0)83 b(No)20 b(weights)g(\(adjwgt)f(is)i(NULL\))581 +2290 y(1)83 b(W)-7 b(eights)21 b(on)e(the)h(edges.)208 +2432 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 2541 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +2683 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 2809 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 2951 y FC(nparts)142 +b FL(The)20 b(number)e(of)i(parts)g(to)h(partition)e(the)h(graph.)208 +3092 y FC(options)114 b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o +(gers)e(that)h(is)i(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n +(arious)f(phases)h(of)g(the)g(algorithm.)581 3202 y(If)j +Fs(options[0]=0)e FL(then)h(def)o(ault)g(v)n(alues)g(are)h(used.)34 +b(If)24 b Fs(options[0]=1)p FL(,)f(then)g(the)g(remaining)f(four)h +(elements)g(of)581 3312 y Fs(options)c FL(are)i(interpreted)d(as)j +(follo)n(ws:)581 3453 y(options[1])108 b(Determines)20 +b(the)g(matching)f(type.)24 b(Possible)d(v)n(alues)e(are:)1033 +3579 y(1)83 b(Random)19 b(Matching)g(\(RM\))1033 3705 +y(2)83 b(Hea)n(vy-Edge)18 b(Matching)h(\(HEM\))1033 3830 +y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f(Matching)h(\(SHEM\))h(\(Def)o +(ault\))1033 3956 y(5)83 b(Sorted)19 b(Hea)n(vy-Edge)f(Matching)h +(follo)n(wed)g(by)h(1-norm)e(Balanced-edge)g(\(SHEBM1N\))1033 +4082 y(6)83 b(Sorted)28 b(Hea)n(vy-Edge)f(Matching)h(follo)n(wed)g(by)h +FM(1)p FL(-norm)e(Balanced-edge)g(\(SHEBMIN\))1158 4191 +y(\(Def)o(ault\))1033 4317 y(7)83 b(1-norm)18 b(Balanced-edge)g(follo)n +(wed)h(by)h(Hea)n(vy-Edge)e(Matching)h(\(SBHEM1N\))1033 +4443 y(8)83 b FM(1)p FL(-norm)18 b(Balanced-edge)g(follo)n(wed)h(by)h +(Hea)n(vy-Edge)e(Matching)h(\(SBHEMIN\))1033 4568 y(Experiments)g(has)j +(sho)n(wn)e(that)h(for)g(simple)g(balancing)e(problems,)h(the)h +(schemes)g(that)g(gi)n(v)o(e)f(pri-)1033 4678 y(ority)15 +b(to)h(hea)n(vy)e(edges)h(\()p Fs(e)o(.g)o FL(.,)h(SHEM,)g(SHEBM1N,)f +(SHEBMIN\))g(perform)e(better)m(,)j(and)f(for)f(hard)1033 +4788 y(balancing)i(problems,)f(the)i(schemes)g(that)g(gi)n(v)o(e)g +(priority)e(to)i(balanced)f(edges)h(\()p Fs(e)o(.g)n +FL(.,)h(SBHEM1N,)1033 4897 y(SBHEMIN\))i(perform)e(better)-5 +b(.)581 5023 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used) +g(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 +5149 y(1)83 b(Multi-constraint)18 b(Greedy)h(Graph)g(Gro)n(wing)1033 +5274 y(2)83 b(Random)19 b(\(Def)o(ault\))581 5400 y(options[3])108 +b(Determines)20 b(the)g(algorithm)f(used)g(for)h(re\002nement.)k +(Possible)c(v)n(alues)g(are:)1908 5649 y(24)p eop +%%Page: 25 25 +25 24 bop 1033 83 a FL(1)83 b(Early-Exit)18 b(Boundary)h(FM)h +(re\002nement)f(\(Def)o(ault\))581 209 y(options[4])108 +b(Used)21 b(for)e(deb)n(ugging)f(purposes.)23 b(Al)o(w)o(ays)e(set)g +(it)g(to)f(0)h(\(Def)o(ault\).)208 352 y FC(edgecut)100 +b FL(Upon)19 b(successful)h(completion,)e(this)j(v)n(ariable)e(stores)i +(the)f(number)e(of)i(edges)g(that)g(are)g(cut)h(by)e(the)i(partition.) +208 495 y FC(part)220 b FL(This)18 b(is)h(a)f(v)o(ector)e(of)i(size)g +Fs(n)g FL(that)g(upon)e(successful)h(completion)f(stores)i(the)g +(partition)f(v)o(ector)f(of)h(the)h(graph.)23 b(The)581 +604 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i(from)e(either)h +(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)0 780 y FB(Note)208 890 y FL(This)d(function)f +(should)g(be)i(used)f(to)h(partition)e(a)i(graph)e(into)h(a)h(small)g +(number)e(of)h(partitions.)23 b(If)16 b(a)h(lar)o(ge)e(number)g(of)h +(partitions)208 1000 y(is)24 b(desired,)g(the)g Fz(METIS)p +957 1000 25 4 v 31 w(mCP)m(ar)s(tGr)o(aphKw)o(a)n(y)g +FL(should)f(be)h(used)g(instead,)g(as)h(it)f(produces)f(some)n(what)g +(better)g(partitions)208 1109 y(\(both)c(in)h(terms)g(of)g(quality)f +(and)h(balance\).)1908 5649 y(25)p eop +%%Page: 26 26 +26 25 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(mCP)n(ar)r(tGraphKwa)n +(y)19 b FL(\(int)i(*n,)e(int)h(*ncon,)f(idxtype)g(*xadj,)g(idxtype)g +(*adjnc)o(y)-5 b(,)17 b(idxtype)i(*vwgt,)g(idxtype)g(*adjwgt,)1058 +193 y(int)i(*wgt\003ag,)e(int)h(*num\003ag,)f(int)h(*nparts,)f(\003oat) +h(*ub)o(v)o(ec,)e(int)i(*options,)f(int)h(*edgecut,)1058 +302 y(idxtype)f(*part\))0 560 y FB(Description)208 669 +y FL(It)g(is)h(used)f(to)h(partition)e(a)h(graph)f(into)h +Ft(k)25 b FL(parts)19 b(such)g(that)g(multiple)g(balancing)e +(constraints)i(are)g(satis\002ed.)25 b(It)20 b(uses)g(the)f(multi-)208 +779 y(constraint)i(multile)n(v)o(el)g Ft(k)5 b FL(-w)o(ay)21 +b(partitioning)f(algorithm.)29 b(It)22 b(pro)o(vides)e(the)i +(functionality)e(of)i(the)g Fp(kmetis)f FL(program)f(when)208 +889 y(it)f(is)g(used)g(to)f(compute)f(a)i(multi-constraint)e +(partitioning.)22 b(The)d(objecti)n(v)o(e)e(of)h(the)h(partitioning)d +(is)k(to)e(minimize)g(the)h(edgecut)208 998 y(\(as)h(described)f(in)h +(Section)g(5.3\).)0 1174 y FB(P)n(arameter)o(s)208 1293 +y FC(n)327 b FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.) +208 1436 y FC(ncon)202 b FL(The)20 b(number)e(of)i(constraints.)25 +b(This)20 b(should)f(be)h(greater)f(than)h(one)g(and)f(smaller)i(than)e +(15.)208 1552 y FC(xadj,)g(adjncy)581 1662 y FL(The)h(adjacenc)o(y)e +(structure)i(of)g(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.) +208 1778 y FC(vwgt,)f(adjwgt)581 1887 y FL(Information)k(about)h(the)h +(weights)g(of)g(the)h(v)o(ertices)e(and)h(edges)g(as)h(described)e(in)h +(Section)g(5.1.)40 b(Note)25 b(that)h(the)581 1997 y(weight)20 +b(v)o(ector)f(must)h(be)g(supplied)f(and)h(it)h(should)e(be)h(of)g +(size)h Fz(n*ncon)p FL(.)208 2140 y FC(wgt\003ag)113 +b FL(Used)21 b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 2282 y(0)83 b(No)20 b(weights)g(\(adjwgt)f(is)i(NULL\))581 +2408 y(1)83 b(W)-7 b(eights)21 b(on)e(the)h(edges.)208 +2551 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 2660 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +2803 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 2929 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 3071 y FC(nparts)142 +b FL(The)20 b(number)e(of)i(parts)g(to)h(partition)e(the)h(graph.)208 +3214 y FC(ub)o(v)o(ec)167 b FL(This)24 b(is)h(a)g(v)o(ector)e(of)g +(size)i Fz(ncon)g FL(that)f(speci\002es)g(the)g(load)g(imbalance)f +(tolerances)g(for)g(each)h(one)f(of)h(the)g Fz(ncon)581 +3323 y FL(constraints.)g(Each)c(tolerance)f(should)g(be)h(greater)g +(than)f(1.0)h(\(preferably)d(greater)j(than)f(1.03\).)208 +3466 y FC(options)114 b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o +(gers)e(that)h(is)i(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n +(arious)f(phases)h(of)g(the)g(algorithm.)581 3575 y(If)j +Fs(options[0]=0)e FL(then)h(def)o(ault)g(v)n(alues)g(are)h(used.)34 +b(If)24 b Fs(options[0]=1)p FL(,)f(then)g(the)g(remaining)f(four)h +(elements)g(of)581 3685 y Fs(options)c FL(are)i(interpreted)d(as)j +(follo)n(ws:)581 3827 y(options[1])108 b(Determines)20 +b(the)g(matching)f(type.)24 b(Possible)d(v)n(alues)e(are:)1033 +3953 y(1)83 b(Random)19 b(Matching)g(\(RM\))1033 4079 +y(2)83 b(Hea)n(vy-Edge)18 b(Matching)h(\(HEM\))1033 4205 +y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f(Matching)h(\(SHEM\))h(\(Def)o +(ault\))1033 4331 y(5)83 b(Sorted)19 b(Hea)n(vy-Edge)f(Matching)h +(follo)n(wed)g(by)h(1-norm)e(Balanced-edge)g(\(SHEBM1N\))1033 +4458 y(6)83 b(Sorted)28 b(Hea)n(vy-Edge)f(Matching)h(follo)n(wed)g(by)h +FM(1)p FL(-norm)e(Balanced-edge)g(\(SHEBMIN\))1158 4567 +y(\(Def)o(ault\))1033 4693 y(7)83 b(1-norm)18 b(Balanced-edge)g(follo)n +(wed)h(by)h(Hea)n(vy-Edge)e(Matching)h(\(SBHEM1N\))1033 +4819 y(8)83 b FM(1)p FL(-norm)18 b(Balanced-edge)g(follo)n(wed)h(by)h +(Hea)n(vy-Edge)e(Matching)h(\(SBHEMIN\))1033 4945 y(Experiments)g(has)j +(sho)n(wn)e(that)h(for)g(simple)g(balancing)e(problems,)h(the)h +(schemes)g(that)g(gi)n(v)o(e)f(pri-)1033 5055 y(ority)15 +b(to)h(hea)n(vy)e(edges)h(\()p Fs(e)o(.g)o FL(.,)h(SHEM,)g(SHEBM1N,)f +(SHEBMIN\))g(perform)e(better)m(,)j(and)f(for)f(hard)1033 +5164 y(balancing)i(problems,)f(the)i(schemes)g(that)g(gi)n(v)o(e)g +(priority)e(to)i(balanced)f(edges)h(\()p Fs(e)o(.g)n +FL(.,)h(SBHEM1N,)1033 5274 y(SBHEMIN\))i(perform)e(better)-5 +b(.)581 5400 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used) +g(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1908 +5649 y(26)p eop +%%Page: 27 27 +27 26 bop 1033 83 a FL(1)83 b(Multile)n(v)o(el)19 b(recursi)n(v)o(e)g +(bisection)1033 209 y(2)83 b(Relax)o(ed)19 b(Multile)n(v)o(el)h +(recursi)n(v)o(e)e(bisection)i(\(Def)o(ault\))581 335 +y(options[3])108 b(Determines)20 b(the)g(algorithm)f(used)g(for)h +(re\002nement.)k(Possible)c(v)n(alues)g(are:)1033 462 +y(1)83 b(Random)19 b(boundary)e(re\002nement)i(\(Def)o(ault\))581 +588 y(options[4])108 b(Used)21 b(for)e(deb)n(ugging)f(purposes.)23 +b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o(ault\).)208 +731 y FC(edgecut)100 b FL(Upon)19 b(successful)h(completion,)e(this)j +(v)n(ariable)e(stores)i(the)f(number)e(of)i(edges)g(that)g(are)g(cut)h +(by)e(the)i(partition.)208 873 y FC(part)220 b FL(This)18 +b(is)h(a)f(v)o(ector)e(of)i(size)g Fs(n)g FL(that)g(upon)e(successful)h +(completion)f(stores)i(the)g(partition)f(v)o(ector)f(of)h(the)h(graph.) +23 b(The)581 983 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i +(from)e(either)h(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)0 1159 y FB(Note)208 1269 y FL(This)24 +b(function)f(should)g(be)i(used)f(to)h(partition)e(a)i(graph)e(into)h +(a)h(lar)o(ge)f(number)e(of)j(partitions)e(\(greater)g(than)h(8\).)38 +b(If)24 b(a)h(small)208 1378 y(number)f(of)i(partitions)g(is)h +(desired,)g(the)g Fz(METIS)p 1683 1378 25 4 v 30 w(mCP)m(ar)s(tGr)o +(aphRecursiv)n(e)g FL(should)e(be)h(used)h(instead,)g(as)g(it)g +(produces)208 1488 y(some)n(what)19 b(better)h(partitions.)1908 +5649 y(27)p eop +%%Page: 28 28 +28 27 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(WP)n(ar)r(tGraphRecur)o +(sive)20 b FL(\(int)h(*n,)e(idxtype)g(*xadj,)g(idxtype)g(*adjnc)o(y)-5 +b(,)17 b(idxtype)i(*vwgt,)g(idxtype)g(*adjwgt,)g(int)i(*wgt\003ag,)1183 +193 y(int)g(*num\003ag,)d(int)i(*nparts,)f(\003oat)i(*tpwgts,)e(int)i +(*options,)d(int)j(*edgecut,)d(idxtype)h(*part\))0 452 +y FB(Description)208 561 y FL(It)29 b(is)h(used)f(to)g(partition)f(a)i +(graph)e(into)h Ft(k)34 b FL(parts)29 b(using)g(multile)n(v)o(el)f +(recursi)n(v)o(e)g(bisection.)51 b(The)29 b(underlying)d(algorithm)i +(is)208 671 y(similar)g(to)h(the)g(one)f(used)g(by)g +Fz(METIS)p 1392 671 V 31 w(P)m(ar)s(tGr)o(aphRecursiv)n(e)p +FL(,)i(b)n(ut)e(it)i(can)e(be)h(used)f(to)h(compute)e(a)i(partitioning) +d(with)208 780 y(prescribed)19 b(partition)h(weights.)27 +b(F)o(or)20 b(e)o(xample,)g(it)h(can)g(be)g(used)g(to)g(compute)e(a)j +(3-w)o(ay)e(partition)g(such)g(that)h(partition)f(1)h(has)208 +890 y(50\045)h(of)g(the)h(weight,)f(partition)g(2)h(has)f(20\045)h(of)f +(the)h(weight,)f(and)g(partition)g(3)h(has)f(30\045)h(of)f(the)h +(weight.)31 b(The)23 b(objecti)n(v)o(e)e(of)208 1000 +y(the)f(partitioning)e(is)j(to)f(minimize)g(the)g(edgecut)f(\(as)i +(described)d(in)j(Section)f(5.3\).)0 1176 y FB(P)n(arameter)o(s)208 +1295 y FC(n)327 b FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h +(graph.)208 1412 y FC(xadj,)e(adjncy)581 1521 y FL(The)h(adjacenc)o(y)e +(structure)i(of)g(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.) +208 1638 y FC(vwgt,)f(adjwgt)581 1748 y FL(Information)f(about)h(the)h +(weights)g(of)g(the)g(v)o(ertices)g(and)f(edges)h(as)h(described)e(in)h +(Section)g(5.1.)208 1890 y FC(wgt\003ag)113 b FL(Used)21 +b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 2033 y(0)83 b(No)20 b(weights)g(\(vwgts)g(and)f(adjwgt)h +(are)g(NULL\))581 2159 y(1)83 b(W)-7 b(eights)21 b(on)e(the)h(edges)g +(only)g(\(vwgts)f(=)i(NULL\))581 2286 y(2)83 b(W)-7 b(eights)21 +b(on)e(the)h(v)o(ertices)g(only)g(\(adjwgt)f(=)i(NULL\))581 +2412 y(3)83 b(W)-7 b(eights)21 b(both)e(on)h(v)o(ertices)f(and)h +(edges.)208 2555 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g +(which)g(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f +(structure)g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 +2664 y FL(can)20 b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:) +581 2807 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g +(starts)h(from)e(0)581 2933 y(1)83 b(F)o(ortran-style)18 +b(numbering)g(is)j(assumed)e(that)i(starts)g(from)e(1)208 +3076 y FC(nparts)142 b FL(The)20 b(number)e(of)i(parts)g(to)h +(partition)e(the)h(graph.)208 3219 y FC(tpwgts)137 b +FL(This)17 b(is)g(an)f(array)f(containing)g Fs(nparts)h +FL(\003oating)f(point)h(numbers.)22 b(F)o(or)16 b(partition)e +Ft(i)9 b FL(,)17 b Fs(tpwgts[)o Ft(i)9 b Fs(])17 b FL(stores)g(the)f +(fraction)581 3328 y(of)g(the)g(total)g(weight)g(that)g(should)f(be)h +(assigned)f(to)i(it.)24 b(F)o(or)15 b(e)o(xample,)h(for)f(a)i(4-w)o(ay) +e(partition)g(the)h(v)o(ector)f Fs(tpwgts[])581 3438 +y(=)j FM(f)p Fs(0.2)e(0.2)g(0.4)g(0.2)p FM(g)g FL(will)i(result)f(in)g +(partitions)f(0,)h(1,)h(and)e(3)h(ha)n(ving)f(20\045)g(of)h(the)g +(weight)g(and)f(partition)g(2)h(ha)n(ving)581 3548 y(40\045)j(of)g(the) +g(weight.)25 b(Note)20 b(that)g(the)g(numbers)f(in)h +Fs(tpwgts)h FL(should)e(add)h(up)g(to)g(1.0.)208 3690 +y FC(options)114 b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o(gers) +e(that)h(is)i(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f +(phases)h(of)g(the)g(algorithm.)581 3800 y(If)j Fs(options[0]=0)e +FL(then)h(def)o(ault)g(v)n(alues)g(are)h(used.)34 b(If)24 +b Fs(options[0]=1)p FL(,)f(then)g(the)g(remaining)f(four)h(elements)g +(of)581 3910 y Fs(options)c FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +4052 y(options[1])108 b(Determines)20 b(the)g(matching)f(type.)24 +b(Possible)d(v)n(alues)e(are:)1033 4179 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 4305 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 4431 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 4557 y(Experiments)f(has)h +(sho)n(wn)g(that)g(both)f(HEM)h(and)g(SHEM)g(perform)f(quite)g(well.) +581 4683 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used)g +(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 +4810 y(1)83 b(Re)o(gion)19 b(Gro)n(wing)g(\(Def)o(ault\))581 +4936 y(options[3])108 b(Determines)20 b(the)g(algorithm)f(used)g(for)h +(re\002nement.)k(Possible)c(v)n(alues)g(are:)1033 5062 +y(1)83 b(Early-Exit)18 b(Boundary)h(FM)h(re\002nement)f(\(Def)o(ault\)) +581 5188 y(options[4])108 b(Used)21 b(for)e(deb)n(ugging)f(purposes.)23 +b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o(ault\).)208 +5331 y FC(edgecut)100 b FL(Upon)19 b(successful)h(completion,)e(this)j +(v)n(ariable)e(stores)i(the)f(number)e(of)i(edges)g(that)g(are)g(cut)h +(by)e(the)i(partition.)1908 5649 y(28)p eop +%%Page: 29 29 +29 28 bop 208 83 a FC(part)220 b FL(This)18 b(is)h(a)f(v)o(ector)e(of)i +(size)g Fs(n)g FL(that)g(upon)e(successful)h(completion)f(stores)i(the) +g(partition)f(v)o(ector)f(of)h(the)h(graph.)23 b(The)581 +193 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i(from)e(either)h +(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)0 369 y FB(Note)208 478 y FL(This)d(function)f +(should)h(be)g(used)g(to)h(partition)f(a)g(graph)g(into)g(a)h(small)g +(number)e(of)h(partitions)g(\(less)h(than)f(8\).)23 b(If)17 +b(a)g(lar)o(ge)e(number)208 588 y(of)k(partitions)h(is)h(desired,)e +(the)h Fz(METIS)p 1369 588 25 4 v 31 w(WP)m(ar)s(tGr)o(aphKw)o(a)n(y)h +FL(should)e(be)h(used)g(instead,)g(as)g(it)h(is)h(signi\002cantly)d(f)o +(aster)-5 b(.)1908 5649 y(29)p eop +%%Page: 30 30 +30 29 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(WP)n(ar)r(tGraphKwa)n(y) +20 b FL(\(int)g(*n,)g(idxtype)e(*xadj,)h(idxtype)g(*adjnc)o(y)-5 +b(,)18 b(idxtype)h(*vwgt,)g(idxtype)g(*adjwgt,)g(int)h(*wgt\003ag,)1003 +193 y(int)g(*num\003ag,)f(int)h(*nparts,)f(\003oat)h(*tpwgts,)g(int)g +(*options,)f(int)h(*edgecut,)e(idxtype)h(*part\))0 444 +y FB(Description)208 554 y FL(It)29 b(is)h(used)f(to)g(partition)f(a)i +(graph)e(into)h Ft(k)34 b FL(parts)29 b(using)g(multile)n(v)o(el)f +(recursi)n(v)o(e)g(bisection.)51 b(The)29 b(underlying)d(algorithm)i +(is)208 663 y(similar)16 b(to)h(the)f(one)g(used)g(by)h +Fz(METIS)p 1320 663 V 30 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)p +FL(,)g(b)n(ut)g(it)g(can)f(be)g(used)h(to)f(compute)f(a)i(partitioning) +e(with)h(prescribed)208 773 y(partition)24 b(weights.)42 +b(F)o(or)25 b(e)o(xample,)h(it)g(can)g(be)g(used)f(to)h(compute)e(a)j +(3-w)o(ay)e(partition)f(such)i(that)g(partition)e(1)i(has)g(50\045)g +(of)208 883 y(the)j(weight,)h(partition)e(2)h(has)g(20\045)g(of)g(the)f +(weight,)j(and)d(partition)g(3)h(has)g(30\045)g(of)g(the)g(weight.)51 +b(The)28 b(objecti)n(v)o(e)g(of)h(the)208 992 y(partitioning)18 +b(is)j(to)f(minimize)g(the)g(edgecut)f(\(as)h(described)f(in)i(Section) +e(5.3\).)0 1167 y FB(P)n(arameter)o(s)208 1284 y FC(n)327 +b FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 +1399 y FC(xadj,)e(adjncy)581 1509 y FL(The)h(adjacenc)o(y)e(structure)i +(of)g(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.)208 +1624 y FC(vwgt,)f(adjwgt)581 1734 y FL(Information)f(about)h(the)h +(weights)g(of)g(the)g(v)o(ertices)g(and)f(edges)h(as)h(described)e(in)h +(Section)g(5.1.)208 1875 y FC(wgt\003ag)113 b FL(Used)21 +b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 2016 y(0)83 b(No)20 b(weights)g(\(vwgts)g(and)f(adjwgt)h +(are)g(NULL\))581 2141 y(1)83 b(W)-7 b(eights)21 b(on)e(the)h(edges)g +(only)g(\(vwgts)f(=)i(NULL\))581 2267 y(2)83 b(W)-7 b(eights)21 +b(on)e(the)h(v)o(ertices)g(only)g(\(adjwgt)f(=)i(NULL\))581 +2392 y(3)83 b(W)-7 b(eights)21 b(both)e(on)h(v)o(ertices)f(and)h +(edges.)208 2533 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g +(which)g(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f +(structure)g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 +2643 y FL(can)20 b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:) +581 2784 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g +(starts)h(from)e(0)581 2909 y(1)83 b(F)o(ortran-style)18 +b(numbering)g(is)j(assumed)e(that)i(starts)g(from)e(1)208 +3051 y FC(nparts)142 b FL(The)20 b(number)e(of)i(parts)g(to)h +(partition)e(the)h(graph.)208 3192 y FC(tpwgts)137 b +FL(This)17 b(is)g(an)f(array)f(containing)g Fs(nparts)h +FL(\003oating)f(point)h(numbers.)22 b(F)o(or)16 b(partition)e +Ft(i)9 b FL(,)17 b Fs(tpwgts[)o Ft(i)9 b Fs(])17 b FL(stores)g(the)f +(fraction)581 3301 y(of)g(the)g(total)g(weight)g(that)g(should)f(be)h +(assigned)f(to)i(it.)24 b(F)o(or)15 b(e)o(xample,)h(for)f(a)i(4-w)o(ay) +e(partition)g(the)h(v)o(ector)f Fs(tpwgts[])581 3411 +y(=)j FM(f)p Fs(0.2)e(0.2)g(0.4)g(0.2)p FM(g)g FL(will)i(result)f(in)g +(partitions)f(0,)h(1,)h(and)e(3)h(ha)n(ving)f(20\045)g(of)h(the)g +(weight)g(and)f(partition)g(2)h(ha)n(ving)581 3520 y(40\045)j(of)g(the) +g(weight.)25 b(Note)20 b(that)g(the)g(numbers)f(in)h +Fs(tpwgts)h FL(should)e(add)h(up)g(to)g(1.0.)208 3662 +y FC(options)114 b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o(gers) +e(that)h(is)i(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f +(phases)h(of)g(the)g(algorithm.)581 3771 y(If)j Fs(options[0]=0)e +FL(then)h(def)o(ault)g(v)n(alues)g(are)h(used.)34 b(If)24 +b Fs(options[0]=1)p FL(,)f(then)g(the)g(remaining)f(four)h(elements)g +(of)581 3881 y Fs(options)c FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +4022 y(options[1])108 b(Determines)20 b(the)g(matching)f(type.)24 +b(Possible)d(v)n(alues)e(are:)1033 4147 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 4273 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 4398 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 4523 y(Experiments)f(has)h +(sho)n(wn)g(that)g(both)f(HEM)h(and)g(SHEM)g(perform)f(quite)g(well.) +581 4649 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used)g +(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 +4774 y(1)83 b(Multile)n(v)o(el)19 b(recursi)n(v)o(e)g(bisection)g +(\(Def)o(ault\))581 4900 y(options[3])108 b(Determines)20 +b(the)g(algorithm)f(used)g(for)h(re\002nement.)k(Possible)c(v)n(alues)g +(are:)1033 5025 y(1)83 b(Random)19 b(boundary)e(re\002nement)1033 +5150 y(2)83 b(Greedy)19 b(boundary)e(re\002nement)1033 +5276 y(3)83 b(Random)19 b(boundary)e(re\002nement)i(that)h(also)h +(minimizes)f(the)g(connecti)n(vity)e(among)h(the)h(sub-)1158 +5385 y(domains)f(\(Def)o(ault\))1908 5649 y(30)p eop +%%Page: 31 31 +31 30 bop 581 83 a FL(options[4])108 b(Used)21 b(for)e(deb)n(ugging)f +(purposes.)23 b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o(ault\).)208 +226 y FC(edgecut)100 b FL(Upon)19 b(successful)h(completion,)e(this)j +(v)n(ariable)e(stores)i(the)f(number)e(of)i(edges)g(that)g(are)g(cut)h +(by)e(the)i(partition.)208 369 y FC(part)220 b FL(This)18 +b(is)h(a)f(v)o(ector)e(of)i(size)g Fs(n)g FL(that)g(upon)e(successful)h +(completion)f(stores)i(the)g(partition)f(v)o(ector)f(of)h(the)h(graph.) +23 b(The)581 478 y(numbering)18 b(of)i(this)g(v)o(ector)f(starts)i +(from)e(either)h(0)g(or)g(1,)g(depending)e(on)i(the)g(v)n(alue)g(of)f +Fs(num\003a)o(g)p FL(.)0 654 y FB(Note)208 764 y FL(This)24 +b(function)f(should)g(be)i(used)f(to)h(partition)e(a)i(graph)e(into)h +(a)h(lar)o(ge)f(number)e(of)j(partitions)e(\(greater)g(than)h(8\).)38 +b(If)24 b(a)h(small)208 873 y(number)j(of)i(partitions)f(is)i(desired,) +h(the)e Fz(METIS)p 1706 873 25 4 v 31 w(WP)m(ar)s(tGr)o(aphRecursiv)n +(e)g FL(should)f(be)h(used)g(instead,)i(as)f(it)g(produces)208 +983 y(some)n(what)19 b(better)h(partitions.)1908 5649 +y(31)p eop +%%Page: 32 32 +32 31 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(WP)n(ar)r(tGraphVKwa)n +(y)20 b FL(\(int)h(*n,)e(idxtype)g(*xadj,)g(idxtype)g(*adjnc)o(y)-5 +b(,)17 b(idxtype)i(*vwgt,)g(idxtype)g(*vsize,)h(int)g(*wgt\003ag,)1058 +193 y(int)h(*num\003ag,)d(int)i(*nparts,)f(\003oat)i(*tpwgts,)e(int)i +(*options,)d(int)j(*v)n(olume,)d(idxtype)h(*part\))0 +450 y FB(Description)208 560 y FL(It)29 b(is)h(used)f(to)g(partition)f +(a)i(graph)e(into)h Ft(k)34 b FL(parts)29 b(using)g(multile)n(v)o(el)f +(recursi)n(v)o(e)g(bisection.)51 b(The)29 b(underlying)d(algorithm)i +(is)208 669 y(similar)16 b(to)h(the)f(one)g(used)g(by)h +Fz(METIS)p 1320 669 V 30 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)p +FL(,)g(b)n(ut)g(it)g(can)f(be)g(used)h(to)f(compute)f(a)i(partitioning) +e(with)h(prescribed)208 779 y(partition)24 b(weights.)42 +b(F)o(or)25 b(e)o(xample,)h(it)g(can)g(be)g(used)f(to)h(compute)e(a)j +(3-w)o(ay)e(partition)f(such)i(that)g(partition)e(1)i(has)g(50\045)g +(of)208 888 y(the)j(weight,)h(partition)e(2)h(has)g(20\045)g(of)g(the)f +(weight,)j(and)d(partition)g(3)h(has)g(30\045)g(of)g(the)g(weight.)51 +b(The)28 b(objecti)n(v)o(e)g(of)h(the)208 998 y(partitioning)18 +b(is)j(to)f(minimize)g(the)g(total)g(communication)e(v)n(olume)h(\(as)h +(described)f(in)h(Section)g(5.3\).)0 1174 y FB(P)n(arameter)o(s)208 +1293 y FC(n)327 b FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h +(graph.)208 1409 y FC(xadj,)e(adjncy)581 1519 y FL(The)h(adjacenc)o(y)e +(structure)i(of)g(the)g(graph)f(as)i(described)d(in)j(Sections)f(5.1)f +(and)h(5.3.)208 1635 y FC(vwgt,)f(vsize)581 1745 y FL(Information)h +(about)j(the)g(weights)g(of)g(the)g(v)o(ertices)f(related)h(to)g(the)g +(computation)e(and)i(communication)d(as)k(de-)581 1854 +y(scribed)c(in)g(Section)g(5.1.)208 1997 y FC(wgt\003ag)113 +b FL(Used)21 b(to)f(indicate)f(if)i(the)f(graph)f(is)i(weighted.)j +Fs(wgt\003a)o(g)19 b FL(can)h(tak)o(e)h(the)f(follo)n(wing)e(v)n +(alues:)581 2139 y(0)83 b(No)20 b(weights)g(\(vwgts)g(and)f(vsize)i +(are)f(NULL\))581 2265 y(1)83 b(Communication)18 b(weights)i(only)f +(\(vwgts)h(=)g(NULL\))581 2391 y(2)83 b(Computation)18 +b(weights)i(only)f(\(vsize)h(=)h(NULL\))581 2517 y(3)83 +b(Both)20 b(communication)d(and)j(computation)e(weights.)208 +2660 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 2769 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +2912 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 3038 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 3180 y FC(nparts)142 +b FL(The)20 b(number)e(of)i(parts)g(to)h(partition)e(the)h(graph.)208 +3322 y FC(tpwgts)137 b FL(This)17 b(is)g(an)f(array)f(containing)g +Fs(nparts)h FL(\003oating)f(point)h(numbers.)22 b(F)o(or)16 +b(partition)e Ft(i)9 b FL(,)17 b Fs(tpwgts[)o Ft(i)9 +b Fs(])17 b FL(stores)g(the)f(fraction)581 3432 y(of)g(the)g(total)g +(weight)g(that)g(should)f(be)h(assigned)f(to)i(it.)24 +b(F)o(or)15 b(e)o(xample,)h(for)f(a)i(4-w)o(ay)e(partition)g(the)h(v)o +(ector)f Fs(tpwgts[])581 3542 y(=)j FM(f)p Fs(0.2)e(0.2)g(0.4)g(0.2)p +FM(g)g FL(will)i(result)f(in)g(partitions)f(0,)h(1,)h(and)e(3)h(ha)n +(ving)f(20\045)g(of)h(the)g(weight)g(and)f(partition)g(2)h(ha)n(ving) +581 3651 y(40\045)j(of)g(the)g(weight.)25 b(Note)20 b(that)g(the)g +(numbers)f(in)h Fs(tpwgts)h FL(should)e(add)h(up)g(to)g(1.0.)208 +3794 y FC(options)114 b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o +(gers)e(that)h(is)i(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n +(arious)f(phases)h(of)g(the)g(algorithm.)581 3903 y(If)j +Fs(options[0]=0)e FL(then)h(def)o(ault)g(v)n(alues)g(are)h(used.)34 +b(If)24 b Fs(options[0]=1)p FL(,)f(then)g(the)g(remaining)f(four)h +(elements)g(of)581 4013 y Fs(options)c FL(are)i(interpreted)d(as)j +(follo)n(ws:)581 4155 y(options[1])108 b(Determines)20 +b(the)g(matching)f(type.)24 b(Possible)d(v)n(alues)e(are:)1033 +4281 y(1)83 b(Random)19 b(Matching)g(\(RM\))1033 4407 +y(2)83 b(Hea)n(vy-Edge)18 b(Matching)h(\(HEM\))1033 4533 +y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f(Matching)h(\(SHEM\))h(\(Def)o +(ault\))1033 4659 y(Experiments)f(has)h(sho)n(wn)g(that)g(both)f(HEM)h +(and)g(SHEM)g(perform)f(quite)g(well.)581 4785 y(options[2])108 +b(Determines)20 b(the)g(algorithm)f(used)g(during)g(initial)i +(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 4911 +y(1)83 b(Multile)n(v)o(el)19 b(recursi)n(v)o(e)g(bisection)g(\(Def)o +(ault\))581 5037 y(options[3])108 b(Determines)20 b(the)g(algorithm)f +(used)g(for)h(re\002nement.)k(Possible)c(v)n(alues)g(are:)1033 +5163 y(1)83 b(Random)19 b(boundary)e(re\002nement)i(\(Def)o(ault\))1033 +5289 y(3)83 b(Random)19 b(boundary)e(re\002nement)i(that)h(also)h +(minimizes)f(the)g(connecti)n(vity)e(among)h(the)h(sub-)1158 +5399 y(domains)1908 5649 y(32)p eop +%%Page: 33 33 +33 32 bop 581 83 a FL(options[4])108 b(Used)21 b(for)e(deb)n(ugging)f +(purposes.)23 b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o(ault\).)208 +226 y FC(v)o(olume)115 b FL(Upon)27 b(successful)h(completion,)g(this)h +(v)n(ariable)e(stores)h(the)g(total)g(communication)e(v)n(olume)h +(required)f(by)i(the)581 335 y(partition.)208 478 y FC(part)220 +b FL(This)18 b(is)h(a)f(v)o(ector)e(of)i(size)g Fs(n)g +FL(that)g(upon)e(successful)h(completion)f(stores)i(the)g(partition)f +(v)o(ector)f(of)h(the)h(graph.)23 b(The)581 588 y(numbering)18 +b(of)i(this)g(v)o(ector)f(starts)i(from)e(either)h(0)g(or)g(1,)g +(depending)e(on)i(the)g(v)n(alue)g(of)f Fs(num\003a)o(g)p +FL(.)1908 5649 y(33)p eop +%%Page: 34 34 +34 33 bop 0 83 a Fr(5.5)100 b(Mesh)28 b(P)m(ar)r(titioning)g(Routines)0 +242 y FB(METIS)p 258 242 25 4 v 31 w(P)n(ar)r(tMeshNodal)20 +b FL(\(int)g(*ne,)f(int)i(*nn,)e(idxtype)g(*elmnts,)g(int)h(*etype,)f +(int)i(*num\003ag,)d(int)i(*nparts,)f(int)i(*edgecut,)908 +352 y(idxtype)e(*epart,)g(idxtype)f(*npart\))0 611 y +FB(Description)208 721 y FL(This)f(function)f(is)j(used)e(to)h +(partition)e(a)i(mesh)f(into)h Ft(k)23 b FL(equal-size)16 +b(parts.)24 b(It)18 b(pro)o(vides)e(the)h(functionality)f(of)h(the)h +Fp(partnmesh)208 830 y FL(program.)0 1006 y FB(P)n(arameter)o(s)208 +1126 y FC(ne)290 b FL(The)20 b(number)e(of)i(elements)g(in)h(the)f +(mesh.)208 1269 y FC(nn)281 b FL(The)20 b(number)e(of)i(nodes)g(in)g +(the)g(mesh.)208 1411 y FC(elmnts)138 b FL(The)20 b(element)g(node)f +(array)g(storing)g(the)i(mesh)f(as)h(described)d(in)j(Section)f(5.2.) +208 1554 y FC(etype)183 b FL(Indicates)20 b(the)g(type)g(of)f(the)i +(elements)f(in)g(the)g(mesh.)25 b Fs(etype)20 b FL(can)g(tak)o(e)g(the) +g(follo)n(wing)f(v)n(alues:)581 1697 y(1)83 b(The)20 +b(elements)f(are)i(triangles.)581 1823 y(2)83 b(The)20 +b(elements)f(are)i(tetrahedra.)581 1949 y(3)83 b(The)20 +b(elements)f(are)i(he)o(xahedra)c(\(bricks\).)581 2076 +y(4)83 b(The)20 b(elements)f(are)i(quadrilaterals.)208 +2218 y FC(num\003ag)82 b FL(Used)22 b(to)h(indicate)e(which)h +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(element)f(node)g(array)-5 +b(.)30 b Fs(num\003a)o(g)20 b FL(can)i(tak)o(e)h(the)581 +2328 y(follo)n(wing)c(tw)o(o)h(v)n(alues:)581 2471 y(0)83 +b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h(from)e(0)581 +2597 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j(assumed)e(that)i +(starts)g(from)e(1)208 2740 y FC(nparts)142 b FL(The)20 +b(number)e(of)i(parts)g(to)h(partition)e(the)h(mesh.)208 +2883 y FC(edgecut)100 b FL(Upon)20 b(successful)h(completion,)f(this)i +(v)n(ariable)e(stores)h(the)g(number)f(of)h(edges)g(that)g(are)g(cut)g +(by)g(the)g(partition)f(in)581 2992 y(the)g(nodal)g(graph.)208 +3135 y FC(epart)183 b FL(This)18 b(is)h(a)g(v)o(ector)d(of)i(size)h +Fs(ne)e FL(that)h(upon)f(successful)h(completion)e(stores)i(the)g +(partition)f(v)o(ector)g(for)g(the)h(elements)581 3245 +y(of)31 b(the)f(mesh.)57 b(The)30 b(numbering)e(of)j(this)g(v)o(ector)e +(starts)j(from)e(either)g(0)h(or)f(1,)k(depending)28 +b(on)i(the)h(v)n(alue)f(of)581 3354 y Fs(num\003a)o(g)p +FL(.)208 3497 y FC(npart)174 b FL(This)19 b(is)g(a)g(v)o(ector)e(of)h +(size)i Fs(nn)e FL(that)g(upon)f(successful)h(completion)f(stores)i +(the)f(partition)g(v)o(ector)f(for)h(the)g(nodes)g(of)581 +3606 y(the)i(mesh.)25 b(The)19 b(numbering)f(of)h(this)i(v)o(ector)d +(starts)j(from)e(either)g(0)h(or)g(1,)g(depending)d(on)j(the)g(v)n +(alue)f(of)h Fs(num\003a)o(g)p FL(.)0 3782 y FB(Note)208 +3892 y FL(This)g(function)f(con)m(v)o(erts)g(the)h(mesh)h(into)f(a)h +(nodal)e(graph)g(and)h(then)g(uses)i Fz(METIS)p 2642 +3892 V 30 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)f FL(to)f(compute)f(a)i +(parti-)208 4002 y(tioning)f(of)h(the)g(nodes.)28 b(This)22 +b(partitioning)d(of)i(nodes)g(is)h(then)f(used)g(to)h(compute)e(a)h +(partitioning)f(for)g(the)i(elements.)28 b(This)22 b(is)208 +4111 y(done)d(by)i(assigning)f(each)h(element)f(to)h(the)g(partition)f +(in)h(which)g(the)g(majority)f(of)g(its)i(nodes)e(belong)g(to)h +(\(subject)f(to)h(balance)208 4221 y(constraints\).)1908 +5649 y(34)p eop +%%Page: 35 35 +35 34 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(P)n(ar)r(tMeshDual)20 +b FL(\(int)g(*ne,)g(int)g(*nn,)f(idxtype)g(*elmnts,)g(int)i(*etype,)e +(int)h(*num\003ag,)e(int)j(*nparts,)e(int)h(*edgecut,)857 +193 y(idxtype)f(*epart,)g(idxtype)g(*npart\))0 452 y +FB(Description)208 561 y FL(This)e(function)f(is)j(used)e(to)h +(partition)e(a)i(mesh)f(into)h Ft(k)23 b FL(equal-size)16 +b(parts.)24 b(It)18 b(pro)o(vides)e(the)h(functionality)f(of)h(the)h +Fp(partdmesh)208 671 y FL(program.)0 847 y FB(P)n(arameter)o(s)208 +966 y FC(ne)290 b FL(The)20 b(number)e(of)i(elements)g(in)h(the)f +(mesh.)208 1109 y FC(nn)281 b FL(The)20 b(number)e(of)i(nodes)g(in)g +(the)g(mesh.)208 1252 y FC(elmnts)138 b FL(The)20 b(element)g(node)f +(array)g(storing)g(the)i(mesh)f(as)h(described)d(in)j(Section)f(5.2.) +208 1395 y FC(etype)183 b FL(Indicates)20 b(the)g(type)g(of)f(the)i +(elements)f(in)g(the)g(mesh.)25 b Fs(etype)20 b FL(can)g(tak)o(e)g(the) +g(follo)n(wing)f(v)n(alues:)581 1538 y(1)83 b(The)20 +b(elements)f(are)i(triangles.)581 1664 y(2)83 b(The)20 +b(elements)f(are)i(tetrahedra.)581 1790 y(3)83 b(The)20 +b(elements)f(are)i(he)o(xahedra)c(\(bricks\).)581 1916 +y(4)83 b(The)20 b(elements)f(are)i(quadrilaterals.)208 +2059 y FC(num\003ag)82 b FL(Used)22 b(to)h(indicate)e(which)h +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(element)f(node)g(array)-5 +b(.)30 b Fs(num\003a)o(g)20 b FL(can)i(tak)o(e)h(the)581 +2169 y(follo)n(wing)c(tw)o(o)h(v)n(alues:)581 2311 y(0)83 +b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h(from)e(0)581 +2438 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j(assumed)e(that)i +(starts)g(from)e(1)208 2580 y FC(nparts)142 b FL(The)20 +b(number)e(of)i(parts)g(to)h(partition)e(the)h(mesh.)208 +2723 y FC(edgecut)100 b FL(Upon)20 b(successful)h(completion,)f(this)i +(v)n(ariable)e(stores)h(the)g(number)f(of)h(edges)g(that)g(are)g(cut)g +(by)g(the)g(partition)f(in)581 2833 y(the)g(dual)g(graph.)208 +2976 y FC(epart)183 b FL(This)18 b(is)h(a)g(v)o(ector)d(of)i(size)h +Fs(ne)e FL(that)h(upon)f(successful)h(completion)e(stores)i(the)g +(partition)f(v)o(ector)g(for)g(the)h(elements)581 3085 +y(of)31 b(the)f(mesh.)57 b(The)30 b(numbering)e(of)j(this)g(v)o(ector)e +(starts)j(from)e(either)g(0)h(or)f(1,)k(depending)28 +b(on)i(the)h(v)n(alue)f(of)581 3195 y Fs(num\003a)o(g)p +FL(.)208 3337 y FC(npart)174 b FL(This)19 b(is)g(a)g(v)o(ector)e(of)h +(size)i Fs(nn)e FL(that)g(upon)f(successful)h(completion)f(stores)i +(the)f(partition)g(v)o(ector)f(for)h(the)g(nodes)g(of)581 +3447 y(the)i(mesh.)25 b(The)19 b(numbering)f(of)h(this)i(v)o(ector)d +(starts)j(from)e(either)g(0)h(or)g(1,)g(depending)d(on)j(the)g(v)n +(alue)f(of)h Fs(num\003a)o(g)p FL(.)0 3623 y FB(Note)208 +3733 y FL(This)j(function)e(con)m(v)o(erts)h(the)h(mesh)g(into)f(a)i +(dual)f(graph)e(and)i(then)g(uses)g Fz(METIS)p 2631 3733 +V 31 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)g FL(to)g(compute)f(a)h(parti-)208 +3842 y(tioning)c(of)h(the)g(elements.)25 b(This)20 b(partitioning)f(of) +h(elements)g(is)h(then)f(used)g(to)g(compute)f(a)i(partitioning)d(for)i +(the)g(nodes.)k(This)208 3952 y(is)d(done)f(by)g(assigning)g(each)g +(node)g(to)h(the)g(partition)e(in)i(which)f(the)h(majority)f(of)g(its)i +(incident)e(elements)g(belong)f(to)i(\(subject)208 4061 +y(to)f(balance)f(constraints\).)1908 5649 y(35)p eop +%%Page: 36 36 +36 35 bop 0 83 a Fr(5.6)100 b(Spar)o(se)29 b(Matrix)f(Reor)n(dering)f +(Routines)0 242 y FB(METIS)p 258 242 25 4 v 31 w(Edg)q(eND)20 +b FL(\(int)g(*n,)g(idxtype)e(*xadj,)h(idxtype)g(*adjnc)o(y)-5 +b(,)18 b(int)i(*num\003ag,)f(int)h(*options,)f(idxtype)f(*perm,)h +(idxtype)g(*iperm\))0 501 y FB(Description)208 611 y +FL(This)25 b(function)f(computes)h(\002ll)h(reducing)e(orderings)f(of)j +(sparse)f(matrices)h(using)f(the)g(multile)n(v)o(el)g(nested)g +(dissection)g(algo-)208 721 y(rithm.)f(It)c(pro)o(vides)f(the)h +(functionality)e(of)i(the)g Fp(oemetis)g FL(program.)0 +897 y FB(P)n(arameter)o(s)208 1016 y FC(n)327 b FL(The)20 +b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 1133 +y FC(xadj,)e(adjncy)581 1242 y FL(The)h(adjacenc)o(y)e(structure)i(of)g +(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.)208 +1385 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 1495 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +1638 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 1764 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 1907 y FC(options)114 +b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o(gers)e(that)h(is)i +(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f(phases)h(of)g +(the)g(algorithm.)581 2016 y(If)j Fs(options[0]=0)e FL(then)h(def)o +(ault)g(v)n(alues)g(are)h(used.)34 b(If)24 b Fs(options[0]=1)p +FL(,)f(then)g(the)g(remaining)f(four)h(elements)g(of)581 +2126 y Fs(options)c FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +2269 y(options[1])108 b(Determined)19 b(the)h(matching)f(type.)24 +b(Possible)d(v)n(alues)f(are:)1033 2395 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 2521 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 2647 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 2773 y(Experiments)f(has)h +(sho)n(wn)g(that)g(both)f(HEM)h(and)g(SHEM)g(perform)f(quite)g(well.) +581 2900 y(options[2])108 b(Determines)20 b(the)g(algorithm)f(used)g +(during)g(initial)i(partitioning.)h(Possible)f(v)n(alues)f(are:)1033 +3026 y(1)83 b(Re)o(gion)19 b(Gro)n(wing)g(\(Def)o(ault\))581 +3152 y(options[3])108 b(Determines)20 b(the)g(algorithm)f(used)g(for)h +(re\002nement.)k(Possible)c(v)n(alues)g(are:)1033 3278 +y(1)83 b(Early-Exit)18 b(Boundary)h(FM)h(re\002nement)f(\(Def)o(ault\)) +581 3404 y(options[4])108 b(Used)21 b(for)e(deb)n(ugging)f(purposes.)23 +b(Al)o(w)o(ays)e(set)g(it)g(to)f(0)h(\(Def)o(ault\).)208 +3521 y FC(perm,)f(iperm)581 3631 y FL(These)25 b(are)g(v)o(ectors,)f +(each)h(of)g(size)g Fs(n)p FL(.)39 b(Upon)24 b(successful)h +(completion,)f(the)o(y)g(store)g(the)h(\002ll-reducing)e(permu-)581 +3740 y(tation)j(and)g(in)m(v)o(erse-permutation.)39 b(Let)34 +b Ft(A)29 b FL(be)d(the)g(original)f(matrix)h(and)34 +b Ft(A)2868 3710 y Fe(0)2915 3740 y FL(be)27 b(the)f(permuted)e +(matrix.)43 b(The)581 3850 y(arrays)21 b Fs(perm)g FL(and)f +Fs(iperm)h FL(are)g(de\002ned)f(as)i(follo)n(ws.)27 b(Ro)n(w)21 +b(\(column\))d Ft(i)30 b FL(of)f Ft(A)2836 3820 y Fe(0)2878 +3850 y FL(is)22 b(the)f(perm)o FM(T)o Ft(i)9 b FM(U)20 +b FL(ro)n(w)h(\(column\))e(of)589 3959 y Ft(A)r FL(,)j(and)f(ro)n(w)g +(\(column\))d Ft(i)31 b FL(of)e Ft(A)24 b FL(is)e(the)g(iperm)n +FM(T)o Ft(i)9 b FM(U)21 b FL(ro)n(w)g(\(column\))f(of)29 +b Ft(A)2659 3929 y Fe(0)2680 3959 y FL(.)g(The)21 b(numbering)e(of)i +(this)h(v)o(ector)f(starts)581 4069 y(from)e(either)h(0)g(or)g(1,)g +(depending)e(on)i(the)g(v)n(alue)f(of)h Fs(num\003a)o(g)p +FL(.)0 4245 y FB(Note)208 4355 y FL(This)25 b(function)f(computes)g +(the)h(v)o(erte)o(x)f(separator)g(from)g(the)h(edge)g(separator)f +(using)h(a)g(minimum)f(co)o(v)o(er)g(algorithm.)38 b(This)208 +4464 y(function)21 b(should)i(be)g(used)h(only)f(in)g(ordering)f(lar)o +(ge)g(graphs)h(arising)g(in)h(3D)f(\002nite)h(element)f(applications.) +34 b(In)23 b(general)g(the)208 4574 y Fz(METIS)p 466 +4574 V 30 w(NodeND)e FL(routine)e(should)g(be)h(preferred,)e(as)j(it)g +(produces)d(better)i(orderings.)1908 5649 y(36)p eop +%%Page: 37 37 +37 36 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(NodeND)20 +b FL(\(int)g(*n,)f(idxtype)g(*xadj,)g(idxtype)g(*adjnc)o(y)-5 +b(,)18 b(int)i(*num\003ag,)e(int)j(*options,)d(idxtype)h(*perm,)g +(idxtype)g(*iperm\))0 342 y FB(Description)208 452 y +FL(This)25 b(function)f(computes)h(\002ll)h(reducing)e(orderings)f(of)j +(sparse)f(matrices)h(using)f(the)g(multile)n(v)o(el)g(nested)g +(dissection)g(algo-)208 561 y(rithm.)f(It)c(pro)o(vides)f(the)h +(functionality)e(of)i(the)g Fp(onmetis)g FL(program.)0 +737 y FB(P)n(arameter)o(s)208 857 y FC(n)327 b FL(The)20 +b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 973 +y FC(xadj,)e(adjncy)581 1083 y FL(The)h(adjacenc)o(y)e(structure)i(of)g +(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.)208 +1226 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 1335 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +1478 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 1604 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 1747 y FC(options)114 +b FL(This)22 b(is)g(an)f(array)f(of)h(8)h(inte)o(gers)e(that)h(is)i +(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f(phases)h(of)g +(the)g(algorithm.)581 1857 y(If)g Fs(options[0]=0)e FL(then)h(def)o +(ault)g(v)n(alues)g(are)h(used.)26 b(If)21 b Fs(options[0]=1)p +FL(,)e(then)h(the)h(remaining)e(se)n(v)o(en)g(elements)i(of)581 +1966 y Fs(options)e FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +2109 y(options[1])108 b(Determines)20 b(the)g(matching)f(type.)24 +b(Possible)d(v)n(alues)e(are:)1033 2235 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 2362 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 2488 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 2614 y(Experiments)14 +b(ha)n(v)o(e)h(sho)n(wn)g(that)h(all)h(three)e(matching)f(schemes)i +(perform)e(quite)h(well.)24 b(In)16 b(general)1033 2724 +y(SHEM)22 b(is)h(f)o(aster)e(and)g(RM)i(is)f(slo)n(wer)m(,)f(b)n(ut)h +(feel)g(free)f(to)g(e)o(xperiment)f(with)i(the)f(other)g(matching)1033 +2833 y(schemes.)581 2959 y(options[2])108 b(Determines)20 +b(the)g(algorithm)f(used)g(during)g(initial)i(partitioning.)h(Possible) +f(v)n(alues)f(are:)1033 3086 y(1)83 b(Edge-based)18 b(re)o(gion)g(gro)n +(wing)h(\(Def)o(ault\))1033 3212 y(2)83 b(Node-based)18 +b(re)o(gion)h(gro)n(wing)581 3338 y(options[3])108 b(Determines)20 +b(the)g(algorithm)f(used)g(for)h(re\002nement.)k(Possible)c(v)n(alues)g +(are:)1033 3464 y(1)83 b(T)-7 b(w)o(o-sided)19 b(node)g(FM)i +(re\002nement)1033 3590 y(2)83 b(One-sided)19 b(node)g(FM)i +(re\002nement)d(\(Def)o(ault\))1033 3717 y(One-sided)i(FM)h +(re\002nement)f(is)i(f)o(aster)f(than)g(tw)o(o-sided,)f(b)n(ut)h(in)g +(some)f(cases)i(tw)o(o-sided)e(re\002ne-)1033 3826 y(ment)g(may)g +(produce)e(better)i(orderings.)j(Feel)d(free)g(to)h(e)o(xperiment)d +(with)i(this)h(option.)581 3952 y(options[4])108 b(Used)21 +b(for)e(deb)n(ugging)f(purposes.)23 b(Al)o(w)o(ays)e(set)g(it)g(to)f(0) +h(\(Def)o(ault\).)581 4079 y(options[5])108 b(Used)17 +b(to)f(select)h(whether)e(or)h(not)f(to)i(compress)e(the)h(graph)f(and) +g(to)i(order)d(connected)h(components)1033 4188 y(separately)-5 +b(.)24 b(The)c(possible)g(v)n(alues)f(and)h(their)g(meaning)f(are)h(as) +h(follo)n(ws.)1033 4314 y(0)83 b(Do)32 b(not)h(try)f(to)h(compress)f +(the)h(graph)e(and)h(do)g(not)h(order)e(each)h(connected)f(component) +1158 4424 y(separately)-5 b(.)1033 4550 y(1)83 b(T)m(ry)23 +b(to)i(compress)e(the)h(graph.)36 b(\(A)24 b(compressed)f(graph)f(is)j +(actually)f(formed)e(if)j(the)f(size)h(of)1158 4660 y(the)20 +b(graph)f(can)h(be)g(reduced)e(by)i(at)h(least)g(15\045\))e(\(Def)o +(ault\).)1033 4786 y(2)83 b(Order)28 b(each)h(connected)e(component)f +(of)j(the)g(graph)e(separately)-5 b(.)50 b(This)30 b(option)d(is)j +(partic-)1158 4895 y(ularly)25 b(useful)h(when)f(after)h(a)h(fe)n(w)f +(le)n(v)o(els)g(of)g(nested)f(dissection,)i(the)g(graph)d(breaks)i(up)f +(in)1158 5005 y(man)o(y)16 b(smaller)i(disconnected)e(subgraphs.)22 +b(This)c(is)g(true)g(for)f(certain)g(types)g(of)h(LP)g(matrices.)1033 +5131 y(3)83 b(T)m(ry)19 b(to)i(compress)e(the)h(graph)f(and)h(also)g +(order)f(each)h(connected)e(component)g(separately)-5 +b(.)1908 5649 y(37)p eop +%%Page: 38 38 +38 37 bop 581 83 a FL(options[6])108 b(Used)20 b(to)f(control)f +(whether)g(or)h(not)g(the)g(ordering)e(algorithm)h(should)g(remo)o(v)o +(e)f(an)o(y)i(v)o(ertices)f(with)1033 193 y(high)j(de)o(gree)e(\()p +Fs(i.e)p FL(.,)i(dense)g(columns\).)27 b(This)21 b(is)h(particularly)e +(helpful)g(for)g(certain)h(classes)h(of)f(LP)1033 302 +y(matrices,)k(in)f(which)g(there)f(a)i(fe)n(w)f(v)o(ertices)g(that)g +(are)g(connected)e(to)j(man)o(y)e(other)g(v)o(ertices.)36 +b(By)1033 412 y(remo)o(ving)20 b(these)j(v)o(ertices)e(prior)h(to)g +(ordering,)f(the)h(quality)g(and)f(the)i(amount)e(of)h(time)g(required) +1033 521 y(to)f(do)e(the)i(ordering)d(impro)o(v)o(es.)23 +b(The)c(possible)h(v)n(alues)g(are)g(as)h(follo)n(ws:)1033 +648 y(0)83 b(Do)20 b(not)g(remo)o(v)o(e)e(an)o(y)h(v)o(ertices)h(\(Def) +o(ault\))1035 774 y Ft(x)91 b FL(Where)34 b Ft(x)54 b +Fu(>)46 b FL(0,)36 b(instructs)d(the)g(algorithm)e(to)i(remo)o(v)o(e)e +(an)o(y)h(v)o(ertices)g(whose)g(de)o(gree)g(is)1158 883 +y(greater)25 b(than)h(0)p Fu(:)p FL(1)21 b FM(\003)k +Ft(x)31 b FM(\003)23 b Fu(.)p FL(a)n(v)o(erage)c(de)o(gree\))m(.)44 +b(F)o(or)26 b(e)o(xample)e(if)29 b Ft(x)41 b FM(D)34 +b FL(40,)27 b(and)f(the)g(a)n(v)o(erage)1158 993 y(de)o(gree)18 +b(is)i(5,)f(then)g(the)g(algorithm)e(will)j(remo)o(v)o(e)e(all)h(v)o +(ertices)g(with)h(de)o(gree)d(greater)h(than)h(20.)1158 +1103 y(The)f(v)o(ertices)g(that)g(are)g(remo)o(v)o(ed)e(are)i(ordered)f +(last)i(\()p Fs(i.e)o FL(.,)g(the)o(y)f(are)g(automatically)f(placed)g +(in)1158 1212 y(the)22 b(top-le)n(v)o(el)f(separator\).)31 +b(Good)22 b(v)n(alues)g(are)h(often)f(in)g(the)h(range)f(of)g(60)g(to)h +(200)f(\()p Fs(i.e)o FL(.,)i(6)e(to)1158 1322 y(20)e(times)g(more)g +(than)f(the)h(a)n(v)o(erage\).)581 1448 y(options[7])108 +b(Used)23 b(to)g(determine)e(ho)n(w)h(man)o(y)g(separators)g(to)h +(\002nd)f(at)h(each)g(step)g(of)f(nested)h(dissection.)32 +b(The)1033 1558 y(lar)o(ger)16 b(the)i(number)d(of)i(separators)g +(found)f(at)h(each)h(step,)g(the)f(higher)f(the)h(runtime)g(and)g +(better)g(the)1033 1667 y(quality)i(is)h(\(in)f(general\).)k(The)18 +b(def)o(ault)h(v)n(alue)f(is)i(1,)f(unless)h(the)f(graph)f(has)h(been)f +(compressed)g(by)1033 1777 y(more)g(than)h(a)g(f)o(actor)g(of)f(2,)h +(in)g(which)g(case)g(it)h(becomes)e(2.)25 b(Reasonable)18 +b(v)n(alues)h(are)f(in)i(the)f(range)1033 1886 y(of)h(1)g(to)h(5.)k(F)o +(or)20 b(most)g(problems,)e(a)j(v)n(alue)e(of)h(5)h(increases)f(the)g +(runtime)f(by)h(a)g(f)o(actor)g(of)g(3.)208 2003 y FC(perm,)g(iperm)581 +2113 y FL(These)25 b(are)g(v)o(ectors,)f(each)h(of)g(size)g +Fs(n)p FL(.)39 b(Upon)24 b(successful)h(completion,)f(the)o(y)g(store)g +(the)h(\002ll-reducing)e(permu-)581 2222 y(tation)j(and)g(in)m(v)o +(erse-permutation.)39 b(Let)34 b Ft(A)29 b FL(be)d(the)g(original)f +(matrix)h(and)34 b Ft(A)2868 2192 y Fe(0)2915 2222 y +FL(be)27 b(the)f(permuted)e(matrix.)43 b(The)581 2332 +y(arrays)21 b Fs(perm)g FL(and)f Fs(iperm)h FL(are)g(de\002ned)f(as)i +(follo)n(ws.)27 b(Ro)n(w)21 b(\(column\))d Ft(i)30 b +FL(of)f Ft(A)2836 2302 y Fe(0)2878 2332 y FL(is)22 b(the)f(perm)o +FM(T)o Ft(i)9 b FM(U)20 b FL(ro)n(w)h(\(column\))e(of)589 +2441 y Ft(A)r FL(,)j(and)f(ro)n(w)g(\(column\))d Ft(i)31 +b FL(of)e Ft(A)24 b FL(is)e(the)g(iperm)n FM(T)o Ft(i)9 +b FM(U)21 b FL(ro)n(w)g(\(column\))f(of)29 b Ft(A)2659 +2411 y Fe(0)2680 2441 y FL(.)g(The)21 b(numbering)e(of)i(this)h(v)o +(ector)f(starts)581 2551 y(from)e(either)h(0)g(or)g(1,)g(depending)e +(on)i(the)g(v)n(alue)f(of)h Fs(num\003a)o(g)p FL(.)0 +2727 y FB(Note)208 2837 y FL(This)25 b(function)g(computes)f(the)i(v)o +(erte)o(x)e(separator)h(directly)g(by)g(using)g(a)h(multile)n(v)o(el)f +(algorithm.)40 b(This)26 b(function)e(produces)208 2946 +y(high)19 b(quality)g(orderings)g(and)g(should)g(be)i(preferred)d(o)o +(v)o(er)g Fz(METIS)p 2192 2946 25 4 v 31 w(EdgeND)p FL(.)1908 +5649 y(38)p eop +%%Page: 39 39 +39 38 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(NodeWND)20 +b FL(\(int)g(*n,)g(idxtype)f(*xadj,)g(idxtype)f(*adjnc)o(y)-5 +b(,)18 b(idxtype)h(*vwgt,)g(int)h(*num\003ag,)f(int)h(*options,)710 +193 y(idxtype)f(*perm,)g(idxtype)f(*iperm\))0 452 y FB(Description)208 +561 y FL(This)25 b(function)f(computes)h(\002ll)h(reducing)e(orderings) +f(of)j(sparse)f(matrices)h(using)f(the)g(multile)n(v)o(el)g(nested)g +(dissection)g(algo-)208 671 y(rithm.)f(It)19 b(is)h(similar)f(to)g +Fz(METIS)p 1171 671 V 31 w(NodeWND)h FL(b)n(ut)f(it)g(assumes)h(that)f +(the)g(compression)e(has)i(been)f(already)g(performed)f(prior)208 +780 y(to)22 b(calling)f(this)i(routine.)29 b(It)22 b(is)h(particularly) +d(suited)i(for)f(ordering)f(v)o(ery)h(lar)o(ge)g(matrices)g(in)h(which) +g(the)g(compressed)e(matrix)208 890 y(is)h(kno)n(wn)d(a)j(priori.)0 +1066 y FB(P)n(arameter)o(s)208 1186 y FC(n)327 b FL(The)20 +b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 1302 +y FC(xadj,)e(adjncy)581 1412 y FL(The)h(adjacenc)o(y)e(structure)i(of)g +(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.)208 +1555 y FC(vwgt)201 b FL(The)20 b(weight)g(of)g(the)g(v)o(ertices.)208 +1697 y FC(num\003ag)82 b FL(Used)22 b(to)f(indicate)g(which)g +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(adjacenc)o(y)f(structure) +g(of)h(the)g(graph.)27 b Fs(num\003a)o(g)581 1807 y FL(can)20 +b(tak)o(e)g(the)h(follo)n(wing)d(tw)o(o)j(v)n(alues:)581 +1950 y(0)83 b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h +(from)e(0)581 2076 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j +(assumed)e(that)i(starts)g(from)e(1)208 2219 y FC(options)114 +b FL(This)22 b(is)g(an)f(array)f(of)h(5)h(inte)o(gers)e(that)h(is)i +(used)e(to)g(pass)h(parameters)e(for)h(the)g(v)n(arious)f(phases)h(of)g +(the)g(algorithm.)581 2328 y(If)j Fs(options[0]=0)e FL(then)h(def)o +(ault)g(v)n(alues)g(are)h(used.)34 b(If)24 b Fs(options[0]=1)p +FL(,)f(then)g(the)g(remaining)f(four)h(elements)g(of)581 +2438 y Fs(options)c FL(are)i(interpreted)d(as)j(follo)n(ws:)581 +2581 y(options[1])108 b(Determines)20 b(the)g(matching)f(type.)24 +b(Possible)d(v)n(alues)e(are:)1033 2707 y(1)83 b(Random)19 +b(Matching)g(\(RM\))1033 2833 y(2)83 b(Hea)n(vy-Edge)18 +b(Matching)h(\(HEM\))1033 2959 y(3)83 b(Sorted)19 b(Hea)n(vy-Edge)f +(Matching)h(\(SHEM\))h(\(Def)o(ault\))1033 3086 y(Experiments)14 +b(ha)n(v)o(e)h(sho)n(wn)g(that)h(all)h(three)e(matching)f(schemes)i +(perform)e(quite)h(well.)24 b(In)16 b(general)1033 3195 +y(SHEM)22 b(is)h(f)o(aster)e(and)g(RM)i(is)f(slo)n(wer)m(,)f(b)n(ut)h +(feel)g(free)f(to)g(e)o(xperiment)f(with)i(the)f(other)g(matching)1033 +3305 y(schemes.)581 3431 y(options[2])108 b(Determines)20 +b(the)g(algorithm)f(used)g(during)g(initial)i(partitioning.)h(Possible) +f(v)n(alues)f(are:)1033 3557 y(1)83 b(Edge-based)18 b(re)o(gion)g(gro)n +(wing)h(\(Def)o(ault\))1033 3683 y(2)83 b(Node-based)18 +b(re)o(gion)h(gro)n(wing)581 3810 y(options[3])108 b(Determines)20 +b(the)g(algorithm)f(used)g(for)h(re\002nement.)k(Possible)c(v)n(alues)g +(are:)1033 3936 y(1)83 b(T)-7 b(w)o(o-sided)19 b(node)g(FM)i +(re\002nement)1033 4062 y(2)83 b(One-sided)19 b(node)g(FM)i +(re\002nement)d(\(Def)o(ault\))1033 4188 y(One-sided)i(FM)h +(re\002nement)f(is)i(f)o(aster)f(than)g(tw)o(o-sided,)f(b)n(ut)h(in)g +(some)f(cases)i(tw)o(o-sided)e(re\002ne-)1033 4298 y(ment)g(may)g +(produce)e(better)i(orderings.)j(Feel)d(free)g(to)h(e)o(xperiment)d +(with)i(this)h(option.)581 4424 y(options[4])108 b(Used)21 +b(for)e(deb)n(ugging)f(purposes.)23 b(Al)o(w)o(ays)e(set)g(it)g(to)f(0) +h(\(Def)o(ault\).)208 4541 y FC(perm,)f(iperm)581 4650 +y FL(These)25 b(are)g(v)o(ectors,)f(each)h(of)g(size)g +Fs(n)p FL(.)39 b(Upon)24 b(successful)h(completion,)f(the)o(y)g(store)g +(the)h(\002ll-reducing)e(permu-)581 4760 y(tation)j(and)g(in)m(v)o +(erse-permutation.)39 b(Let)34 b Ft(A)29 b FL(be)d(the)g(original)f +(matrix)h(and)34 b Ft(A)2868 4730 y Fe(0)2915 4760 y +FL(be)27 b(the)f(permuted)e(matrix.)43 b(The)581 4869 +y(arrays)21 b Fs(perm)g FL(and)f Fs(iperm)h FL(are)g(de\002ned)f(as)i +(follo)n(ws.)27 b(Ro)n(w)21 b(\(column\))d Ft(i)30 b +FL(of)f Ft(A)2836 4839 y Fe(0)2878 4869 y FL(is)22 b(the)f(perm)o +FM(T)o Ft(i)9 b FM(U)20 b FL(ro)n(w)h(\(column\))e(of)589 +4979 y Ft(A)r FL(,)j(and)f(ro)n(w)g(\(column\))d Ft(i)31 +b FL(of)e Ft(A)24 b FL(is)e(the)g(iperm)n FM(T)o Ft(i)9 +b FM(U)21 b FL(ro)n(w)g(\(column\))f(of)29 b Ft(A)2659 +4949 y Fe(0)2680 4979 y FL(.)g(The)21 b(numbering)e(of)i(this)h(v)o +(ector)f(starts)581 5089 y(from)e(either)h(0)g(or)g(1,)g(depending)e +(on)i(the)g(v)n(alue)f(of)h Fs(num\003a)o(g)p FL(.)1908 +5649 y(39)p eop +%%Page: 40 40 +40 39 bop 0 83 a Fr(5.7)100 b(A)m(uxiliar)q(y)28 b(Routines)0 +242 y FB(METIS)p 258 242 25 4 v 31 w(MeshT)-7 b(oNodal)20 +b FL(\(int)g(*ne,)f(int)i(*nn,)e(idxtype)g(*elmnts,)g(int)i(*etype,)d +(int)j(*num\003ag,)d(idxtype)h(*nxadj,)f(idxtype)h(*nadjnc)o(y\))0 +501 y FB(Description)208 611 y FL(This)26 b(function)f(is)i(used)f(to)g +(con)m(v)o(ert)f(a)h(mesh)g(into)g(a)h(nodal)f(graph,)g(in)g(a)h +(format)e(suitable)h(for)i Fz(M)l FG(E)-17 b Fz(T)g FG(I)p +Fz(S)r(lib)p FL(.)46 b(It)27 b(pro)o(vides)e(the)208 +721 y(function)18 b(of)i(the)g Fp(mesh2nodal)f FL(program.)0 +897 y FB(P)n(arameter)o(s)208 1016 y FC(ne)290 b FL(The)20 +b(number)e(of)i(elements)g(in)h(the)f(mesh.)208 1159 +y FC(nn)281 b FL(The)20 b(number)e(of)i(nodes)g(in)g(the)g(mesh.)208 +1302 y FC(elmnts)138 b FL(The)20 b(element)g(node)f(array)g(storing)g +(the)i(mesh)f(as)h(described)d(in)j(Section)f(5.2.)208 +1445 y FC(etype)183 b FL(Indicates)20 b(the)g(type)g(of)f(the)i +(elements)f(in)g(the)g(mesh.)25 b Fs(etype)20 b FL(can)g(tak)o(e)g(the) +g(follo)n(wing)f(v)n(alues:)581 1587 y(1)83 b(The)20 +b(elements)f(are)i(triangles.)581 1714 y(2)83 b(The)20 +b(elements)f(are)i(tetrahedra.)581 1840 y(3)83 b(The)20 +b(elements)f(are)i(he)o(xahedra)c(\(bricks\).)581 1966 +y(4)83 b(The)20 b(elements)f(are)i(quadrilaterals.)208 +2109 y FC(num\003ag)82 b FL(Used)22 b(to)h(indicate)e(which)h +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(element)f(node)g(array)-5 +b(.)30 b Fs(num\003a)o(g)20 b FL(can)i(tak)o(e)h(the)581 +2218 y(follo)n(wing)c(tw)o(o)h(v)n(alues:)581 2361 y(0)83 +b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h(from)e(0)581 +2487 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j(assumed)e(that)i +(starts)g(from)e(1)208 2604 y FC(nxadj,)g(nadjncy)581 +2714 y FL(These)29 b(arrays)f(store)g(the)h(adjacenc)o(y)e(structure)h +(of)g(the)h(nodal)e(graph.)49 b(The)29 b(user)f(must)h(pro)o(vide)d +(arrays)i(that)581 2823 y(are)c(suf)n(\002ciently)g(lar)o(ge)f(to)i +(store)f(the)g(graph.)36 b(The)24 b(size)h(of)f(array)f +Fs(nxadj)h FL(is)h Fs(nn+1)e FL(where)h(the)g(size)h(of)f +Fs(nadjncy)581 2933 y FL(depends)i(on)g(the)h(type)f(of)h(the)g(mesh.) +44 b(F)o(or)27 b(triangular)n(-element)d(and)i(he)o(xahedra-element)d +(meshes,)28 b Fs(nadjncy)581 3042 y FL(should)19 b(be)g(at)h(least)h(6) +15 b FM(\003)h Fs(nn)o FL(,)k(for)f(quadrilateral-element)e(meshes,)i +Fs(nadjncy)f FL(should)g(be)i(at)g(least)g(4)c FM(\003)g +Fs(nn)o FL(,)k(and)f(for)581 3152 y(tetrahedra-element)e(meshes,)j +Fs(nadjncy)f FL(should)g(be)h(at)h(least)g(15)c FM(\003)i +Fs(nn)o FL(.)0 3328 y FB(Note)208 3438 y FL(The)k(nodal)h(graph)e(is)k +(de\002ned)d(as)i(the)f(graph)f(in)h(which)g(each)g(v)o(erte)o(x)e(of)i +(the)h(graph)d(corresponds)g(to)j(a)f(node)f(in)i(the)f(mesh,)208 +3547 y(and)19 b(tw)o(o)i(v)o(ertices)e(are)h(connected)f(by)h(an)g +(edge)f(if)i(the)f(corresponding)d(nodes)i(a)i(connected)d(by)i(an)g +(element.)1908 5649 y(40)p eop +%%Page: 41 41 +41 40 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(MeshT)-7 +b(oDual)20 b FL(\(int)g(*ne,)g(int)g(*nn,)f(idxtype)g(*elmnts,)g(int)i +(*etype,)e(int)h(*num\003ag,)e(idxtype)h(*dxadj,)g(idxtype)f(*dadjnc)o +(y\))0 342 y FB(Description)208 452 y FL(This)28 b(function)e(is)j +(used)f(to)h(con)m(v)o(ert)d(a)i(mesh)g(into)g(a)h(dual)f(graph,)g(in)g +(a)h(format)e(suitable)h(for)i Fz(M)l FG(E)-17 b Fz(T)g +FG(I)p Fz(S)r(lib)p FL(.)52 b(It)28 b(pro)o(vides)f(the)208 +561 y(function)18 b(of)i(the)g Fp(mesh2nodal)f FL(program.)0 +737 y FB(P)n(arameter)o(s)208 857 y FC(ne)290 b FL(The)20 +b(number)e(of)i(elements)g(in)h(the)f(mesh.)208 1000 +y FC(nn)281 b FL(The)20 b(number)e(of)i(nodes)g(in)g(the)g(mesh.)208 +1142 y FC(elmnts)138 b FL(The)20 b(element)g(node)f(array)g(storing)g +(the)i(mesh)f(as)h(described)d(in)j(Section)f(5.2.)208 +1285 y FC(etype)183 b FL(Indicates)20 b(the)g(type)g(of)f(the)i +(elements)f(in)g(the)g(mesh.)25 b Fs(etype)20 b FL(can)g(tak)o(e)g(the) +g(follo)n(wing)f(v)n(alues:)581 1428 y(1)83 b(The)20 +b(elements)f(are)i(triangles.)581 1554 y(2)83 b(The)20 +b(elements)f(are)i(tetrahedra.)581 1680 y(3)83 b(The)20 +b(elements)f(are)i(he)o(xahedra)c(\(bricks\).)581 1807 +y(4)83 b(The)20 b(elements)f(are)i(quadrilaterals.)208 +1949 y FC(num\003ag)82 b FL(Used)22 b(to)h(indicate)e(which)h +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(element)f(node)g(array)-5 +b(.)30 b Fs(num\003a)o(g)20 b FL(can)i(tak)o(e)h(the)581 +2059 y(follo)n(wing)c(tw)o(o)h(v)n(alues:)581 2202 y(0)83 +b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h(from)e(0)581 +2328 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j(assumed)e(that)i +(starts)g(from)e(1)208 2445 y FC(dxadj,)g(dadjncy)581 +2554 y FL(These)31 b(arrays)g(store)g(the)g(adjacenc)o(y)e(structure)h +(of)h(the)g(dual)g(graph.)56 b(The)31 b(user)g(must)g(pro)o(vide)e +(arrays)h(that)581 2664 y(are)25 b(suf)n(\002ciently)e(lar)o(ge)h(to)g +(store)h(the)f(graph.)37 b(The)24 b(size)h(of)g(array)e +Fs(dxadj)h FL(is)h Fs(ne+1)f FL(where)g(the)h(size)g(of)f +Fs(dadjncy)581 2773 y FL(depends)e(on)g(the)h(type)f(of)h(the)g(mesh.) +33 b(F)o(or)22 b(triangular)n(-element)e(meshes,)j Fs(dadjncy)f +FL(should)f(be)i(at)h(least)f(3)d FM(\003)h Fs(ne)o FL(,)581 +2883 y(for)i(tetrahedra-element)d(and)j(quadrilateral-element)d +(meshes,)j Fs(dadjncy)f FL(should)g(be)i(at)f(least)h(4)d +FM(\003)g Fs(ne)o FL(,)j(and)f(for)581 2993 y(he)o(xahedra-element)16 +b(meshes,)k Fs(dadjncy)f FL(should)g(be)h(at)h(least)g(6)d +FM(\003)g Fs(ne)p FL(.)0 3169 y FB(Note)208 3278 y FL(The)h(dual)f +(graph)g(is)j(de\002ned)d(as)i(the)g(graph)e(in)h(which)g(each)g(v)o +(erte)o(x)f(of)h(the)g(graph)f(corresponds)f(to)j(an)f(element)g(in)h +(the)f(mesh,)208 3388 y(and)g(tw)o(o)i(v)o(ertices)e(are)h(connected)f +(by)h(an)g(edge)f(if)i(the)f(corresponding)d(elements)j(share)f(a)i(f)o +(ace.)1908 5649 y(41)p eop +%%Page: 42 42 +42 41 bop 0 83 a FB(METIS)p 258 83 25 4 v 31 w(EstimateMemor)q(y)21 +b FL(\(int)f(*n,)f(idxtype)g(*xadj,)g(int)h(*adjnc)o(y)-5 +b(,)18 b(int)i(*num\003ag,)f(int)h(*optype,)e(int)j(*nbytes\))0 +342 y FB(Description)208 452 y FL(This)d(function)e(is)j(used)e(to)h +(estimate)g(the)g(amount)f(of)g(memory)g(that)h(will)g(be)g(used)g(by)h +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r FL(.)20 b(Ev)o(en)d(though,)h +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)22 b FL(dynam-)208 +561 y(ically)f(allocates)g(the)g(amount)f(of)g(memory)g(that)h(it)h +(needs,)e(this)i(function)d(can)i(be)g(useful)g(in)g(determining)e(if)i +(the)g(amount)f(of)208 671 y(memory)e(in)i(the)h(system)f(is)h(suf)n +(\002cient)f(for)h Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r +FL(.)0 847 y FB(P)n(arameter)o(s)208 966 y FC(n)327 b +FL(The)20 b(number)e(of)i(v)o(ertices)g(in)g(the)h(graph.)208 +1083 y FC(xadj,)e(adjncy)581 1193 y FL(The)h(adjacenc)o(y)e(structure)i +(of)g(the)g(graph)f(as)i(described)d(in)j(Section)f(5.1.)208 +1335 y FC(num\003ag)82 b FL(Used)22 b(to)h(indicate)e(which)h +(numbering)d(scheme)j(is)h(used)f(for)g(the)g(element)f(node)g(array)-5 +b(.)30 b Fs(num\003a)o(g)20 b FL(can)i(tak)o(e)h(the)581 +1445 y(follo)n(wing)c(tw)o(o)h(v)n(alues:)581 1588 y(0)83 +b(C-style)20 b(numbering)e(is)j(assumed)f(that)g(starts)h(from)e(0)581 +1714 y(1)83 b(F)o(ortran-style)18 b(numbering)g(is)j(assumed)e(that)i +(starts)g(from)e(1)208 1857 y FC(optype)132 b FL(Indicates)15 +b(the)h(operation)d(for)i(which)g(the)h(memory)e(will)i(be)g +(estimated.)23 b Fs(optype)14 b FL(can)i(tak)o(e)f(the)h(follo)n(wing)e +(v)n(alues:)581 2000 y(1)83 b(Estimates)15 b(the)h(memory)d(needed)h +(for)h Fz(METIS)p 2076 2000 V 30 w(P)m(ar)s(tGr)o(aphRecursiv)n(e)g +FL(and)g Fz(METIS)p 3260 2000 V 30 w(WP)m(ar)s(tGr)o(aphRecursiv)n(e)p +FL(.)581 2126 y(2)83 b(Estimates)20 b(the)h(memory)d(needed)h(for)g +Fz(METIS)p 2100 2126 V 31 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)h +FL(and)g Fz(METIS)p 3127 2126 V 30 w(WP)m(ar)s(tGr)o(aphKw)o(a)n(y)p +FL(.)581 2252 y(3)83 b(Estimates)20 b(the)h(memory)d(needed)h(for)g +Fz(METIS)p 2100 2252 V 31 w(EdgeND)p FL(.)581 2378 y(4)83 +b(Estimates)25 b(the)g(memory)d(needed)i(for)g Fz(METIS)p +2123 2378 V 30 w(NodeND)p FL(,)i(b)n(ut)e(it)i(does)e(not)h(tak)o(e)f +(into)h(account)e(memory)706 2488 y(sa)n(v)o(ed)d(due)f(to)i +(compression.)208 2631 y FC(nbytes)142 b FL(Upon)19 b(return,)g +Fs(nbytes)h FL(stores)g(an)h(estimate)f(on)g(the)g(number)e(of)i(bytes) +g(that)j Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)24 b FL(requires.)1908 +5649 y(42)p eop +%%Page: 43 43 +43 42 bop 0 83 a Fr(5.8)100 b(C)28 b(and)g(For)r(tran)f(Suppor)r(t)0 +242 y FL(The)g(v)n(arious)g(routines)f(in)k Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)r(lib)31 b FL(can)c(be)h(called)f(from)g(either)g +(C)h(or)f(F)o(ortran)g(programs.)45 b(Using)27 b(C)i(with)h +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)30 b FL(is)f(quite)0 +352 y(straightforw)o(ard)24 b(\(as)30 b Fz(M)l FG(E)-17 +b Fz(T)g FG(I)p Fz(S)31 b FL(is)d(written)f(entirely)f(in)h(C\).)g(Ho)n +(we)n(v)o(er)m(,)h Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)31 +b FL(fully)26 b(supports)g(F)o(ortran)g(as)h(well.)46 +b(This)27 b(support)0 462 y(comes)20 b(in)g(three)g(forms.)104 +638 y(1.)41 b(All)20 b(the)h(scalar)f(ar)o(guments)e(in)i(the)h +(routines)e(are)h(passed)g(by)g(reference)e(to)j(f)o(acilitate)f(F)o +(ortran)f(programs.)104 814 y(2.)41 b(All)22 b(the)g(routines)f(tak)o +(e)h(a)h(parameter)d(called)i Fs(num\003a)o(g)e FL(indicating)h +(whether)g(or)h(not)f(the)h(numbering)e(of)h(the)h(graph)f(or)h(mesh) +208 923 y(starts)28 b(from)e(0)h(or)g(1.)46 b(In)27 b(C)h(programs)e +(numbering)e(usually)j(starts)h(from)e(0,)j(whereas)e(in)g(F)o(ortran)f +(programs)f(numbering)208 1033 y(starts)c(from)e(1.)104 +1209 y(3.)43 b Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)21 +b FL(incorporates)c(alternati)n(v)o(e)g(names)i(for)f(each)g(of)g(the)h +(routines)e(to)i(f)o(acilitate)g(linking)e(the)i(library)f(with)g(F)o +(ortran)g(pro-)208 1318 y(grams.)29 b(In)22 b(particular)m(,)f(for)g(e) +n(v)o(ery)g(function)h Fz(M)l FG(E)-17 b Fz(T)g FG(I)p +Fz(S)r(lib)25 b FL(pro)o(vides)c(three)g(additional)g(names,)h(one)f +(all)i(capital,)f(one)f(all)i(lo)n(wer)208 1428 y(case,)f(and)g(one)f +(all)i(lo)n(wer)e(case)h(with)h(`)p 1363 1428 25 4 v +29 w(')f(appended)e(to)i(it.)31 b(F)o(or)22 b(e)o(xample,)e(for)i +Fz(METIS)p 2801 1428 V 30 w(P)m(ar)s(tGr)o(aphKw)o(a)n(y)p +FL(,)i Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)r(lib)26 +b FL(pro-)208 1538 y(vides)c Fz(METIS)p 664 1538 V 30 +w(P)-10 b(AR)n(TGRAPHKW)l(A)i(Y)p FL(,)24 b Fz(metis)p +1672 1538 V 30 w(par)s(tg)o(r)o(aphkw)o(a)n(y)p FL(,)f(and)e +Fz(metis)p 2629 1538 V 31 w(par)s(tg)o(r)o(aphkw)o(a)n(y)p +3203 1538 V 29 w FL(.)31 b(These)22 b(e)o(xtra)g(names)208 +1647 y(allo)n(w)j(the)h(library)f(to)h(be)g(directly)f(link)o(ed)g +(into)g(F)o(ortran)g(programs)f(on)h(a)i(wide)e(range)g(of)h +(architectures)e(including)g(Cray)-5 b(,)208 1757 y(SGI,)20 +b(and)h(HP)-9 b(.)21 b(If)f(you)g(still)i(encounter)d(problems)g +(linking)h(with)h(the)g(library)f(let)h(us)g(kno)n(w)f(so)h(we)g(can)g +(include)f(appropriate)208 1866 y(support.)1908 5649 +y(43)p eop +%%Page: 44 44 +44 43 bop 0 85 a FD(6)116 b(System)31 b(Requirements)g(and)h(Contact)f +(Inf)n(ormation)0 261 y FL(The)24 b(distrib)n(ution)g(of)i +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)30 b FL(contains)24 +b(a)h(number)e(of)h(\002les,)j(that)e(total)g(to)g(o)o(v)o(er)e(22,000) +g(lines)i(of)f(code.)38 b(It)25 b(is)h(written)e(entirely)g(in)0 +370 y(ANSI)f(C,)h(and)e(is)i(portable)e(on)g(most)h(Unix)g(systems)g +(that)g(ha)n(v)o(e)f(an)h(ANSI)g(C)h(compiler)e(\(the)g(GNU)i(C)g +(compiler)d(will)j(do\).)32 b(It)23 b(has)0 480 y(been)17 +b(e)o(xtensi)n(v)o(ely)g(tested)h(on)g(AIX,)g(SunOS,)f(Solaris,)i +(IRIX,)f(Linux,)f(HP-UX,)h(BSD,)h(and)f(Unicos.)24 b(Instructions)16 +b(on)i(ho)n(w)g(to)g(b)n(uild)0 590 y(and)i(install)i +Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)25 b FL(can)20 b(be)g(found)e(in)j +(the)f(\002le)h Fp(INSTALL)e FL(of)h(the)g(distrib)n(ution.)100 +699 y(Ev)o(en)d(though,)i Fz(M)l FG(E)-17 b Fz(T)g FG(I)p +Fz(S)23 b FL(contains)18 b(no)h(kno)n(wn)e(b)n(ugs,)h(it)i(does)e(not)h +(mean)f(that)h(all)g(of)f(its)i(b)n(ugs)f(ha)n(v)o(e)f(been)g(found)f +(and)h(\002x)o(ed.)24 b(If)18 b(you)0 809 y(\002nd)24 +b(an)o(y)f(problems,)g(please)h(send)f(email)h(to)g Fs +(metis@cs.umn.edu)p FL(,)g(with)g(a)g(brief)f(description)g(of)g(the)h +(problem)e(you)h(ha)n(v)o(e)h(found.)0 918 y(Also,)c(an)o(y)g(future)f +(updates)g(to)j Fz(M)l FG(E)-17 b Fz(T)g FG(I)p Fz(S)25 +b FL(will)c(be)f(made)g(a)n(v)n(ailable)f(on)h(WWW)i(at)f +Fs(http://www)-6 b(.cs.umn.edu/\230metis)p FL(.)0 1164 +y FD(Ref)o(erences)37 1331 y FK([1])42 b(Stephen)26 b(T)-6 +b(.)26 b(Barnard)g(and)g(Horst)g(D.)f(Simon.)49 b(A)25 +b(f)o(ast)h(multile)n(v)o(el)g(implementation)g(of)g(recursi)n(v)o(e)g +(spectral)g(bisection)h(for)e(partitioning)166 1431 y(unstructured)d +(problems.)34 b(In)21 b FJ(Pr)m(oceedings)h(of)e(the)h(sixth)g(SIAM)g +(confer)m(ence)i(on)e(P)-6 b(ar)o(allel)20 b(Pr)m(ocessing)i(for)e +(Scienti\002c)i(Computing)p FK(,)g(pages)166 1532 y(711\226718,)f +(1993.)37 1649 y([2])42 b(A.)19 b(Geor)o(ge)h(and)h(J.)e(W)-7 +b(.-H.)18 b(Liu.)29 b FJ(Computer)21 b(Solution)f(of)g(Lar)m(g)o(e)h +(Spar)o(se)g(P)-6 b(ositive)19 b(De\002nite)h(Systems)p +FK(.)30 b(Prentice-Hall,)19 b(Engle)n(w)o(ood)i(Clif)n(fs,)166 +1749 y(NJ,)d(1981.)37 1866 y([3])42 b(Anshul)d(Gupta,)44 +b(Geor)o(ge)39 b(Karypis,)44 b(and)c(V)l(ipin)e(K)o(umar)l(.)91 +b(Highly)39 b(scalable)g(parallel)g(algorithms)g(for)g(sparse)g(matrix) +f(f)o(actoriza-)166 1967 y(tion.)64 b FJ(IEEE)30 b(T)l(r)o(ansactions)h +(on)g(P)-6 b(ar)o(allel)30 b(and)i(Distrib)o(uted)e(Systems)p +FK(,)k(8\(5\):502\226520,)i(May)31 b(1997.)66 b(A)-6 +b(v)n(ailable)31 b(on)g(WWW)e(at)i(URL)166 2067 y(http://www)-5 +b(.cs.umn.edu/\230karypis.)37 2184 y([4])42 b(Bruce)15 +b(Hendrickson)i(and)f(Robert)f(Leland.)k(The)c(chaco)h(user')l(s)f +(guide,)h(v)o(ersion)g(1.0.)i(T)-5 b(echnical)16 b(Report)f +(SAND93-2339,)h(Sandia)g(National)166 2285 y(Laboratories,)j(1993.)37 +2402 y([5])42 b(Bruce)26 b(Hendrickson)h(and)f(Robert)g(Leland.)48 +b(A)25 b(multile)n(v)o(el)g(algorithm)h(for)g(partitioning)g(graphs.)49 +b(T)-5 b(echnical)25 b(Report)h(SAND93-1301,)166 2502 +y(Sandia)19 b(National)g(Laboratories,)g(1993.)37 2619 +y([6])42 b(G.)30 b(Karypis)g(and)h(V)-10 b(.)30 b(K)o(umar)l(.)62 +b(Multile)n(v)o(el)31 b(algorithms)f(for)g(multi-constraint)g(graph)i +(partitioning.)63 b(T)-5 b(echnical)30 b(Report)g(TR)g(98-019,)166 +2720 y(Department)19 b(of)g(Computer)h(Science,)f(Uni)n(v)o(ersity)g +(of)g(Minnesota,)h(1998.)37 2837 y([7])42 b(G.)24 b(Karypis)h(and)g(V) +-10 b(.)24 b(K)o(umar)l(.)44 b(Multile)n(v)o(el)25 b(k-w)o(ay)g +(partitioning)g(scheme)g(for)f(irre)o(gular)g(graphs.)46 +b FJ(J)n(ournal)26 b(of)e(P)-6 b(ar)o(allel)24 b(and)h(Distrib)o(uted) +166 2937 y(Computing)p FK(,)19 b(48\(1\):96\226129,)j(1998.)28 +b(Also)18 b(a)o(v)n(ailable)i(on)f(WWW)e(at)i(URL)f(http://www)-5 +b(.cs.umn.edu/\230karypis.)37 3055 y([8])42 b(G.)23 b(Karypis)h(and)g +(V)-10 b(.)23 b(K)o(umar)l(.)42 b(A)23 b(f)o(ast)h(and)g(highly)g +(quality)g(multile)n(v)o(el)f(scheme)i(for)e(partitioning)h(irre)o +(gular)f(graphs.)43 b FJ(SIAM)23 b(J)n(ournal)i(on)166 +3155 y(Scienti\002c)f(Computing)p FK(,)g(1998)g(\(to)f(appear\).)40 +b(Also)23 b(a)o(v)n(ailable)g(on)h(WWW)d(at)i(URL)f(http://www)-5 +b(.cs.umn.edu/\230karypis.)23 b(A)g(short)g(v)o(ersion)166 +3255 y(appears)d(in)f(Intl.)f(Conf.)h(on)g(P)o(arallel)f(Processing)h +(1995.)37 3372 y([9])42 b(Geor)o(ge)21 b(Karypis,)f(Rajat)g(Aggarw)o +(al,)h(V)l(ipin)f(K)o(umar)m(,)g(and)i(Shashi)e(Shekhar)l(.)32 +b(Multile)n(v)o(el)20 b(hyper)o(graph)i(partitioning:)27 +b(Application)21 b(in)f(vlsi)166 3473 y(domain.)28 b(In)19 +b FJ(Pr)m(oceedings)g(of)g(the)g(Design)h(and)f(A)o(utomation)g(Confer) +m(ence)p FK(,)h(1997.)0 3590 y([10])42 b(V)l(ipin)19 +b(K)o(umar)m(,)h(Ananth)g(Grama,)f(Anshul)i(Gupta,)e(and)i(Geor)o(ge)e +(Karypis.)30 b FJ(Intr)m(oduction)20 b(to)g(P)-6 b(ar)o(allel)19 +b(Computing:)25 b(Design)20 b(and)h(Analysis)166 3690 +y(of)e(Algorithms)p FK(.)27 b(Benjamin/Cummings)20 b(Publishing)f +(Compan)o(y)-5 b(,)20 b(Redw)o(ood)g(City)-5 b(,)19 b(CA,)f(1994.)1908 +5649 y FL(44)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/Metis/balance.c b/Metis/balance.c new file mode 100644 index 0000000000..b5fc3d50ea --- /dev/null +++ b/Metis/balance.c @@ -0,0 +1,278 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * balance.c + * + * This file contains code that is used to forcefully balance either + * bisections or k-sections + * + * Started 7/29/97 + * George + * + * $Id: balance.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function is the entry point of the bisection balancing algorithms. +**************************************************************************/ +void Balance2Way(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, j, nvtxs, from, imax, gain, mindiff; + idxtype *id, *ed; + + /* Return right away if the balance is OK */ + mindiff = abs(tpwgts[0]-graph->pwgts[0]); + if (mindiff < 3*(graph->pwgts[0]+graph->pwgts[1])/graph->nvtxs) + return; + if (graph->pwgts[0] > tpwgts[0] && graph->pwgts[0] < (int)(ubfactor*tpwgts[0])) + return; + if (graph->pwgts[1] > tpwgts[1] && graph->pwgts[1] < (int)(ubfactor*tpwgts[1])) + return; + + if (graph->nbnd > 0) + Bnd2WayBalance(ctrl, graph, tpwgts); + else + General2WayBalance(ctrl, graph, tpwgts); + +} + + + +/************************************************************************* +* This function balances two partitions by moving boundary nodes +* from the domain that is overweight to the one that is underweight. +**************************************************************************/ +void Bnd2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts) +{ + int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; + idxtype *moved, *perm; + PQueueType parts; + int higain, oldgain, mincut, mindiff; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + pwgts = graph->pwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + /* Determine from which domain you will be moving data */ + mindiff = abs(tpwgts[0]-pwgts[0]); + from = (pwgts[0] < tpwgts[0] ? 1 : 0); + to = (from+1)%2; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n", + pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; + PQueueInit(ctrl, &parts, nvtxs, tmp); + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert the boundary nodes of the proper partition whose size is OK in the priority queue */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = perm[ii]; + ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0); + ASSERT(bndptr[bndind[i]] != -1); + if (where[bndind[i]] == from && vwgt[bndind[i]] <= mindiff) + PQueueInsert(&parts, bndind[i], ed[bndind[i]]-id[bndind[i]]); + } + + mincut = graph->mincut; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if ((higain = PQueueGetMax(&parts)) == -1) + break; + ASSERT(bndptr[higain] != -1); + + if (pwgts[to]+vwgt[higain] > tpwgts[to]) + break; + + mincut -= (ed[higain]-id[higain]); + INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); + + where[higain] = to; + moved[higain] = nswaps; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1])); + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) /* Remove it if in the queues */ + PQueueDelete(&parts, k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) + PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) + PQueueInsert(&parts, k, ed[k]-id[k]); + } + } + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function balances two partitions by moving the highest gain +* (including negative gain) vertices to the other domain. +* It is used only when tha unbalance is due to non contigous +* subdomains. That is, the are no boundary vertices. +* It moves vertices from the domain that is overweight to the one that +* is underweight. +**************************************************************************/ +void General2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts) +{ + int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; + idxtype *moved, *perm; + PQueueType parts; + int higain, oldgain, mincut, mindiff; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + pwgts = graph->pwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + /* Determine from which domain you will be moving data */ + mindiff = abs(tpwgts[0]-pwgts[0]); + from = (pwgts[0] < tpwgts[0] ? 1 : 0); + to = (from+1)%2; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n", + pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; + PQueueInit(ctrl, &parts, nvtxs, tmp); + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert the nodes of the proper partition whose size is OK in the priority queue */ + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (where[i] == from && vwgt[i] <= mindiff) + PQueueInsert(&parts, i, ed[i]-id[i]); + } + + mincut = graph->mincut; + nbnd = graph->nbnd; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if ((higain = PQueueGetMax(&parts)) == -1) + break; + + if (pwgts[to]+vwgt[higain] > tpwgts[to]) + break; + + mincut -= (ed[higain]-id[higain]); + INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); + + where[higain] = to; + moved[higain] = nswaps; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1])); + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) + PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]); + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} diff --git a/Metis/bucketsort.c b/Metis/bucketsort.c new file mode 100644 index 0000000000..8f44b66bb9 --- /dev/null +++ b/Metis/bucketsort.c @@ -0,0 +1,43 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * bucketsort.c + * + * This file contains code that implement a variety of counting sorting + * algorithms + * + * Started 7/25/97 + * George + * + * $Id: bucketsort.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function uses simple counting sort to return a permutation array +* corresponding to the sorted order. The keys are assumed to start from +* 0 and they are positive. This sorting is used during matching. +**************************************************************************/ +void BucketSortKeysInc(int n, int max, idxtype *keys, idxtype *tperm, idxtype *perm) +{ + int i, ii; + idxtype *counts; + + counts = idxsmalloc(max+2, 0, "BucketSortKeysInc: counts"); + + for (i=0; i<n; i++) + counts[keys[i]]++; + MAKECSR(i, max+1, counts); + + for (ii=0; ii<n; ii++) { + i = tperm[ii]; + perm[counts[keys[i]]++] = i; + } + + free(counts); +} + diff --git a/Metis/ccgraph.c b/Metis/ccgraph.c new file mode 100644 index 0000000000..b1def86912 --- /dev/null +++ b/Metis/ccgraph.c @@ -0,0 +1,599 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * ccgraph.c + * + * This file contains the functions that create the coarse graph + * + * Started 8/11/97 + * George + * + * $Id: ccgraph.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function creates the coarser graph +**************************************************************************/ +void CreateCoarseGraph(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm) +{ + int i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask, dovsize; + idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj; + idxtype *cmap, *htable; + idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum; + float *nvwgt, *cnvwgt; + GraphType *cgraph; + + dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0); + + mask = HTLENGTH; + if (cnvtxs < 8*mask || graph->nedges/graph->nvtxs > 15) { + CreateCoarseGraphNoMask(ctrl, graph, cnvtxs, match, perm); + return; + } + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + vsize = graph->vsize; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + cmap = graph->cmap; + + /* Initialize the coarser graph */ + cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cvsize = cgraph->vsize; + cnvwgt = cgraph->nvwgt; + cadjwgtsum = cgraph->adjwgtsum; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + + iend = xadj[nvtxs]; + auxadj = ctrl->wspace.auxcore; + memcpy(auxadj, adjncy, iend*sizeof(idxtype)); + for (i=0; i<iend; i++) + auxadj[i] = cmap[auxadj[i]]; + + htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1)); + + cxadj[0] = cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + u = match[v]; + if (ncon == 1) + cvwgt[cnvtxs] = vwgt[v]; + else + scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon); + + if (dovsize) + cvsize[cnvtxs] = vsize[v]; + + cadjwgtsum[cnvtxs] = adjwgtsum[v]; + nedges = 0; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m] += adjwgt[j]; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj] += adjwgt[j]; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = adjwgt[j]; + } + } + } + + if (v != u) { + if (ncon == 1) + cvwgt[cnvtxs] += vwgt[u]; + else + saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1); + + if (dovsize) + cvsize[cnvtxs] += vsize[u]; + + cadjwgtsum[cnvtxs] += adjwgtsum[u]; + + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m] += adjwgt[j]; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj] += adjwgt[j]; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = adjwgt[j]; + } + } + } + + /* Remove the contracted adjacency weight */ + jj = htable[cnvtxs&mask]; + if (jj >= 0 && cadjncy[jj] != cnvtxs) { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == cnvtxs) + break; + } + } + if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */ + cadjwgtsum[cnvtxs] -= cadjwgt[jj]; + cadjncy[jj] = cadjncy[--nedges]; + cadjwgt[jj] = cadjwgt[nedges]; + } + } + + ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v])); + + for (j=0; j<nedges; j++) + htable[cadjncy[j]&mask] = -1; /* Zero out the htable */ + htable[cnvtxs&mask] = -1; + + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + cadjncy += nedges; + cadjwgt += nedges; + } + + cgraph->nedges = cnedges; + + ReAdjustMemory(graph, cgraph, dovsize); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr)); + + idxwspacefree(ctrl, mask+1); + +} + + +/************************************************************************* +* This function creates the coarser graph +**************************************************************************/ +void CreateCoarseGraphNoMask(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm) +{ + int i, j, k, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, dovsize; + idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj; + idxtype *cmap, *htable; + idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum; + float *nvwgt, *cnvwgt; + GraphType *cgraph; + + dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + vsize = graph->vsize; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + cmap = graph->cmap; + + + /* Initialize the coarser graph */ + cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cvsize = cgraph->vsize; + cnvwgt = cgraph->nvwgt; + cadjwgtsum = cgraph->adjwgtsum; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + + htable = idxset(cnvtxs, -1, idxwspacemalloc(ctrl, cnvtxs)); + + iend = xadj[nvtxs]; + auxadj = ctrl->wspace.auxcore; + memcpy(auxadj, adjncy, iend*sizeof(idxtype)); + for (i=0; i<iend; i++) + auxadj[i] = cmap[auxadj[i]]; + + cxadj[0] = cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + u = match[v]; + if (ncon == 1) + cvwgt[cnvtxs] = vwgt[v]; + else + scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon); + + if (dovsize) + cvsize[cnvtxs] = vsize[v]; + + cadjwgtsum[cnvtxs] = adjwgtsum[v]; + nedges = 0; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + if ((m = htable[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + if (v != u) { + if (ncon == 1) + cvwgt[cnvtxs] += vwgt[u]; + else + saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1); + + if (dovsize) + cvsize[cnvtxs] += vsize[u]; + + cadjwgtsum[cnvtxs] += adjwgtsum[u]; + + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + if ((m = htable[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + /* Remove the contracted adjacency weight */ + if ((j = htable[cnvtxs]) != -1) { + ASSERT(cadjncy[j] == cnvtxs); + cadjwgtsum[cnvtxs] -= cadjwgt[j]; + cadjncy[j] = cadjncy[--nedges]; + cadjwgt[j] = cadjwgt[nedges]; + htable[cnvtxs] = -1; + } + } + + ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d\n", cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt))); + + for (j=0; j<nedges; j++) + htable[cadjncy[j]] = -1; /* Zero out the htable */ + + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + cadjncy += nedges; + cadjwgt += nedges; + } + + cgraph->nedges = cnedges; + + ReAdjustMemory(graph, cgraph, dovsize); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr)); + + idxwspacefree(ctrl, cnvtxs); +} + + +/************************************************************************* +* This function creates the coarser graph +**************************************************************************/ +void CreateCoarseGraph_NVW(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm) +{ + int i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask; + idxtype *xadj, *adjncy, *adjwgtsum, *auxadj; + idxtype *cmap, *htable; + idxtype *cxadj, *cvwgt, *cadjncy, *cadjwgt, *cadjwgtsum; + float *nvwgt, *cnvwgt; + GraphType *cgraph; + + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgtsum = graph->adjwgtsum; + cmap = graph->cmap; + + /* Initialize the coarser graph */ + cgraph = SetUpCoarseGraph(graph, cnvtxs, 0); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cnvwgt = cgraph->nvwgt; + cadjwgtsum = cgraph->adjwgtsum; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + + iend = xadj[nvtxs]; + auxadj = ctrl->wspace.auxcore; + memcpy(auxadj, adjncy, iend*sizeof(idxtype)); + for (i=0; i<iend; i++) + auxadj[i] = cmap[auxadj[i]]; + + mask = HTLENGTH; + htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1)); + + cxadj[0] = cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + u = match[v]; + cvwgt[cnvtxs] = 1; + cadjwgtsum[cnvtxs] = adjwgtsum[v]; + nedges = 0; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = 1; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m]++; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj]++; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = 1; + } + } + } + + if (v != u) { + cvwgt[cnvtxs]++; + cadjwgtsum[cnvtxs] += adjwgtsum[u]; + + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = auxadj[j]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = 1; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m]++; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj]++; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = 1; + } + } + } + + /* Remove the contracted adjacency weight */ + jj = htable[cnvtxs&mask]; + if (jj >= 0 && cadjncy[jj] != cnvtxs) { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == cnvtxs) + break; + } + } + if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */ + cadjwgtsum[cnvtxs] -= cadjwgt[jj]; + cadjncy[jj] = cadjncy[--nedges]; + cadjwgt[jj] = cadjwgt[nedges]; + } + } + + ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v])); + + for (j=0; j<nedges; j++) + htable[cadjncy[j]&mask] = -1; /* Zero out the htable */ + htable[cnvtxs&mask] = -1; + + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + cadjncy += nedges; + cadjwgt += nedges; + } + + cgraph->nedges = cnedges; + + ReAdjustMemory(graph, cgraph, 0); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr)); + + idxwspacefree(ctrl, mask+1); + +} + + +/************************************************************************* +* Setup the various arrays for the coarse graph +**************************************************************************/ +GraphType *SetUpCoarseGraph(GraphType *graph, int cnvtxs, int dovsize) +{ + GraphType *cgraph; + + cgraph = CreateGraph(); + cgraph->nvtxs = cnvtxs; + cgraph->ncon = graph->ncon; + + cgraph->finer = graph; + graph->coarser = cgraph; + + + /* Allocate memory for the coarser graph */ + if (graph->ncon == 1) { + if (dovsize) { + cgraph->gdata = idxmalloc(5*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cnvtxs+1; + cgraph->vsize = cgraph->gdata + 2*cnvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 3*cnvtxs+1; + cgraph->cmap = cgraph->gdata + 4*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 5*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 5*cnvtxs+1 + graph->nedges; + } + else { + cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cnvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges; + } + } + else { + if (dovsize) { + cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->vsize = cgraph->gdata + cnvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges; + } + else { + cgraph->gdata = idxmalloc(3*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata"); + cgraph->xadj = cgraph->gdata; + cgraph->adjwgtsum = cgraph->gdata + cnvtxs+1; + cgraph->cmap = cgraph->gdata + 2*cnvtxs+1; + cgraph->adjncy = cgraph->gdata + 3*cnvtxs+1; + cgraph->adjwgt = cgraph->gdata + 3*cnvtxs+1 + graph->nedges; + } + + cgraph->nvwgt = fmalloc(graph->ncon*cnvtxs, "SetUpCoarseGraph: nvwgt"); + } + + return cgraph; +} + + +/************************************************************************* +* This function re-adjusts the amount of memory that was allocated if +* it will lead to significant savings +**************************************************************************/ +void ReAdjustMemory(GraphType *graph, GraphType *cgraph, int dovsize) +{ + + if (cgraph->nedges > 100000 && graph->nedges < 0.7*graph->nedges) { + idxcopy(cgraph->nedges, cgraph->adjwgt, cgraph->adjncy+cgraph->nedges); + + if (graph->ncon == 1) { + if (dovsize) { + cgraph->gdata = realloc(cgraph->gdata, (5*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1; + cgraph->vsize = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 4*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 5*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 5*cgraph->nvtxs+1 + cgraph->nedges; + } + else { + cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges; + } + } + else { + if (dovsize) { + cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->vsize = cgraph->gdata + cgraph->nvtxs+1; + cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges; + } + else { + cgraph->gdata = realloc(cgraph->gdata, (3*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype)); + + /* Do this, in case everything was copied into new space */ + cgraph->xadj = cgraph->gdata; + cgraph->adjwgtsum = cgraph->gdata + cgraph->nvtxs+1; + cgraph->cmap = cgraph->gdata + 2*cgraph->nvtxs+1; + cgraph->adjncy = cgraph->gdata + 3*cgraph->nvtxs+1; + cgraph->adjwgt = cgraph->gdata + 3*cgraph->nvtxs+1 + cgraph->nedges; + } + } + } + +} diff --git a/Metis/coarsen.c b/Metis/coarsen.c new file mode 100644 index 0000000000..904cb28522 --- /dev/null +++ b/Metis/coarsen.c @@ -0,0 +1,83 @@ +/* + * coarsen.c + * + * This file contains the driving routines for the coarsening process + * + * Started 7/23/97 + * George + * + * $Id: coarsen.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function takes a graph and creates a sequence of coarser graphs +**************************************************************************/ +GraphType *Coarsen2Way(CtrlType *ctrl, GraphType *graph) +{ + int clevel; + GraphType *cgraph; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr)); + + cgraph = graph; + + /* The following is ahack to allow the multiple bisections to go through with correct + coarsening */ + if (ctrl->CType > 20) { + clevel = 1; + ctrl->CType -= 20; + } + else + clevel = 0; + + do { + IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n", + cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt, + (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs))); + + if (cgraph->adjwgt) { + switch (ctrl->CType) { + case MATCH_RM: + Match_RM(ctrl, cgraph); + break; + case MATCH_HEM: + if (clevel < 1) + Match_RM(ctrl, cgraph); + else + Match_HEM(ctrl, cgraph); + break; + case MATCH_SHEM: + if (clevel < 1) + Match_RM(ctrl, cgraph); + else + Match_SHEM(ctrl, cgraph); + break; + case MATCH_SHEMKWAY: + Match_SHEM(ctrl, cgraph); + break; + default: + errexit("Unknown CType: %d\n", ctrl->CType); + } + } + else { + Match_RM_NVW(ctrl, cgraph); + } + + cgraph = cgraph->coarser; + clevel++; + + } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2); + + IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n", + cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt, + (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs))); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr)); + + return cgraph; +} + diff --git a/Metis/compress.c b/Metis/compress.c new file mode 100644 index 0000000000..11ff2926c9 --- /dev/null +++ b/Metis/compress.c @@ -0,0 +1,256 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * compress.c + * + * This file contains code for compressing nodes with identical adjacency + * structure and for prunning dense columns + * + * Started 9/17/97 + * George + * + * $Id: compress.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + +/************************************************************************* +* This function compresses a graph by merging identical vertices +* The compression should lead to at least 10% reduction. +**************************************************************************/ +void CompressGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *cptr, idxtype *cind) +{ + int i, ii, iii, j, jj, k, l, cnvtxs, cnedges; + idxtype *cxadj, *cadjncy, *cvwgt, *mark, *map; + KeyValueType *keys; + + mark = idxsmalloc(nvtxs, -1, "CompressGraph: mark"); + map = idxsmalloc(nvtxs, -1, "CompressGraph: map"); + keys = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "CompressGraph: keys"); + + /* Compute a key for each adjacency list */ + for (i=0; i<nvtxs; i++) { + k = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + k += adjncy[j]; + keys[i].key = k+i; /* Add the diagonal entry as well */ + keys[i].val = i; + } + + ikeysort(nvtxs, keys); + + l = cptr[0] = 0; + for (cnvtxs=i=0; i<nvtxs; i++) { + ii = keys[i].val; + if (map[ii] == -1) { + mark[ii] = i; /* Add the diagonal entry */ + for (j=xadj[ii]; j<xadj[ii+1]; j++) + mark[adjncy[j]] = i; + + cind[l++] = ii; + map[ii] = cnvtxs; + + for (j=i+1; j<nvtxs; j++) { + iii = keys[j].val; + + if (keys[i].key != keys[j].key || xadj[ii+1]-xadj[ii] != xadj[iii+1]-xadj[iii]) + break; /* Break if keys or degrees are different */ + + if (map[iii] == -1) { /* Do a comparison if iii has not been mapped */ + for (jj=xadj[iii]; jj<xadj[iii+1]; jj++) { + if (mark[adjncy[jj]] != i) + break; + } + + if (jj == xadj[iii+1]) { /* Identical adjacency structure */ + map[iii] = cnvtxs; + cind[l++] = iii; + } + } + } + + cptr[++cnvtxs] = l; + } + } + + /* printf("Original: %6d, Compressed: %6d\n", nvtxs, cnvtxs); */ + + + InitGraph(graph); + + if (cnvtxs >= COMPRESSION_FRACTION*nvtxs) { + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = 1; + graph->xadj = xadj; + graph->adjncy = adjncy; + + graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata"); + graph->vwgt = graph->gdata; + graph->adjwgtsum = graph->gdata+nvtxs; + graph->cmap = graph->gdata+2*nvtxs; + graph->adjwgt = graph->gdata+3*nvtxs; + + idxset(nvtxs, 1, graph->vwgt); + idxset(graph->nedges, 1, graph->adjwgt); + for (i=0; i<nvtxs; i++) + graph->adjwgtsum[i] = xadj[i+1]-xadj[i]; + + graph->label = idxmalloc(nvtxs, "CompressGraph: label"); + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + else { /* Ok, form the compressed graph */ + cnedges = 0; + for (i=0; i<cnvtxs; i++) { + ii = cind[cptr[i]]; + cnedges += xadj[ii+1]-xadj[ii]; + } + + /* Allocate memory for the compressed graph*/ + graph->gdata = idxmalloc(4*cnvtxs+1 + 2*cnedges, "CompressGraph: gdata"); + cxadj = graph->xadj = graph->gdata; + cvwgt = graph->vwgt = graph->gdata + cnvtxs+1; + graph->adjwgtsum = graph->gdata + 2*cnvtxs+1; + graph->cmap = graph->gdata + 3*cnvtxs+1; + cadjncy = graph->adjncy = graph->gdata + 4*cnvtxs+1; + graph->adjwgt = graph->gdata + 4*cnvtxs+1 + cnedges; + + /* Now go and compress the graph */ + idxset(nvtxs, -1, mark); + l = cxadj[0] = 0; + for (i=0; i<cnvtxs; i++) { + cvwgt[i] = cptr[i+1]-cptr[i]; + mark[i] = i; /* Remove any dioganal entries in the compressed graph */ + for (j=cptr[i]; j<cptr[i+1]; j++) { + ii = cind[j]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + k = map[adjncy[jj]]; + if (mark[k] != i) + cadjncy[l++] = k; + mark[k] = i; + } + } + cxadj[i+1] = l; + } + + graph->nvtxs = cnvtxs; + graph->nedges = l; + graph->ncon = 1; + + idxset(graph->nedges, 1, graph->adjwgt); + for (i=0; i<cnvtxs; i++) + graph->adjwgtsum[i] = cxadj[i+1]-cxadj[i]; + + graph->label = idxmalloc(cnvtxs, "CompressGraph: label"); + for (i=0; i<cnvtxs; i++) + graph->label[i] = i; + + } + + GKfree(&keys, &map, &mark, LTERM); +} + + + +/************************************************************************* +* This function prunes all the vertices in a graph with degree greater +* than factor*average +**************************************************************************/ +void PruneGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *iperm, float factor) +{ + int i, j, k, l, nlarge, pnvtxs, pnedges; + idxtype *pxadj, *padjncy, *padjwgt, *pvwgt; + idxtype *perm; + + perm = idxmalloc(nvtxs, "PruneGraph: perm"); + + factor = factor*xadj[nvtxs]/nvtxs; + + pnvtxs = pnedges = nlarge = 0; + for (i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] < factor) { + perm[i] = pnvtxs; + iperm[pnvtxs++] = i; + pnedges += xadj[i+1]-xadj[i]; + } + else { + perm[i] = nvtxs - ++nlarge; + iperm[nvtxs-nlarge] = i; + } + } + + /* printf("Pruned %d vertices\n", nlarge); */ + + InitGraph(graph); + + if (nlarge == 0) { /* No prunning */ + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = 1; + graph->xadj = xadj; + graph->adjncy = adjncy; + + graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata"); + graph->vwgt = graph->gdata; + graph->adjwgtsum = graph->gdata+nvtxs; + graph->cmap = graph->gdata+2*nvtxs; + graph->adjwgt = graph->gdata+3*nvtxs; + + idxset(nvtxs, 1, graph->vwgt); + idxset(graph->nedges, 1, graph->adjwgt); + for (i=0; i<nvtxs; i++) + graph->adjwgtsum[i] = xadj[i+1]-xadj[i]; + + graph->label = idxmalloc(nvtxs, "CompressGraph: label"); + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + else { /* Prune the graph */ + /* Allocate memory for the compressed graph*/ + graph->gdata = idxmalloc(4*pnvtxs+1 + 2*pnedges, "PruneGraph: gdata"); + pxadj = graph->xadj = graph->gdata; + graph->vwgt = graph->gdata + pnvtxs+1; + graph->adjwgtsum = graph->gdata + 2*pnvtxs+1; + graph->cmap = graph->gdata + 3*pnvtxs+1; + padjncy = graph->adjncy = graph->gdata + 4*pnvtxs+1; + graph->adjwgt = graph->gdata + 4*pnvtxs+1 + pnedges; + + pxadj[0] = pnedges = l = 0; + for (i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] < factor) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = perm[adjncy[j]]; + if (k < pnvtxs) + padjncy[pnedges++] = k; + } + pxadj[++l] = pnedges; + } + } + + graph->nvtxs = pnvtxs; + graph->nedges = pnedges; + graph->ncon = 1; + + idxset(pnvtxs, 1, graph->vwgt); + idxset(pnedges, 1, graph->adjwgt); + for (i=0; i<pnvtxs; i++) + graph->adjwgtsum[i] = pxadj[i+1]-pxadj[i]; + + graph->label = idxmalloc(pnvtxs, "CompressGraph: label"); + for (i=0; i<pnvtxs; i++) + graph->label[i] = i; + } + + free(perm); + +} + + + + + + + + + diff --git a/Metis/debug.c b/Metis/debug.c new file mode 100644 index 0000000000..17f19e31f4 --- /dev/null +++ b/Metis/debug.c @@ -0,0 +1,239 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * debug.c + * + * This file contains code that performs self debuging + * + * Started 7/24/97 + * George + * + * $Id: debug.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the cut given the graph and a where vector +**************************************************************************/ +int ComputeCut(GraphType *graph, idxtype *where) +{ + int i, j, cut; + + if (graph->adjwgt == NULL) { + for (cut=0, i=0; i<graph->nvtxs; i++) { + for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) + if (where[i] != where[graph->adjncy[j]]) + cut++; + } + } + else { + for (cut=0, i=0; i<graph->nvtxs; i++) { + for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) + if (where[i] != where[graph->adjncy[j]]) + cut += graph->adjwgt[j]; + } + } + + return cut/2; +} + + +/************************************************************************* +* This function checks whether or not the boundary information is correct +**************************************************************************/ +int CheckBnd(GraphType *graph) +{ + int i, j, nvtxs, nbnd; + idxtype *xadj, *adjncy, *where, *bndptr, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + for (nbnd=0, i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] == 0) + nbnd++; /* Islands are considered to be boundary vertices */ + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) { + nbnd++; + ASSERT(bndptr[i] != -1); + ASSERT(bndind[bndptr[i]] == i); + break; + } + } + } + + ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd)); + + return 1; +} + + + +/************************************************************************* +* This function checks whether or not the boundary information is correct +**************************************************************************/ +int CheckBnd2(GraphType *graph) +{ + int i, j, nvtxs, nbnd, id, ed; + idxtype *xadj, *adjncy, *where, *bndptr, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + for (nbnd=0, i=0; i<nvtxs; i++) { + id = ed = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) + ed += graph->adjwgt[j]; + else + id += graph->adjwgt[j]; + } + if (ed - id >= 0 && xadj[i] < xadj[i+1]) { + nbnd++; + ASSERTP(bndptr[i] != -1, ("%d %d %d\n", i, id, ed)); + ASSERT(bndind[bndptr[i]] == i); + } + } + + ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd)); + + return 1; +} + +/************************************************************************* +* This function checks whether or not the boundary information is correct +**************************************************************************/ +int CheckNodeBnd(GraphType *graph, int onbnd) +{ + int i, j, nvtxs, nbnd; + idxtype *xadj, *adjncy, *where, *bndptr, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + for (nbnd=0, i=0; i<nvtxs; i++) { + if (where[i] == 2) + nbnd++; + } + + ASSERTP(nbnd == onbnd, ("%d %d\n", nbnd, onbnd)); + + for (i=0; i<nvtxs; i++) { + if (where[i] != 2) { + ASSERTP(bndptr[i] == -1, ("%d %d\n", i, bndptr[i])); + } + else { + ASSERTP(bndptr[i] != -1, ("%d %d\n", i, bndptr[i])); + } + } + + return 1; +} + + + +/************************************************************************* +* This function checks whether or not the rinfo of a vertex is consistent +**************************************************************************/ +int CheckRInfo(RInfoType *rinfo) +{ + int i, j; + + for (i=0; i<rinfo->ndegrees; i++) { + for (j=i+1; j<rinfo->ndegrees; j++) + ASSERTP(rinfo->edegrees[i].pid != rinfo->edegrees[j].pid, ("%d %d %d %d\n", i, j, rinfo->edegrees[i].pid, rinfo->edegrees[j].pid)); + } + + return 1; +} + + + +/************************************************************************* +* This function checks the correctness of the NodeFM data structures +**************************************************************************/ +int CheckNodePartitionParams(GraphType *graph) +{ + int i, j, k, l, nvtxs, me, other; + idxtype *xadj, *adjncy, *adjwgt, *vwgt, *where; + idxtype edegrees[2], pwgts[3]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + + /*------------------------------------------------------------ + / Compute now the separator external degrees + /------------------------------------------------------------*/ + pwgts[0] = pwgts[1] = pwgts[2] = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + if (me == 2) { /* If it is on the separator do some computations */ + edegrees[0] = edegrees[1] = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (other != 2) + edegrees[other] += vwgt[adjncy[j]]; + } + if (edegrees[0] != graph->nrinfo[i].edegrees[0] || edegrees[1] != graph->nrinfo[i].edegrees[1]) { + printf("Something wrong with edegrees: %d %d %d %d %d\n", i, edegrees[0], edegrees[1], graph->nrinfo[i].edegrees[0], graph->nrinfo[i].edegrees[1]); + return 0; + } + } + } + + if (pwgts[0] != graph->pwgts[0] || pwgts[1] != graph->pwgts[1] || pwgts[2] != graph->pwgts[2]) + printf("Something wrong with part-weights: %d %d %d %d %d %d\n", pwgts[0], pwgts[1], pwgts[2], graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]); + + return 1; +} + + +/************************************************************************* +* This function checks if the separator is indeed a separator +**************************************************************************/ +int IsSeparable(GraphType *graph) +{ + int i, j, nvtxs, other; + idxtype *xadj, *adjncy, *where; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + for (i=0; i<nvtxs; i++) { + if (where[i] == 2) + continue; + other = (where[i]+1)%2; + for (j=xadj[i]; j<xadj[i+1]; j++) { + ASSERTP(where[adjncy[j]] != other, ("%d %d %d %d %d %d\n", i, where[i], adjncy[j], where[adjncy[j]], xadj[i+1]-xadj[i], xadj[adjncy[j]+1]-xadj[adjncy[j]])); + } + } + + return 1; +} + + diff --git a/Metis/defs.h b/Metis/defs.h new file mode 100644 index 0000000000..7696998e61 --- /dev/null +++ b/Metis/defs.h @@ -0,0 +1,161 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * defs.h + * + * This file contains constant definitions + * + * Started 8/27/94 + * George + * + * $Id: defs.h,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#define METISTITLE " METIS 4.0.1 Copyright 1998, Regents of the University of Minnesota\n\n" +#define MAXLINE 1280000 + +#define LTERM (void **) 0 /* List terminator for GKfree() */ + +#define MAXNCON 16 /* The maximum number of constrains */ +#define MAXNOBJ 16 /* The maximum number of objectives */ + +#define PLUS_GAINSPAN 500 /* Parameters for FM buckets */ +#define NEG_GAINSPAN 500 + +#define HTLENGTH ((1<<11)-1) + +/* Meaning of various options[] parameters */ +#define OPTION_PTYPE 0 +#define OPTION_CTYPE 1 +#define OPTION_ITYPE 2 +#define OPTION_RTYPE 3 +#define OPTION_DBGLVL 4 +#define OPTION_OFLAGS 5 +#define OPTION_PFACTOR 6 +#define OPTION_NSEPS 7 + +#define OFLAG_COMPRESS 1 /* Try to compress the graph */ +#define OFLAG_CCMP 2 /* Find and order connected components */ + + +/* Default options for PMETIS */ +#define PMETIS_CTYPE MATCH_SHEM +#define PMETIS_ITYPE IPART_GGPKL +#define PMETIS_RTYPE RTYPE_FM +#define PMETIS_DBGLVL 0 + +/* Default options for KMETIS */ +#define KMETIS_CTYPE MATCH_SHEM +#define KMETIS_ITYPE IPART_PMETIS +#define KMETIS_RTYPE RTYPE_KWAYRANDOM_MCONN +#define KMETIS_DBGLVL 0 + +/* Default options for OEMETIS */ +#define OEMETIS_CTYPE MATCH_SHEM +#define OEMETIS_ITYPE IPART_GGPKL +#define OEMETIS_RTYPE RTYPE_FM +#define OEMETIS_DBGLVL 0 + +/* Default options for ONMETIS */ +#define ONMETIS_CTYPE MATCH_SHEM +#define ONMETIS_ITYPE IPART_GGPKL +#define ONMETIS_RTYPE RTYPE_SEP1SIDED +#define ONMETIS_DBGLVL 0 +#define ONMETIS_OFLAGS OFLAG_COMPRESS +#define ONMETIS_PFACTOR -1 +#define ONMETIS_NSEPS 1 + +/* Default options for McPMETIS */ +#define McPMETIS_CTYPE MATCH_SHEBM_ONENORM +#define McPMETIS_ITYPE IPART_RANDOM +#define McPMETIS_RTYPE RTYPE_FM +#define McPMETIS_DBGLVL 0 + +/* Default options for McKMETIS */ +#define McKMETIS_CTYPE MATCH_SHEBM_ONENORM +#define McKMETIS_ITYPE IPART_McHPMETIS +#define McKMETIS_RTYPE RTYPE_KWAYRANDOM +#define McKMETIS_DBGLVL 0 + +/* Default options for KVMETIS */ +#define KVMETIS_CTYPE MATCH_SHEM +#define KVMETIS_ITYPE IPART_PMETIS +#define KVMETIS_RTYPE RTYPE_KWAYRANDOM +#define KVMETIS_DBGLVL 0 + + +/* Operations supported by stand-alone code */ +#define OP_PMETIS 1 +#define OP_KMETIS 2 +#define OP_OEMETIS 3 +#define OP_ONMETIS 4 +#define OP_ONWMETIS 5 +#define OP_KVMETIS 6 + + +/* Matching Schemes */ +#define MATCH_RM 1 +#define MATCH_HEM 2 +#define MATCH_SHEM 3 +#define MATCH_SHEMKWAY 4 +#define MATCH_SHEBM_ONENORM 5 +#define MATCH_SHEBM_INFNORM 6 +#define MATCH_SBHEM_ONENORM 7 +#define MATCH_SBHEM_INFNORM 8 + +/* Initial partitioning schemes for PMETIS and ONMETIS */ +#define IPART_GGPKL 1 +#define IPART_GGPKLNODE 2 +#define IPART_RANDOM 2 + +/* Refinement schemes for PMETIS */ +#define RTYPE_FM 1 + +/* Initial partitioning schemes for KMETIS */ +#define IPART_PMETIS 1 + +/* Refinement schemes for KMETIS */ +#define RTYPE_KWAYRANDOM 1 +#define RTYPE_KWAYGREEDY 2 +#define RTYPE_KWAYRANDOM_MCONN 3 + +/* Refinement schemes for ONMETIS */ +#define RTYPE_SEP2SIDED 1 +#define RTYPE_SEP1SIDED 2 + +/* Initial Partitioning Schemes for McKMETIS */ +#define IPART_McPMETIS 1 /* Simple McPMETIS */ +#define IPART_McHPMETIS 2 /* horizontally relaxed McPMETIS */ + +#define UNMATCHED -1 + +#define HTABLE_EMPTY -1 + +#define NGR_PASSES 4 /* Number of greedy refinement passes */ +#define NLGR_PASSES 5 /* Number of GR refinement during IPartition */ + +#define LARGENIPARTS 8 /* Number of random initial partitions */ +#define SMALLNIPARTS 3 /* Number of random initial partitions */ + +#define COARSEN_FRACTION 0.75 /* Node reduction between succesive coarsening levels */ +#define COARSEN_FRACTION2 0.90 /* Node reduction between succesive coarsening levels */ +#define UNBALANCE_FRACTION 1.05 + +#define COMPRESSION_FRACTION 0.85 + +#define ORDER_UNBALANCE_FRACTION 1.10 + +#define MMDSWITCH 200 + +#define HORIZONTAL_IMBALANCE 1.05 + +/* Debug Levels */ +#define DBG_TIME 1 /* Perform timing analysis */ +#define DBG_OUTPUT 2 +#define DBG_COARSEN 4 /* Show the coarsening progress */ +#define DBG_REFINE 8 /* Show info on communication during folding */ +#define DBG_IPART 16 /* Show info on initial partition */ +#define DBG_MOVEINFO 32 /* Show info on communication during folding */ +#define DBG_KWAYPINFO 64 /* Show info on communication during folding */ +#define DBG_SEPINFO 128 /* Show info on communication during folding */ diff --git a/Metis/estmem.c b/Metis/estmem.c new file mode 100644 index 0000000000..576d0b645f --- /dev/null +++ b/Metis/estmem.c @@ -0,0 +1,157 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * estmem.c + * + * This file contains code for estimating the amount of memory required by + * the various routines in METIS + * + * Started 11/4/97 + * George + * + * $Id: estmem.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes how much memory will be required by the various +* routines in METIS +**************************************************************************/ +void METIS_EstimateMemory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + int i, j, k, nedges, nlevels; + float vfraction, efraction, vmult, emult; + int coresize, gdata, rdata; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + nedges = xadj[*nvtxs]; + + InitRandom(-1); + EstimateCFraction(*nvtxs, xadj, adjncy, &vfraction, &efraction); + + /* Estimate the amount of memory for coresize */ + if (*optype == 2) + coresize = nedges; + else + coresize = 0; + coresize += nedges + 11*(*nvtxs) + 4*1024 + 2*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)); + coresize += 2*(*nvtxs); /* add some more fore other vectors */ + + gdata = nedges; /* Assume that the user does not pass weights */ + + nlevels = (int)(log(100.0/(*nvtxs))/log(vfraction) + .5); + vmult = 0.5 + (1.0 - pow(vfraction, nlevels))/(1.0 - vfraction); + emult = 1.0 + (1.0 - pow(efraction, nlevels+1))/(1.0 - efraction); + + gdata += vmult*4*(*nvtxs) + emult*2*nedges; + if ((vmult-1.0)*4*(*nvtxs) + (emult-1.0)*2*nedges < 5*(*nvtxs)) + rdata = 0; + else + rdata = 5*(*nvtxs); + + *nbytes = sizeof(idxtype)*(coresize+gdata+rdata+(*nvtxs)); + + if (*numflag == 1) + Change2FNumbering2(*nvtxs, xadj, adjncy); +} + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void EstimateCFraction(int nvtxs, idxtype *xadj, idxtype *adjncy, float *vfraction, float *efraction) +{ + int i, ii, j, cnvtxs, cnedges, maxidx; + idxtype *match, *cmap, *perm; + + cmap = idxmalloc(nvtxs, "cmap"); + match = idxsmalloc(nvtxs, UNMATCHED, "match"); + perm = idxmalloc(nvtxs, "perm"); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED) { + maxidx = adjncy[j]; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + cnedges = ComputeCoarseGraphSize(nvtxs, xadj, adjncy, cnvtxs, cmap, match, perm); + + *vfraction = (1.0*cnvtxs)/(1.0*nvtxs); + *efraction = (1.0*cnedges)/(1.0*xadj[nvtxs]); + + GKfree(&cmap, &match, &perm, LTERM); +} + + + + +/************************************************************************* +* This function computes the size of the coarse graph +**************************************************************************/ +int ComputeCoarseGraphSize(int nvtxs, idxtype *xadj, idxtype *adjncy, int cnvtxs, idxtype *cmap, idxtype *match, idxtype *perm) +{ + int i, j, k, istart, iend, nedges, cnedges, v, u; + idxtype *htable; + + htable = idxsmalloc(cnvtxs, -1, "htable"); + + cnvtxs = cnedges = 0; + for (i=0; i<nvtxs; i++) { + v = perm[i]; + if (cmap[v] != cnvtxs) + continue; + + htable[cnvtxs] = cnvtxs; + + u = match[v]; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if (htable[k] != cnvtxs) { + htable[k] = cnvtxs; + cnedges++; + } + } + + if (v != u) { + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if (htable[k] != cnvtxs) { + htable[k] = cnvtxs; + cnedges++; + } + } + } + cnvtxs++; + } + + GKfree(&htable, LTERM); + + return cnedges; +} + + diff --git a/Metis/fm.c b/Metis/fm.c new file mode 100644 index 0000000000..341d2b4f73 --- /dev/null +++ b/Metis/fm.c @@ -0,0 +1,194 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * fm.c + * + * This file contains code that implements the edge-based FM refinement + * + * Started 7/23/97 + * George + * + * $Id: fm.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void FM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, int *tpwgts, int npasses) +{ + int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, limit, tmp; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; + idxtype *moved, *swaps, *perm; + PQueueType parts[2]; + int higain, oldgain, mincut, mindiff, origdiff, initcut, newcut, mincutorder, avgvwgt; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + pwgts = graph->pwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + avgvwgt = amin((pwgts[0]+pwgts[1])/20, 2*(pwgts[0]+pwgts[1])/nvtxs); + + tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; + PQueueInit(ctrl, &parts[0], nvtxs, tmp); + PQueueInit(ctrl, &parts[1], nvtxs, tmp); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d\n", + pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + origdiff = abs(tpwgts[0]-pwgts[0]); + idxset(nvtxs, -1, moved); + for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + newcut = mincut = initcut = graph->mincut; + mindiff = abs(tpwgts[0]-pwgts[0]); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert boundary nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = perm[ii]; + ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0); + ASSERT(bndptr[bndind[i]] != -1); + PQueueInsert(&parts[where[bndind[i]]], bndind[i], ed[bndind[i]]-id[bndind[i]]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + from = (tpwgts[0]-pwgts[0] < tpwgts[1]-pwgts[1] ? 0 : 1); + to = (from+1)%2; + + if ((higain = PQueueGetMax(&parts[from])) == -1) + break; + ASSERT(bndptr[higain] != -1); + + newcut -= (ed[higain]-id[higain]); + INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); + + if ((newcut < mincut && abs(tpwgts[0]-pwgts[0]) <= origdiff+avgvwgt) || + (newcut == mincut && abs(tpwgts[0]-pwgts[0]) < mindiff)) { + mincut = newcut; + mindiff = abs(tpwgts[0]-pwgts[0]); + mincutorder = nswaps; + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + INC_DEC(pwgts[from], pwgts[to], vwgt[higain]); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], newcut, pwgts[0], pwgts[1])); + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1) /* Remove it if in the queues */ + PQueueDelete(&parts[where[k]], k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1) + PQueueUpdate(&parts[where[k]], k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1) + PQueueInsert(&parts[where[k]], k, ed[k]-id[k]); + } + } + } + + } + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + INC_DEC(pwgts[to], pwgts[(to+1)%2], vwgt[higain]); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum cut: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut == initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + diff --git a/Metis/fortran.c b/Metis/fortran.c new file mode 100644 index 0000000000..7d84eae989 --- /dev/null +++ b/Metis/fortran.c @@ -0,0 +1,141 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * fortran.c + * + * This file contains code for the fortran to C interface + * + * Started 8/19/97 + * George + * + * $Id: fortran.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function changes the numbering to start from 0 instead of 1 +**************************************************************************/ +void Change2CNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i, nedges; + + for (i=0; i<=nvtxs; i++) + xadj[i]--; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]--; +} + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void Change2FNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vector) +{ + int i, nedges; + + for (i=0; i<nvtxs; i++) + vector[i]++; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; +} + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void Change2FNumbering2(int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i, nedges; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; +} + + + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void Change2FNumberingOrder(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *v1, idxtype *v2) +{ + int i, nedges; + + for (i=0; i<nvtxs; i++) { + v1[i]++; + v2[i]++; + } + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; + +} + + + +/************************************************************************* +* This function changes the numbering to start from 0 instead of 1 +**************************************************************************/ +void ChangeMesh2CNumbering(int n, idxtype *mesh) +{ + int i; + + for (i=0; i<n; i++) + mesh[i]--; + +} + + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void ChangeMesh2FNumbering(int n, idxtype *mesh, int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i, nedges; + + for (i=0; i<n; i++) + mesh[i]++; + + nedges = xadj[nvtxs]; + for (i=0; i<nedges; i++) + adjncy[i]++; + + for (i=0; i<=nvtxs; i++) + xadj[i]++; + +} + + +/************************************************************************* +* This function changes the numbering to start from 1 instead of 0 +**************************************************************************/ +void ChangeMesh2FNumbering2(int n, idxtype *mesh, int ne, int nn, idxtype *epart, idxtype *npart) +{ + int i, nedges; + + for (i=0; i<n; i++) + mesh[i]++; + + for (i=0; i<ne; i++) + epart[i]++; + + for (i=0; i<nn; i++) + npart[i]++; + +} + diff --git a/Metis/frename.c b/Metis/frename.c new file mode 100644 index 0000000000..0ef94ab1b4 --- /dev/null +++ b/Metis/frename.c @@ -0,0 +1,312 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * frename.c + * + * This file contains some renaming routines to deal with different Fortran compilers + * + * Started 9/15/97 + * George + * + * $Id: frename.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +void METIS_PARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} + + +void METIS_WPARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} + + + +void METIS_PARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_partgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} + + + +void METIS_WPARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} +void metis_wpartgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part); +} + + + +void METIS_EDGEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_edgend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_edgend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_edgend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} + + + +void METIS_NODEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_nodend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_nodend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} +void metis_nodend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm); +} + + + +void METIS_NODEWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} +void metis_nodewnd(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} +void metis_nodewnd_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} +void metis_nodewnd__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm) +{ + METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm); +} + + + +void METIS_PARTMESHNODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshnodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshnodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshnodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} + + +void METIS_PARTMESHDUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshdual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshdual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} +void metis_partmeshdual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart); +} + + +void METIS_MESHTONODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtonodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtonodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtonodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} + + +void METIS_MESHTODUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtodual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtodual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} +void metis_meshtodual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy) +{ + METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy); +} + + +void METIS_ESTIMATEMEMORY(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} +void metis_estimatememory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} +void metis_estimatememory_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} +void metis_estimatememory__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes) +{ + METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes); +} + + + +void METIS_MCPARTGRAPHRECURSIVE(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_mcpartgraphrecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_mcpartgraphrecursive_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} +void metis_mcpartgraphrecursive__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); +} + + +void METIS_MCPARTGRAPHKWAY(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} +void metis_mcpartgraphkway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} +void metis_mcpartgraphkway_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} +void metis_mcpartgraphkway__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part) +{ + METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part); +} + + +void METIS_PARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} +void metis_partgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} +void metis_partgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} +void metis_partgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part) +{ + METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part); +} + +void METIS_WPARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} +void metis_wpartgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} +void metis_wpartgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} +void metis_wpartgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part) +{ + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part); +} + + + diff --git a/Metis/graph.c b/Metis/graph.c new file mode 100644 index 0000000000..5bb06c51de --- /dev/null +++ b/Metis/graph.c @@ -0,0 +1,616 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * graph.c + * + * This file contains functions that deal with setting up the graphs + * for METIS. + * + * Started 7/25/97 + * George + * + * $Id: graph.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void SetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, + idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int wgtflag) +{ + int i, j, k, sum, gsize; + float *nvwgt; + idxtype tvwgt[MAXNCON]; + + if (OpType == OP_KMETIS && ncon == 1 && (wgtflag&2) == 0 && (wgtflag&1) == 0) { + SetUpGraphKway(graph, nvtxs, xadj, adjncy); + return; + } + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = ncon; + graph->xadj = xadj; + graph->adjncy = adjncy; + + if (ncon == 1) { /* We are in the non mC mode */ + gsize = 0; + if ((wgtflag&2) == 0) + gsize += nvtxs; + if ((wgtflag&1) == 0) + gsize += graph->nedges; + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + + /* Create the vertex/edge weight vectors if they are not supplied */ + gsize = 0; + if ((wgtflag&2) == 0) { + vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vwgt = vwgt; + + if ((wgtflag&1) == 0) { + adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize); + gsize += graph->nedges; + } + else + graph->adjwgt = adjwgt; + + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + else { /* Set up the graph in MOC mode */ + gsize = 0; + if ((wgtflag&1) == 0) + gsize += graph->nedges; + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + gsize = 0; + + for (i=0; i<ncon; i++) + tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon); + + nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]); + } + + + /* Create the edge weight vectors if they are not supplied */ + if ((wgtflag&1) == 0) { + adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize); + gsize += graph->nedges; + } + else + graph->adjwgt = adjwgt; + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + + if (OpType != OP_KMETIS && OpType != OP_KVMETIS) { + graph->label = idxmalloc(nvtxs, "SetUpGraph: label"); + + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + +} + + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void SetUpGraphKway(GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy) +{ + int i; + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = 1; + graph->xadj = xadj; + graph->vwgt = NULL; + graph->adjncy = adjncy; + graph->adjwgt = NULL; + + graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata"); + graph->adjwgtsum = graph->gdata; + graph->cmap = graph->gdata + nvtxs; + + /* Compute the initial values of the adjwgtsum */ + for (i=0; i<nvtxs; i++) + graph->adjwgtsum[i] = xadj[i+1]-xadj[i]; + +} + + + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void SetUpGraph2(GraphType *graph, int nvtxs, int ncon, idxtype *xadj, + idxtype *adjncy, float *nvwgt, idxtype *adjwgt) +{ + int i, j, sum; + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = ncon; + graph->xadj = xadj; + graph->adjncy = adjncy; + graph->adjwgt = adjwgt; + + graph->nvwgt = fmalloc(nvtxs*ncon, "SetUpGraph2: graph->nvwgt"); + scopy(nvtxs*ncon, nvwgt, graph->nvwgt); + + graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata"); + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata; + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata+nvtxs; + + graph->label = idxmalloc(nvtxs, "SetUpGraph: label"); + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + +} + + +/************************************************************************* +* This function sets up the graph from the user input +**************************************************************************/ +void VolSetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, idxtype *xadj, + idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int wgtflag) +{ + int i, j, k, sum, gsize; + idxtype *adjwgt; + float *nvwgt; + idxtype tvwgt[MAXNCON]; + + InitGraph(graph); + + graph->nvtxs = nvtxs; + graph->nedges = xadj[nvtxs]; + graph->ncon = ncon; + graph->xadj = xadj; + graph->adjncy = adjncy; + + if (ncon == 1) { /* We are in the non mC mode */ + gsize = graph->nedges; /* This is for the edge weights */ + if ((wgtflag&2) == 0) + gsize += nvtxs; /* vwgts */ + if ((wgtflag&1) == 0) + gsize += nvtxs; /* vsize */ + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + + /* Create the vertex/edge weight vectors if they are not supplied */ + gsize = 0; + if ((wgtflag&2) == 0) { + vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vwgt = vwgt; + + if ((wgtflag&1) == 0) { + vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vsize = vsize; + + /* Allocate memory for edge weights and initialize them to the sum of the vsize */ + adjwgt = graph->adjwgt = graph->gdata+gsize; + gsize += graph->nedges; + + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) + adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]]; + } + + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + else { /* Set up the graph in MOC mode */ + gsize = graph->nedges; + if ((wgtflag&1) == 0) + gsize += nvtxs; + + gsize += 2*nvtxs; + + graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata"); + gsize = 0; + + /* Create the normalized vertex weights along each constrain */ + if ((wgtflag&2) == 0) + vwgt = idxsmalloc(nvtxs, 1, "SetUpGraph: vwgt"); + + for (i=0; i<ncon; i++) + tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon); + + nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]); + } + if ((wgtflag&2) == 0) + free(vwgt); + + + /* Create the vsize vector if it is not supplied */ + if ((wgtflag&1) == 0) { + vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata); + gsize += nvtxs; + } + else + graph->vsize = vsize; + + /* Allocate memory for edge weights and initialize them to the sum of the vsize */ + adjwgt = graph->adjwgt = graph->gdata+gsize; + gsize += graph->nedges; + + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) + adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]]; + } + + /* Compute the initial values of the adjwgtsum */ + graph->adjwgtsum = graph->gdata + gsize; + gsize += nvtxs; + + for (i=0; i<nvtxs; i++) { + sum = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) + sum += adjwgt[j]; + graph->adjwgtsum[i] = sum; + } + + graph->cmap = graph->gdata + gsize; + gsize += nvtxs; + + } + + if (OpType != OP_KVMETIS) { + graph->label = idxmalloc(nvtxs, "SetUpGraph: label"); + + for (i=0; i<nvtxs; i++) + graph->label[i] = i; + } + +} + + +/************************************************************************* +* This function randomly permutes the adjacency lists of a graph +**************************************************************************/ +void RandomizeGraph(GraphType *graph) +{ + int i, j, k, l, tmp, nvtxs; + idxtype *xadj, *adjncy, *adjwgt; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + for (i=0; i<nvtxs; i++) { + l = xadj[i+1]-xadj[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = xadj[i] + RandomInRange(l); + SWAP(adjncy[j], adjncy[k], tmp); + SWAP(adjwgt[j], adjwgt[k], tmp); + } + } +} + + +/************************************************************************* +* This function checks whether or not partition pid is contigous +**************************************************************************/ +int IsConnectedSubdomain(CtrlType *ctrl, GraphType *graph, int pid, int report) +{ + int i, j, k, nvtxs, first, last, nleft, ncmps, wgt; + idxtype *xadj, *adjncy, *where, *touched, *queue; + idxtype *cptr; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: touched"); + queue = idxmalloc(nvtxs, "IsConnected: queue"); + cptr = idxmalloc(nvtxs, "IsConnected: cptr"); + + nleft = 0; + for (i=0; i<nvtxs; i++) { + if (where[i] == pid) + nleft++; + } + + for (i=0; i<nvtxs; i++) { + if (where[i] == pid) + break; + } + + touched[i] = 1; + queue[0] = i; + first = 0; last = 1; + + cptr[0] = 0; /* This actually points to queue */ + ncmps = 0; + while (first != nleft) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + for (i=0; i<nvtxs; i++) { + if (where[i] == pid && !touched[i]) + break; + } + queue[last++] = i; + touched[i] = 1; + } + + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == pid && !touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + if (ncmps > 1 && report) { + printf("The graph has %d connected components in partition %d:\t", ncmps, pid); + for (i=0; i<ncmps; i++) { + wgt = 0; + for (j=cptr[i]; j<cptr[i+1]; j++) + wgt += graph->vwgt[queue[j]]; + printf("[%5d %5d] ", cptr[i+1]-cptr[i], wgt); + /* + if (cptr[i+1]-cptr[i] == 1) + printf("[%d %d] ", queue[cptr[i]], xadj[queue[cptr[i]]+1]-xadj[queue[cptr[i]]]); + */ + } + printf("\n"); + } + + GKfree(&touched, &queue, &cptr, LTERM); + + return (ncmps == 1 ? 1 : 0); +} + + +/************************************************************************* +* This function checks whether a graph is contigous or not +**************************************************************************/ +int IsConnected(CtrlType *ctrl, GraphType *graph, int report) +{ + int i, j, k, nvtxs, first, last; + idxtype *xadj, *adjncy, *touched, *queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: touched"); + queue = idxmalloc(nvtxs, "IsConnected: queue"); + + touched[0] = 1; + queue[0] = 0; + first = 0; last = 1; + + while (first < last) { + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (!touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + + if (first != nvtxs && report) + printf("The graph is not connected. It has %d disconnected vertices!\n", nvtxs-first); + + return (first == nvtxs ? 1 : 0); +} + + +/************************************************************************* +* This function checks whether or not partition pid is contigous +**************************************************************************/ +int IsConnected2(GraphType *graph, int report) +{ + int i, j, k, nvtxs, first, last, nleft, ncmps, wgt; + idxtype *xadj, *adjncy, *where, *touched, *queue; + idxtype *cptr; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: touched"); + queue = idxmalloc(nvtxs, "IsConnected: queue"); + cptr = idxmalloc(nvtxs, "IsConnected: cptr"); + + nleft = nvtxs; + touched[0] = 1; + queue[0] = 0; + first = 0; last = 1; + + cptr[0] = 0; /* This actually points to queue */ + ncmps = 0; + while (first != nleft) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + for (i=0; i<nvtxs; i++) { + if (!touched[i]) + break; + } + queue[last++] = i; + touched[i] = 1; + } + + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (!touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + if (ncmps > 1 && report) { + printf("%d connected components:\t", ncmps); + for (i=0; i<ncmps; i++) { + if (cptr[i+1]-cptr[i] > 200) + printf("[%5d] ", cptr[i+1]-cptr[i]); + } + printf("\n"); + } + + GKfree(&touched, &queue, &cptr, LTERM); + + return (ncmps == 1 ? 1 : 0); +} + + +/************************************************************************* +* This function returns the number of connected components in cptr,cind +* The separator of the graph is used to split it and then find its components. +**************************************************************************/ +int FindComponents(CtrlType *ctrl, GraphType *graph, idxtype *cptr, idxtype *cind) +{ + int i, j, k, nvtxs, first, last, nleft, ncmps, wgt; + idxtype *xadj, *adjncy, *where, *touched, *queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + where = graph->where; + + touched = idxsmalloc(nvtxs, 0, "IsConnected: queue"); + + for (i=0; i<graph->nbnd; i++) + touched[graph->bndind[i]] = 1; + + queue = cind; + + nleft = 0; + for (i=0; i<nvtxs; i++) { + if (where[i] != 2) + nleft++; + } + + for (i=0; i<nvtxs; i++) { + if (where[i] != 2) + break; + } + + touched[i] = 1; + queue[0] = i; + first = 0; last = 1; + + cptr[0] = 0; /* This actually points to queue */ + ncmps = 0; + while (first != nleft) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + for (i=0; i<nvtxs; i++) { + if (!touched[i]) + break; + } + queue[last++] = i; + touched[i] = 1; + } + + i = queue[first++]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (!touched[k]) { + queue[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + free(touched); + + return ncmps; +} + + + diff --git a/Metis/initpart.c b/Metis/initpart.c new file mode 100644 index 0000000000..58b01056ee --- /dev/null +++ b/Metis/initpart.c @@ -0,0 +1,422 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * initpart.c + * + * This file contains code that performs the initial partition of the + * coarsest graph + * + * Started 7/23/97 + * George + * + * $Id: initpart.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void Init2WayPartition(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + switch (ctrl->IType) { + case IPART_GGPKL: + GrowBisection(ctrl, graph, tpwgts, ubfactor); + break; + case 3: + RandomBisection(ctrl, graph, tpwgts, ubfactor); + break; + default: + errexit("Unknown initial partition type: %d\n", ctrl->IType); + } + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut)); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + ctrl->dbglvl = dbglvl; + +/* + IsConnectedSubdomain(ctrl, graph, 0); + IsConnectedSubdomain(ctrl, graph, 1); +*/ +} + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + GrowBisectionNode(ctrl, graph, ubfactor); + Compute2WayNodePartitionParams(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Sep: %d\n", graph->mincut)); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + + ctrl->dbglvl = dbglvl; + +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void GrowBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where; + idxtype *queue, *touched, *gain, *bestwhere; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + Allocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + queue = idxmalloc(nvtxs, "BisectGraph: queue"); + touched = idxmalloc(nvtxs, "BisectGraph: touched"); + + ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt))); + + maxpwgt[0] = ubfactor*tpwgts[0]; + maxpwgt[1] = ubfactor*tpwgts[1]; + minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; + minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; + + nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */ + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 0, touched); + + pwgts[1] = tpwgts[0]+tpwgts[1]; + pwgts[0] = 0; + + idxset(nvtxs, 1, where); + + queue[0] = RandomInRange(nvtxs); + touched[queue[0]] = 1; + first = 0; last = 1; + nleft = nvtxs-1; + drain = 0; + + /* Start the BFS from queue to get a partition */ + for (;;) { + if (first == last) { /* Empty. Disconnected graph! */ + if (nleft == 0 || drain) + break; + + k = RandomInRange(nleft); + for (i=0; i<nvtxs; i++) { + if (touched[i] == 0) { + if (k == 0) + break; + else + k--; + } + } + + queue[0] = i; + touched[i] = 1; + first = 0; last = 1;; + nleft--; + } + + i = queue[first++]; + if (pwgts[0] > 0 && pwgts[1]-vwgt[i] < minpwgt[1]) { + drain = 1; + continue; + } + + where[i] = 0; + INC_DEC(pwgts[0], pwgts[1], vwgt[i]); + if (pwgts[1] <= maxpwgt[1]) + break; + + drain = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (touched[k] == 0) { + queue[last++] = k; + touched[k] = 1; + nleft--; + } + } + } + + /* Check to see if we hit any bad limiting cases */ + if (pwgts[1] == 0) { + i = RandomInRange(nvtxs); + where[i] = 1; + INC_DEC(pwgts[1], pwgts[0], vwgt[i]); + } + + /************************************************************* + * Do some partition refinement + **************************************************************/ + Compute2WayPartitionParams(ctrl, graph); + /*printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + Balance2Way(ctrl, graph, tpwgts, ubfactor); + /*printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/ + + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + /*printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/ + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, &queue, &touched, LTERM); +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void GrowBisectionNode(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], tpwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *bndind; + idxtype *queue, *touched, *gain, *bestwhere; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + queue = idxmalloc(nvtxs, "BisectGraph: queue"); + touched = idxmalloc(nvtxs, "BisectGraph: touched"); + + tpwgts[0] = idxsum(nvtxs, vwgt); + tpwgts[1] = tpwgts[0]/2; + tpwgts[0] -= tpwgts[1]; + + maxpwgt[0] = ubfactor*tpwgts[0]; + maxpwgt[1] = ubfactor*tpwgts[1]; + minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; + minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; + + /* Allocate memory for graph->rdata. Allocate sufficient memory for both edge and node */ + graph->rdata = idxmalloc(5*nvtxs+3, "GrowBisectionNode: graph->rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + 3; + graph->bndptr = graph->rdata + nvtxs + 3; + graph->bndind = graph->rdata + 2*nvtxs + 3; + graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3); + graph->id = graph->rdata + 3*nvtxs + 3; + graph->ed = graph->rdata + 4*nvtxs + 3; + + where = graph->where; + bndind = graph->bndind; + + nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = tpwgts[0]+tpwgts[1]; + for (nbfs++; nbfs>0; nbfs--) { + idxset(nvtxs, 0, touched); + + pwgts[1] = tpwgts[0]+tpwgts[1]; + pwgts[0] = 0; + + idxset(nvtxs, 1, where); + + queue[0] = RandomInRange(nvtxs); + touched[queue[0]] = 1; + first = 0; last = 1; + nleft = nvtxs-1; + drain = 0; + + /* Start the BFS from queue to get a partition */ + if (nbfs >= 1) { + for (;;) { + if (first == last) { /* Empty. Disconnected graph! */ + if (nleft == 0 || drain) + break; + + k = RandomInRange(nleft); + for (i=0; i<nvtxs; i++) { + if (touched[i] == 0) { + if (k == 0) + break; + else + k--; + } + } + + queue[0] = i; + touched[i] = 1; + first = 0; last = 1;; + nleft--; + } + + i = queue[first++]; + if (pwgts[1]-vwgt[i] < minpwgt[1]) { + drain = 1; + continue; + } + + where[i] = 0; + INC_DEC(pwgts[0], pwgts[1], vwgt[i]); + if (pwgts[1] <= maxpwgt[1]) + break; + + drain = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (touched[k] == 0) { + queue[last++] = k; + touched[k] = 1; + nleft--; + } + } + } + } + + /************************************************************* + * Do some partition refinement + **************************************************************/ + Compute2WayPartitionParams(ctrl, graph); + Balance2Way(ctrl, graph, tpwgts, ubfactor); + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + + /* Construct and refine the vertex separator */ + for (i=0; i<graph->nbnd; i++) + where[bndind[i]] = 2; + + Compute2WayNodePartitionParams(ctrl, graph); + FM_2WayNodeRefine(ctrl, graph, ubfactor, 6); + + /* printf("ISep: [%d %d %d] %d\n", graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */ + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + Compute2WayNodePartitionParams(ctrl, graph); + + GKfree(&bestwhere, &queue, &touched, LTERM); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void RandomBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, ii, j, k, nvtxs, pwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where; + idxtype *perm, *bestwhere; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + Allocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + perm = idxmalloc(nvtxs, "BisectGraph: queue"); + + ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt))); + + maxpwgt[0] = ubfactor*tpwgts[0]; + maxpwgt[1] = ubfactor*tpwgts[1]; + minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; + minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; + + nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */ + for (; nbfs>0; nbfs--) { + RandomPermute(nvtxs, perm, 1); + + idxset(nvtxs, 1, where); + pwgts[1] = tpwgts[0]+tpwgts[1]; + pwgts[0] = 0; + + + if (nbfs != 1) { + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (pwgts[0]+vwgt[i] < maxpwgt[0]) { + where[i] = 0; + pwgts[0] += vwgt[i]; + pwgts[1] -= vwgt[i]; + if (pwgts[0] > minpwgt[0]) + break; + } + } + } + + /************************************************************* + * Do some partition refinement + **************************************************************/ + Compute2WayPartitionParams(ctrl, graph); + /* printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + Balance2Way(ctrl, graph, tpwgts, ubfactor); + /* printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + /* printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */ + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, &perm, LTERM); +} + + + + diff --git a/Metis/kmetis.c b/Metis/kmetis.c new file mode 100644 index 0000000000..f684c1bbad --- /dev/null +++ b/Metis/kmetis.c @@ -0,0 +1,129 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kmetis.c + * + * This file contains the top level routines for the multilevel k-way partitioning + * algorithm KMETIS. + * + * Started 7/28/97 + * George + * + * $Id: kmetis.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for KMETIS +**************************************************************************/ +void METIS_PartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, + tpwgts, options, edgecut, part); + + free(tpwgts); +} + + +/************************************************************************* +* This function is the entry point for KWMETIS +**************************************************************************/ +void METIS_WPartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = KMETIS_CTYPE; + ctrl.IType = KMETIS_ITYPE; + ctrl.RType = KMETIS_RTYPE; + ctrl.dbglvl = KMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KMETIS; + ctrl.CoarsenTo = amax((*nvtxs)/(40*log2(*nparts)), 20*(*nparts)); + ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor) +{ + int i, j, nvtxs, tvwgt, tpwgts2[2]; + GraphType *cgraph; + int wgtflag=3, numflag=0, options[10], edgecut; + + cgraph = Coarsen2Way(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + AllocateKWayPartitionMemory(ctrl, cgraph, nparts); + + options[0] = 1; + options[OPTION_CTYPE] = MATCH_SHEMKWAY; + options[OPTION_ITYPE] = IPART_GGPKL; + options[OPTION_RTYPE] = RTYPE_FM; + options[OPTION_DBGLVL] = 0; + + METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, + cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options, + &edgecut, cgraph->where); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); + + IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); + + RefineKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor); + + idxcopy(graph->nvtxs, graph->where, part); + + GKfree(&graph->gdata, &graph->rdata, LTERM); + + return graph->mincut; + +} + diff --git a/Metis/kvmetis.c b/Metis/kvmetis.c new file mode 100644 index 0000000000..6cb7f17b18 --- /dev/null +++ b/Metis/kvmetis.c @@ -0,0 +1,130 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kvmetis.c + * + * This file contains the top level routines for the multilevel k-way partitioning + * algorithm KMETIS. + * + * Started 7/28/97 + * George + * + * $Id: kvmetis.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for KMETIS +**************************************************************************/ +void METIS_PartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *vsize, int *wgtflag, int *numflag, int *nparts, + int *options, int *volume, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, + tpwgts, options, volume, part); + + free(tpwgts); +} + + +/************************************************************************* +* This function is the entry point for KWMETIS +**************************************************************************/ +void METIS_WPartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *vsize, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *volume, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + VolSetUpGraph(&graph, OP_KVMETIS, *nvtxs, 1, xadj, adjncy, vwgt, vsize, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = KVMETIS_CTYPE; + ctrl.IType = KVMETIS_ITYPE; + ctrl.RType = KVMETIS_RTYPE; + ctrl.dbglvl = KVMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KVMETIS; + ctrl.CoarsenTo = amax((*nvtxs)/(40*log2(*nparts)), 20*(*nparts)); + ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *volume = MlevelVolKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MlevelVolKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float *tpwgts, float ubfactor) +{ + int i, j, nvtxs, tvwgt, tpwgts2[2]; + GraphType *cgraph; + int wgtflag=3, numflag=0, options[10], edgecut; + + cgraph = Coarsen2Way(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + AllocateVolKWayPartitionMemory(ctrl, cgraph, nparts); + + options[0] = 1; + options[OPTION_CTYPE] = MATCH_SHEMKWAY; + options[OPTION_ITYPE] = IPART_GGPKL; + options[OPTION_RTYPE] = RTYPE_FM; + options[OPTION_DBGLVL] = 0; + + METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, + cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options, + &edgecut, cgraph->where); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); + + IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); + + RefineVolKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor); + + idxcopy(graph->nvtxs, graph->where, part); + + GKfree(&graph->gdata, &graph->rdata, LTERM); + + return graph->minvol; + +} + diff --git a/Metis/kwayfm.c b/Metis/kwayfm.c new file mode 100644 index 0000000000..5b376e5db3 --- /dev/null +++ b/Metis/kwayfm.c @@ -0,0 +1,672 @@ +/* + * kwayfm.c + * + * This file contains code that implements the multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: kwayfm.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees; + int from, me, to, oldcut, vwgt, gain; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= nbnd) + continue; + i = bndind[ii]; + + myrinfo = graph->rinfo+i; + + if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + j = myrinfo->id; + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || + (myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + nmoves++; + } + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, ComputeVolume(graph, where))); + + if (graph->mincut == oldcut) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + + + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain; + int from, me, to, oldcut, vwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + for (iii=0;;iii++) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + j = myrinfo->id; + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ + if (pwgts[to]+vwgt <= maxwgt[to]+gain && gain >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || + (myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed < myrinfo->id) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (gain >= 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && gain >= 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, graph->mincut)); + + if (graph->mincut == oldcut) + break; + } + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayEdgeBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves; + int from, me, to, oldcut, vwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + nmoves = 0; + for (;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed == 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed > 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed == 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (myrinfo->ed > 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && myrinfo->ed > 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + } + nmoves++; + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut)); + } + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + diff --git a/Metis/kwayrefine.c b/Metis/kwayrefine.c new file mode 100644 index 0000000000..8a9ff04008 --- /dev/null +++ b/Metis/kwayrefine.c @@ -0,0 +1,392 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kwayrefine.c + * + * This file contains the driving routines for multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: kwayrefine.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor) +{ + int i, nlevels, mustfree=0; + GraphType *ptr; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + ComputeKWayPartitionParams(ctrl, graph, nparts); + + /* Take care any non-contiguity */ + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr1)); + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { + EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25); + EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts); + EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr1)); + + /* Determine how many levels are there */ + for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); + + for (i=0; ;i++) { + /* PrintSubDomainGraph(graph, nparts, graph->where); */ + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN && (i == nlevels/2 || i == nlevels/2+1)) + EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + + if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) { + ComputeKWayBalanceBoundary(ctrl, graph, nparts); + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) + Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1); + else + Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1); + ComputeKWayBoundary(ctrl, graph, nparts); + } + + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1); + break; + case RTYPE_KWAYGREEDY: + Greedy_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10); + break; + case RTYPE_KWAYRANDOM_MCONN: + Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1); + break; + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */ + + graph = graph->finer; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + if (graph->vwgt == NULL) { + graph->vwgt = idxsmalloc(graph->nvtxs, 1, "RefineKWay: graph->vwgt"); + graph->adjwgt = idxsmalloc(graph->nedges, 1, "RefineKWay: graph->adjwgt"); + mustfree = 1; + } + ProjectKWayPartition(ctrl, graph, nparts); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) { + ComputeKWayBalanceBoundary(ctrl, graph, nparts); + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { + Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + } + else { + Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + } + } + + /* Take care any trivial non-contiguity */ + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr2)); + EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr2)); + + if (mustfree) + GKfree(&graph->vwgt, &graph->adjwgt, LTERM); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for k-way edge refinement +**************************************************************************/ +void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int nvtxs, pad64; + + nvtxs = graph->nvtxs; + + pad64 = (3*nvtxs+nparts)%2; + + graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + nparts; + graph->bndptr = graph->rdata + nvtxs + nparts; + graph->bndind = graph->rdata + 2*nvtxs + nparts; + graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64); + +/* + if (ctrl->wspace.edegrees != NULL) + free(ctrl->wspace.edegrees); + ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateKWayPartitionMemory: edegrees"); +*/ +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, l, nvtxs, nbnd, mincut, me, other; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr; + RInfoType *rinfo, *myrinfo; + EDegreeType *myedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + rinfo = graph->rinfo; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + ctrl->wspace.cdegree = 0; + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + myrinfo->ed += adjwgt[j]; + } + myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed; + + if (myrinfo->ed > 0) + mincut += myrinfo->ed; + + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + /* Time to compute the particular external degrees */ + if (myrinfo->ed > 0) { + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (me != other) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = other; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *bndptr, *bndind; + idxtype *cwhere; + GraphType *cgraph; + RInfoType *crinfo, *rinfo, *myrinfo; + EDegreeType *myedegrees; + idxtype *htable; + + cgraph = graph->coarser; + cwhere = cgraph->where; + crinfo = cgraph->rinfo; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + AllocateKWayPartitionMemory(ctrl, graph, nparts); + where = graph->where; + rinfo = graph->rinfo; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = crinfo[k].ed; /* For optimization */ + } + + htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + ctrl->wspace.cdegree = 0; + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + myrinfo->id = adjwgtsum[i]; + + if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ + istart = xadj[i]; + iend = xadj[i+1]; + + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += iend-istart; + + ndegrees = 0; + for (j=istart; j<iend; j++) { + other = where[adjncy[j]]; + if (me != other) { + myrinfo->ed += adjwgt[j]; + if ((k = htable[other]) == -1) { + htable[other] = ndegrees; + myedegrees[ndegrees].pid = other; + myedegrees[ndegrees++].ed = adjwgt[j]; + } + else { + myedegrees[k].ed += adjwgt[j]; + } + } + } + myrinfo->id -= myrinfo->ed; + + /* Remove space for edegrees if it was interior */ + if (myrinfo->ed == 0) { + myrinfo->edegrees = NULL; + ctrl->wspace.cdegree -= iend-istart; + } + else { + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + myrinfo->ndegrees = ndegrees; + + for (j=0; j<ndegrees; j++) + htable[myedegrees[j].pid] = -1; + } + } + } + + idxcopy(nparts, cgraph->pwgts, graph->pwgts); + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + idxwspacefree(ctrl, nparts); + + ASSERT(CheckBnd2(graph)); + +} + + + +/************************************************************************* +* This function checks if the partition weights are within the balance +* contraints +**************************************************************************/ +int IsBalanced(idxtype *pwgts, int nparts, float *tpwgts, float ubfactor) +{ + int i, j, tvwgt; + + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) { + if (pwgts[i] > tpwgts[i]*tvwgt*(ubfactor+0.005)) + return 0; + } + + return 1; +} + + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->rinfo[i].ed-graph->rinfo[i].id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->rinfo[i].ed > 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + diff --git a/Metis/kwayvolfm.c b/Metis/kwayvolfm.c new file mode 100644 index 0000000000..16ce80b29a --- /dev/null +++ b/Metis/kwayvolfm.c @@ -0,0 +1,1778 @@ +/* + * kwayvolfm.c + * + * This file contains code that implements the multilevel k-way refinement + * + * Started 7/8/98 + * George + * + * $Id: kwayvolfm.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayVolRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, oldcut, oldvol, vwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + oldvol = graph->minvol; + + RandomPermute(graph->nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= graph->nbnd) + continue; + i = bndind[ii]; + myrinfo = graph->vrinfo+i; + + if (myrinfo->gv >= 0) { /* Total volume gain is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (pwgts[to]+vwgt > maxwgt[to]) + continue; + if (myedegrees[j].gv > myedegrees[k].gv || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&5) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + if (graph->minvol == oldvol && graph->mincut == oldcut) + break; + } + + GKfree(&marker, &updind, &phtable, LTERM); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayVolRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, oldcut, oldvol, vwgt, nadd, maxndoms; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + idxtype *pmat, *pmatptr, *ndoms; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + pmat = ctrl->wspace.pmat; + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + oldcut = graph->mincut; + oldvol = graph->minvol; + + RandomPermute(graph->nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= graph->nbnd) + continue; + i = bndind[ii]; + myrinfo = graph->vrinfo+i; + + if (myrinfo->gv >= 0) { /* Total volume gain is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + if (nadd == 0) + phtable[to] = 2; + } + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to] || pwgts[to]+vwgt > maxwgt[to]) + continue; + if (myedegrees[j].gv > myedegrees[k].gv || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) || + (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if ((iii&5) == 0 || phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + + if (j == 0) + continue; + + for (j=0; j<myndegrees; j++) + phtable[myedegrees[j].pid] = -1; + + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + } + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + if (graph->minvol == oldvol && graph->mincut == oldcut) + break; + } + + GKfree(&marker, &updind, &phtable, LTERM); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayVolBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, vwgt, gain; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + RandomPermute(graph->nbnd, perm, 1); + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->vrinfo[i].gv); + moved[i] = 2; + } + + for (nmoves=0;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->vrinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (pwgts[to]+vwgt <= maxwgt[to] || + itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && + (xgain+myedegrees[k].gv < 0 || + (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0)) + ) + continue; + + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + } + + GKfree(&marker, &updind, &phtable, LTERM); + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayVolBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, + float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain; + int from, me, to, vwgt, gain, maxndoms, nadd; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable; + idxtype *pmat, *pmatptr, *ndoms; + VEDegreeType *myedegrees; + VRInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind"); + marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker"); + phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable"); + + pmat = ctrl->wspace.pmat; + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut, graph->minvol)); + + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + RandomPermute(graph->nbnd, perm, 1); + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->vrinfo[i].gv); + moved[i] = 2; + } + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + for (nmoves=0;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->vrinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0); + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + } + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + if (pwgts[to]+vwgt <= maxwgt[to] || + itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to]) + continue; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + for (j=0; j<myndegrees; j++) + phtable[myedegrees[j].pid] = -1; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && + (xgain+myedegrees[k].gv < 0 || + (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0)) + ) + continue; + + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + INC_DEC(pwgts[to], pwgts[from], vwgt); + graph->mincut -= myedegrees[k].ed-myrinfo->id; + graph->minvol -= (xgain+myedegrees[k].gv); + where[i] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n", + i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + } + + KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind); + + nmoves++; + + /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */ + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, + graph->minvol)); + + } + + GKfree(&marker, &updind, &phtable, LTERM); + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + + +/************************************************************************* +* This function updates the edge and volume gains as a result of moving +* v from 'from' to 'to'. +* The working arrays marker and phtable are assumed to be initialized to +* -1, and they left to -1 upon return +**************************************************************************/ +void KWayVolUpdate(CtrlType *ctrl, GraphType *graph, int v, int from, int to, + idxtype *marker, idxtype *phtable, idxtype *updind) +{ + int ii, iii, j, jj, k, kk, l, u, nupd, other, me, myidx; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *where; + VEDegreeType *myedegrees, *oedegrees; + VRInfoType *myrinfo, *orinfo; + + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + vsize = graph->vsize; + where = graph->where; + + myrinfo = graph->vrinfo+v; + myedegrees = myrinfo->edegrees; + + + /*====================================================================== + * Remove the contributions on the gain made by 'v'. + *=====================================================================*/ + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = k; + phtable[from] = k; + + myidx = phtable[to]; /* Keep track of the index in myedegrees of the 'to' domain */ + + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = graph->vrinfo+ii; + oedegrees = orinfo->edegrees; + + if (other == from) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv += vsize[v]; + } + } + else { + ASSERT(phtable[other] != -1); + + if (myedegrees[phtable[other]].ned > 1) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv += vsize[v]; + } + } + else { /* There is only one connection */ + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] != -1) + oedegrees[k].gv -= vsize[v]; + } + } + } + } + + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = -1; + phtable[from] = -1; + + + /*====================================================================== + * Update the id/ed of vertex 'v' + *=====================================================================*/ + myrinfo->ed += myrinfo->id-myedegrees[myidx].ed; + SWAP(myrinfo->id, myedegrees[myidx].ed, j); + SWAP(myrinfo->nid, myedegrees[myidx].ned, j); + if (myedegrees[myidx].ed == 0) + myedegrees[myidx] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[myidx].pid = from; + + /*====================================================================== + * Update the degrees of adjacent vertices and their volume gains + *=====================================================================*/ + marker[v] = 1; + updind[0] = v; + nupd = 1; + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + if (!marker[ii]) { /* The marking is done for boundary and max gv calculations */ + marker[ii] = 2; + updind[nupd++] = ii; + } + + myrinfo = graph->vrinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + myrinfo->nid--; + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + myrinfo->nid++; + } + + /* Remove the edgeweight from the 'pid == from' entry of the vertex */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ned == 1) { + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + marker[ii] = 1; /* You do a complete .gv calculation */ + + /* All vertices adjacent to 'ii' need to be updated */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == from) { + oedegrees[kk].gv -= vsize[ii]; + break; + } + } + } + } + else { + myedegrees[k].ed -= adjwgt[j]; + myedegrees[k].ned--; + + /* Update the gv due to single 'ii' connection to 'from' */ + if (myedegrees[k].ned == 1) { + /* find the vertex 'u' that 'ii' was connected into 'from' */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + if (other == from) { + for (kk=0; kk<orinfo->ndegrees; kk++) + oedegrees[kk].gv += vsize[ii]; + break; + } + } + } + } + + break; + } + } + } + + /* Add the edgeweight to the 'pid == to' entry of the vertex */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + myedegrees[k].ned++; + + /* Update the gv due to non-single 'ii' connection to 'to' */ + if (myedegrees[k].ned == 2) { + /* find the vertex 'u' that 'ii' was connected into 'to' */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + if (u != v && other == to) { + for (kk=0; kk<orinfo->ndegrees; kk++) + oedegrees[kk].gv -= vsize[ii]; + break; + } + } + } + break; + } + } + + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees].ed = adjwgt[j]; + myedegrees[myrinfo->ndegrees++].ned = 1; + marker[ii] = 1; /* You do a complete .gv calculation */ + + /* All vertices adjacent to 'ii' need to be updated */ + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + u = adjncy[jj]; + other = where[u]; + orinfo = graph->vrinfo+u; + oedegrees = orinfo->edegrees; + + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == to) { + oedegrees[kk].gv += vsize[ii]; + if (!marker[u]) { /* Need to update boundary etc */ + marker[u] = 2; + updind[nupd++] = u; + } + break; + } + } + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + } + + /*====================================================================== + * Add the contributions on the volume gain due to 'v' + *=====================================================================*/ + myrinfo = graph->vrinfo+v; + myedegrees = myrinfo->edegrees; + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = k; + phtable[to] = k; + + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = graph->vrinfo+ii; + oedegrees = orinfo->edegrees; + + if (other == to) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv -= vsize[v]; + } + } + else { + ASSERT(phtable[other] != -1); + + if (myedegrees[phtable[other]].ned > 1) { + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] == -1) + oedegrees[k].gv -= vsize[v]; + } + } + else { /* There is only one connection */ + for (k=0; k<orinfo->ndegrees; k++) { + if (phtable[oedegrees[k].pid] != -1) + oedegrees[k].gv += vsize[v]; + } + } + } + } + for (k=0; k<myrinfo->ndegrees; k++) + phtable[myedegrees[k].pid] = -1; + phtable[to] = -1; + + + /*====================================================================== + * Recompute the volume information of the 'hard' nodes, and update the + * max volume gain for all the update vertices + *=====================================================================*/ + ComputeKWayVolume(graph, nupd, updind, marker, phtable); + + + /*====================================================================== + * Maintain a consistent boundary + *=====================================================================*/ + for (j=0; j<nupd; j++) { + k = updind[j]; + marker[k] = 0; + myrinfo = graph->vrinfo+k; + + if ((myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) && graph->bndptr[k] == -1) + BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, k); + + if (myrinfo->gv < 0 && myrinfo->ed-myrinfo->id < 0 && graph->bndptr[k] != -1) + BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, k); + } + +} + + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeKWayVolume(GraphType *graph, int nupd, idxtype *updind, idxtype *marker, idxtype *phtable) +{ + int ii, iii, i, j, k, kk, l, nvtxs, me, other, pid; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *where; + VRInfoType *rinfo, *myrinfo, *orinfo; + VEDegreeType *myedegrees, *oedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->vrinfo; + + + /*------------------------------------------------------------ + / Compute now the iv/ev degrees + /------------------------------------------------------------*/ + for (iii=0; iii<nupd; iii++) { + i = updind[iii]; + me = where[i]; + + myrinfo = rinfo+i; + myedegrees = myrinfo->edegrees; + + if (marker[i] == 1) { /* Only complete gain updates go through */ + for (k=0; k<myrinfo->ndegrees; k++) + myedegrees[k].gv = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = rinfo+ii; + oedegrees = orinfo->edegrees; + + for (kk=0; kk<orinfo->ndegrees; kk++) + phtable[oedegrees[kk].pid] = kk; + phtable[other] = 1; + + if (me == other) { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (phtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + else { + ASSERT(phtable[me] != -1); + + /* I'm the only connection of 'ii' in 'me' */ + if (oedegrees[phtable[me]].ned == 1) { + /* Increase the gains for all the common domains between 'i' and 'ii' */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (phtable[myedegrees[k].pid] != -1) + myedegrees[k].gv += vsize[ii]; + } + } + else { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (phtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + } + + for (kk=0; kk<orinfo->ndegrees; kk++) + phtable[oedegrees[kk].pid] = -1; + phtable[other] = -1; + + } + } + + myrinfo->gv = -MAXIDX; + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].gv > myrinfo->gv) + myrinfo->gv = myedegrees[k].gv; + } + if (myrinfo->ed > 0 && myrinfo->id == 0) + myrinfo->gv += vsize[i]; + + } + +} + + + +/************************************************************************* +* This function computes the total volume +**************************************************************************/ +int ComputeVolume(GraphType *graph, idxtype *where) +{ + int i, j, k, me, nvtxs, nparts, totalv; + idxtype *xadj, *adjncy, *vsize, *marker; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vsize = (graph->vsize == NULL ? graph->vwgt : graph->vsize); + + nparts = where[idxamax(nvtxs, where)]+1; + marker = idxsmalloc(nparts, -1, "ComputeVolume: marker"); + + totalv = 0; + + for (i=0; i<nvtxs; i++) { + marker[where[i]] = i; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = where[adjncy[j]]; + if (marker[k] != i) { + marker[k] = i; + totalv += vsize[i]; + } + } + } + + free(marker); + + return totalv; +} + + + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void CheckVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr; + VRInfoType *rinfo, *myrinfo, *orinfo, tmprinfo; + VEDegreeType *myedegrees, *oedegrees, *tmpdegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->vrinfo; + + tmpdegrees = (VEDegreeType *)GKmalloc(nparts*sizeof(VEDegreeType), "CheckVolKWayPartitionParams: tmpdegrees"); + + /*------------------------------------------------------------ + / Compute now the iv/ev degrees + /------------------------------------------------------------*/ + for (i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myedegrees = myrinfo->edegrees; + + for (k=0; k<myrinfo->ndegrees; k++) + tmpdegrees[k] = myedegrees[k]; + + tmprinfo.ndegrees = myrinfo->ndegrees; + tmprinfo.id = myrinfo->id; + tmprinfo.ed = myrinfo->ed; + + myrinfo = &tmprinfo; + myedegrees = tmpdegrees; + + + for (k=0; k<myrinfo->ndegrees; k++) + myedegrees[k].gv = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = rinfo+ii; + oedegrees = orinfo->edegrees; + + if (me == other) { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + pid = myedegrees[k].pid; + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == pid) + break; + } + if (kk == orinfo->ndegrees) + myedegrees[k].gv -= vsize[ii]; + } + } + else { + /* Find the orinfo[me].ed and see if I'm the only connection */ + for (k=0; k<orinfo->ndegrees; k++) { + if (oedegrees[k].pid == me) + break; + } + + if (oedegrees[k].ned == 1) { /* I'm the only connection of 'ii' in 'me' */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].gv += vsize[ii]; + break; + } + } + + /* Increase the gains for all the common domains between 'i' and 'ii' */ + for (k=0; k<myrinfo->ndegrees; k++) { + if ((pid = myedegrees[k].pid) == other) + continue; + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == pid) { + myedegrees[k].gv += vsize[ii]; + break; + } + } + } + + } + else { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myrinfo->ndegrees; k++) { + if ((pid = myedegrees[k].pid) == other) + continue; + for (kk=0; kk<orinfo->ndegrees; kk++) { + if (oedegrees[kk].pid == pid) + break; + } + if (kk == orinfo->ndegrees) + myedegrees[k].gv -= vsize[ii]; + } + } + } + } + + myrinfo = rinfo+i; + myedegrees = myrinfo->edegrees; + + for (k=0; k<myrinfo->ndegrees; k++) { + pid = myedegrees[k].pid; + for (kk=0; kk<tmprinfo.ndegrees; kk++) { + if (tmpdegrees[kk].pid == pid) { + if (tmpdegrees[kk].gv != myedegrees[k].gv) + printf("[%d %d %d %d]\n", i, pid, myedegrees[k].gv, tmpdegrees[kk].gv); + break; + } + } + } + + } + + free(tmpdegrees); + +} + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void ComputeVolSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms) +{ + int i, j, k, me, nvtxs, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *where; + VRInfoType *rinfo; + VEDegreeType *edegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->vrinfo; + + idxset(nparts*nparts, 0, pmat); + + for (i=0; i<nvtxs; i++) { + if (rinfo[i].ed > 0) { + me = where[i]; + ndegrees = rinfo[i].ndegrees; + edegrees = rinfo[i].edegrees; + + k = me*nparts; + for (j=0; j<ndegrees; j++) + pmat[k+edegrees[j].pid] += edegrees[j].ed; + } + } + + for (i=0; i<nparts; i++) { + ndoms[i] = 0; + for (j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + ndoms[i]++; + } + } +} + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void EliminateVolSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts) +{ + int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd; + int min, move, cpwgt, tvwgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind; + KeyValueType *cand, *cand2; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + + maxpwgt = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + otherpmat = idxwspacemalloc(ctrl, nparts); + ind = idxwspacemalloc(ctrl, nvtxs); + pmat = idxset(nparts*nparts, 0, ctrl->wspace.pmat); + + cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + + /* Compute the pmat matrix */ + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != me) + pmat[me*nparts+where[k]] += adjwgt[j]; + } + } + + /* Compute the maximum allowed weight for each domain */ + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = 1.25*tpwgts[i]*tvwgt; + + /* Determine the domain connectivity */ + for (i=0; i<nparts; i++) { + for (k=0, j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + k++; + } + ndoms[i] = k; + } + + /* Get into the loop eliminating subdomain connections */ + for (;;) { + total = idxsum(nparts, ndoms); + avg = total/nparts; + max = ndoms[idxamax(nparts, ndoms)]; + + /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d\n", total, max, avg); */ + + if (max < 1.5*avg) + break; + + me = idxamax(nparts, ndoms); + mypmat = pmat + me*nparts; + totalout = idxsum(nparts, mypmat); + + /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/ + + /* Sort the connections according to their cut */ + for (ncand2=0, i=0; i<nparts; i++) { + if (mypmat[i] > 0) { + cand2[ncand2].key = mypmat[i]; + cand2[ncand2++].val = i; + } + } + ikeysort(ncand2, cand2); + + move = 0; + for (min=0; min<ncand2; min++) { + if (cand2[min].key > totalout/(2*ndoms[me])) + break; + + other = cand2[min].val; + + /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/ + + idxset(nparts, 0, otherpmat); + + /* Go and find the vertices in 'other' that are connected in 'me' */ + for (nind=0, i=0; i<nvtxs; i++) { + if (where[i] == other) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[adjncy[j]] == me) { + ind[nind++] = i; + break; + } + } + } + } + + /* Go and construct the otherpmat to see where these nind vertices are connected to */ + for (cpwgt=0, ii=0; ii<nind; ii++) { + i = ind[ii]; + cpwgt += vwgt[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != other) + otherpmat[where[k]] += adjwgt[j]; + } + } + + for (ncand=0, i=0; i<nparts; i++) { + if (otherpmat[i] > 0) { + cand[ncand].key = -otherpmat[i]; + cand[ncand++].val = i; + } + } + ikeysort(ncand, cand); + + /* + * Go through and the select the first domain that is common with 'me', and + * does not increase the ndoms[target] higher than my ndoms, subject to the + * maxpwgt constraint. Traversal is done from the mostly connected to the least. + */ + target = target2 = -1; + for (i=0; i<ncand; i++) { + k = cand[i].val; + + if (mypmat[k] > 0) { + if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */ + continue; + + for (j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0) + break; + } + if (j == nparts) { /* No bad second level effects */ + for (nadd=0, j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0) + nadd++; + } + + /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/ + if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) { + target2 = k; + } + if (nadd == 0) { + target = k; + break; + } + } + } + } + if (target == -1 && target2 != -1) + target = target2; + + if (target == -1) { + /* printf("\t\tCould not make the move\n");*/ + continue; + } + + /*printf("\t\tMoving to %d\n", target);*/ + + /* Update the partition weights */ + INC_DEC(pwgts[target], pwgts[other], cpwgt); + + /* Set all nind vertices to belong to 'target' */ + for (ii=0; ii<nind; ii++) { + i = ind[ii]; + where[i] = target; + + /* First remove any contribution that this vertex may have made */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != other) { + if (pmat[nparts*other + where[k]] == 0) + printf("Something wrong\n"); + pmat[nparts*other + where[k]] -= adjwgt[j]; + if (pmat[nparts*other + where[k]] == 0) + ndoms[other]--; + + if (pmat[nparts*where[k] + other] == 0) + printf("Something wrong\n"); + pmat[nparts*where[k] + other] -= adjwgt[j]; + if (pmat[nparts*where[k] + other] == 0) + ndoms[where[k]]--; + } + } + + /* Next add the new contributions as a result of the move */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != target) { + if (pmat[nparts*target + where[k]] == 0) + ndoms[target]++; + pmat[nparts*target + where[k]] += adjwgt[j]; + + if (pmat[nparts*where[k] + target] == 0) + ndoms[where[k]]++; + pmat[nparts*where[k] + target] += adjwgt[j]; + } + } + } + + move = 1; + break; + } + + if (move == 0) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + + GKfree(&cand, &cand2, LTERM); +} + + + +/************************************************************************* +* This function finds all the connected components induced by the +* partitioning vector in wgraph->where and tries to push them around to +* remove some of them +**************************************************************************/ +void EliminateVolComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor) +{ + int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, ncand, other, target, deltawgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt; + idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps; + KeyValueType *cand; + int recompute=0; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + + touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs)); + cptr = idxwspacemalloc(ctrl, nvtxs); + cind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + todo = idxwspacemalloc(ctrl, nvtxs); + maxpwgt = idxwspacemalloc(ctrl, nparts); + cpvec = idxwspacemalloc(ctrl, nparts); + npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts)); + + for (i=0; i<nvtxs; i++) + perm[i] = todo[i] = i; + + /* Find the connected componends induced by the partition */ + ncmps = -1; + first = last = 0; + nleft = nvtxs; + while (nleft > 0) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + ASSERT(touched[todo[0]] == 0); + i = todo[0]; + cind[last++] = i; + touched[i] = 1; + me = where[i]; + npcmps[me]++; + } + + i = cind[first++]; + k = perm[i]; + j = todo[k] = todo[--nleft]; + perm[j] = k; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == me && !touched[k]) { + cind[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */ + + if (ncmps > nparts) { /* There are more components than processors */ + cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + + /* First determine the partition sizes and max allowed load imbalance */ + for (i=0; i<nvtxs; i++) + pwgts[where[i]] += vwgt[i]; + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt; + + deltawgt = tvwgt/(100*nparts); + deltawgt = 5; + + for (i=0; i<ncmps; i++) { + me = where[cind[cptr[i]]]; /* Get the domain of this component */ + if (npcmps[me] == 1) + continue; /* Skip it because it is contigous */ + + /*printf("Trying to move %d from %d\n", i, me); */ + + /* Determine the connectivity */ + idxset(nparts, 0, cpvec); + for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++) { + ii = cind[j]; + cwgt += vwgt[ii]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + other = where[adjncy[jj]]; + if (me != other) + cpvec[other] += adjwgt[jj]; + } + } + + /*printf("\tCmp weight: %d\n", cwgt);*/ + + if (cwgt > .30*pwgts[me]) + continue; /* Skip the component if it is over 30% of the weight */ + + for (ncand=0, j=0; j<nparts; j++) { + if (cpvec[j] > 0) { + cand[ncand].key = -cpvec[j]; + cand[ncand++].val = j; + } + } + if (ncand == 0) + continue; + + ikeysort(ncand, cand); + + target = -1; + for (j=0; j<ncand; j++) { + k = cand[j].val; + if (cwgt < deltawgt || pwgts[k] + cwgt < maxpwgt[k]) { + target = k; + break; + } + } + + /*printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/ + + if (target != -1) { + /* Assign all the vertices of 'me' to 'target' and update data structures */ + pwgts[me] -= cwgt; + pwgts[target] += cwgt; + npcmps[me]--; + + for (j=cptr[i]; j<cptr[i+1]; j++) + where[cind[j]] = target; + + graph->mincut -= cpvec[target]; + recompute = 1; + } + } + + free(cand); + } + + if (recompute) { + int ttlv; + idxtype *marker; + + marker = idxset(nparts, -1, cpvec); + for (ttlv=0, i=0; i<nvtxs; i++) { + marker[where[i]] = i; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (marker[where[adjncy[j]]] != i) { + ttlv += graph->vsize[i]; + marker[where[adjncy[j]]] = i; + } + } + } + graph->minvol = ttlv; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + diff --git a/Metis/kwayvolrefine.c b/Metis/kwayvolrefine.c new file mode 100644 index 0000000000..2c4e56ed0c --- /dev/null +++ b/Metis/kwayvolrefine.c @@ -0,0 +1,460 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * kwayvolrefine.c + * + * This file contains the driving routines for multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: kwayvolrefine.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void RefineVolKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, + float *tpwgts, float ubfactor) +{ + int i, nlevels; + GraphType *ptr; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Take care any non-contiguity */ + if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { + ComputeVolKWayPartitionParams(ctrl, graph, nparts); + EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25); + EliminateVolSubDomainEdges(ctrl, graph, nparts, tpwgts); + EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25); + } + + + /* Determine how many levels are there */ + for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); + + /* Compute the parameters of the coarsest graph */ + ComputeVolKWayPartitionParams(ctrl, graph, nparts); + + for (i=0; ;i++) { + /*PrintSubDomainGraph(graph, nparts, graph->where);*/ + MALLOC_CHECK(NULL); + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + + if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) { + ComputeVolKWayBalanceBoundary(ctrl, graph, nparts); + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1); + break; + case RTYPE_KWAYRANDOM_MCONN: + Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1); + break; + } + ComputeVolKWayBoundary(ctrl, graph, nparts); + } + + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + case RTYPE_KWAYRANDOM_MCONN: + Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */ + + graph = graph->finer; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + ProjectVolKWayPartition(ctrl, graph, nparts); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) { + ComputeVolKWayBalanceBoundary(ctrl, graph, nparts); + switch (ctrl->RType) { + case RTYPE_KWAYRANDOM: + Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + case RTYPE_KWAYRANDOM_MCONN: + Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8); + Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); + break; + } + } + + EliminateVolComponents(ctrl, graph, nparts, tpwgts, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + + +/************************************************************************* +* This function allocates memory for k-way edge refinement +**************************************************************************/ +void AllocateVolKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int nvtxs, pad64; + + nvtxs = graph->nvtxs; + + pad64 = (3*nvtxs+nparts)%2; + + graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(VRInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateVolKWayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + nparts; + graph->bndptr = graph->rdata + nvtxs + nparts; + graph->bndind = graph->rdata + 2*nvtxs + nparts; + graph->vrinfo = (VRInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64); + +} + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where; + VRInfoType *rinfo, *myrinfo, *orinfo; + VEDegreeType *myedegrees, *oedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(nparts, 0, graph->pwgts); + rinfo = graph->vrinfo; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + ctrl->wspace.cdegree = 0; + mincut = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me == where[adjncy[j]]) { + myrinfo->id += adjwgt[j]; + myrinfo->nid++; + } + } + myrinfo->ed = graph->adjwgtsum[i] - myrinfo->id; + + mincut += myrinfo->ed; + + /* Time to compute the particular external degrees */ + if (myrinfo->ed > 0) { + myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (me != other) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].ed += adjwgt[j]; + myedegrees[k].ned++; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].gv = 0; + myedegrees[myrinfo->ndegrees].pid = other; + myedegrees[myrinfo->ndegrees].ed = adjwgt[j]; + myedegrees[myrinfo->ndegrees++].ned = 1; + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); + } + } + graph->mincut = mincut/2; + + + ComputeKWayVolGains(ctrl, graph, nparts); + +} + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void ComputeKWayVolGains(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, ii, j, k, kk, l, nvtxs, me, other, pid, myndegrees; + idxtype *xadj, *vsize, *adjncy, *adjwgt, *where, *bndind, *bndptr, *ophtable; + VRInfoType *rinfo, *myrinfo, *orinfo; + VEDegreeType *myedegrees, *oedegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + rinfo = graph->vrinfo; + + ophtable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + /*------------------------------------------------------------ + / Compute now the iv/ev degrees + /------------------------------------------------------------*/ + graph->minvol = graph->nbnd = 0; + for (i=0; i<nvtxs; i++) { + myrinfo = rinfo+i; + myrinfo->gv = -MAXIDX; + + if (myrinfo->ndegrees > 0) { + me = where[i]; + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + graph->minvol += myndegrees*vsize[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + other = where[ii]; + orinfo = rinfo+ii; + oedegrees = orinfo->edegrees; + + for (k=0; k<orinfo->ndegrees; k++) + ophtable[oedegrees[k].pid] = k; + ophtable[other] = 1; /* this is to simplify coding */ + + if (me == other) { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myndegrees; k++) { + if (ophtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + else { + ASSERT(ophtable[me] != -1); + + if (oedegrees[ophtable[me]].ned == 1) { /* I'm the only connection of 'ii' in 'me' */ + /* Increase the gains for all the common domains between 'i' and 'ii' */ + for (k=0; k<myndegrees; k++) { + if (ophtable[myedegrees[k].pid] != -1) + myedegrees[k].gv += vsize[ii]; + } + } + else { + /* Find which domains 'i' is connected and 'ii' is not and update their gain */ + for (k=0; k<myndegrees; k++) { + if (ophtable[myedegrees[k].pid] == -1) + myedegrees[k].gv -= vsize[ii]; + } + } + } + + for (kk=0; kk<orinfo->ndegrees; kk++) + ophtable[oedegrees[kk].pid] = -1; + ophtable[other] = -1; + } + + /* Compute the max vgain */ + for (k=0; k<myndegrees; k++) { + if (myedegrees[k].gv > myrinfo->gv) + myrinfo->gv = myedegrees[k].gv; + } + } + + if (myrinfo->ed > 0 && myrinfo->id == 0) + myrinfo->gv += vsize[i]; + + if (myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) + BNDInsert(graph->nbnd, bndind, bndptr, i); + } + + idxwspacefree(ctrl, nparts); + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void ProjectVolKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, nvtxs, me, other, istart, iend, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where; + idxtype *cwhere; + GraphType *cgraph; + VRInfoType *crinfo, *rinfo, *myrinfo; + VEDegreeType *myedegrees; + idxtype *htable; + + cgraph = graph->coarser; + cwhere = cgraph->where; + crinfo = cgraph->vrinfo; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + AllocateVolKWayPartitionMemory(ctrl, graph, nparts); + where = graph->where; + rinfo = graph->vrinfo; + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = crinfo[k].ed; /* For optimization */ + } + + htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + ctrl->wspace.cdegree = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + myrinfo->id = adjwgtsum[i]; + myrinfo->nid = xadj[i+1]-xadj[i]; + + if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ + istart = xadj[i]; + iend = xadj[i+1]; + + myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += iend-istart; + + ndegrees = 0; + for (j=istart; j<iend; j++) { + other = where[adjncy[j]]; + if (me != other) { + myrinfo->ed += adjwgt[j]; + myrinfo->nid--; + if ((k = htable[other]) == -1) { + htable[other] = ndegrees; + myedegrees[ndegrees].gv = 0; + myedegrees[ndegrees].pid = other; + myedegrees[ndegrees].ed = adjwgt[j]; + myedegrees[ndegrees++].ned = 1; + } + else { + myedegrees[k].ed += adjwgt[j]; + myedegrees[k].ned++; + } + } + } + myrinfo->id -= myrinfo->ed; + + /* Remove space for edegrees if it was interior */ + if (myrinfo->ed == 0) { + myrinfo->edegrees = NULL; + ctrl->wspace.cdegree -= iend-istart; + } + else { + myrinfo->ndegrees = ndegrees; + + for (j=0; j<ndegrees; j++) + htable[myedegrees[j].pid] = -1; + } + } + } + + ComputeKWayVolGains(ctrl, graph, nparts); + + idxcopy(nparts, cgraph->pwgts, graph->pwgts); + graph->mincut = cgraph->mincut; + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + idxwspacefree(ctrl, nparts); + +} + + + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeVolKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->vrinfo[i].gv >=0 || graph->vrinfo[i].ed-graph->vrinfo[i].id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void ComputeVolKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute the new boundary + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->vrinfo[i].ed > 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + diff --git a/Metis/macros.h b/Metis/macros.h new file mode 100644 index 0000000000..16634f73b4 --- /dev/null +++ b/Metis/macros.h @@ -0,0 +1,143 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * macros.h + * + * This file contains macros used in multilevel + * + * Started 9/25/94 + * George + * + * $Id: macros.h,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + + +/************************************************************************* +* The following macro returns a random number in the specified range +**************************************************************************/ +#ifdef __VC__ +#define RandomInRange(u) ((rand()>>3)%(u)) +#define RandomInRangeFast(u) ((rand()>>3)%(u)) +#else +#define RandomInRange(u) ((int)(drand48()*((double)(u)))) +#define RandomInRangeFast(u) ((rand()>>3)%(u)) +#endif + + + +#define amax(a, b) ((a) >= (b) ? (a) : (b)) +#define amin(a, b) ((a) >= (b) ? (b) : (a)) + +#define AND(a, b) ((a) < 0 ? ((-(a))&(b)) : ((a)&(b))) +#define OR(a, b) ((a) < 0 ? -((-(a))|(b)) : ((a)|(b))) +#define XOR(a, b) ((a) < 0 ? -((-(a))^(b)) : ((a)^(b))) + +#define SWAP(a, b, tmp) \ + do {(tmp) = (a); (a) = (b); (b) = (tmp);} while(0) + +#define INC_DEC(a, b, val) \ + do {(a) += (val); (b) -= (val);} while(0) + + +#define scopy(n, a, b) (float *)memcpy((void *)(b), (void *)(a), sizeof(float)*(n)) +#define idxcopy(n, a, b) (idxtype *)memcpy((void *)(b), (void *)(a), sizeof(idxtype)*(n)) + +#define HASHFCT(key, size) ((key)%(size)) + + +/************************************************************************* +* Timer macros +**************************************************************************/ +#define cleartimer(tmr) (tmr = 0.0) +#define starttimer(tmr) (tmr -= seconds()) +#define stoptimer(tmr) (tmr += seconds()) +#define gettimer(tmr) (tmr) + + +/************************************************************************* +* This macro is used to handle dbglvl +**************************************************************************/ +#define IFSET(a, flag, cmd) if ((a)&(flag)) (cmd); + +/************************************************************************* +* These macros are used for debuging memory leaks +**************************************************************************/ +#ifdef DMALLOC +#define imalloc(n, msg) (malloc(sizeof(int)*(n))) +#define fmalloc(n, msg) (malloc(sizeof(float)*(n))) +#define idxmalloc(n, msg) (malloc(sizeof(idxtype)*(n))) +#define ismalloc(n, val, msg) (iset((n), (val), malloc(sizeof(int)*(n)))) +#define idxsmalloc(n, val, msg) (idxset((n), (val), malloc(sizeof(idxtype)*(n)))) +#define GKmalloc(a, b) (malloc((a))) +#endif + +#ifdef DMALLOC +# define MALLOC_CHECK(ptr) \ + if (malloc_verify((ptr)) == DMALLOC_VERIFY_ERROR) { \ + printf("***MALLOC_CHECK failed on line %d of file %s: " #ptr "\n", \ + __LINE__, __FILE__); \ + abort(); \ + } +#else +# define MALLOC_CHECK(ptr) ; +#endif + + + +/************************************************************************* +* This macro converts a length array in a CSR one +**************************************************************************/ +#define MAKECSR(i, n, a) \ + do { \ + for (i=1; i<n; i++) a[i] += a[i-1]; \ + for (i=n; i>0; i--) a[i] = a[i-1]; \ + a[0] = 0; \ + } while(0) + + +/************************************************************************* +* These macros insert and remove nodes from the boundary list +**************************************************************************/ +#define BNDInsert(nbnd, bndind, bndptr, vtx) \ + do { \ + ASSERT(bndptr[vtx] == -1); \ + bndind[nbnd] = vtx; \ + bndptr[vtx] = nbnd++;\ + } while(0) + +#define BNDDelete(nbnd, bndind, bndptr, vtx) \ + do { \ + ASSERT(bndptr[vtx] != -1); \ + bndind[bndptr[vtx]] = bndind[--nbnd]; \ + bndptr[bndind[nbnd]] = bndptr[vtx]; \ + bndptr[vtx] = -1; \ + } while(0) + + + +/************************************************************************* +* These are debugging macros +**************************************************************************/ +#ifdef DEBUG +# define ASSERT(expr) \ + if (!(expr)) { \ + printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ + __LINE__, __FILE__); \ + abort(); \ + } +#else +# define ASSERT(expr) ; +#endif + +#ifdef DEBUG +# define ASSERTP(expr, msg) \ + if (!(expr)) { \ + printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ + __LINE__, __FILE__); \ + printf msg ; \ + abort(); \ + } +#else +# define ASSERTP(expr, msg) ; +#endif diff --git a/Metis/match.c b/Metis/match.c new file mode 100644 index 0000000000..c1434576a2 --- /dev/null +++ b/Metis/match.c @@ -0,0 +1,267 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * match.c + * + * This file contains the code that computes matchings and creates the next + * level coarse graph. + * + * Started 7/23/97 + * George + * + * $Id: match.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_RM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, nvtxs, cnvtxs, maxidx; + idxtype *xadj, *vwgt, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) { + maxidx = adjncy[j]; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_RM_NVW(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, nvtxs, cnvtxs, maxidx; + idxtype *xadj, *adjncy; + idxtype *match, *cmap, *perm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED) { + maxidx = adjncy[j]; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph_NVW(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_HEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt; + idxtype *xadj, *vwgt, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[k] <= ctrl->maxvwgt) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void Match_SHEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt, avgdegree; + idxtype *xadj, *vwgt, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (match[adjncy[j]] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + diff --git a/Metis/mbalance.c b/Metis/mbalance.c new file mode 100644 index 0000000000..b97938e87e --- /dev/null +++ b/Metis/mbalance.c @@ -0,0 +1,260 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mbalance.c + * + * This file contains code that is used to forcefully balance either + * bisections or k-sections + * + * Started 7/29/97 + * George + * + * $Id: mbalance.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of the bisection balancing algorithms. +**************************************************************************/ +void MocBalance2Way(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor) +{ + + if (Compute2WayHLoadImbalance(graph->ncon, graph->npwgts, tpwgts) < lbfactor) + return; + + MocGeneral2WayBalance(ctrl, graph, tpwgts, lbfactor); + +} + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocGeneral2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, newcut, mincutorder; + int qsizes[MAXNCON][2]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + qsizes[i][0] = qsizes[i][1] = 0; + } + + for (i=0; i<nvtxs; i++) { + qnum[i] = samax(ncon, nvwgt+i*ncon); + qsizes[qnum[i]][where[i]]++; + } + +/* + printf("Weight Distribution: \t"); + for (i=0; i<ncon; i++) + printf(" [%d %d]", qsizes[i][0], qsizes[i][1]); + printf("\n"); +*/ + + for (from=0; from<2; from++) { + for (j=0; j<ncon; j++) { + if (qsizes[j][from] == 0) { + for (i=0; i<nvtxs; i++) { + if (where[i] != from) + continue; + + k = samax2(ncon, nvwgt+i*ncon); + if (k == j && qsizes[qnum[i]][from] > qsizes[j][from] && nvwgt[i*ncon+qnum[i]] < 1.3*nvwgt[i*ncon+j]) { + qsizes[qnum[i]][from]--; + qsizes[j][from]++; + qnum[i] = j; + } + } + } + } + } + +/* + printf("Weight Distribution (after):\t "); + for (i=0; i<ncon; i++) + printf(" [%d %d]", qsizes[i][0], qsizes[i][1]); + printf("\n"); +*/ + + + + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + minbal = origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + newcut = mincut = graph->mincut; + mincutorder = -1; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal); + } + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert all nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if (minbal < lbfactor) + break; + + SelectQueue(ncon, npwgts, tpwgts, &from, &cnum, parts); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + newcut -= (ed[higain]-id[higain]); + newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + if (newbal < minbal || (newbal == minbal && + (newcut < mincut || (newcut == mincut && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) { + mincut = newcut; + minbal = newbal; + mincutorder = nswaps; + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", %.3f LB: %.3f\n", minbal, newbal); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + diff --git a/Metis/mbalance2.c b/Metis/mbalance2.c new file mode 100644 index 0000000000..717bcef352 --- /dev/null +++ b/Metis/mbalance2.c @@ -0,0 +1,328 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mbalance2.c + * + * This file contains code that is used to forcefully balance either + * bisections or k-sections + * + * Started 7/29/97 + * George + * + * $Id: mbalance2.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of the bisection balancing algorithms. +**************************************************************************/ +void MocBalance2Way2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i; + float tvec[MAXNCON]; + + Compute2WayHLoadImbalanceVec(graph->ncon, graph->npwgts, tpwgts, tvec); + if (!AreAllBelow(graph->ncon, tvec, ubvec)) + MocGeneral2WayBalance2(ctrl, graph, tpwgts, ubvec); +} + + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocGeneral2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, origbal[MAXNCON], minbal[MAXNCON], newbal[MAXNCON]; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, newcut, mincutorder; + float *maxwgt, *minwgt, tvec[MAXNCON]; + + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + + /* Setup the weight intervals of the two subdomains */ + minwgt = fwspacemalloc(ctrl, 2*ncon); + maxwgt = fwspacemalloc(ctrl, 2*ncon); + + for (i=0; i<2; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j]; + minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]); + } + } + + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal); + for (i=0; i<ncon; i++) + minbal[i] = origbal[i]; + + newcut = mincut = graph->mincut; + mincutorder = -1; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1], + graph->nvtxs, graph->nbnd, graph->mincut); + for (i=0; i<ncon; i++) + printf("%.3f ", origbal[i]); + printf("[B]\n"); + } + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert all nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if (AreAllBelow(ncon, minbal, ubvec)) + break; + + SelectQueue3(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + newcut -= (ed[higain]-id[higain]); + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, newbal); + + if (IsBetter2wayBalance(ncon, newbal, minbal, ubvec) || + (IsBetter2wayBalance(ncon, newbal, origbal, ubvec) && newcut < mincut)) { + mincut = newcut; + for (i=0; i<ncon; i++) + minbal[i] = newbal[i]; + mincutorder = nswaps; + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (i=0; i<ncon; i++) + printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + printf(", LB: "); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + if (mincutorder == nswaps) + printf(" *\n"); + else + printf("\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + + } + + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (i=0; i<ncon; i++) + printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]); + printf("], LB: "); + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + fwspacefree(ctrl, 2*ncon); + fwspacefree(ctrl, 2*ncon); + +} + + + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +void SelectQueue3(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, + PQueueType queues[MAXNCON][2], float *maxwgt) +{ + int i, j, maxgain=0; + float maxdiff=0.0, diff; + + *from = -1; + *cnum = -1; + + /* First determine the side and the queue, irrespective of the presence of nodes */ + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i]; + if (diff >= maxdiff) { + maxdiff = diff; + *from = j; + *cnum = i; + } + } + } + +/* DELETE +j = *from; +for (i=0; i<ncon; i++) + printf("[%5d %5d %.4f %.4f] ", i, PQueueGetSize(&queues[i][j]), npwgts[j*ncon+i], maxwgt[j*ncon+i]); +printf("***[%5d %5d]\n", *cnum, *from); +*/ + + /* If the desired queue is empty, select a node from that side anyway */ + if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][*from]) > 0) { + maxdiff = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]); + *cnum = i; + break; + } + } + + for (i++; i<ncon; i++) { + diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]; + if (diff > maxdiff && PQueueGetSize(&queues[i][*from]) > 0) { + maxdiff = diff; + *cnum = i; + } + } + } + + /* If the constraints ar OK, select a high gain vertex */ + if (*from == -1) { + maxgain = -100000; + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][0]); + *from = j; + *cnum = i; + } + } + } + + /* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */ + } +} diff --git a/Metis/mcoarsen.c b/Metis/mcoarsen.c new file mode 100644 index 0000000000..34bd5da46c --- /dev/null +++ b/Metis/mcoarsen.c @@ -0,0 +1,91 @@ +/* + * mcoarsen.c + * + * This file contains the driving routines for the coarsening process + * + * Started 7/23/97 + * George + * + * $Id: mcoarsen.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function takes a graph and creates a sequence of coarser graphs +**************************************************************************/ +GraphType *MCCoarsen2Way(CtrlType *ctrl, GraphType *graph) +{ + int i, clevel; + GraphType *cgraph; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr)); + + cgraph = graph; + + clevel = 0; + do { + if (ctrl->dbglvl&DBG_COARSEN) { + printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges, + idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt); + for (i=0; i<graph->ncon; i++) + printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon)); + printf("]\n"); + } + + switch (ctrl->CType) { + case MATCH_RM: + MCMatch_RM(ctrl, cgraph); + break; + case MATCH_HEM: + if (clevel < 1) + MCMatch_RM(ctrl, cgraph); + else + MCMatch_HEM(ctrl, cgraph); + break; + case MATCH_SHEM: + if (clevel < 1) + MCMatch_RM(ctrl, cgraph); + else + MCMatch_SHEM(ctrl, cgraph); + break; + case MATCH_SHEMKWAY: + MCMatch_SHEM(ctrl, cgraph); + break; + case MATCH_SHEBM_ONENORM: + MCMatch_SHEBM(ctrl, cgraph, 1); + break; + case MATCH_SHEBM_INFNORM: + MCMatch_SHEBM(ctrl, cgraph, -1); + break; + case MATCH_SBHEM_ONENORM: + MCMatch_SBHEM(ctrl, cgraph, 1); + break; + case MATCH_SBHEM_INFNORM: + MCMatch_SBHEM(ctrl, cgraph, -1); + break; + default: + errexit("Unknown CType: %d\n", ctrl->CType); + } + + cgraph = cgraph->coarser; + clevel++; + + } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2); + + if (ctrl->dbglvl&DBG_COARSEN) { + printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges, + idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt); + for (i=0; i<graph->ncon; i++) + printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon)); + printf("]\n"); + } + + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr)); + + return cgraph; +} + diff --git a/Metis/memory.c b/Metis/memory.c new file mode 100644 index 0000000000..2342de3d91 --- /dev/null +++ b/Metis/memory.c @@ -0,0 +1,208 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * memory.c + * + * This file contains routines that deal with memory allocation + * + * Started 2/24/96 + * George + * + * $Id: memory.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function allocates memory for the workspace +**************************************************************************/ +void AllocateWorkSpace(CtrlType *ctrl, GraphType *graph, int nparts) +{ + ctrl->wspace.pmat = NULL; + + if (ctrl->optype == OP_KMETIS) { + ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateWorkSpace: edegrees"); + ctrl->wspace.vedegrees = NULL; + ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees; + + ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat"); + + /* Memory requirements for different phases + Coarsening + Matching: 4*nvtxs vectors + Contraction: 2*nvtxs vectors (from the above 4), 1*nparts, 1*Nedges + Total = MAX(4*nvtxs, 2*nvtxs+nparts+nedges) + + Refinement + Random Refinement/Balance: 5*nparts + 1*nvtxs + 2*nedges + Greedy Refinement/Balance: 5*nparts + 2*nvtxs + 2*nedges + 1*PQueue(==Nvtxs) + Total = 5*nparts + 3*nvtxs + 2*nedges + + Total = 5*nparts + 3*nvtxs + 2*nedges + */ + ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */ + 5*(nparts+1) + /* Partition weights etc */ + graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */ + 20 /* padding for 64 bit machines */ + ; + } + else if (ctrl->optype == OP_KVMETIS) { + ctrl->wspace.edegrees = NULL; + ctrl->wspace.vedegrees = (VEDegreeType *)GKmalloc(graph->nedges*sizeof(VEDegreeType), "AllocateWorkSpace: vedegrees"); + ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.vedegrees; + + ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat"); + + /* Memory requirements for different phases are identical to KMETIS */ + ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */ + 3*(nparts+1) + /* Partition weights etc */ + graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */ + 20 /* padding for 64 bit machines */ + ; + } + else { + ctrl->wspace.edegrees = (EDegreeType *)idxmalloc(graph->nedges, "AllocateWorkSpace: edegrees"); + ctrl->wspace.vedegrees = NULL; + ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees; + + ctrl->wspace.maxcore = 5*(graph->nvtxs+1) + /* Refinement vectors */ + 4*(nparts+1) + /* Partition weights etc */ + 2*graph->ncon*graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* 2-way refinement */ + 2*graph->ncon*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)) + /* 2-way refinement */ + 20 /* padding for 64 bit machines */ + ; + } + + ctrl->wspace.maxcore += HTLENGTH; + ctrl->wspace.core = idxmalloc(ctrl->wspace.maxcore, "AllocateWorkSpace: maxcore"); + ctrl->wspace.ccore = 0; +} + + +/************************************************************************* +* This function allocates memory for the workspace +**************************************************************************/ +void FreeWorkSpace(CtrlType *ctrl, GraphType *graph) +{ + GKfree(&ctrl->wspace.edegrees, &ctrl->wspace.vedegrees, &ctrl->wspace.core, &ctrl->wspace.pmat, LTERM); +} + +/************************************************************************* +* This function returns how may words are left in the workspace +**************************************************************************/ +int WspaceAvail(CtrlType *ctrl) +{ + return ctrl->wspace.maxcore - ctrl->wspace.ccore; +} + + +/************************************************************************* +* This function allocate space from the core +**************************************************************************/ +idxtype *idxwspacemalloc(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore += n; + ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore); + return ctrl->wspace.core + ctrl->wspace.ccore - n; +} + +/************************************************************************* +* This function frees space from the core +**************************************************************************/ +void idxwspacefree(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore -= n; + ASSERT(ctrl->wspace.ccore >= 0); +} + + +/************************************************************************* +* This function allocate space from the core +**************************************************************************/ +float *fwspacemalloc(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore += n; + ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore); + return (float *) (ctrl->wspace.core + ctrl->wspace.ccore - n); +} + +/************************************************************************* +* This function frees space from the core +**************************************************************************/ +void fwspacefree(CtrlType *ctrl, int n) +{ + n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */ + + ctrl->wspace.ccore -= n; + ASSERT(ctrl->wspace.ccore >= 0); +} + + + +/************************************************************************* +* This function creates a CoarseGraphType data structure and initializes +* the various fields +**************************************************************************/ +GraphType *CreateGraph(void) +{ + GraphType *graph; + + graph = (GraphType *)GKmalloc(sizeof(GraphType), "CreateCoarseGraph: graph"); + + InitGraph(graph); + + return graph; +} + + +/************************************************************************* +* This function creates a CoarseGraphType data structure and initializes +* the various fields +**************************************************************************/ +void InitGraph(GraphType *graph) +{ + graph->gdata = graph->rdata = NULL; + + graph->nvtxs = graph->nedges = -1; + graph->mincut = graph->minvol = -1; + + graph->xadj = graph->vwgt = graph->adjncy = graph->adjwgt = NULL; + graph->adjwgtsum = NULL; + graph->label = NULL; + graph->cmap = NULL; + + graph->where = graph->pwgts = NULL; + graph->id = graph->ed = NULL; + graph->bndptr = graph->bndind = NULL; + graph->rinfo = NULL; + graph->vrinfo = NULL; + graph->nrinfo = NULL; + + graph->ncon = -1; + graph->nvwgt = NULL; + graph->npwgts = NULL; + + graph->vsize = NULL; + + graph->coarser = graph->finer = NULL; + +} + +/************************************************************************* +* This function deallocates any memory stored in a graph +**************************************************************************/ +void FreeGraph(GraphType *graph) +{ + + GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, LTERM); + free(graph); +} + diff --git a/Metis/mesh.c b/Metis/mesh.c new file mode 100644 index 0000000000..015f693fed --- /dev/null +++ b/Metis/mesh.c @@ -0,0 +1,398 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mesh.c + * + * This file contains routines for converting 3D and 4D finite element + * meshes into dual or nodal graphs + * + * Started 8/18/97 + * George + * + * $Id: mesh.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/***************************************************************************** +* This function creates a graph corresponding to the dual of a finite element +* mesh. At this point the supported elements are triangles, tetrahedrons, and +* bricks. +******************************************************************************/ +void METIS_MeshToDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + idxtype *dxadj, idxtype *dadjncy) +{ + int esizes[] = {-1, 3, 4, 8, 4}; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts); + + GENDUALMETIS(*ne, *nn, *etype, elmnts, dxadj, dadjncy); + + if (*numflag == 1) + ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *ne, dxadj, dadjncy); +} + + +/***************************************************************************** +* This function creates a graph corresponding to the finite element mesh. +* At this point the supported elements are triangles, tetrahedrons. +******************************************************************************/ +void METIS_MeshToNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + idxtype *dxadj, idxtype *dadjncy) +{ + int esizes[] = {-1, 3, 4, 8, 4}; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts); + + switch (*etype) { + case 1: + TRINODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + case 2: + TETNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + case 3: + HEXNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + case 4: + QUADNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy); + break; + } + + if (*numflag == 1) + ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *nn, dxadj, dadjncy); +} + + + +/***************************************************************************** +* This function creates the dual of a finite element mesh +******************************************************************************/ +void GENDUALMETIS(int nelmnts, int nvtxs, int etype, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges, mask; + idxtype *nptr, *nind; + idxtype *mark, ind[200], wgt[200]; + int esize, esizes[] = {-1, 3, 4, 8, 4}, + mgcnum, mgcnums[] = {-1, 2, 3, 4, 2}; + + mask = (1<<11)-1; + mark = idxsmalloc(mask+1, -1, "GENDUALMETIS: mark"); + + /* Get the element size and magic number for the particular element */ + esize = esizes[etype]; + mgcnum = mgcnums[etype]; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "GENDUALMETIS: nptr"); + for (j=esize*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "GENDUALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<esize; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + for (i=0; i<nelmnts; i++) + dxadj[i] = esize*i; + + for (i=0; i<nelmnts; i++) { + for (m=j=0; j<esize; j++) { + n = elmnts[esize*i+j]; + for (k=nptr[n+1]-1; k>=nptr[n]; k--) { + if ((kk = nind[k]) <= i) + break; + + kkk = kk&mask; + if ((l = mark[kkk]) == -1) { + ind[m] = kk; + wgt[m] = 1; + mark[kkk] = m++; + } + else if (ind[l] == kk) { + wgt[l]++; + } + else { + for (jj=0; jj<m; jj++) { + if (ind[jj] == kk) { + wgt[jj]++; + break; + } + } + if (jj == m) { + ind[m] = kk; + wgt[m++] = 1; + } + } + } + } + for (j=0; j<m; j++) { + if (wgt[j] == mgcnum) { + k = ind[j]; + dadjncy[dxadj[i]++] = k; + dadjncy[dxadj[k]++] = i; + } + mark[ind[j]&mask] = -1; + } + } + + /* Go and consolidate the dxadj and dadjncy */ + for (j=i=0; i<nelmnts; i++) { + for (k=esize*i; k<dxadj[i]; k++, j++) + dadjncy[j] = dadjncy[k]; + dxadj[i] = j; + } + for (i=nelmnts; i>0; i--) + dxadj[i] = dxadj[i-1]; + dxadj[0] = 0; + + free(mark); + free(nptr); + free(nind); + +} + + + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void TRINODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "TRINODALMETIS: nptr"); + for (j=3*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "TRINODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<3; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "TRINODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + for (jj=3*nind[j], k=0; k<3; k++, jj++) { + kk = elmnts[jj]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void TETNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "TETNODALMETIS: nptr"); + for (j=4*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "TETNODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<4; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "TETNODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + for (jj=4*nind[j], k=0; k<4; k++, jj++) { + kk = elmnts[jj]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void HEXNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + int table[8][3] = {1, 3, 4, + 0, 2, 5, + 1, 3, 6, + 0, 2, 7, + 0, 5, 7, + 1, 4, 6, + 2, 5, 7, + 3, 4, 6}; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "HEXNODALMETIS: nptr"); + for (j=8*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "HEXNODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<8; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "HEXNODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + jj=8*nind[j]; + for (k=0; k<8; k++) { + if (elmnts[jj+k] == i) + break; + } + ASSERT(k != 8); + + /* You found the index, now go and put the 3 neighbors */ + kk = elmnts[jj+table[k][0]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + kk = elmnts[jj+table[k][1]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + kk = elmnts[jj+table[k][2]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} + + +/***************************************************************************** +* This function creates the nodal graph of a finite element mesh +******************************************************************************/ +void QUADNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy) +{ + int i, j, jj, k, kk, kkk, l, m, n, nedges; + idxtype *nptr, *nind; + idxtype *mark; + int table[4][2] = {1, 3, + 0, 2, + 1, 3, + 0, 2}; + + /* Construct the node-element list first */ + nptr = idxsmalloc(nvtxs+1, 0, "QUADNODALMETIS: nptr"); + for (j=4*nelmnts, i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, nvtxs, nptr); + + nind = idxmalloc(nptr[nvtxs], "QUADNODALMETIS: nind"); + for (k=i=0; i<nelmnts; i++) { + for (j=0; j<4; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=nvtxs; i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + mark = idxsmalloc(nvtxs, -1, "QUADNODALMETIS: mark"); + + nedges = dxadj[0] = 0; + for (i=0; i<nvtxs; i++) { + mark[i] = i; + for (j=nptr[i]; j<nptr[i+1]; j++) { + jj=4*nind[j]; + for (k=0; k<4; k++) { + if (elmnts[jj+k] == i) + break; + } + ASSERT(k != 4); + + /* You found the index, now go and put the 2 neighbors */ + kk = elmnts[jj+table[k][0]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + kk = elmnts[jj+table[k][1]]; + if (mark[kk] != i) { + mark[kk] = i; + dadjncy[nedges++] = kk; + } + } + dxadj[i+1] = nedges; + } + + free(mark); + free(nptr); + free(nind); + +} diff --git a/Metis/meshpart.c b/Metis/meshpart.c new file mode 100644 index 0000000000..e010fe3a80 --- /dev/null +++ b/Metis/meshpart.c @@ -0,0 +1,204 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * meshpart.c + * + * This file contains routines for partitioning finite element meshes. + * + * Started 9/29/97 + * George + * + * $Id: meshpart.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function partitions a finite element mesh by partitioning its nodal +* graph using KMETIS and then assigning elements in a load balanced fashion. +**************************************************************************/ +void METIS_PartMeshNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + int i, j, k, me; + idxtype *xadj, *adjncy, *pwgts; + int options[10], pnumflag=0, wgtflag=0; + int nnbrs, nbrind[200], nbrwgt[200], maxpwgt; + int esize, esizes[] = {-1, 3, 4, 8, 4}; + + esize = esizes[*etype]; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esize, elmnts); + + xadj = idxmalloc(*nn+1, "METIS_MESHPARTNODAL: xadj"); + adjncy = idxmalloc(20*(*nn), "METIS_MESHPARTNODAL: adjncy"); + + METIS_MeshToNodal(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy); + + adjncy = realloc(adjncy, xadj[*nn]*sizeof(idxtype)); + + options[0] = 0; + METIS_PartGraphKway(nn, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, npart); + + /* OK, now compute an element partition based on the nodal partition npart */ + idxset(*ne, -1, epart); + pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTNODAL: pwgts"); + for (i=0; i<*ne; i++) { + me = npart[elmnts[i*esize]]; + for (j=1; j<esize; j++) { + if (npart[elmnts[i*esize+j]] != me) + break; + } + if (j == esize) { + epart[i] = me; + pwgts[me]++; + } + } + + maxpwgt = 1.03*(*ne)/(*nparts); + for (i=0; i<*ne; i++) { + if (epart[i] == -1) { /* Assign the boundary element */ + nnbrs = 0; + for (j=0; j<esize; j++) { + me = npart[elmnts[i*esize+j]]; + for (k=0; k<nnbrs; k++) { + if (nbrind[k] == me) { + nbrwgt[k]++; + break; + } + } + if (k == nnbrs) { + nbrind[nnbrs] = me; + nbrwgt[nnbrs++] = 1; + } + } + /* Try to assign it first to the domain with most things in common */ + j = iamax(nnbrs, nbrwgt); + if (pwgts[nbrind[j]] < maxpwgt) { + epart[i] = nbrind[j]; + } + else { + /* If that fails, assign it to a light domain */ + for (j=0; j<nnbrs; j++) { + if (pwgts[nbrind[j]] < maxpwgt) { + epart[i] = nbrind[j]; + break; + } + } + if (j == nnbrs) + epart[i] = nbrind[iamax(nnbrs, nbrwgt)]; + } + pwgts[epart[i]]++; + } + } + + if (*numflag == 1) + ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart); + + GKfree(&xadj, &adjncy, &pwgts, LTERM); + +} + + +/************************************************************************* +* This function partitions a finite element mesh by partitioning its dual +* graph using KMETIS and then assigning nodes in a load balanced fashion. +**************************************************************************/ +void METIS_PartMeshDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, + int *nparts, int *edgecut, idxtype *epart, idxtype *npart) +{ + int i, j, k, me; + idxtype *xadj, *adjncy, *pwgts, *nptr, *nind; + int options[10], pnumflag=0, wgtflag=0; + int nnbrs, nbrind[200], nbrwgt[200], maxpwgt; + int esize, esizes[] = {-1, 3, 4, 8, 4}; + + esize = esizes[*etype]; + + if (*numflag == 1) + ChangeMesh2CNumbering((*ne)*esize, elmnts); + + xadj = idxmalloc(*ne+1, "METIS_MESHPARTNODAL: xadj"); + adjncy = idxmalloc(esize*(*ne), "METIS_MESHPARTNODAL: adjncy"); + + METIS_MeshToDual(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy); + + options[0] = 0; + METIS_PartGraphKway(ne, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, epart); + + /* Construct the node-element list */ + nptr = idxsmalloc(*nn+1, 0, "METIS_MESHPARTDUAL: nptr"); + for (j=esize*(*ne), i=0; i<j; i++) + nptr[elmnts[i]]++; + MAKECSR(i, *nn, nptr); + + nind = idxmalloc(nptr[*nn], "METIS_MESHPARTDUAL: nind"); + for (k=i=0; i<(*ne); i++) { + for (j=0; j<esize; j++, k++) + nind[nptr[elmnts[k]]++] = i; + } + for (i=(*nn); i>0; i--) + nptr[i] = nptr[i-1]; + nptr[0] = 0; + + + /* OK, now compute a nodal partition based on the element partition npart */ + idxset(*nn, -1, npart); + pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTDUAL: pwgts"); + for (i=0; i<*nn; i++) { + me = epart[nind[nptr[i]]]; + for (j=nptr[i]+1; j<nptr[i+1]; j++) { + if (epart[nind[j]] != me) + break; + } + if (j == nptr[i+1]) { + npart[i] = me; + pwgts[me]++; + } + } + + maxpwgt = 1.03*(*nn)/(*nparts); + for (i=0; i<*nn; i++) { + if (npart[i] == -1) { /* Assign the boundary element */ + nnbrs = 0; + for (j=nptr[i]; j<nptr[i+1]; j++) { + me = epart[nind[j]]; + for (k=0; k<nnbrs; k++) { + if (nbrind[k] == me) { + nbrwgt[k]++; + break; + } + } + if (k == nnbrs) { + nbrind[nnbrs] = me; + nbrwgt[nnbrs++] = 1; + } + } + /* Try to assign it first to the domain with most things in common */ + j = iamax(nnbrs, nbrwgt); + if (pwgts[nbrind[j]] < maxpwgt) { + npart[i] = nbrind[j]; + } + else { + /* If that fails, assign it to a light domain */ + npart[i] = nbrind[0]; + for (j=0; j<nnbrs; j++) { + if (pwgts[nbrind[j]] < maxpwgt) { + npart[i] = nbrind[j]; + break; + } + } + } + pwgts[npart[i]]++; + } + } + + if (*numflag == 1) + ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart); + + GKfree(&xadj, &adjncy, &pwgts, &nptr, &nind, LTERM); + +} diff --git a/Metis/metis.h b/Metis/metis.h new file mode 100644 index 0000000000..13c0b9cd2a --- /dev/null +++ b/Metis/metis.h @@ -0,0 +1,37 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * metis.h + * + * This file includes all necessary header files + * + * Started 8/27/94 + * George + * + * $Id: metis.h,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + + +#include <stdio.h> +#ifdef __STDC__ +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <strings.h> +#include <string.h> +#include <ctype.h> +#include <math.h> +#include <stdarg.h> +#include <time.h> + +#ifdef DMALLOC +#include <dmalloc.h> +#endif + +#include <defs.h> +#include <struct.h> +#include <macros.h> +#include <rename.h> +#include <proto.h> + diff --git a/Metis/mfm.c b/Metis/mfm.c new file mode 100644 index 0000000000..820278f799 --- /dev/null +++ b/Metis/mfm.c @@ -0,0 +1,344 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mfm.c + * + * This file contains code that implements the edge-based FM refinement + * + * Started 7/23/97 + * George + * + * $Id: mfm.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, initcut, newcut, mincutorder; + float rtpwgts[2]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 25), 150); + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + rtpwgts[0] = origbal*tpwgts[0]; + rtpwgts[1] = origbal*tpwgts[1]; + + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal); + } + + idxset(nvtxs, -1, moved); + for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ + for (i=0; i<ncon; i++) { + PQueueReset(&parts[i][0]); + PQueueReset(&parts[i][1]); + } + + mincutorder = -1; + newcut = mincut = initcut = graph->mincut; + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + minbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert boundary nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(ed[i] > 0 || id[i] == 0); + ASSERT(bndptr[i] != -1); + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + ASSERT(bndptr[higain] != -1); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + newcut -= (ed[higain]-id[higain]); + newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); + + if ((newcut < mincut && newbal-origbal <= .00001) || + (newcut == mincut && (newbal < minbal || + (newbal == minbal && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) { + mincut = newcut; + minbal = newbal; + mincutorder = nswaps; + for (i=0; i<ncon; i++) + mindiff[i] = fabs(tpwgts[0]-npwgts[i]); + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", %.3f LB: %.3f\n", minbal, newbal); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1) /* Remove it if in the queues */ + PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1) + PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]); + } + } + } + + } + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut == initcut) + break; + } + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +void SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2]) +{ + int i, part, maxgain=0; + float max, maxdiff=0.0; + + *from = -1; + *cnum = -1; + + /* First determine the side and the queue, irrespective of the presence of nodes */ + for (part=0; part<2; part++) { + for (i=0; i<ncon; i++) { + if (npwgts[part*ncon+i]-tpwgts[part] >= maxdiff) { + maxdiff = npwgts[part*ncon+i]-tpwgts[part]; + *from = part; + *cnum = i; + } + } + } + + /* printf("Selected1 %d(%d) -> %d [%5f]\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from]), maxdiff); */ + + if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) { + /* The desired queue is empty, select a node from that side anyway */ + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][*from]) > 0) { + max = npwgts[(*from)*ncon + i]; + *cnum = i; + break; + } + } + + for (i++; i<ncon; i++) { + if (npwgts[(*from)*ncon + i] > max && PQueueGetSize(&queues[i][*from]) > 0) { + max = npwgts[(*from)*ncon + i]; + *cnum = i; + } + } + } + + /* Check to see if you can focus on the cut */ + if (maxdiff <= 0.0 || *from == -1) { + maxgain = -100000; + + for (part=0; part<2; part++) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][part]) > 0 && PQueueGetKey(&queues[i][part]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][part]); + *from = part; + *cnum = i; + } + } + } + } + + /* printf("Selected2 %d(%d) -> %d\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from])); */ +} + + + + + +/************************************************************************* +* This function checks if the balance achieved is better than the diff +* For now, it uses a 2-norm measure +**************************************************************************/ +int BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff) +{ + int i; + float ndiff[MAXNCON]; + + for (i=0; i<ncon; i++) + ndiff[i] = fabs(tpwgts[0]-npwgts[i]); + + return snorm2(ncon, ndiff) < snorm2(ncon, diff); +} + + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +**************************************************************************/ +float Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts) +{ + int i; + float max=0.0, temp; + + for (i=0; i<ncon; i++) { + /* temp = amax(npwgts[i]/tpwgts[0], npwgts[ncon+i]/tpwgts[1]); */ + temp = fabs(tpwgts[0]-npwgts[i])/tpwgts[0]; + max = (max < temp ? temp : max); + } + return 1.0+max; +} + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +* For now assume that we just want balanced partitionings +**************************************************************************/ +void Compute2WayHLoadImbalanceVec(int ncon, float *npwgts, float *tpwgts, float *lbvec) +{ + int i; + + for (i=0; i<ncon; i++) + lbvec[i] = 1.0 + fabs(tpwgts[0]-npwgts[i])/tpwgts[0]; +} + diff --git a/Metis/mfm2.c b/Metis/mfm2.c new file mode 100644 index 0000000000..0b2a4d5211 --- /dev/null +++ b/Metis/mfm2.c @@ -0,0 +1,349 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mfm2.c + * + * This file contains code that implements the edge-based FM refinement + * + * Started 7/23/97 + * George + * + * $Id: mfm2.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs an edge-based FM refinement +**************************************************************************/ +void MocFM_2WayEdgeRefine2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *orgubvec, + int npasses) +{ + int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *swaps, *perm, *qnum; + float *nvwgt, *npwgts, origdiff[MAXNCON], origbal[MAXNCON], minbal[MAXNCON]; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut, initcut, newcut, mincutorder; + float *maxwgt, *minwgt, ubvec[MAXNCON], tvec[MAXNCON]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + limit = amin(amax(0.01*nvtxs, 15), 100); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal); + for (i=0; i<ncon; i++) { + origdiff[i] = fabs(tpwgts[0]-npwgts[i]); + ubvec[i] = amax(origbal[i], orgubvec[i]); + } + + /* Setup the weight intervals of the two subdomains */ + minwgt = fwspacemalloc(ctrl, 2*ncon); + maxwgt = fwspacemalloc(ctrl, 2*ncon); + + for (i=0; i<2; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j]; + minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]); + } + } + + /* Initialize the queues */ + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1], + graph->nvtxs, graph->nbnd, graph->mincut); + for (i=0; i<ncon; i++) + printf("%.3f ", origbal[i]); + printf("\n"); + } + + idxset(nvtxs, -1, moved); + for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ + for (i=0; i<ncon; i++) { + PQueueReset(&parts[i][0]); + PQueueReset(&parts[i][1]); + } + + mincutorder = -1; + newcut = mincut = initcut = graph->mincut; + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, minbal); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + /* Insert boundary nodes in the priority queues */ + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(ed[i] > 0 || id[i] == 0); + ASSERT(bndptr[i] != -1); + PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); + } + + for (nswaps=0; nswaps<nvtxs; nswaps++) { + SelectQueue2(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt); + to = (from+1)%2; + + if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) + break; + ASSERT(bndptr[higain] != -1); + + newcut -= (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + if ((newcut < mincut && AreAllBelow(ncon, tvec, ubvec)) || + (newcut == mincut && IsBetter2wayBalance(ncon, tvec, minbal, ubvec))) { + mincut = newcut; + for (i=0; i<ncon; i++) + minbal[i] = tvec[i]; + mincutorder = nswaps; + } + else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ + newcut += (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + break; + } + + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + + printf(", LB: "); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + if (mincutorder == nswaps) + printf(" *\n"); + else + printf("\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update its boundary information and queue position */ + if (bndptr[k] != -1) { /* If k was a boundary vertex */ + if (ed[k] == 0) { /* Not a boundary vertex any more */ + BNDDelete(nbnd, bndind, bndptr, k); + if (moved[k] == -1) /* Remove it if in the queues */ + PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain); + } + else { /* If it has not been moved, update its position in the queue */ + if (moved[k] == -1) + PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); + } + } + else { + if (ed[k] > 0) { /* It will now become a boundary vertex */ + BNDInsert(nbnd, bndind, bndptr, k); + if (moved[k] == -1) + PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]); + } + } + } + + } + + + /**************************************************************** + * Roll back computations + *****************************************************************/ + for (i=0; i<nswaps; i++) + moved[swaps[i]] = -1; /* reset moved array */ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + to = where[higain] = (where[higain]+1)%2; + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + else if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + if (bndptr[k] != -1 && ed[k] == 0) + BNDDelete(nbnd, bndind, bndptr, k); + if (bndptr[k] == -1 && ed[k] > 0) + BNDInsert(nbnd, bndind, bndptr, k); + } + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("], LB: "); + Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut == initcut) + break; + } + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + fwspacefree(ctrl, 2*ncon); + fwspacefree(ctrl, 2*ncon); + +} + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +void SelectQueue2(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, + PQueueType queues[MAXNCON][2], float *maxwgt) +{ + int i, j, maxgain=0; + float diff, max, maxdiff=0.0; + + *from = -1; + *cnum = -1; + + /* First determine the side and the queue, irrespective of the presence of nodes */ + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i]; + if (diff >= maxdiff) { + maxdiff = diff; + *from = j; + *cnum = i; + } + } + } + + if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) { + /* The desired queue is empty, select a node from that side anyway */ + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][*from]) > 0) { + max = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]); + *cnum = i; + break; + } + } + + for (i++; i<ncon; i++) { + diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]; + if (diff > max && PQueueGetSize(&queues[i][*from]) > 0) { + max = diff; + *cnum = i; + } + } + } + + /* Check to see if you can focus on the cut */ + if (maxdiff <= 0.0 || *from == -1) { + maxgain = -100000; + + for (j=0; j<2; j++) { + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][j]); + *from = j; + *cnum = i; + } + } + } + + /* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */ + } +} + + +/************************************************************************* +* This function checks if the newbal is better than oldbal given the +* ubvector ubvec +**************************************************************************/ +int IsBetter2wayBalance(int ncon, float *newbal, float *oldbal, float *ubvec) +{ + int i, j; + float max1=0.0, max2=0.0, sum1=0.0, sum2=0.0, tmp; + + for (i=0; i<ncon; i++) { + tmp = (newbal[i]-1)/(ubvec[i]-1); + max1 = (max1 < tmp ? tmp : max1); + sum1 += tmp; + + tmp = (oldbal[i]-1)/(ubvec[i]-1); + max2 = (max2 < tmp ? tmp : max2); + sum2 += tmp; + } + + if (max1 < max2) + return 1; + else if (max1 > max2) + return 0; + else + return sum1 <= sum2; +} + + diff --git a/Metis/mincover.c b/Metis/mincover.c new file mode 100644 index 0000000000..3ebd4091c7 --- /dev/null +++ b/Metis/mincover.c @@ -0,0 +1,259 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mincover.c + * + * This file implements the minimum cover algorithm + * + * Started 8/1/97 + * George + * + * $Id: mincover.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + +/************************************************************************* +* Constants used by mincover algorithm +**************************************************************************/ +#define INCOL 10 +#define INROW 20 +#define VC 1 +#define SC 2 +#define HC 3 +#define VR 4 +#define SR 5 +#define HR 6 + + +/************************************************************************* +* This function returns the min-cover of a bipartite graph. +* The algorithm used is due to Hopcroft and Karp as modified by Duff etal +* adj: the adjacency list of the bipartite graph +* asize: the number of vertices in the first part of the bipartite graph +* bsize-asize: the number of vertices in the second part +* 0..(asize-1) > A vertices +* asize..bsize > B vertices +* +* Returns: +* cover : the actual cover (array) +* csize : the size of the cover +**************************************************************************/ +void MinCover(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *cover, int *csize) +{ + int i, j; + idxtype *mate, *queue, *flag, *level, *lst; + int fptr, rptr, lstptr; + int row, maxlevel, col; + + mate = idxsmalloc(bsize, -1, "MinCover: mate"); + flag = idxmalloc(bsize, "MinCover: flag"); + level = idxmalloc(bsize, "MinCover: level"); + queue = idxmalloc(bsize, "MinCover: queue"); + lst = idxmalloc(bsize, "MinCover: lst"); + + /* Get a cheap matching */ + for (i=0; i<asize; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (mate[adjncy[j]] == -1) { + mate[i] = adjncy[j]; + mate[adjncy[j]] = i; + break; + } + } + } + + /* Get into the main loop */ + while (1) { + /* Initialization */ + fptr = rptr = 0; /* Empty Queue */ + lstptr = 0; /* Empty List */ + for (i=0; i<bsize; i++) { + level[i] = -1; + flag[i] = 0; + } + maxlevel = bsize; + + /* Insert free nodes into the queue */ + for (i=0; i<asize; i++) + if (mate[i] == -1) { + queue[rptr++] = i; + level[i] = 0; + } + + /* Perform the BFS */ + while (fptr != rptr) { + row = queue[fptr++]; + if (level[row] < maxlevel) { + flag[row] = 1; + for (j=xadj[row]; j<xadj[row+1]; j++) { + col = adjncy[j]; + if (!flag[col]) { /* If this column has not been accessed yet */ + flag[col] = 1; + if (mate[col] == -1) { /* Free column node was found */ + maxlevel = level[row]; + lst[lstptr++] = col; + } + else { /* This column node is matched */ + if (flag[mate[col]]) + printf("\nSomething wrong, flag[%d] is 1",mate[col]); + queue[rptr++] = mate[col]; + level[mate[col]] = level[row] + 1; + } + } + } + } + } + + if (lstptr == 0) + break; /* No free columns can be reached */ + + /* Perform restricted DFS from the free column nodes */ + for (i=0; i<lstptr; i++) + MinCover_Augment(xadj, adjncy, lst[i], mate, flag, level, maxlevel); + } + + MinCover_Decompose(xadj, adjncy, asize, bsize, mate, cover, csize); + + GKfree(&mate, &flag, &level, &queue, &lst, LTERM); + +} + + +/************************************************************************* +* This function perfoms a restricted DFS and augments matchings +**************************************************************************/ +int MinCover_Augment(idxtype *xadj, idxtype *adjncy, int col, idxtype *mate, idxtype *flag, idxtype *level, int maxlevel) +{ + int i; + int row = -1; + int status; + + flag[col] = 2; + for (i=xadj[col]; i<xadj[col+1]; i++) { + row = adjncy[i]; + + if (flag[row] == 1) { /* First time through this row node */ + if (level[row] == maxlevel) { /* (col, row) is an edge of the G^T */ + flag[row] = 2; /* Mark this node as being visited */ + if (maxlevel != 0) + status = MinCover_Augment(xadj, adjncy, mate[row], mate, flag, level, maxlevel-1); + else + status = 1; + + if (status) { + mate[col] = row; + mate[row] = col; + return 1; + } + } + } + } + + return 0; +} + + + +/************************************************************************* +* This function performs a coarse decomposition and determines the +* min-cover. +* REF: Pothen ACMTrans. on Amth Software +**************************************************************************/ +void MinCover_Decompose(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *mate, idxtype *cover, int *csize) +{ + int i, k; + idxtype *where; + int card[10]; + + where = idxmalloc(bsize, "MinCover_Decompose: where"); + for (i=0; i<10; i++) + card[i] = 0; + + for (i=0; i<asize; i++) + where[i] = SC; + for (; i<bsize; i++) + where[i] = SR; + + for (i=0; i<asize; i++) + if (mate[i] == -1) + MinCover_ColDFS(xadj, adjncy, i, mate, where, INCOL); + for (; i<bsize; i++) + if (mate[i] == -1) + MinCover_RowDFS(xadj, adjncy, i, mate, where, INROW); + + for (i=0; i<bsize; i++) + card[where[i]]++; + + k = 0; + if (abs(card[VC]+card[SC]-card[HR]) < abs(card[VC]-card[SR]-card[HR])) { /* S = VC+SC+HR */ + /* printf("%d %d ",vc+sc, hr); */ + for (i=0; i<bsize; i++) + if (where[i] == VC || where[i] == SC || where[i] == HR) + cover[k++] = i; + } + else { /* S = VC+SR+HR */ + /* printf("%d %d ",vc, hr+sr); */ + for (i=0; i<bsize; i++) + if (where[i] == VC || where[i] == SR || where[i] == HR) + cover[k++] = i; + } + + *csize = k; + free(where); + +} + + +/************************************************************************* +* This function perfoms a dfs starting from an unmatched col node +* forming alternate paths +**************************************************************************/ +void MinCover_ColDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag) +{ + int i; + + if (flag == INCOL) { + if (where[root] == HC) + return; + where[root] = HC; + for (i=xadj[root]; i<xadj[root+1]; i++) + MinCover_ColDFS(xadj, adjncy, adjncy[i], mate, where, INROW); + } + else { + if (where[root] == HR) + return; + where[root] = HR; + if (mate[root] != -1) + MinCover_ColDFS(xadj, adjncy, mate[root], mate, where, INCOL); + } + +} + +/************************************************************************* +* This function perfoms a dfs starting from an unmatched col node +* forming alternate paths +**************************************************************************/ +void MinCover_RowDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag) +{ + int i; + + if (flag == INROW) { + if (where[root] == VR) + return; + where[root] = VR; + for (i=xadj[root]; i<xadj[root+1]; i++) + MinCover_RowDFS(xadj, adjncy, adjncy[i], mate, where, INCOL); + } + else { + if (where[root] == VC) + return; + where[root] = VC; + if (mate[root] != -1) + MinCover_RowDFS(xadj, adjncy, mate[root], mate, where, INROW); + } + +} + + + diff --git a/Metis/minitpart.c b/Metis/minitpart.c new file mode 100644 index 0000000000..2f77d221a9 --- /dev/null +++ b/Metis/minitpart.c @@ -0,0 +1,355 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * minitpart.c + * + * This file contains code that performs the initial partition of the + * coarsest graph + * + * Started 7/23/97 + * George + * + * $Id: minitpart.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void MocInit2WayPartition(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i, dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + switch (ctrl->IType) { + case IPART_GGPKL: + MocGrowBisection(ctrl, graph, tpwgts, ubfactor); + break; + case IPART_RANDOM: + MocRandomBisection(ctrl, graph, tpwgts, ubfactor); + break; + default: + errexit("Unknown initial partition type: %d\n", ctrl->IType); + } + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d [%d]\n", graph->mincut, graph->where[0])); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + ctrl->dbglvl = dbglvl; + +} + + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; + idxtype *bestwhere, *where; + + nvtxs = graph->nvtxs; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 1, where); + where[RandomInRange(nvtxs)] = 0; + + MocCompute2WayPartitionParams(ctrl, graph); + + MocInit2WayBalance(ctrl, graph, tpwgts); + + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + + MocBalance2Way(ctrl, graph, tpwgts, 1.02); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); + + if (bestcut >= graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, LTERM); +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i, ii, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs, qnum; + idxtype *bestwhere, *where, *perm; + int counts[MAXNCON]; + float *nvwgt; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + nvwgt = graph->nvwgt; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + perm = idxmalloc(nvtxs, "BisectGraph: perm"); + + for (; nbfs>0; nbfs--) { + for (i=0; i<ncon; i++) + counts[i] = 0; + + RandomPermute(nvtxs, perm, 1); + + /* Partition by spliting the queues randomly */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + qnum = samax(ncon, nvwgt+i*ncon); + where[i] = counts[qnum]; + counts[qnum] = (counts[qnum]+1)%2; + } + + MocCompute2WayPartitionParams(ctrl, graph); + + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); + MocBalance2Way(ctrl, graph, tpwgts, 1.02); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); + MocBalance2Way(ctrl, graph, tpwgts, 1.02); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); + + /* + printf("Edgecut: %6d, NPwgts: [", graph->mincut); + for (i=0; i<graph->ncon; i++) + printf("(%.3f %.3f) ", graph->npwgts[i], graph->npwgts[graph->ncon+i]); + printf("]\n"); + */ + + if (bestcut >= graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, &perm, LTERM); +} + + + + +/************************************************************************* +* This function balances two partitions by moving the highest gain +* (including negative gain) vertices to the other domain. +* It is used only when tha unbalance is due to non contigous +* subdomains. That is, the are no boundary vertices. +* It moves vertices from the domain that is overweight to the one that +* is underweight. +**************************************************************************/ +void MocInit2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts) +{ + int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *perm, *qnum; + float *nvwgt, *npwgts; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + nvwgt = graph->nvwgt; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + /* This is called for initial partitioning so we know from where to pick nodes */ + from = 1; + to = (from+1)%2; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], + graph->nvtxs, graph->nbnd, graph->mincut, + Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + ASSERT(CheckGraph(graph)); + + /* Compute the queues in which each vertex will be assigned to */ + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + /* Insert the nodes of the proper partition in the appropriate priority queue */ + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (where[i] == from) { + if (ed[i] > 0) + PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]); + else + PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]); + } + } + + + mincut = graph->mincut; + nbnd = graph->nbnd; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if (AreAnyVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, tpwgts[from])) + break; + + if ((cnum = SelectQueueOneWay(ncon, npwgts, tpwgts, from, parts)) == -1) + break; + + if ((higain = PQueueGetMax(&parts[cnum][0])) == -1) + higain = PQueueGetMax(&parts[cnum][1]); + + mincut -= (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + where[higain] = to; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + if (ed[higain] == 0 && id[higain] > 0) + printf("\t Pulled from the interior!\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (where[k] == from) { + if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */ + PQueueDelete(&parts[qnum[k]][1], k, oldgain); + PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]); + } + else { /* It must be in the boundary already */ + if (bndptr[k] == -1) + printf("What you thought was wrong!\n"); + PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]); + } + } + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + + ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut)); + + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +int SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from, PQueueType queues[MAXNCON][2]) +{ + int i, cnum=-1; + float max=0.0; + + for (i=0; i<ncon; i++) { + if (npwgts[from*ncon+i]-tpwgts[from] >= max && + PQueueGetSize(&queues[i][0]) + PQueueGetSize(&queues[i][1]) > 0) { + max = npwgts[from*ncon+i]-tpwgts[0]; + cnum = i; + } + } + + return cnum; +} + + diff --git a/Metis/minitpart2.c b/Metis/minitpart2.c new file mode 100644 index 0000000000..efda6fbdf2 --- /dev/null +++ b/Metis/minitpart2.c @@ -0,0 +1,368 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * minitpart2.c + * + * This file contains code that performs the initial partition of the + * coarsest graph + * + * Started 7/23/97 + * George + * + * $Id: minitpart2.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function computes the initial bisection of the coarsest graph +**************************************************************************/ +void MocInit2WayPartition2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int dbglvl; + + dbglvl = ctrl->dbglvl; + IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); + IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + + switch (ctrl->IType) { + case IPART_GGPKL: + case IPART_RANDOM: + MocGrowBisection2(ctrl, graph, tpwgts, ubvec); + break; + case 3: + MocGrowBisectionNew2(ctrl, graph, tpwgts, ubvec); + break; + default: + errexit("Unknown initial partition type: %d\n", ctrl->IType); + } + + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut)); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + ctrl->dbglvl = dbglvl; + +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocGrowBisection2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; + idxtype *bestwhere, *where; + + nvtxs = graph->nvtxs; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 1, where); + where[RandomInRange(nvtxs)] = 0; + + MocCompute2WayPartitionParams(ctrl, graph); + + MocBalance2Way2(ctrl, graph, tpwgts, ubvec); + + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4); + + MocBalance2Way2(ctrl, graph, tpwgts, ubvec); + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4); + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, LTERM); +} + + + + + + +/************************************************************************* +* This function takes a graph and produces a bisection by using a region +* growing algorithm. The resulting partition is returned in +* graph->where +**************************************************************************/ +void MocGrowBisectionNew2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; + idxtype *bestwhere, *where; + + nvtxs = graph->nvtxs; + + MocAllocate2WayPartitionMemory(ctrl, graph); + where = graph->where; + + bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); + nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); + bestcut = idxsum(graph->nedges, graph->adjwgt); + + for (; nbfs>0; nbfs--) { + idxset(nvtxs, 1, where); + where[RandomInRange(nvtxs)] = 0; + + MocCompute2WayPartitionParams(ctrl, graph); + + MocInit2WayBalance2(ctrl, graph, tpwgts, ubvec); + + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4); + + if (bestcut > graph->mincut) { + bestcut = graph->mincut; + idxcopy(nvtxs, where, bestwhere); + if (bestcut == 0) + break; + } + } + + graph->mincut = bestcut; + idxcopy(nvtxs, bestwhere, where); + + GKfree(&bestwhere, LTERM); +} + + + +/************************************************************************* +* This function balances two partitions by moving the highest gain +* (including negative gain) vertices to the other domain. +* It is used only when tha unbalance is due to non contigous +* subdomains. That is, the are no boundary vertices. +* It moves vertices from the domain that is overweight to the one that +* is underweight. +**************************************************************************/ +void MocInit2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp, imin; + idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; + idxtype *moved, *perm, *qnum; + float *nvwgt, *npwgts, minwgt; + PQueueType parts[MAXNCON][2]; + int higain, oldgain, mincut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + nvwgt = graph->nvwgt; + adjwgt = graph->adjwgt; + where = graph->where; + id = graph->id; + ed = graph->ed; + npwgts = graph->npwgts; + bndptr = graph->bndptr; + bndind = graph->bndind; + + moved = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + qnum = idxwspacemalloc(ctrl, nvtxs); + + /* This is called for initial partitioning so we know from where to pick nodes */ + from = 1; + to = (from+1)%2; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Parts: ["); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, ComputeLoadImbalance(ncon, 2, npwgts, tpwgts)); + } + + for (i=0; i<ncon; i++) { + PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); + PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); + } + + idxset(nvtxs, -1, moved); + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + ASSERT(CheckGraph(graph)); + + /* Compute the queues in which each vertex will be assigned to */ + for (i=0; i<nvtxs; i++) + qnum[i] = samax(ncon, nvwgt+i*ncon); + + /* Insert the nodes of the proper partition in the appropriate priority queue */ + RandomPermute(nvtxs, perm, 1); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + if (where[i] == from) { + if (ed[i] > 0) + PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]); + else + PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]); + } + } + +/* + for (i=0; i<ncon; i++) + printf("Queue #%d has %d %d\n", i, parts[i][0].nnodes, parts[i][1].nnodes); +*/ + + /* Determine the termination criterion */ + imin = 0; + for (i=1; i<ncon; i++) + imin = (ubvec[i] < ubvec[imin] ? i : imin); + minwgt = .5/ubvec[imin]; + + mincut = graph->mincut; + nbnd = graph->nbnd; + for (nswaps=0; nswaps<nvtxs; nswaps++) { + /* Exit as soon as the minimum weight crossed over */ + if (npwgts[to*ncon+imin] > minwgt) + break; + + if ((cnum = SelectQueueOneWay2(ncon, npwgts+to*ncon, parts, ubvec)) == -1) + break; + + if ((higain = PQueueGetMax(&parts[cnum][0])) == -1) + higain = PQueueGetMax(&parts[cnum][1]); + + mincut -= (ed[higain]-id[higain]); + saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); + + where[higain] = to; + moved[higain] = nswaps; + + if (ctrl->dbglvl&DBG_MOVEINFO) { + printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts)); + if (ed[higain] == 0 && id[higain] > 0) + printf("\t Pulled from the interior!\n"); + } + + + /************************************************************** + * Update the id[i]/ed[i] values of the affected nodes + ***************************************************************/ + SWAP(id[higain], ed[higain], tmp); + if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) + BNDDelete(nbnd, bndind, bndptr, higain); + if (ed[higain] > 0 && bndptr[higain] == -1) + BNDInsert(nbnd, bndind, bndptr, higain); + + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + oldgain = ed[k]-id[k]; + + kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); + INC_DEC(id[k], ed[k], kwgt); + + /* Update the queue position */ + if (moved[k] == -1 && where[k] == from) { + if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */ + PQueueDelete(&parts[qnum[k]][1], k, oldgain); + PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]); + } + else { /* It must be in the boundary already */ + if (bndptr[k] == -1) + printf("What you thought was wrong!\n"); + PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]); + } + } + + /* Update its boundary information */ + if (ed[k] == 0 && bndptr[k] != -1) + BNDDelete(nbnd, bndind, bndptr, k); + else if (ed[k] > 0 && bndptr[k] == -1) + BNDInsert(nbnd, bndind, bndptr, k); + } + + ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut)); + + } + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd); + for (l=0; l<ncon; l++) + printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); + printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts)); + } + + graph->mincut = mincut; + graph->nbnd = nbnd; + + for (i=0; i<ncon; i++) { + PQueueFree(ctrl, &parts[i][0]); + PQueueFree(ctrl, &parts[i][1]); + } + + ASSERT(ComputeCut(graph, where) == graph->mincut); + ASSERT(CheckBnd(graph)); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function selects the partition number and the queue from which +* we will move vertices out +**************************************************************************/ +int SelectQueueOneWay2(int ncon, float *pto, PQueueType queues[MAXNCON][2], float *ubvec) +{ + int i, cnum=-1, imax, maxgain; + float max=0.0; + float twgt[MAXNCON]; + + for (i=0; i<ncon; i++) { + if (max < pto[i]) { + imax = i; + max = pto[i]; + } + } + for (i=0; i<ncon; i++) + twgt[i] = (max/(ubvec[imax]*ubvec[i]))/pto[i]; + twgt[imax] = 0.0; + + max = 0.0; + for (i=0; i<ncon; i++) { + if (max < twgt[i] && (PQueueGetSize(&queues[i][0]) > 0 || PQueueGetSize(&queues[i][1]) > 0)) { + max = twgt[i]; + cnum = i; + } + } + if (max > 1) + return cnum; + + /* optimize of cut */ + maxgain = -10000000; + for (i=0; i<ncon; i++) { + if (PQueueGetSize(&queues[i][0]) > 0 && PQueueGetKey(&queues[i][0]) > maxgain) { + maxgain = PQueueGetKey(&queues[i][0]); + cnum = i; + } + } + + return cnum; + +} + diff --git a/Metis/mkmetis.c b/Metis/mkmetis.c new file mode 100644 index 0000000000..ed270e1c1a --- /dev/null +++ b/Metis/mkmetis.c @@ -0,0 +1,123 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mkmetis.c + * + * This file contains the top level routines for the multilevel k-way partitioning + * algorithm KMETIS. + * + * Started 7/28/97 + * George + * + * $Id: mkmetis.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function is the entry point for KWMETIS +**************************************************************************/ +void METIS_mCPartGraphKway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, + int *nparts, float *rubvec, int *options, int *edgecut, + idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_KMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = McKMETIS_CTYPE; + ctrl.IType = McKMETIS_ITYPE; + ctrl.RType = McKMETIS_RTYPE; + ctrl.dbglvl = McKMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KMETIS; + ctrl.CoarsenTo = amax((*nvtxs)/(20*log2(*nparts)), 30*(*nparts)); + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCMlevelKWayPartitioning(&ctrl, &graph, *nparts, part, rubvec); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float *rubvec) +{ + int i, j, nvtxs; + GraphType *cgraph; + int options[10], edgecut; + + cgraph = MCCoarsen2Way(ctrl, graph); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); + MocAllocateKWayPartitionMemory(ctrl, cgraph, nparts); + + options[0] = 1; + options[OPTION_CTYPE] = MATCH_SBHEM_INFNORM; + options[OPTION_ITYPE] = IPART_RANDOM; + options[OPTION_RTYPE] = RTYPE_FM; + options[OPTION_DBGLVL] = 0; + + /* Determine what you will use as the initial partitioner, based on tolerances */ + for (i=0; i<graph->ncon; i++) { + if (rubvec[i] > 1.2) + break; + } + if (i == graph->ncon) + METIS_mCPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, + cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, + options, &edgecut, cgraph->where); + else + METIS_mCHPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, + cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, + rubvec, options, &edgecut, cgraph->where); + + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); + + IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); + + MocRefineKWayHorizontal(ctrl, graph, cgraph, nparts, rubvec); + + idxcopy(graph->nvtxs, graph->where, part); + + GKfree(&graph->nvwgt, &graph->npwgts, &graph->gdata, &graph->rdata, LTERM); + + return graph->mincut; + +} + diff --git a/Metis/mkwayfmh.c b/Metis/mkwayfmh.c new file mode 100644 index 0000000000..0d06ed0e38 --- /dev/null +++ b/Metis/mkwayfmh.c @@ -0,0 +1,677 @@ +/* + * mkwayfmh.c + * + * This file contains code that implements the multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: mkwayfmh.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void MCRandom_KWayEdgeRefineHorizontal(CtrlType *ctrl, GraphType *graph, int nparts, + float *orgubvec, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, ncon, nmoves, nbnd, myndegrees, same; + int from, me, to, oldcut, gain; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *perm, *bndptr, *bndind; + EDegreeType *myedegrees; + RInfoType *myrinfo; + float *npwgts, *nvwgt, *minwgt, *maxwgt, maxlb, minlb, ubvec[MAXNCON], tvec[MAXNCON]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + npwgts = graph->npwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = fwspacemalloc(ctrl, nparts*ncon); + maxwgt = fwspacemalloc(ctrl, nparts*ncon); + + /* See if the orgubvec consists of identical constraints */ + maxlb = minlb = orgubvec[0]; + for (i=1; i<ncon; i++) { + minlb = (orgubvec[i] < minlb ? orgubvec[i] : minlb); + maxlb = (orgubvec[i] > maxlb ? orgubvec[i] : maxlb); + } + same = (fabs(maxlb-minlb) < .01 ? 1 : 0); + + + /* Let's not get very optimistic. Let Balancing do the work */ + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, ubvec); + for (i=0; i<ncon; i++) + ubvec[i] = amax(ubvec[i], orgubvec[i]); + + if (!same) { + for (i=0; i<nparts; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = ubvec[j]/nparts; + minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts); + } + } + } + else { + maxlb = ubvec[0]; + for (i=1; i<ncon; i++) + maxlb = (ubvec[i] > maxlb ? ubvec[i] : maxlb); + + for (i=0; i<nparts; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = maxlb/nparts; + minwgt[i*ncon+j] = 1.0/(maxlb*nparts); + } + } + } + + + perm = idxwspacemalloc(ctrl, nvtxs); + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + graph->nvtxs, graph->nbnd, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= nbnd) + continue; + i = bndind[ii]; + + myrinfo = graph->rinfo+i; + + if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ + from = where[i]; + nvwgt = graph->nvwgt+i*ncon; + + if (myrinfo->id > 0 && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon)) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + gain = myedegrees[k].ed - myrinfo->id; + if (gain >= 0 && + (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) || + IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if ((myedegrees[j].ed > myedegrees[k].ed && + (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) || + IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))) || + (myedegrees[j].ed == myedegrees[k].ed && + IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec))) + k = j; + } + + to = myedegrees[k].pid; + + if (myedegrees[k].ed-myrinfo->id == 0 + && !IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec) + && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, npwgts+from*ncon, maxwgt+from*ncon)) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1); + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + nmoves++; + } + } + + graph->nbnd = nbnd; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + nbnd, nmoves, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + if (graph->mincut == oldcut) + break; + } + + fwspacefree(ctrl, ncon*nparts); + fwspacefree(ctrl, ncon*nparts); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *ctrl, GraphType *graph, int nparts, + float *ubvec, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, ncon, nbnd, myndegrees, oldgain, gain, nmoves; + int from, me, to, oldcut; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *perm, *bndptr, *bndind, *moved; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + float *npwgts, *nvwgt, *minwgt, *maxwgt, tvec[MAXNCON]; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + npwgts = graph->npwgts; + + /* Setup the weight intervals of the various subdomains */ + minwgt = fwspacemalloc(ctrl, ncon*nparts); + maxwgt = fwspacemalloc(ctrl, ncon*nparts); + + for (i=0; i<nparts; i++) { + for (j=0; j<ncon; j++) { + maxwgt[i*ncon+j] = ubvec[j]/nparts; + minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts); + } + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + if (ctrl->dbglvl&DBG_REFINE) { + printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + graph->nvtxs, graph->nbnd, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("[B]\n"); + } + + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + /* Check to see if things are out of balance, given the tolerance */ + if (MocIsHBalanced(ncon, nparts, npwgts, ubvec)) + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + nmoves = 0; + for (;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + nvwgt = graph->nvwgt+i*ncon; + + if (AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon)) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec)) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec)) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (!AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon)) + j++; + if (myedegrees[k].ed-myrinfo->id >= 0) + j++; + if (!AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) && + AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon)) + j++; + if (j == 0) + continue; + +/* DELETE + if (myedegrees[k].ed-myrinfo->id < 0 && + AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon) && + AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) && + AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon)) + continue; +*/ + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update where, weight, and ID/ED information of the vertex you moved */ + saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1); + saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1); + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed == 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed > 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed == 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (myrinfo->ed > 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && myrinfo->ed > 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + } + nmoves++; + } + + graph->nbnd = nbnd; + + if (ctrl->dbglvl&DBG_REFINE) { + printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ", + npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)], + nbnd, nmoves, graph->mincut); + ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec); + for (i=0; i<ncon; i++) + printf("%.3f ", tvec[i]); + printf("\n"); + } + + if (nmoves == 0) + break; + } + + PQueueFree(ctrl, &queue); + + fwspacefree(ctrl, ncon*nparts); + fwspacefree(ctrl, ncon*nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + + + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllHVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] > limit[i]) + return 0; + + return 1; +} + + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are above +* a given set of values +**************************************************************************/ +int AreAllHVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] < limit[i]) + return 0; + + return 1; +} + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +* For now assume that we just want balanced partitionings +**************************************************************************/ +void ComputeHKWayLoadImbalance(int ncon, int nparts, float *npwgts, float *lbvec) +{ + int i, j; + float max; + + for (i=0; i<ncon; i++) { + max = 0.0; + for (j=0; j<nparts; j++) { + if (npwgts[j*ncon+i] > max) + max = npwgts[j*ncon+i]; + } + + lbvec[i] = max*nparts; + } +} + + +/************************************************************************* +* This function determines if a partitioning is horizontally balanced +**************************************************************************/ +int MocIsHBalanced(int ncon, int nparts, float *npwgts, float *ubvec) +{ + int i, j; + float max; + + for (i=0; i<ncon; i++) { + max = 0.0; + for (j=0; j<nparts; j++) { + if (npwgts[j*ncon+i] > max) + max = npwgts[j*ncon+i]; + } + + if (ubvec[i] < max*nparts) + return 0; + } + + return 1; +} + + + + + +/************************************************************************* +* This function checks if the pairwise balance of the between the two +* partitions will improve by moving the vertex v from pfrom to pto, +* subject to the target partition weights of tfrom, and tto respectively +**************************************************************************/ +int IsHBalanceBetterFT(int ncon, int nparts, float *pfrom, float *pto, float *vwgt, float *ubvec) +{ + int i, j, k; + float blb1=0.0, alb1=0.0, sblb=0.0, salb=0.0; + float blb2=0.0, alb2=0.0; + float temp; + + for (i=0; i<ncon; i++) { + temp = amax(pfrom[i], pto[i])*nparts/ubvec[i]; + if (blb1 < temp) { + blb2 = blb1; + blb1 = temp; + } + else if (blb2 < temp) + blb2 = temp; + sblb += temp; + + temp = amax(pfrom[i]-vwgt[i], pto[i]+vwgt[i])*nparts/ubvec[i]; + if (alb1 < temp) { + alb2 = alb1; + alb1 = temp; + } + else if (alb2 < temp) + alb2 = temp; + salb += temp; + } + + if (alb1 < blb1) + return 1; + if (blb1 < alb1) + return 0; + if (alb2 < blb2) + return 1; + if (blb2 < alb2) + return 0; + + return salb < sblb; + +} + + + + +/************************************************************************* +* This function checks if it will be better to move a vertex to pt2 than +* to pt1 subject to their target weights of tt1 and tt2, respectively +* This routine takes into account the weight of the vertex in question +**************************************************************************/ +int IsHBalanceBetterTT(int ncon, int nparts, float *pt1, float *pt2, float *vwgt, float *ubvec) +{ + int i; + float m11=0.0, m12=0.0, m21=0.0, m22=0.0, sm1=0.0, sm2=0.0, temp; + + for (i=0; i<ncon; i++) { + temp = (pt1[i]+vwgt[i])*nparts/ubvec[i]; + if (m11 < temp) { + m12 = m11; + m11 = temp; + } + else if (m12 < temp) + m12 = temp; + sm1 += temp; + + temp = (pt2[i]+vwgt[i])*nparts/ubvec[i]; + if (m21 < temp) { + m22 = m21; + m21 = temp; + } + else if (m22 < temp) + m22 = temp; + sm2 += temp; + } + + if (m21 < m11) + return 1; + if (m21 > m11) + return 0; + if (m22 < m12) + return 1; + if (m22 > m12) + return 0; + + return sm2 < sm1; +} + diff --git a/Metis/mkwayrefine.c b/Metis/mkwayrefine.c new file mode 100644 index 0000000000..0984ad707d --- /dev/null +++ b/Metis/mkwayrefine.c @@ -0,0 +1,297 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mkwayrefine.c + * + * This file contains the driving routines for multilevel k-way refinement + * + * Started 7/28/97 + * George + * + * $Id: mkwayrefine.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void MocRefineKWayHorizontal(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, + float *ubvec) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + MocComputeKWayPartitionParams(ctrl, graph, nparts); + + for (;;) { + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + + if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) { + MocComputeKWayBalanceBoundary(ctrl, graph, nparts); + MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4); + ComputeKWayBoundary(ctrl, graph, nparts); + } + + MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + MocProjectKWayPartition(ctrl, graph, nparts); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) { + MocComputeKWayBalanceBoundary(ctrl, graph, nparts); + MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4); + ComputeKWayBoundary(ctrl, graph, nparts); + MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + + + +/************************************************************************* +* This function allocates memory for k-way edge refinement +**************************************************************************/ +void MocAllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int nvtxs, ncon, pad64; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + + pad64 = (3*nvtxs)%2; + + graph->rdata = idxmalloc(3*nvtxs+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata"); + graph->where = graph->rdata; + graph->bndptr = graph->rdata + nvtxs; + graph->bndind = graph->rdata + 2*nvtxs; + graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs + pad64); + + graph->npwgts = fmalloc(ncon*nparts, "MocAllocateKWayPartitionMemory: npwgts"); +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void MocComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, l, nvtxs, ncon, nbnd, mincut, me, other; + idxtype *xadj, *adjncy, *adjwgt, *where, *bndind, *bndptr; + RInfoType *rinfo, *myrinfo; + EDegreeType *myedegrees; + float *nvwgt, *npwgts; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + npwgts = sset(ncon*nparts, 0.0, graph->npwgts); + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + rinfo = graph->rinfo; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + ctrl->wspace.cdegree = 0; + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1); + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + myrinfo->ed += adjwgt[j]; + } + myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed; + + if (myrinfo->ed > 0) + mincut += myrinfo->ed; + + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + /* Time to compute the particular external degrees */ + if (myrinfo->ed > 0) { + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (me != other) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == other) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = other; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + } + + ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void MocProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *bndptr, *bndind; + idxtype *cwhere; + GraphType *cgraph; + RInfoType *crinfo, *rinfo, *myrinfo; + EDegreeType *myedegrees; + idxtype *htable; + + cgraph = graph->coarser; + cwhere = cgraph->where; + crinfo = cgraph->rinfo; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + MocAllocateKWayPartitionMemory(ctrl, graph, nparts); + where = graph->where; + rinfo = graph->rinfo; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = crinfo[k].ed; /* For optimization */ + } + + htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); + + ctrl->wspace.cdegree = 0; + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + myrinfo = rinfo+i; + myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; + myrinfo->edegrees = NULL; + + myrinfo->id = adjwgtsum[i]; + + if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ + istart = xadj[i]; + iend = xadj[i+1]; + + myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += iend-istart; + + ndegrees = 0; + for (j=istart; j<iend; j++) { + other = where[adjncy[j]]; + if (me != other) { + myrinfo->ed += adjwgt[j]; + if ((k = htable[other]) == -1) { + htable[other] = ndegrees; + myedegrees[ndegrees].pid = other; + myedegrees[ndegrees++].ed = adjwgt[j]; + } + else { + myedegrees[k].ed += adjwgt[j]; + } + } + } + myrinfo->id -= myrinfo->ed; + + /* Remove space for edegrees if it was interior */ + if (myrinfo->ed == 0) { + myrinfo->edegrees = NULL; + ctrl->wspace.cdegree -= iend-istart; + } + else { + if (myrinfo->ed-myrinfo->id >= 0) + BNDInsert(nbnd, bndind, bndptr, i); + + myrinfo->ndegrees = ndegrees; + + for (j=0; j<ndegrees; j++) + htable[myedegrees[j].pid] = -1; + } + } + } + + scopy(graph->ncon*nparts, cgraph->npwgts, graph->npwgts); + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + idxwspacefree(ctrl, nparts); + + ASSERT(CheckBnd2(graph)); + +} + + + +/************************************************************************* +* This function computes the boundary definition for balancing +**************************************************************************/ +void MocComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) +{ + int i, nvtxs, nbnd; + idxtype *bndind, *bndptr; + + nvtxs = graph->nvtxs; + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /* Compute the new boundary */ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + if (graph->rinfo[i].ed > 0) + BNDInsert(nbnd, bndind, bndptr, i); + } + + graph->nbnd = nbnd; +} + diff --git a/Metis/mmatch.c b/Metis/mmatch.c new file mode 100644 index 0000000000..45259570d4 --- /dev/null +++ b/Metis/mmatch.c @@ -0,0 +1,506 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mmatch.c + * + * This file contains the code that computes matchings and creates the next + * level coarse graph. + * + * Started 7/23/97 + * George + * + * $Id: mmatch.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_RM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, ncon, cnvtxs, maxidx; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + /* Find a random matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_HEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, l, nvtxs, cnvtxs, ncon, maxidx, maxwgt; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *perm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + RandomPermute(nvtxs, perm, 1); + + cnvtxs = 0; + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] && + AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_SHEM(CtrlType *ctrl, GraphType *graph) +{ + int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = 0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] && + AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + maxwgt = adjwgt[j]; + maxidx = adjncy[j]; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_SHEBM(CtrlType *ctrl, GraphType *graph, int norm) +{ + int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + float *nvwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = -1; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + + if (match[k] == UNMATCHED && + AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt) && + (maxwgt < adjwgt[j] || + (maxwgt == adjwgt[j] && + BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon) >= 0 + ) + ) + ) { + maxwgt = adjwgt[j]; + maxidx = k; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function finds a matching using the HEM heuristic +**************************************************************************/ +void MCMatch_SBHEM(CtrlType *ctrl, GraphType *graph, int norm) +{ + int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *match, *cmap, *degrees, *perm, *tperm; + float *nvwgt, vbal; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + cmap = graph->cmap; + match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs)); + + perm = idxwspacemalloc(ctrl, nvtxs); + tperm = idxwspacemalloc(ctrl, nvtxs); + degrees = idxwspacemalloc(ctrl, nvtxs); + + RandomPermute(nvtxs, tperm, 1); + avgdegree = 0.7*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) + degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm); + + cnvtxs = 0; + + /* Take care any islands. Islands are matched with non-islands due to coarsening */ + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + if (xadj[i] < xadj[i+1]) + break; + + maxidx = i; + for (j=nvtxs-1; j>ii; j--) { + k = perm[j]; + if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) { + maxidx = k; + break; + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + /* Continue with normal matching */ + for (; ii<nvtxs; ii++) { + i = perm[ii]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + maxwgt = -1; + vbal = 0.0; + + /* Find a heavy-edge matching, subject to maxvwgt constraints */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) { + if (maxidx != i) + vbal = BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon); + + if (vbal > 0 || (vbal > -.01 && maxwgt < adjwgt[j])) { + maxwgt = adjwgt[j]; + maxidx = k; + } + } + } + + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr)); + + idxwspacefree(ctrl, nvtxs); /* degrees */ + idxwspacefree(ctrl, nvtxs); /* tperm */ + + CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + + + +/************************************************************************* +* This function checks if v+u2 provides a better balance in the weight +* vector that v+u1 +**************************************************************************/ +float BetterVBalance(int ncon, int norm, float *vwgt, float *u1wgt, float *u2wgt) +{ + int i; + float sum1, sum2, max1, max2, min1, min2, diff1, diff2; + + if (norm == -1) { + max1 = min1 = vwgt[0]+u1wgt[0]; + max2 = min2 = vwgt[0]+u2wgt[0]; + sum1 = vwgt[0]+u1wgt[0]; + sum2 = vwgt[0]+u2wgt[0]; + + for (i=1; i<ncon; i++) { + if (max1 < vwgt[i]+u1wgt[i]) + max1 = vwgt[i]+u1wgt[i]; + if (min1 > vwgt[i]+u1wgt[i]) + min1 = vwgt[i]+u1wgt[i]; + + if (max2 < vwgt[i]+u2wgt[i]) + max2 = vwgt[i]+u2wgt[i]; + if (min2 > vwgt[i]+u2wgt[i]) + min2 = vwgt[i]+u2wgt[i]; + + sum1 += vwgt[i]+u1wgt[i]; + sum2 += vwgt[i]+u2wgt[i]; + } + + if (sum1 == 0.0) + return 1; + else if (sum2 == 0.0) + return -1; + else + return ((max1-min1)/sum1) - ((max2-min2)/sum2); + } + else if (norm == 1) { + sum1 = sum2 = 0.0; + for (i=0; i<ncon; i++) { + sum1 += vwgt[i]+u1wgt[i]; + sum2 += vwgt[i]+u2wgt[i]; + } + sum1 = sum1/(1.0*ncon); + sum2 = sum2/(1.0*ncon); + + diff1 = diff2 = 0.0; + for (i=0; i<ncon; i++) { + diff1 += fabs(sum1 - (vwgt[i]+u1wgt[i])); + diff2 += fabs(sum2 - (vwgt[i]+u2wgt[i])); + } + + return diff1 - diff2; + } + else { + errexit("Unknown norm: %d\n", norm); + } + return 0.0; +} + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllVwgtsBelowFast(int ncon, float *vwgt1, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (vwgt1[i] + vwgt2[i] > limit) + return 0; + + return 1; +} + diff --git a/Metis/mmd.c b/Metis/mmd.c new file mode 100644 index 0000000000..bf3d16d786 --- /dev/null +++ b/Metis/mmd.c @@ -0,0 +1,593 @@ +/* + * mmd.c + * + * ************************************************************** + * The following C function was developed from a FORTRAN subroutine + * in SPARSPAK written by Eleanor Chu, Alan George, Joseph Liu + * and Esmond Ng. + * + * The FORTRAN-to-C transformation and modifications such as dynamic + * memory allocation and deallocation were performed by Chunguang + * Sun. + * ************************************************************** + * + * Taken from SMMS, George 12/13/94 + * + * The meaning of invperm, and perm vectors is different from that + * in genqmd_ of SparsPak + * + * $Id: mmd.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* genmmd -- multiple minimum external degree +* purpose -- this routine implements the minimum degree +* algorithm. it makes use of the implicit representation +* of elimination graphs by quotient graphs, and the notion +* of indistinguishable nodes. It also implements the modifications +* by multiple elimination and minimum external degree. +* Caution -- the adjacency vector adjncy will be destroyed. +* Input parameters -- +* neqns -- number of equations. +* (xadj, adjncy) -- the adjacency structure. +* delta -- tolerance value for multiple elimination. +* maxint -- maximum machine representable (short) integer +* (any smaller estimate will do) for marking nodes. +* Output parameters -- +* perm -- the minimum degree ordering. +* invp -- the inverse of perm. +* *ncsub -- an upper bound on the number of nonzero subscripts +* for the compressed storage scheme. +* Working parameters -- +* head -- vector for head of degree lists. +* invp -- used temporarily for degree forward link. +* perm -- used temporarily for degree backward link. +* qsize -- vector for size of supernodes. +* list -- vector for temporary linked lists. +* marker -- a temporary marker vector. +* Subroutines used -- mmdelm, mmdint, mmdnum, mmdupd. +**************************************************************************/ +void genmmd(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *invp, idxtype *perm, + int delta, idxtype *head, idxtype *qsize, idxtype *list, idxtype *marker, + int maxint, int *ncsub) +{ + int ehead, i, mdeg, mdlmt, mdeg_node, nextmd, num, tag; + + if (neqns <= 0) + return; + + /* Adjust from C to Fortran */ + xadj--; adjncy--; invp--; perm--; head--; qsize--; list--; marker--; + + /* initialization for the minimum degree algorithm. */ + *ncsub = 0; + mmdint(neqns, xadj, adjncy, head, invp, perm, qsize, list, marker); + + /* 'num' counts the number of ordered nodes plus 1. */ + num = 1; + + /* eliminate all isolated nodes. */ + nextmd = head[1]; + while (nextmd > 0) { + mdeg_node = nextmd; + nextmd = invp[mdeg_node]; + marker[mdeg_node] = maxint; + invp[mdeg_node] = -num; + num = num + 1; + } + + /* search for node of the minimum degree. 'mdeg' is the current */ + /* minimum degree; 'tag' is used to facilitate marking nodes. */ + if (num > neqns) + goto n1000; + tag = 1; + head[1] = 0; + mdeg = 2; + + /* infinite loop here ! */ + while (1) { + while (head[mdeg] <= 0) + mdeg++; + + /* use value of 'delta' to set up 'mdlmt', which governs */ + /* when a degree update is to be performed. */ + mdlmt = mdeg + delta; + ehead = 0; + +n500: + mdeg_node = head[mdeg]; + while (mdeg_node <= 0) { + mdeg++; + + if (mdeg > mdlmt) + goto n900; + mdeg_node = head[mdeg]; + }; + + /* remove 'mdeg_node' from the degree structure. */ + nextmd = invp[mdeg_node]; + head[mdeg] = nextmd; + if (nextmd > 0) + perm[nextmd] = -mdeg; + invp[mdeg_node] = -num; + *ncsub += mdeg + qsize[mdeg_node] - 2; + if ((num+qsize[mdeg_node]) > neqns) + goto n1000; + + /* eliminate 'mdeg_node' and perform quotient graph */ + /* transformation. reset 'tag' value if necessary. */ + tag++; + if (tag >= maxint) { + tag = 1; + for (i = 1; i <= neqns; i++) + if (marker[i] < maxint) + marker[i] = 0; + }; + + mmdelm(mdeg_node, xadj, adjncy, head, invp, perm, qsize, list, marker, maxint, tag); + + num += qsize[mdeg_node]; + list[mdeg_node] = ehead; + ehead = mdeg_node; + if (delta >= 0) + goto n500; + + n900: + /* update degrees of the nodes involved in the */ + /* minimum degree nodes elimination. */ + if (num > neqns) + goto n1000; + mmdupd( ehead, neqns, xadj, adjncy, delta, &mdeg, head, invp, perm, qsize, list, marker, maxint, &tag); + }; /* end of -- while ( 1 ) -- */ + +n1000: + mmdnum( neqns, perm, invp, qsize ); + + /* Adjust from Fortran back to C*/ + xadj++; adjncy++; invp++; perm++; head++; qsize++; list++; marker++; +} + + +/************************************************************************** +* mmdelm ...... multiple minimum degree elimination +* Purpose -- This routine eliminates the node mdeg_node of minimum degree +* from the adjacency structure, which is stored in the quotient +* graph format. It also transforms the quotient graph representation +* of the elimination graph. +* Input parameters -- +* mdeg_node -- node of minimum degree. +* maxint -- estimate of maximum representable (short) integer. +* tag -- tag value. +* Updated parameters -- +* (xadj, adjncy) -- updated adjacency structure. +* (head, forward, backward) -- degree doubly linked structure. +* qsize -- size of supernode. +* marker -- marker vector. +* list -- temporary linked list of eliminated nabors. +***************************************************************************/ +void mmdelm(int mdeg_node, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward, + idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker, int maxint,int tag) +{ + int element, i, istop, istart, j, + jstop, jstart, link, + nabor, node, npv, nqnbrs, nxnode, + pvnode, rlmt, rloc, rnode, xqnbr; + + /* find the reachable set of 'mdeg_node' and */ + /* place it in the data structure. */ + marker[mdeg_node] = tag; + istart = xadj[mdeg_node]; + istop = xadj[mdeg_node+1] - 1; + + /* 'element' points to the beginning of the list of */ + /* eliminated nabors of 'mdeg_node', and 'rloc' gives the */ + /* storage location for the next reachable node. */ + element = 0; + rloc = istart; + rlmt = istop; + for ( i = istart; i <= istop; i++ ) { + nabor = adjncy[i]; + if ( nabor == 0 ) break; + if ( marker[nabor] < tag ) { + marker[nabor] = tag; + if ( forward[nabor] < 0 ) { + list[nabor] = element; + element = nabor; + } else { + adjncy[rloc] = nabor; + rloc++; + }; + }; /* end of -- if -- */ + }; /* end of -- for -- */ + + /* merge with reachable nodes from generalized elements. */ + while ( element > 0 ) { + adjncy[rlmt] = -element; + link = element; + +n400: + jstart = xadj[link]; + jstop = xadj[link+1] - 1; + for ( j = jstart; j <= jstop; j++ ) { + node = adjncy[j]; + link = -node; + if ( node < 0 ) goto n400; + if ( node == 0 ) break; + if ((marker[node]<tag)&&(forward[node]>=0)) { + marker[node] = tag; + /*use storage from eliminated nodes if necessary.*/ + while ( rloc >= rlmt ) { + link = -adjncy[rlmt]; + rloc = xadj[link]; + rlmt = xadj[link+1] - 1; + }; + adjncy[rloc] = node; + rloc++; + }; + }; /* end of -- for ( j = jstart; -- */ + element = list[element]; + }; /* end of -- while ( element > 0 ) -- */ + if ( rloc <= rlmt ) adjncy[rloc] = 0; + /* for each node in the reachable set, do the following. */ + link = mdeg_node; + +n1100: + istart = xadj[link]; + istop = xadj[link+1] - 1; + for ( i = istart; i <= istop; i++ ) { + rnode = adjncy[i]; + link = -rnode; + if ( rnode < 0 ) goto n1100; + if ( rnode == 0 ) return; + + /* 'rnode' is in the degree list structure. */ + pvnode = backward[rnode]; + if (( pvnode != 0 ) && ( pvnode != (-maxint) )) { + /* then remove 'rnode' from the structure. */ + nxnode = forward[rnode]; + if ( nxnode > 0 ) backward[nxnode] = pvnode; + if ( pvnode > 0 ) forward[pvnode] = nxnode; + npv = -pvnode; + if ( pvnode < 0 ) head[npv] = nxnode; + }; + + /* purge inactive quotient nabors of 'rnode'. */ + jstart = xadj[rnode]; + jstop = xadj[rnode+1] - 1; + xqnbr = jstart; + for ( j = jstart; j <= jstop; j++ ) { + nabor = adjncy[j]; + if ( nabor == 0 ) break; + if ( marker[nabor] < tag ) { + adjncy[xqnbr] = nabor; + xqnbr++; + }; + }; + + /* no active nabor after the purging. */ + nqnbrs = xqnbr - jstart; + if ( nqnbrs <= 0 ) { + /* merge 'rnode' with 'mdeg_node'. */ + qsize[mdeg_node] += qsize[rnode]; + qsize[rnode] = 0; + marker[rnode] = maxint; + forward[rnode] = -mdeg_node; + backward[rnode] = -maxint; + } else { + /* flag 'rnode' for degree update, and */ + /* add 'mdeg_node' as a nabor of 'rnode'. */ + forward[rnode] = nqnbrs + 1; + backward[rnode] = 0; + adjncy[xqnbr] = mdeg_node; + xqnbr++; + if ( xqnbr <= jstop ) adjncy[xqnbr] = 0; + }; + }; /* end of -- for ( i = istart; -- */ + return; + } + +/*************************************************************************** +* mmdint ---- mult minimum degree initialization +* purpose -- this routine performs initialization for the +* multiple elimination version of the minimum degree algorithm. +* input parameters -- +* neqns -- number of equations. +* (xadj, adjncy) -- adjacency structure. +* output parameters -- +* (head, dfrow, backward) -- degree doubly linked structure. +* qsize -- size of supernode ( initialized to one). +* list -- linked list. +* marker -- marker vector. +****************************************************************************/ +int mmdint(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward, + idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker) +{ + int fnode, ndeg, node; + + for ( node = 1; node <= neqns; node++ ) { + head[node] = 0; + qsize[node] = 1; + marker[node] = 0; + list[node] = 0; + }; + + /* initialize the degree doubly linked lists. */ + for ( node = 1; node <= neqns; node++ ) { + ndeg = xadj[node+1] - xadj[node]/* + 1*/; /* george */ + if (ndeg == 0) + ndeg = 1; + fnode = head[ndeg]; + forward[node] = fnode; + head[ndeg] = node; + if ( fnode > 0 ) backward[fnode] = node; + backward[node] = -ndeg; + }; + return 0; +} + +/**************************************************************************** +* mmdnum --- multi minimum degree numbering +* purpose -- this routine performs the final step in producing +* the permutation and inverse permutation vectors in the +* multiple elimination version of the minimum degree +* ordering algorithm. +* input parameters -- +* neqns -- number of equations. +* qsize -- size of supernodes at elimination. +* updated parameters -- +* invp -- inverse permutation vector. on input, +* if qsize[node] = 0, then node has been merged +* into the node -invp[node]; otherwise, +* -invp[node] is its inverse labelling. +* output parameters -- +* perm -- the permutation vector. +****************************************************************************/ +void mmdnum(int neqns, idxtype *perm, idxtype *invp, idxtype *qsize) +{ + int father, nextf, node, nqsize, num, root; + + for ( node = 1; node <= neqns; node++ ) { + nqsize = qsize[node]; + if ( nqsize <= 0 ) perm[node] = invp[node]; + if ( nqsize > 0 ) perm[node] = -invp[node]; + }; + + /* for each node which has been merged, do the following. */ + for ( node = 1; node <= neqns; node++ ) { + if ( perm[node] <= 0 ) { + + /* trace the merged tree until one which has not */ + /* been merged, call it root. */ + father = node; + while ( perm[father] <= 0 ) + father = - perm[father]; + + /* number node after root. */ + root = father; + num = perm[root] + 1; + invp[node] = -num; + perm[root] = num; + + /* shorten the merged tree. */ + father = node; + nextf = - perm[father]; + while ( nextf > 0 ) { + perm[father] = -root; + father = nextf; + nextf = -perm[father]; + }; + }; /* end of -- if ( perm[node] <= 0 ) -- */ + }; /* end of -- for ( node = 1; -- */ + + /* ready to compute perm. */ + for ( node = 1; node <= neqns; node++ ) { + num = -invp[node]; + invp[node] = num; + perm[num] = node; + }; + return; +} + +/**************************************************************************** +* mmdupd ---- multiple minimum degree update +* purpose -- this routine updates the degrees of nodes after a +* multiple elimination step. +* input parameters -- +* ehead -- the beginning of the list of eliminated nodes +* (i.e., newly formed elements). +* neqns -- number of equations. +* (xadj, adjncy) -- adjacency structure. +* delta -- tolerance value for multiple elimination. +* maxint -- maximum machine representable (short) integer. +* updated parameters -- +* mdeg -- new minimum degree after degree update. +* (head, forward, backward) -- degree doubly linked structure. +* qsize -- size of supernode. +* list -- marker vector for degree update. +* *tag -- tag value. +****************************************************************************/ +void mmdupd(int ehead, int neqns, idxtype *xadj, idxtype *adjncy, int delta, int *mdeg, + idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list, + idxtype *marker, int maxint,int *tag) +{ + int deg, deg0, element, enode, fnode, i, iq2, istop, + istart, j, jstop, jstart, link, mdeg0, mtag, nabor, + node, q2head, qxhead; + + mdeg0 = *mdeg + delta; + element = ehead; + +n100: + if ( element <= 0 ) return; + + /* for each of the newly formed element, do the following. */ + /* reset tag value if necessary. */ + mtag = *tag + mdeg0; + if ( mtag >= maxint ) { + *tag = 1; + for ( i = 1; i <= neqns; i++ ) + if ( marker[i] < maxint ) marker[i] = 0; + mtag = *tag + mdeg0; + }; + + /* create two linked lists from nodes associated with 'element': */ + /* one with two nabors (q2head) in the adjacency structure, and the*/ + /* other with more than two nabors (qxhead). also compute 'deg0',*/ + /* number of nodes in this element. */ + q2head = 0; + qxhead = 0; + deg0 = 0; + link =element; + +n400: + istart = xadj[link]; + istop = xadj[link+1] - 1; + for ( i = istart; i <= istop; i++ ) { + enode = adjncy[i]; + link = -enode; + if ( enode < 0 ) goto n400; + if ( enode == 0 ) break; + if ( qsize[enode] != 0 ) { + deg0 += qsize[enode]; + marker[enode] = mtag; + + /*'enode' requires a degree update*/ + if ( backward[enode] == 0 ) { + /* place either in qxhead or q2head list. */ + if ( forward[enode] != 2 ) { + list[enode] = qxhead; + qxhead = enode; + } else { + list[enode] = q2head; + q2head = enode; + }; + }; + }; /* enf of -- if ( qsize[enode] != 0 ) -- */ + }; /* end of -- for ( i = istart; -- */ + + /* for each node in q2 list, do the following. */ + enode = q2head; + iq2 = 1; + +n900: + if ( enode <= 0 ) goto n1500; + if ( backward[enode] != 0 ) goto n2200; + (*tag)++; + deg = deg0; + + /* identify the other adjacent element nabor. */ + istart = xadj[enode]; + nabor = adjncy[istart]; + if ( nabor == element ) nabor = adjncy[istart+1]; + link = nabor; + if ( forward[nabor] >= 0 ) { + /* nabor is uneliminated, increase degree count. */ + deg += qsize[nabor]; + goto n2100; + }; + + /* the nabor is eliminated. for each node in the 2nd element */ + /* do the following. */ +n1000: + istart = xadj[link]; + istop = xadj[link+1] - 1; + for ( i = istart; i <= istop; i++ ) { + node = adjncy[i]; + link = -node; + if ( node != enode ) { + if ( node < 0 ) goto n1000; + if ( node == 0 ) goto n2100; + if ( qsize[node] != 0 ) { + if ( marker[node] < *tag ) { + /* 'node' is not yet considered. */ + marker[node] = *tag; + deg += qsize[node]; + } else { + if ( backward[node] == 0 ) { + if ( forward[node] == 2 ) { + /* 'node' is indistinguishable from 'enode'.*/ + /* merge them into a new supernode. */ + qsize[enode] += qsize[node]; + qsize[node] = 0; + marker[node] = maxint; + forward[node] = -enode; + backward[node] = -maxint; + } else { + /* 'node' is outmacthed by 'enode' */ + if (backward[node]==0) backward[node] = -maxint; + }; + }; /* end of -- if ( backward[node] == 0 ) -- */ + }; /* end of -- if ( marker[node] < *tag ) -- */ + }; /* end of -- if ( qsize[node] != 0 ) -- */ + }; /* end of -- if ( node != enode ) -- */ + }; /* end of -- for ( i = istart; -- */ + goto n2100; + +n1500: + /* for each 'enode' in the 'qx' list, do the following. */ + enode = qxhead; + iq2 = 0; + +n1600: if ( enode <= 0 ) goto n2300; + if ( backward[enode] != 0 ) goto n2200; + (*tag)++; + deg = deg0; + + /*for each unmarked nabor of 'enode', do the following.*/ + istart = xadj[enode]; + istop = xadj[enode+1] - 1; + for ( i = istart; i <= istop; i++ ) { + nabor = adjncy[i]; + if ( nabor == 0 ) break; + if ( marker[nabor] < *tag ) { + marker[nabor] = *tag; + link = nabor; + if ( forward[nabor] >= 0 ) + /*if uneliminated, include it in deg count.*/ + deg += qsize[nabor]; + else { +n1700: + /* if eliminated, include unmarked nodes in this*/ + /* element into the degree count. */ + jstart = xadj[link]; + jstop = xadj[link+1] - 1; + for ( j = jstart; j <= jstop; j++ ) { + node = adjncy[j]; + link = -node; + if ( node < 0 ) goto n1700; + if ( node == 0 ) break; + if ( marker[node] < *tag ) { + marker[node] = *tag; + deg += qsize[node]; + }; + }; /* end of -- for ( j = jstart; -- */ + }; /* end of -- if ( forward[nabor] >= 0 ) -- */ + }; /* end of -- if ( marker[nabor] < *tag ) -- */ + }; /* end of -- for ( i = istart; -- */ + +n2100: + /* update external degree of 'enode' in degree structure, */ + /* and '*mdeg' if necessary. */ + deg = deg - qsize[enode] + 1; + fnode = head[deg]; + forward[enode] = fnode; + backward[enode] = -deg; + if ( fnode > 0 ) backward[fnode] = enode; + head[deg] = enode; + if ( deg < *mdeg ) *mdeg = deg; + +n2200: + /* get next enode in current element. */ + enode = list[enode]; + if ( iq2 == 1 ) goto n900; + goto n1600; + +n2300: + /* get next element in the list. */ + *tag = mtag; + element = list[element]; + goto n100; + } diff --git a/Metis/mpmetis.c b/Metis/mpmetis.c new file mode 100644 index 0000000000..e8795cafdc --- /dev/null +++ b/Metis/mpmetis.c @@ -0,0 +1,402 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mpmetis.c + * + * This file contains the top level routines for the multilevel recursive + * bisection algorithm PMETIS. + * + * Started 7/24/97 + * George + * + * $Id: mpmetis.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = McPMETIS_CTYPE; + ctrl.IType = McPMETIS_ITYPE; + ctrl.RType = McPMETIS_RTYPE; + ctrl.dbglvl = McPMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCHPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *ubvec, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + float *myubvec; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts"); + scopy(*ncon, ubvec, myubvec); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + GKfree(&myubvec, LTERM); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + float *nvwgt, idxtype *adjwgt, int *nparts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + +} + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_mCHPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, + float *nvwgt, idxtype *adjwgt, int *nparts, float *ubvec, int *options, int *edgecut, + idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + float *myubvec; + + SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 100; + + ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); + + myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts"); + scopy(*ncon, ubvec, myubvec); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + GKfree(&myubvec, LTERM); + +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MCMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float ubfactor, int fpart) +{ + int i, j, nvtxs, ncon, cut; + idxtype *label, *where; + GraphType lgraph, rgraph; + float tpwgts[2]; + + nvtxs = graph->nvtxs; + if (nvtxs == 0) { + printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); + return 0; + } + + /* Determine the weights of the partitions */ + tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts); + tpwgts[1] = 1.0 - tpwgts[0]; + + MCMlevelEdgeBisection(ctrl, graph, tpwgts, ubfactor); + cut = graph->mincut; + + label = graph->label; + where = graph->where; + for (i=0; i<nvtxs; i++) + part[label[i]] = where[i] + fpart; + + if (nparts > 2) + SplitGraphPart(ctrl, graph, &lgraph, &rgraph); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, &graph->label, LTERM); + + + /* Do the recursive call */ + if (nparts > 3) { + cut += MCMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, ubfactor, fpart); + cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2); + } + else if (nparts == 3) { + cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2); + GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM); + } + + return cut; + +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MCHMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, + float *ubvec, int fpart) +{ + int i, j, nvtxs, ncon, cut; + idxtype *label, *where; + GraphType lgraph, rgraph; + float tpwgts[2], *npwgts, *lubvec, *rubvec; + + lubvec = rubvec = NULL; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + if (nvtxs == 0) { + printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); + return 0; + } + + /* Determine the weights of the partitions */ + tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts); + tpwgts[1] = 1.0 - tpwgts[0]; + + /* For now, relax at the coarsest level only */ + if (nparts == 2) + MCHMlevelEdgeBisection(ctrl, graph, tpwgts, ubvec); + else + MCMlevelEdgeBisection(ctrl, graph, tpwgts, 1.000); + cut = graph->mincut; + + label = graph->label; + where = graph->where; + for (i=0; i<nvtxs; i++) + part[label[i]] = where[i] + fpart; + + if (nparts > 2) { + /* Adjust the ubvecs before the split */ + npwgts = graph->npwgts; + lubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection"); + rubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection"); + + for (i=0; i<ncon; i++) { + lubvec[i] = ubvec[i]*tpwgts[0]/npwgts[i]; + lubvec[i] = amax(lubvec[i], 1.01); + + rubvec[i] = ubvec[i]*tpwgts[1]/npwgts[ncon+i]; + rubvec[i] = amax(rubvec[i], 1.01); + } + + SplitGraphPart(ctrl, graph, &lgraph, &rgraph); + } + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, &graph->label, LTERM); + + + /* Do the recursive call */ + if (nparts > 3) { + cut += MCHMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, lubvec, fpart); + cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2); + } + else if (nparts == 3) { + cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2); + GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM); + } + + GKfree(&lubvec, &rubvec, LTERM); + + return cut; + +} + + + + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MCMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) +{ + GraphType *cgraph; + + cgraph = MCCoarsen2Way(ctrl, graph); + + MocInit2WayPartition(ctrl, cgraph, tpwgts, ubfactor); + + MocRefine2Way(ctrl, graph, cgraph, tpwgts, ubfactor); + +} + + + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MCHMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) +{ + int i; + GraphType *cgraph; + +/* + for (i=0; i<graph->ncon; i++) + printf("%.4f ", ubvec[i]); + printf("\n"); +*/ + + cgraph = MCCoarsen2Way(ctrl, graph); + + MocInit2WayPartition2(ctrl, cgraph, tpwgts, ubvec); + + MocRefine2Way2(ctrl, graph, cgraph, tpwgts, ubvec); + +} + + diff --git a/Metis/mrefine.c b/Metis/mrefine.c new file mode 100644 index 0000000000..1012311581 --- /dev/null +++ b/Metis/mrefine.c @@ -0,0 +1,219 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * refine.c + * + * This file contains the driving routines for multilevel refinement + * + * Started 7/24/97 + * George + * + * $Id: mrefine.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor) +{ + int i; + float tubvec[MAXNCON]; + + for (i=0; i<graph->ncon; i++) + tubvec[i] = 1.0; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + MocCompute2WayPartitionParams(ctrl, graph); + + for (;;) { + ASSERT(CheckBnd(graph)); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + switch (ctrl->RType) { + case RTYPE_FM: + MocBalance2Way(ctrl, graph, tpwgts, 1.03); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); + break; + case 2: + MocBalance2Way(ctrl, graph, tpwgts, 1.03); + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, tubvec, 8); + break; + default: + errexit("Unknown refinement type: %d\n", ctrl->RType); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + MocProject2WayPartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + MocBalance2Way(ctrl, graph, tpwgts, 1.01); + MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for 2-way edge refinement +**************************************************************************/ +void MocAllocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph) +{ + int nvtxs, ncon; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + + graph->rdata = idxmalloc(5*nvtxs, "Allocate2WayPartitionMemory: rdata"); + graph->where = graph->rdata; + graph->id = graph->rdata + nvtxs; + graph->ed = graph->rdata + 2*nvtxs; + graph->bndptr = graph->rdata + 3*nvtxs; + graph->bndind = graph->rdata + 4*nvtxs; + + graph->npwgts = fmalloc(2*ncon, "npwgts"); +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void MocCompute2WayPartitionParams(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, l, nvtxs, ncon, nbnd, mincut; + idxtype *xadj, *adjncy, *adjwgt; + float *nvwgt, *npwgts; + idxtype *id, *ed, *where; + idxtype *bndptr, *bndind; + int me, other; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + npwgts = sset(2*ncon, 0.0, graph->npwgts); + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + ASSERT(where[i] >= 0 && where[i] <= 1); + me = where[i]; + saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1); + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me == where[adjncy[j]]) + id[i] += adjwgt[j]; + else + ed[i] += adjwgt[j]; + } + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + mincut += ed[i]; + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void MocProject2WayPartition(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, nvtxs, nbnd, me; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *id, *ed, *bndptr, *bndind; + idxtype *cwhere, *cid, *ced, *cbndptr; + GraphType *cgraph; + + cgraph = graph->coarser; + cwhere = cgraph->where; + cid = cgraph->id; + ced = cgraph->ed; + cbndptr = cgraph->bndptr; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + MocAllocate2WayPartitionMemory(ctrl, graph); + + where = graph->where; + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = cbndptr[k]; + } + + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + id[i] = adjwgtsum[i]; + + if (xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + else { + if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + ed[i] += adjwgt[j]; + } + id[i] -= ed[i]; + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + } + } + + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + scopy(2*graph->ncon, cgraph->npwgts, graph->npwgts); + + FreeGraph(graph->coarser); + graph->coarser = NULL; + +} + diff --git a/Metis/mrefine2.c b/Metis/mrefine2.c new file mode 100644 index 0000000000..636c9a5337 --- /dev/null +++ b/Metis/mrefine2.c @@ -0,0 +1,55 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * mrefine2.c + * + * This file contains the driving routines for multilevel refinement + * + * Started 7/24/97 + * George + * + * $Id: mrefine2.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void MocRefine2Way2(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, + float *ubvec) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + MocCompute2WayPartitionParams(ctrl, graph); + + for (;;) { + ASSERT(CheckBnd(graph)); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + switch (ctrl->RType) { + case RTYPE_FM: + MocBalance2Way2(ctrl, graph, tpwgts, ubvec); + MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 8); + break; + default: + errexit("Unknown refinement type: %d\n", ctrl->RType); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + MocProject2WayPartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + diff --git a/Metis/mutil.c b/Metis/mutil.c new file mode 100644 index 0000000000..08871df652 --- /dev/null +++ b/Metis/mutil.c @@ -0,0 +1,101 @@ +/* + * mutil.c + * + * This file contains various utility functions for the MOC portion of the + * code + * + * Started 2/15/98 + * George + * + * $Id: mutil.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] > limit) + return 0; + + return 1; +} + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAnyVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] < limit) + return 1; + + return 0; +} + + + +/************************************************************************* +* This function checks if the vertex weights of two vertices are above +* a given set of values +**************************************************************************/ +int AreAllVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit) +{ + int i; + + for (i=0; i<ncon; i++) + if (alpha*vwgt1[i] + beta*vwgt2[i] < limit) + return 0; + + return 1; +} + + +/************************************************************************* +* This function computes the load imbalance over all the constrains +* For now assume that we just want balanced partitionings +**************************************************************************/ +float ComputeLoadImbalance(int ncon, int nparts, float *npwgts, float *tpwgts) +{ + int i, j; + float max, lb=0.0; + + for (i=0; i<ncon; i++) { + max = 0.0; + for (j=0; j<nparts; j++) { + if (npwgts[j*ncon+i] > max) + max = npwgts[j*ncon+i]; + } + if (max*nparts > lb) + lb = max*nparts; + } + + return lb; +} + +/************************************************************************* +* This function checks if the vertex weights of two vertices are below +* a given set of values +**************************************************************************/ +int AreAllBelow(int ncon, float *v1, float *v2) +{ + int i; + + for (i=0; i<ncon; i++) + if (v1[i] > v2[i]) + return 0; + + return 1; +} diff --git a/Metis/myqsort.c b/Metis/myqsort.c new file mode 100644 index 0000000000..07267ae34a --- /dev/null +++ b/Metis/myqsort.c @@ -0,0 +1,547 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * myqsort.c + * + * This file contains a fast idxtype increasing qsort algorithm. + * Addopted from TeX + * + * Started 10/18/96 + * George + * + * $Id: myqsort.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + */ + +#include <metis.h> /* only for type declarations */ + +#define THRESH 1 /* threshold for insertion */ +#define MTHRESH 6 /* threshold for median */ + + + + +static void siqst(idxtype *, idxtype *); +static void iiqst(int *, int *); +static void keyiqst(KeyValueType *, KeyValueType *); +static void keyvaliqst(KeyValueType *, KeyValueType *); + + +/************************************************************************* +* Entry point of idxtype increasing sort +**************************************************************************/ +void iidxsort(int n, idxtype *base) +{ + register idxtype *i; + register idxtype *j; + register idxtype *lo; + register idxtype *hi; + register idxtype *min; + register idxtype c; + idxtype *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + siqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if (*j > *lo) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while (*(--hi) > *min); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} + +static void siqst(idxtype *base, idxtype *max) +{ + register idxtype *i; + register idxtype *j; + register idxtype *jj; + register idxtype *mid; + register int ii; + register idxtype c; + idxtype *tmp; + int lo; + int hi; + + lo = max - base; /* number of elements as idxtype */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (*base > *mid ? base : mid); + tmp = max - 1; + if (*j > *tmp) { + j = (j == base ? mid : base); /* switch to first loser */ + if (*j < *tmp) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && *i <= *mid) + i++; + while (j > mid) { + if (*mid <= *j) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = j - base) <= (hi = max - i)) { + if (lo >= THRESH) + siqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + siqst(i, max); + max = j; + } + } while (lo >= THRESH); +} + + + + + +/************************************************************************* +* Entry point of int increasing sort +**************************************************************************/ +void iintsort(int n, int *base) +{ + register int *i; + register int *j; + register int *lo; + register int *hi; + register int *min; + register int c; + int *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + iiqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if (*j > *lo) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while (*(--hi) > *min); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} + + +static void iiqst(int *base, int *max) +{ + register int *i; + register int *j; + register int *jj; + register int *mid; + register int ii; + register int c; + int *tmp; + int lo; + int hi; + + lo = max - base; /* number of elements as ints */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (*base > *mid ? base : mid); + tmp = max - 1; + if (*j > *tmp) { + j = (j == base ? mid : base); /* switch to first loser */ + if (*j < *tmp) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && *i <= *mid) + i++; + while (j > mid) { + if (*mid <= *j) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = j - base) <= (hi = max - i)) { + if (lo >= THRESH) + iiqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + iiqst(i, max); + max = j; + } + } while (lo >= THRESH); +} + + + + + +/************************************************************************* +* Entry point of KeyVal increasing sort, ONLY key part +**************************************************************************/ +void ikeysort(int n, KeyValueType *base) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *lo; + register KeyValueType *hi; + register KeyValueType *min; + register KeyValueType c; + KeyValueType *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + keyiqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if (j->key > lo->key) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while ((--hi)->key > min->key); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } + + /* Sanity check */ + { + int i; + for (i=0; i<n-1; i++) + if (base[i].key > base[i+1].key) + printf("Something went wrong!\n"); + } +} + + +static void keyiqst(KeyValueType *base, KeyValueType *max) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *jj; + register KeyValueType *mid; + register KeyValueType c; + KeyValueType *tmp; + int lo; + int hi; + + lo = (max - base)>>1; /* number of elements as KeyValueType */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (base->key > mid->key ? base : mid); + tmp = max - 1; + if (j->key > tmp->key) { + j = (j == base ? mid : base); /* switch to first loser */ + if (j->key < tmp->key) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && i->key <= mid->key) + i++; + while (j > mid) { + if (mid->key <= j->key) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) { + if (lo >= THRESH) + keyiqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + keyiqst(i, max); + max = j; + } + } while (lo >= THRESH); +} + + + + +/************************************************************************* +* Entry point of KeyVal increasing sort, BOTH key and val part +**************************************************************************/ +void ikeyvalsort(int n, KeyValueType *base) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *lo; + register KeyValueType *hi; + register KeyValueType *min; + register KeyValueType c; + KeyValueType *max; + + if (n <= 1) + return; + + max = base + n; + + if (n >= THRESH) { + keyvaliqst(base, max); + hi = base + THRESH; + } + else + hi = max; + + for (j = lo = base; lo++ < hi;) { + if ((j->key > lo->key) || (j->key == lo->key && j->val > lo->val)) + j = lo; + } + if (j != base) { /* swap j into place */ + c = *base; + *base = *j; + *j = c; + } + + for (min = base; (hi = min += 1) < max;) { + while ((--hi)->key > min->key || (hi->key == min->key && hi->val > min->val)); + if ((hi += 1) != min) { + for (lo = min + 1; --lo >= min;) { + c = *lo; + for (i = j = lo; (j -= 1) >= hi; i = j) + *i = *j; + *i = c; + } + } + } +} + + +static void keyvaliqst(KeyValueType *base, KeyValueType *max) +{ + register KeyValueType *i; + register KeyValueType *j; + register KeyValueType *jj; + register KeyValueType *mid; + register KeyValueType c; + KeyValueType *tmp; + int lo; + int hi; + + lo = (max - base)>>1; /* number of elements as KeyValueType */ + do { + mid = base + ((unsigned) lo>>1); + if (lo >= MTHRESH) { + j = (base->key > mid->key || (base->key == mid->key && base->val > mid->val) ? base : mid); + tmp = max - 1; + if (j->key > tmp->key || (j->key == tmp->key && j->val > tmp->val)) { + j = (j == base ? mid : base); /* switch to first loser */ + if (j->key < tmp->key || (j->key == tmp->key && j->val < tmp->val)) + j = tmp; + } + + if (j != mid) { /* SWAP */ + c = *mid; + *mid = *j; + *j = c; + } + } + + /* Semi-standard quicksort partitioning/swapping */ + for (i = base, j = max - 1;;) { + while (i < mid && (i->key < mid->key || (i->key == mid->key && i->val <= mid->val))) + i++; + while (j > mid) { + if (mid->key < j->key || (mid->key == j->key && mid->val <= j->val)) { + j--; + continue; + } + tmp = i + 1; /* value of i after swap */ + if (i == mid) /* j <-> mid, new mid is j */ + mid = jj = j; + else /* i <-> j */ + jj = j--; + goto swap; + } + + if (i == mid) + break; + else { /* i <-> mid, new mid is i */ + jj = mid; + tmp = mid = i; /* value of i after swap */ + j--; + } +swap: + c = *i; + *i = *jj; + *jj = c; + i = tmp; + } + + i = (j = mid) + 1; + if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) { + if (lo >= THRESH) + keyvaliqst(base, j); + base = i; + lo = hi; + } + else { + if (hi >= THRESH) + keyvaliqst(i, max); + max = j; + } + } while (lo >= THRESH); +} diff --git a/Metis/ometis.c b/Metis/ometis.c new file mode 100644 index 0000000000..9ed53b4105 --- /dev/null +++ b/Metis/ometis.c @@ -0,0 +1,764 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * ometis.c + * + * This file contains the top level routines for the multilevel recursive + * bisection algorithm PMETIS. + * + * Started 7/24/97 + * George + * + * $Id: ometis.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for OEMETIS +**************************************************************************/ +void METIS_EdgeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, + idxtype *perm, idxtype *iperm) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_OEMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = OEMETIS_CTYPE; + ctrl.IType = OEMETIS_ITYPE; + ctrl.RType = OEMETIS_RTYPE; + ctrl.dbglvl = OEMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.oflags = 0; + ctrl.pfactor = -1; + ctrl.nseps = 1; + + ctrl.optype = OP_OEMETIS; + ctrl.CoarsenTo = 20; + ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, 2); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + for (i=0; i<*nvtxs; i++) + perm[iperm[i]] = i; + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); +} + + +/************************************************************************* +* This function is the entry point for ONCMETIS +**************************************************************************/ +void METIS_NodeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, + idxtype *perm, idxtype *iperm) +{ + int i, ii, j, l, wflag, nflag; + GraphType graph; + CtrlType ctrl; + idxtype *cptr, *cind, *piperm; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + ctrl.oflags = ONMETIS_OFLAGS; + ctrl.pfactor = ONMETIS_PFACTOR; + ctrl.nseps = ONMETIS_NSEPS; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + ctrl.oflags = options[OPTION_OFLAGS]; + ctrl.pfactor = options[OPTION_PFACTOR]; + ctrl.nseps = options[OPTION_NSEPS]; + } + if (ctrl.nseps < 1) + ctrl.nseps = 1; + + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = 100; + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + InitRandom(-1); + + if (ctrl.pfactor > 0) { + /*============================================================ + * Prune the dense columns + ==============================================================*/ + piperm = idxmalloc(*nvtxs, "ONMETIS: piperm"); + + PruneGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, piperm, (float)(0.1*ctrl.pfactor)); + } + else if (ctrl.oflags&OFLAG_COMPRESS) { + /*============================================================ + * Compress the graph + ==============================================================*/ + cptr = idxmalloc(*nvtxs+1, "ONMETIS: cptr"); + cind = idxmalloc(*nvtxs, "ONMETIS: cind"); + + CompressGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, cptr, cind); + + if (graph.nvtxs >= COMPRESSION_FRACTION*(*nvtxs)) { + ctrl.oflags--; /* We actually performed no compression */ + GKfree(&cptr, &cind, LTERM); + } + else if (2*graph.nvtxs < *nvtxs && ctrl.nseps == 1) + ctrl.nseps = 2; + } + else { + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0); + } + + + /*============================================================= + * Do the nested dissection ordering + --=============================================================*/ + ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo); + AllocateWorkSpace(&ctrl, &graph, 2); + + if (ctrl.oflags&OFLAG_CCMP) + MlevelNestedDissectionCC(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs); + else + MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs); + + FreeWorkSpace(&ctrl, &graph); + + if (ctrl.pfactor > 0) { /* Order any prunned vertices */ + if (graph.nvtxs < *nvtxs) { + idxcopy(graph.nvtxs, iperm, perm); /* Use perm as an auxiliary array */ + for (i=0; i<graph.nvtxs; i++) + iperm[piperm[i]] = perm[i]; + for (i=graph.nvtxs; i<*nvtxs; i++) + iperm[piperm[i]] = i; + } + + GKfree(&piperm, LTERM); + } + else if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */ + if (graph.nvtxs < COMPRESSION_FRACTION*(*nvtxs)) { + /* construct perm from iperm */ + for (i=0; i<graph.nvtxs; i++) + perm[iperm[i]] = i; + for (l=ii=0; ii<graph.nvtxs; ii++) { + i = perm[ii]; + for (j=cptr[i]; j<cptr[i+1]; j++) + iperm[cind[j]] = l++; + } + } + + GKfree(&cptr, &cind, LTERM); + } + + + for (i=0; i<*nvtxs; i++) + perm[iperm[i]] = i; + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + if (*numflag == 1) + Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); + +} + + +/************************************************************************* +* This function is the entry point for ONWMETIS. It requires weights on the +* vertices. It is for the case that the matrix has been pre-compressed. +**************************************************************************/ +void METIS_NodeWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, + int *options, idxtype *perm, idxtype *iperm) +{ + int i, j, tvwgt; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, NULL, 2); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + + ctrl.oflags = OFLAG_COMPRESS; + ctrl.pfactor = 0; + ctrl.nseps = 2; + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = 100; + ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, 2); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + for (i=0; i<*nvtxs; i++) + perm[iperm[i]] = i; + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); +} + + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +void MlevelNestedDissection(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx) +{ + int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2]; + idxtype *label, *bndind; + GraphType lgraph, rgraph; + + nvtxs = graph->nvtxs; + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt/2; + tpwgts2[1] = tvwgt-tpwgts2[0]; + + switch (ctrl->optype) { + case OP_OEMETIS: + MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr)); + ConstructMinCoverSeparator(ctrl, graph, ubfactor); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr)); + + break; + case OP_ONMETIS: + MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); + + break; + } + + /* Order the nodes in the separator */ + nbnd = graph->nbnd; + bndind = graph->bndind; + label = graph->label; + for (i=0; i<nbnd; i++) + order[label[bndind[i]]] = --lastvtx; + + SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + if (rgraph.nvtxs > MMDSWITCH) + MlevelNestedDissection(ctrl, &rgraph, order, ubfactor, lastvtx); + else { + MMDOrder(ctrl, &rgraph, order, lastvtx); + GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM); + } + if (lgraph.nvtxs > MMDSWITCH) + MlevelNestedDissection(ctrl, &lgraph, order, ubfactor, lastvtx-rgraph.nvtxs); + else { + MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs); + GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM); + } +} + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +void MlevelNestedDissectionCC(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx) +{ + int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2], nsgraphs, ncmps, rnvtxs; + idxtype *label, *bndind; + idxtype *cptr, *cind; + GraphType *sgraphs; + + nvtxs = graph->nvtxs; + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt/2; + tpwgts2[1] = tvwgt-tpwgts2[0]; + + MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); + IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); + + /* Order the nodes in the separator */ + nbnd = graph->nbnd; + bndind = graph->bndind; + label = graph->label; + for (i=0; i<nbnd; i++) + order[label[bndind[i]]] = --lastvtx; + + cptr = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cptr"); + cind = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cind"); + ncmps = FindComponents(ctrl, graph, cptr, cind); + +/* + if (ncmps > 2) + printf("[%5d] has %3d components\n", nvtxs, ncmps); +*/ + + sgraphs = (GraphType *)GKmalloc(ncmps*sizeof(GraphType), "MlevelNestedDissectionCC: sgraphs"); + + nsgraphs = SplitGraphOrderCC(ctrl, graph, sgraphs, ncmps, cptr, cind); + + GKfree(&cptr, &cind, LTERM); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + /* Go and process the subgraphs */ + for (rnvtxs=i=0; i<nsgraphs; i++) { + if (sgraphs[i].adjwgt == NULL) { + MMDOrder(ctrl, sgraphs+i, order, lastvtx-rnvtxs); + GKfree(&sgraphs[i].gdata, &sgraphs[i].label, LTERM); + } + else { + MlevelNestedDissectionCC(ctrl, sgraphs+i, order, ubfactor, lastvtx-rnvtxs); + } + rnvtxs += sgraphs[i].nvtxs; + } + + free(sgraphs); +} + + + +/************************************************************************* +* This function performs multilevel bisection. It performs multiple +* bisections and selects the best. +**************************************************************************/ +void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + int i, nvtxs, cnvtxs, mincut, tmp; + GraphType *cgraph; + idxtype *bestwhere; + + if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->oflags&OFLAG_COMPRESS ? 1000 : 2000)) { + MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); + return; + } + + nvtxs = graph->nvtxs; + + if (ctrl->oflags&OFLAG_COMPRESS) { /* Multiple separators at the original graph */ + bestwhere = idxmalloc(nvtxs, "MlevelNodeBisection2: bestwhere"); + mincut = nvtxs; + + for (i=ctrl->nseps; i>0; i--) { + MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); + + /* printf("%5d ", cgraph->mincut); */ + + if (graph->mincut < mincut) { + mincut = graph->mincut; + idxcopy(nvtxs, graph->where, bestwhere); + } + + GKfree(&graph->rdata, LTERM); + + if (mincut == 0) + break; + } + /* printf("[%5d]\n", mincut); */ + + Allocate2WayNodePartitionMemory(ctrl, graph); + idxcopy(nvtxs, bestwhere, graph->where); + free(bestwhere); + + Compute2WayNodePartitionParams(ctrl, graph); + } + else { /* Coarsen it a bit */ + ctrl->CoarsenTo = nvtxs-1; + + cgraph = Coarsen2Way(ctrl, graph); + + cnvtxs = cgraph->nvtxs; + + bestwhere = idxmalloc(cnvtxs, "MlevelNodeBisection2: bestwhere"); + mincut = nvtxs; + + for (i=ctrl->nseps; i>0; i--) { + ctrl->CType += 20; /* This is a hack. Look at coarsen.c */ + MlevelNodeBisection(ctrl, cgraph, tpwgts, ubfactor); + + /* printf("%5d ", cgraph->mincut); */ + + if (cgraph->mincut < mincut) { + mincut = cgraph->mincut; + idxcopy(cnvtxs, cgraph->where, bestwhere); + } + + GKfree(&cgraph->rdata, LTERM); + + if (mincut == 0) + break; + } + /* printf("[%5d]\n", mincut); */ + + Allocate2WayNodePartitionMemory(ctrl, cgraph); + idxcopy(cnvtxs, bestwhere, cgraph->where); + free(bestwhere); + + Compute2WayNodePartitionParams(ctrl, cgraph); + + Refine2WayNode(ctrl, graph, cgraph, ubfactor); + } + +} + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MlevelNodeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + GraphType *cgraph; + + ctrl->CoarsenTo = graph->nvtxs/8; + if (ctrl->CoarsenTo > 100) + ctrl->CoarsenTo = 100; + else if (ctrl->CoarsenTo < 40) + ctrl->CoarsenTo = 40; + ctrl->maxvwgt = 1.5*((tpwgts[0]+tpwgts[1])/ctrl->CoarsenTo); + + cgraph = Coarsen2Way(ctrl, graph); + + switch (ctrl->IType) { + case IPART_GGPKL: + Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr)); + + Compute2WayPartitionParams(ctrl, cgraph); + ConstructSeparator(ctrl, cgraph, ubfactor); + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr)); + break; + case IPART_GGPKLNODE: + InitSeparator(ctrl, cgraph, ubfactor); + break; + } + + Refine2WayNode(ctrl, graph, cgraph, ubfactor); + +} + + + + +/************************************************************************* +* This function takes a graph and a bisection and splits it into two graphs. +* This function relies on the fact that adjwgt is all equal to 1. +**************************************************************************/ +void SplitGraphOrder(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph) +{ + int i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3]; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind; + idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2]; + idxtype *rename; + idxtype *auxadjncy, *auxadjwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + label = graph->label; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + ASSERT(bndptr != NULL); + + rename = idxwspacemalloc(ctrl, nvtxs); + + snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0; + for (i=0; i<nvtxs; i++) { + k = where[i]; + rename[i] = snvtxs[k]++; + snedges[k] += xadj[i+1]-xadj[i]; + } + + SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]); + sxadj[0] = lgraph->xadj; + svwgt[0] = lgraph->vwgt; + sadjwgtsum[0] = lgraph->adjwgtsum; + sadjncy[0] = lgraph->adjncy; + sadjwgt[0] = lgraph->adjwgt; + slabel[0] = lgraph->label; + + SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]); + sxadj[1] = rgraph->xadj; + svwgt[1] = rgraph->vwgt; + sadjwgtsum[1] = rgraph->adjwgtsum; + sadjncy[1] = rgraph->adjncy; + sadjwgt[1] = rgraph->adjwgt; + slabel[1] = rgraph->label; + + /* Go and use bndptr to also mark the boundary nodes in the two partitions */ + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[ii]; + for (j=xadj[i]; j<xadj[i+1]; j++) + bndptr[adjncy[j]] = 1; + } + + snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; + sxadj[0][0] = sxadj[1][0] = 0; + for (i=0; i<nvtxs; i++) { + if ((mypart = where[i]) == 2) + continue; + + istart = xadj[i]; + iend = xadj[i+1]; + if (bndptr[i] == -1) { /* This is an interior vertex */ + auxadjncy = sadjncy[mypart] + snedges[mypart] - istart; + for(j=istart; j<iend; j++) + auxadjncy[j] = adjncy[j]; + snedges[mypart] += iend-istart; + } + else { + auxadjncy = sadjncy[mypart]; + l = snedges[mypart]; + for (j=istart; j<iend; j++) { + k = adjncy[j]; + if (where[k] == mypart) + auxadjncy[l++] = k; + } + snedges[mypart] = l; + } + + svwgt[mypart][snvtxs[mypart]] = vwgt[i]; + sadjwgtsum[mypart][snvtxs[mypart]] = snedges[mypart]-sxadj[mypart][snvtxs[mypart]]; + slabel[mypart][snvtxs[mypart]] = label[i]; + sxadj[mypart][++snvtxs[mypart]] = snedges[mypart]; + } + + for (mypart=0; mypart<2; mypart++) { + iend = snedges[mypart]; + idxset(iend, 1, sadjwgt[mypart]); + + auxadjncy = sadjncy[mypart]; + for (i=0; i<iend; i++) + auxadjncy[i] = rename[auxadjncy[i]]; + } + + lgraph->nvtxs = snvtxs[0]; + lgraph->nedges = snedges[0]; + rgraph->nvtxs = snvtxs[1]; + rgraph->nedges = snedges[1]; + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr)); + + idxwspacefree(ctrl, nvtxs); + +} + +/************************************************************************* +* This function uses MMD to order the graph. The vertices are numbered +* from lastvtx downwards +**************************************************************************/ +void MMDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx) +{ + int i, j, k, nvtxs, nofsub, firstvtx; + idxtype *xadj, *adjncy, *label; + idxtype *perm, *iperm, *head, *qsize, *list, *marker; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + /* Relabel the vertices so that it starts from 1 */ + k = xadj[nvtxs]; + for (i=0; i<k; i++) + adjncy[i]++; + for (i=0; i<nvtxs+1; i++) + xadj[i]++; + + perm = idxmalloc(6*(nvtxs+5), "MMDOrder: perm"); + iperm = perm + nvtxs + 5; + head = iperm + nvtxs + 5; + qsize = head + nvtxs + 5; + list = qsize + nvtxs + 5; + marker = list + nvtxs + 5; + + genmmd(nvtxs, xadj, adjncy, iperm, perm, 1, head, qsize, list, marker, MAXIDX, &nofsub); + + label = graph->label; + firstvtx = lastvtx-nvtxs; + for (i=0; i<nvtxs; i++) + order[label[i]] = firstvtx+iperm[i]-1; + + free(perm); + + /* Relabel the vertices so that it starts from 0 */ + for (i=0; i<nvtxs+1; i++) + xadj[i]--; + k = xadj[nvtxs]; + for (i=0; i<k; i++) + adjncy[i]--; +} + + +/************************************************************************* +* This function takes a graph and a bisection and splits it into two graphs. +* It relies on the fact that adjwgt is all set to 1. +**************************************************************************/ +int SplitGraphOrderCC(CtrlType *ctrl, GraphType *graph, GraphType *sgraphs, int ncmps, idxtype *cptr, idxtype *cind) +{ + int i, ii, iii, j, k, l, istart, iend, mypart, nvtxs, snvtxs, snedges; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind; + idxtype *sxadj, *svwgt, *sadjncy, *sadjwgt, *sadjwgtsum, *slabel; + idxtype *rename; + idxtype *auxadjncy, *auxadjwgt; + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr)); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + label = graph->label; + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + ASSERT(bndptr != NULL); + + /* Go and use bndptr to also mark the boundary nodes in the two partitions */ + for (ii=0; ii<graph->nbnd; ii++) { + i = bndind[ii]; + for (j=xadj[i]; j<xadj[i+1]; j++) + bndptr[adjncy[j]] = 1; + } + + rename = idxwspacemalloc(ctrl, nvtxs); + + /* Go and split the graph a component at a time */ + for (iii=0; iii<ncmps; iii++) { + RandomPermute(cptr[iii+1]-cptr[iii], cind+cptr[iii], 0); + snvtxs = snedges = 0; + for (j=cptr[iii]; j<cptr[iii+1]; j++) { + i = cind[j]; + rename[i] = snvtxs++; + snedges += xadj[i+1]-xadj[i]; + } + + SetUpSplitGraph(graph, sgraphs+iii, snvtxs, snedges); + sxadj = sgraphs[iii].xadj; + svwgt = sgraphs[iii].vwgt; + sadjwgtsum = sgraphs[iii].adjwgtsum; + sadjncy = sgraphs[iii].adjncy; + sadjwgt = sgraphs[iii].adjwgt; + slabel = sgraphs[iii].label; + + snvtxs = snedges = sxadj[0] = 0; + for (ii=cptr[iii]; ii<cptr[iii+1]; ii++) { + i = cind[ii]; + + istart = xadj[i]; + iend = xadj[i+1]; + if (bndptr[i] == -1) { /* This is an interior vertex */ + auxadjncy = sadjncy + snedges - istart; + auxadjwgt = sadjwgt + snedges - istart; + for(j=istart; j<iend; j++) + auxadjncy[j] = adjncy[j]; + snedges += iend-istart; + } + else { + l = snedges; + for (j=istart; j<iend; j++) { + k = adjncy[j]; + if (where[k] != 2) + sadjncy[l++] = k; + } + snedges = l; + } + + svwgt[snvtxs] = vwgt[i]; + sadjwgtsum[snvtxs] = snedges-sxadj[snvtxs]; + slabel[snvtxs] = label[i]; + sxadj[++snvtxs] = snedges; + } + + idxset(snedges, 1, sadjwgt); + for (i=0; i<snedges; i++) + sadjncy[i] = rename[sadjncy[i]]; + + sgraphs[iii].nvtxs = snvtxs; + sgraphs[iii].nedges = snedges; + sgraphs[iii].ncon = 1; + + if (snvtxs < MMDSWITCH) + sgraphs[iii].adjwgt = NULL; /* A marker to call MMD on the driver */ + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr)); + + idxwspacefree(ctrl, nvtxs); + + return ncmps; + +} + + + + + diff --git a/Metis/parmetis.c b/Metis/parmetis.c new file mode 100644 index 0000000000..b20396a551 --- /dev/null +++ b/Metis/parmetis.c @@ -0,0 +1,371 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * parmetis.c + * + * This file contains top level routines that are used by ParMETIS + * + * Started 10/14/97 + * George + * + * $Id: parmetis.c,v 1.1 2005-09-07 14:36:45 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for KMETIS with seed specification +* in options[7] +**************************************************************************/ +void METIS_PartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphKway2(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, + tpwgts, options, edgecut, part); + + free(tpwgts); +} + + +/************************************************************************* +* This function is the entry point for KWMETIS with seed specification +* in options[7] +**************************************************************************/ +void METIS_WPartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = KMETIS_CTYPE; + ctrl.IType = KMETIS_ITYPE; + ctrl.RType = KMETIS_RTYPE; + ctrl.dbglvl = KMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_KMETIS; + ctrl.CoarsenTo = 20*(*nparts); + ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo); + + InitRandom(options[7]); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + +/************************************************************************* +* This function is the entry point for the node ND code for ParMETIS +**************************************************************************/ +void METIS_NodeNDP(int nvtxs, idxtype *xadj, idxtype *adjncy, int npes, + int *options, idxtype *perm, idxtype *iperm, idxtype *sizes) +{ + int i, ii, j, l, wflag, nflag; + GraphType graph; + CtrlType ctrl; + idxtype *cptr, *cind; + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + ctrl.oflags = ONMETIS_OFLAGS; + ctrl.pfactor = ONMETIS_PFACTOR; + ctrl.nseps = ONMETIS_NSEPS; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + ctrl.oflags = options[OPTION_OFLAGS]; + ctrl.pfactor = options[OPTION_PFACTOR]; + ctrl.nseps = options[OPTION_NSEPS]; + } + if (ctrl.nseps < 1) + ctrl.nseps = 1; + + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = 100; + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + InitRandom(-1); + + if (ctrl.oflags&OFLAG_COMPRESS) { + /*============================================================ + * Compress the graph + ==============================================================*/ + cptr = idxmalloc(nvtxs+1, "ONMETIS: cptr"); + cind = idxmalloc(nvtxs, "ONMETIS: cind"); + + CompressGraph(&ctrl, &graph, nvtxs, xadj, adjncy, cptr, cind); + + if (graph.nvtxs >= COMPRESSION_FRACTION*(nvtxs)) { + ctrl.oflags--; /* We actually performed no compression */ + GKfree(&cptr, &cind, LTERM); + } + else if (2*graph.nvtxs < nvtxs && ctrl.nseps == 1) + ctrl.nseps = 2; + } + else { + SetUpGraph(&graph, OP_ONMETIS, nvtxs, 1, xadj, adjncy, NULL, NULL, 0); + } + + + /*============================================================= + * Do the nested dissection ordering + --=============================================================*/ + ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo); + AllocateWorkSpace(&ctrl, &graph, 2); + + idxset(2*npes-1, 0, sizes); + MlevelNestedDissectionP(&ctrl, &graph, iperm, graph.nvtxs, npes, 0, sizes); + + FreeWorkSpace(&ctrl, &graph); + + if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */ + if (graph.nvtxs < COMPRESSION_FRACTION*(nvtxs)) { + /* construct perm from iperm */ + for (i=0; i<graph.nvtxs; i++) + perm[iperm[i]] = i; + for (l=ii=0; ii<graph.nvtxs; ii++) { + i = perm[ii]; + for (j=cptr[i]; j<cptr[i+1]; j++) + iperm[cind[j]] = l++; + } + } + + GKfree(&cptr, &cind, LTERM); + } + + + for (i=0; i<nvtxs; i++) + perm[iperm[i]] = i; + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +void MlevelNestedDissectionP(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx, + int npes, int cpos, idxtype *sizes) +{ + int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2]; + idxtype *label, *bndind; + GraphType lgraph, rgraph; + float ubfactor; + + nvtxs = graph->nvtxs; + + if (nvtxs == 0) { + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + return; + } + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt/2; + tpwgts2[1] = tvwgt-tpwgts2[0]; + + if (cpos >= npes-1) + ubfactor = ORDER_UNBALANCE_FRACTION; + else + ubfactor = 1.05; + + + MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); + + if (cpos < npes-1) { + sizes[2*npes-2-cpos] = graph->pwgts[2]; + sizes[2*npes-2-(2*cpos+1)] = graph->pwgts[1]; + sizes[2*npes-2-(2*cpos+2)] = graph->pwgts[0]; + } + + /* Order the nodes in the separator */ + nbnd = graph->nbnd; + bndind = graph->bndind; + label = graph->label; + for (i=0; i<nbnd; i++) + order[label[bndind[i]]] = --lastvtx; + + SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + if (rgraph.nvtxs > MMDSWITCH || 2*cpos+1 < npes-1) + MlevelNestedDissectionP(ctrl, &rgraph, order, lastvtx, npes, 2*cpos+1, sizes); + else { + MMDOrder(ctrl, &rgraph, order, lastvtx); + GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM); + } + if (lgraph.nvtxs > MMDSWITCH || 2*cpos+2 < npes-1) + MlevelNestedDissectionP(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs, npes, 2*cpos+2, sizes); + else { + MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs); + GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM); + } +} + + + + +/************************************************************************* +* This function is the entry point for ONWMETIS. It requires weights on the +* vertices. It is for the case that the matrix has been pre-compressed. +**************************************************************************/ +void METIS_NodeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *options, int *sepsize, idxtype *part) +{ + int i, j, tvwgt, tpwgts[2]; + GraphType graph; + CtrlType ctrl; + + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); + tvwgt = idxsum(*nvtxs, graph.vwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + + ctrl.oflags = 0; + ctrl.pfactor = 0; + ctrl.nseps = 1; + ctrl.optype = OP_ONMETIS; + ctrl.CoarsenTo = amin(100, *nvtxs-1); + ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo; + + InitRandom(options[7]); + + AllocateWorkSpace(&ctrl, &graph, 2); + + /*============================================================ + * Perform the bisection + *============================================================*/ + tpwgts[0] = tvwgt/2; + tpwgts[1] = tvwgt-tpwgts[0]; + + MlevelNodeBisectionMultiple(&ctrl, &graph, tpwgts, 1.05); + + *sepsize = graph.pwgts[2]; + idxcopy(*nvtxs, graph.where, part); + + GKfree(&graph.gdata, &graph.rdata, &graph.label, LTERM); + + + FreeWorkSpace(&ctrl, &graph); + +} + + + +/************************************************************************* +* This function is the entry point for ONWMETIS. It requires weights on the +* vertices. It is for the case that the matrix has been pre-compressed. +**************************************************************************/ +void METIS_EdgeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *options, int *sepsize, idxtype *part) +{ + int i, j, tvwgt, tpwgts[2]; + GraphType graph; + CtrlType ctrl; + + SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); + tvwgt = idxsum(*nvtxs, graph.vwgt); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = ONMETIS_CTYPE; + ctrl.IType = ONMETIS_ITYPE; + ctrl.RType = ONMETIS_RTYPE; + ctrl.dbglvl = ONMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + + ctrl.oflags = 0; + ctrl.pfactor = 0; + ctrl.nseps = 1; + ctrl.optype = OP_OEMETIS; + ctrl.CoarsenTo = amin(100, *nvtxs-1); + ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo; + + InitRandom(options[7]); + + AllocateWorkSpace(&ctrl, &graph, 2); + + /*============================================================ + * Perform the bisection + *============================================================*/ + tpwgts[0] = tvwgt/2; + tpwgts[1] = tvwgt-tpwgts[0]; + + MlevelEdgeBisection(&ctrl, &graph, tpwgts, 1.05); + ConstructMinCoverSeparator(&ctrl, &graph, 1.05); + + *sepsize = graph.pwgts[2]; + idxcopy(*nvtxs, graph.where, part); + + GKfree(&graph.gdata, &graph.rdata, &graph.label, LTERM); + + + FreeWorkSpace(&ctrl, &graph); + +} diff --git a/Metis/pmetis.c b/Metis/pmetis.c new file mode 100644 index 0000000000..9e17cdfe73 --- /dev/null +++ b/Metis/pmetis.c @@ -0,0 +1,341 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * pmetis.c + * + * This file contains the top level routines for the multilevel recursive + * bisection algorithm PMETIS. + * + * Started 7/24/97 + * George + * + * $Id: pmetis.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point for PMETIS +**************************************************************************/ +void METIS_PartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + int *options, int *edgecut, idxtype *part) +{ + int i; + float *tpwgts; + + tpwgts = fmalloc(*nparts, "KMETIS: tpwgts"); + for (i=0; i<*nparts; i++) + tpwgts[i] = 1.0/(1.0*(*nparts)); + + METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, + tpwgts, options, edgecut, part); + + free(tpwgts); +} + + + +/************************************************************************* +* This function is the entry point for PWMETIS that accepts exact weights +* for the target partitions +**************************************************************************/ +void METIS_WPartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, + idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, + float *tpwgts, int *options, int *edgecut, idxtype *part) +{ + int i, j; + GraphType graph; + CtrlType ctrl; + float *mytpwgts; + + if (*numflag == 1) + Change2CNumbering(*nvtxs, xadj, adjncy); + + SetUpGraph(&graph, OP_PMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); + + if (options[0] == 0) { /* Use the default parameters */ + ctrl.CType = PMETIS_CTYPE; + ctrl.IType = PMETIS_ITYPE; + ctrl.RType = PMETIS_RTYPE; + ctrl.dbglvl = PMETIS_DBGLVL; + } + else { + ctrl.CType = options[OPTION_CTYPE]; + ctrl.IType = options[OPTION_ITYPE]; + ctrl.RType = options[OPTION_RTYPE]; + ctrl.dbglvl = options[OPTION_DBGLVL]; + } + ctrl.optype = OP_PMETIS; + ctrl.CoarsenTo = 20; + ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); + + mytpwgts = fmalloc(*nparts, "PWMETIS: mytpwgts"); + for (i=0; i<*nparts; i++) + mytpwgts[i] = tpwgts[i]; + + InitRandom(-1); + + AllocateWorkSpace(&ctrl, &graph, *nparts); + + IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); + IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); + + *edgecut = MlevelRecursiveBisection(&ctrl, &graph, *nparts, part, mytpwgts, 1.000, 0); + + IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); + IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); + + FreeWorkSpace(&ctrl, &graph); + free(mytpwgts); + + if (*numflag == 1) + Change2FNumbering(*nvtxs, xadj, adjncy, part); +} + + + +/************************************************************************* +* This function takes a graph and produces a bisection of it +**************************************************************************/ +int MlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor, int fpart) +{ + int i, j, nvtxs, cut, tvwgt, tpwgts2[2]; + idxtype *label, *where; + GraphType lgraph, rgraph; + float wsum; + + nvtxs = graph->nvtxs; + if (nvtxs == 0) { + printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); + return 0; + } + + /* Determine the weights of the partitions */ + tvwgt = idxsum(nvtxs, graph->vwgt); + tpwgts2[0] = tvwgt*ssum(nparts/2, tpwgts); + tpwgts2[1] = tvwgt-tpwgts2[0]; + + MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor); + cut = graph->mincut; + + /* printf("%5d %5d %5d [%5d %f]\n", tpwgts2[0], tpwgts2[1], cut, tvwgt, ssum(nparts/2, tpwgts));*/ + + label = graph->label; + where = graph->where; + for (i=0; i<nvtxs; i++) + part[label[i]] = where[i] + fpart; + + if (nparts > 2) { + SplitGraphPart(ctrl, graph, &lgraph, &rgraph); + /* printf("%d %d\n", lgraph.nvtxs, rgraph.nvtxs); */ + } + + + /* Free the memory of the top level graph */ + GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM); + + /* Scale the fractions in the tpwgts according to the true weight */ + wsum = ssum(nparts/2, tpwgts); + sscale(nparts/2, 1.0/wsum, tpwgts); + sscale(nparts-nparts/2, 1.0/(1.0-wsum), tpwgts+nparts/2); + /* + for (i=0; i<nparts; i++) + printf("%5.3f ", tpwgts[i]); + printf("[%5.3f]\n", wsum); + */ + + /* Do the recursive call */ + if (nparts > 3) { + cut += MlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, tpwgts, ubfactor, fpart); + cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2); + } + else if (nparts == 3) { + cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2); + GKfree(&lgraph.gdata, &lgraph.label, LTERM); + } + + return cut; + +} + + +/************************************************************************* +* This function performs multilevel bisection +**************************************************************************/ +void MlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) +{ + GraphType *cgraph; + + cgraph = Coarsen2Way(ctrl, graph); + + Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor); + + Refine2Way(ctrl, graph, cgraph, tpwgts, ubfactor); + +/* + IsConnectedSubdomain(ctrl, graph, 0); + IsConnectedSubdomain(ctrl, graph, 1); +*/ +} + + + + +/************************************************************************* +* This function takes a graph and a bisection and splits it into two graphs. +**************************************************************************/ +void SplitGraphPart(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph) +{ + int i, j, k, kk, l, istart, iend, mypart, nvtxs, ncon, snvtxs[2], snedges[2], sum; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr; + idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2]; + idxtype *rename; + idxtype *auxadjncy, *auxadjwgt; + float *nvwgt, *snvwgt[2], *npwgts; + + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + nvwgt = graph->nvwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + label = graph->label; + where = graph->where; + bndptr = graph->bndptr; + npwgts = graph->npwgts; + + ASSERT(bndptr != NULL); + + rename = idxwspacemalloc(ctrl, nvtxs); + + snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; + for (i=0; i<nvtxs; i++) { + k = where[i]; + rename[i] = snvtxs[k]++; + snedges[k] += xadj[i+1]-xadj[i]; + } + + SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]); + sxadj[0] = lgraph->xadj; + svwgt[0] = lgraph->vwgt; + snvwgt[0] = lgraph->nvwgt; + sadjwgtsum[0] = lgraph->adjwgtsum; + sadjncy[0] = lgraph->adjncy; + sadjwgt[0] = lgraph->adjwgt; + slabel[0] = lgraph->label; + + SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]); + sxadj[1] = rgraph->xadj; + svwgt[1] = rgraph->vwgt; + snvwgt[1] = rgraph->nvwgt; + sadjwgtsum[1] = rgraph->adjwgtsum; + sadjncy[1] = rgraph->adjncy; + sadjwgt[1] = rgraph->adjwgt; + slabel[1] = rgraph->label; + + snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; + sxadj[0][0] = sxadj[1][0] = 0; + for (i=0; i<nvtxs; i++) { + mypart = where[i]; + sum = adjwgtsum[i]; + + istart = xadj[i]; + iend = xadj[i+1]; + if (bndptr[i] == -1) { /* This is an interior vertex */ + auxadjncy = sadjncy[mypart] + snedges[mypart] - istart; + auxadjwgt = sadjwgt[mypart] + snedges[mypart] - istart; + for(j=istart; j<iend; j++) { + auxadjncy[j] = adjncy[j]; + auxadjwgt[j] = adjwgt[j]; + } + snedges[mypart] += iend-istart; + } + else { + auxadjncy = sadjncy[mypart]; + auxadjwgt = sadjwgt[mypart]; + l = snedges[mypart]; + for (j=istart; j<iend; j++) { + k = adjncy[j]; + if (where[k] == mypart) { + auxadjncy[l] = k; + auxadjwgt[l++] = adjwgt[j]; + } + else { + sum -= adjwgt[j]; + } + } + snedges[mypart] = l; + } + + if (ncon == 1) + svwgt[mypart][snvtxs[mypart]] = vwgt[i]; + else { + for (kk=0; kk<ncon; kk++) + snvwgt[mypart][snvtxs[mypart]*ncon+kk] = nvwgt[i*ncon+kk]/npwgts[mypart*ncon+kk]; + } + + sadjwgtsum[mypart][snvtxs[mypart]] = sum; + slabel[mypart][snvtxs[mypart]] = label[i]; + sxadj[mypart][++snvtxs[mypart]] = snedges[mypart]; + } + + for (mypart=0; mypart<2; mypart++) { + iend = sxadj[mypart][snvtxs[mypart]]; + auxadjncy = sadjncy[mypart]; + for (i=0; i<iend; i++) + auxadjncy[i] = rename[auxadjncy[i]]; + } + + lgraph->nedges = snedges[0]; + rgraph->nedges = snedges[1]; + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr)); + + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* Setup the various arrays for the splitted graph +**************************************************************************/ +void SetUpSplitGraph(GraphType *graph, GraphType *sgraph, int snvtxs, int snedges) +{ + InitGraph(sgraph); + sgraph->nvtxs = snvtxs; + sgraph->nedges = snedges; + sgraph->ncon = graph->ncon; + + /* Allocate memory for the splitted graph */ + if (graph->ncon == 1) { + sgraph->gdata = idxmalloc(4*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata"); + + sgraph->xadj = sgraph->gdata; + sgraph->vwgt = sgraph->gdata + snvtxs+1; + sgraph->adjwgtsum = sgraph->gdata + 2*snvtxs+1; + sgraph->cmap = sgraph->gdata + 3*snvtxs+1; + sgraph->adjncy = sgraph->gdata + 4*snvtxs+1; + sgraph->adjwgt = sgraph->gdata + 4*snvtxs+1 + snedges; + } + else { + sgraph->gdata = idxmalloc(3*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata"); + + sgraph->xadj = sgraph->gdata; + sgraph->adjwgtsum = sgraph->gdata + snvtxs+1; + sgraph->cmap = sgraph->gdata + 2*snvtxs+1; + sgraph->adjncy = sgraph->gdata + 3*snvtxs+1; + sgraph->adjwgt = sgraph->gdata + 3*snvtxs+1 + snedges; + + sgraph->nvwgt = fmalloc(graph->ncon*snvtxs, "SetUpSplitGraph: nvwgt"); + } + + sgraph->label = idxmalloc(snvtxs, "SetUpSplitGraph: sgraph->label"); +} + diff --git a/Metis/pqueue.c b/Metis/pqueue.c new file mode 100644 index 0000000000..c5b8c8b3b5 --- /dev/null +++ b/Metis/pqueue.c @@ -0,0 +1,579 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * pqueue.c + * + * This file contains functions for manipulating the bucket list + * representation of the gains associated with each vertex in a graph. + * These functions are used by the refinement algorithms + * + * Started 9/2/94 + * George + * + * $Id: pqueue.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function initializes the data structures of the priority queue +**************************************************************************/ +void PQueueInit(CtrlType *ctrl, PQueueType *queue, int maxnodes, int maxgain) +{ + int i, j, ncore; + + queue->nnodes = 0; + queue->maxnodes = maxnodes; + + queue->buckets = NULL; + queue->nodes = NULL; + queue->heap = NULL; + queue->locator = NULL; + + if (maxgain > PLUS_GAINSPAN || maxnodes < 500) + queue->type = 2; + else + queue->type = 1; + + if (queue->type == 1) { + queue->pgainspan = amin(PLUS_GAINSPAN, maxgain); + queue->ngainspan = amin(NEG_GAINSPAN, maxgain); + + j = queue->ngainspan+queue->pgainspan+1; + + ncore = 2 + (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes + (sizeof(ListNodeType *)/sizeof(idxtype))*j; + + if (WspaceAvail(ctrl) > ncore) { + queue->nodes = (ListNodeType *)idxwspacemalloc(ctrl, (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes); + queue->buckets = (ListNodeType **)idxwspacemalloc(ctrl, (sizeof(ListNodeType *)/sizeof(idxtype))*j); + queue->mustfree = 0; + } + else { /* Not enough memory in the wspace, allocate it */ + queue->nodes = (ListNodeType *)idxmalloc((sizeof(ListNodeType)/sizeof(idxtype))*maxnodes, "PQueueInit: queue->nodes"); + queue->buckets = (ListNodeType **)idxmalloc((sizeof(ListNodeType *)/sizeof(idxtype))*j, "PQueueInit: queue->buckets"); + queue->mustfree = 1; + } + + for (i=0; i<maxnodes; i++) + queue->nodes[i].id = i; + + for (i=0; i<j; i++) + queue->buckets[i] = NULL; + + queue->buckets += queue->ngainspan; /* Advance buckets by the ngainspan proper indexing */ + queue->maxgain = -queue->ngainspan; + } + else { + queue->heap = (KeyValueType *)idxwspacemalloc(ctrl, (sizeof(KeyValueType)/sizeof(idxtype))*maxnodes); + queue->locator = idxwspacemalloc(ctrl, maxnodes); + idxset(maxnodes, -1, queue->locator); + } + +} + + +/************************************************************************* +* This function resets the buckets +**************************************************************************/ +void PQueueReset(PQueueType *queue) +{ + int i, j; + queue->nnodes = 0; + + if (queue->type == 1) { + queue->maxgain = -queue->ngainspan; + + j = queue->ngainspan+queue->pgainspan+1; + queue->buckets -= queue->ngainspan; + for (i=0; i<j; i++) + queue->buckets[i] = NULL; + queue->buckets += queue->ngainspan; + } + else { + idxset(queue->maxnodes, -1, queue->locator); + } + +} + + +/************************************************************************* +* This function frees the buckets +**************************************************************************/ +void PQueueFree(CtrlType *ctrl, PQueueType *queue) +{ + + if (queue->type == 1) { + if (queue->mustfree) { + queue->buckets -= queue->ngainspan; + GKfree(&queue->nodes, &queue->buckets, LTERM); + } + else { + idxwspacefree(ctrl, sizeof(ListNodeType *)*(queue->ngainspan+queue->pgainspan+1)/sizeof(idxtype)); + idxwspacefree(ctrl, sizeof(ListNodeType)*queue->maxnodes/sizeof(idxtype)); + } + } + else { + idxwspacefree(ctrl, sizeof(KeyValueType)*queue->maxnodes/sizeof(idxtype)); + idxwspacefree(ctrl, queue->maxnodes); + } + + queue->maxnodes = 0; +} + + +/************************************************************************* +* This function returns the number of nodes in the queue +**************************************************************************/ +int PQueueGetSize(PQueueType *queue) +{ + return queue->nnodes; +} + + +/************************************************************************* +* This function adds a node of certain gain into a partition +**************************************************************************/ +int PQueueInsert(PQueueType *queue, int node, int gain) +{ + int i, j, k; + idxtype *locator; + ListNodeType *newnode; + KeyValueType *heap; + + if (queue->type == 1) { + ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan); + + /* Allocate and add the node */ + queue->nnodes++; + newnode = queue->nodes + node; + + /* Attach this node in the doubly-linked list */ + newnode->next = queue->buckets[gain]; + newnode->prev = NULL; + if (newnode->next != NULL) + newnode->next->prev = newnode; + queue->buckets[gain] = newnode; + + if (queue->maxgain < gain) + queue->maxgain = gain; + } + else { + ASSERT(CheckHeap(queue)); + + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] == -1); + + i = queue->nnodes++; + while (i > 0) { + j = (i-1)/2; + if (heap[j].key < gain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + ASSERT(i >= 0); + heap[i].key = gain; + heap[i].val = node; + locator[node] = i; + + ASSERT(CheckHeap(queue)); + } + + return 0; +} + + +/************************************************************************* +* This function deletes a node from a partition and reinserts it with +* an updated gain +**************************************************************************/ +int PQueueDelete(PQueueType *queue, int node, int gain) +{ + int i, j, newgain, oldgain; + idxtype *locator; + ListNodeType *newnode, **buckets; + KeyValueType *heap; + + if (queue->type == 1) { + ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan); + ASSERT(queue->nnodes > 0); + + buckets = queue->buckets; + queue->nnodes--; + newnode = queue->nodes+node; + + /* Remove newnode from the doubly-linked list */ + if (newnode->prev != NULL) + newnode->prev->next = newnode->next; + else + buckets[gain] = newnode->next; + if (newnode->next != NULL) + newnode->next->prev = newnode->prev; + + if (buckets[gain] == NULL && gain == queue->maxgain) { + if (queue->nnodes == 0) + queue->maxgain = -queue->ngainspan; + else + for (; buckets[queue->maxgain]==NULL; queue->maxgain--); + } + } + else { /* Heap Priority Queue */ + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] != -1); + ASSERT(heap[locator[node]].val == node); + + ASSERT(CheckHeap(queue)); + + i = locator[node]; + locator[node] = -1; + + if (--queue->nnodes > 0 && heap[queue->nnodes].val != node) { + node = heap[queue->nnodes].val; + newgain = heap[queue->nnodes].key; + oldgain = heap[i].key; + + if (oldgain < newgain) { /* Filter-up */ + while (i > 0) { + j = (i-1)>>1; + if (heap[j].key < newgain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + else { /* Filter down */ + while ((j=2*i+1) < queue->nnodes) { + if (heap[j].key > newgain) { + if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key) + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else if (j+1 < queue->nnodes && heap[j+1].key > newgain) { + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + + heap[i].key = newgain; + heap[i].val = node; + locator[node] = i; + } + + ASSERT(CheckHeap(queue)); + } + + return 0; +} + + + +/************************************************************************* +* This function deletes a node from a partition and reinserts it with +* an updated gain +**************************************************************************/ +int PQueueUpdate(PQueueType *queue, int node, int oldgain, int newgain) +{ + int i, j; + idxtype *locator; + ListNodeType *newnode; + KeyValueType *heap; + + if (oldgain == newgain) + return 0; + + if (queue->type == 1) { + /* First delete the node and then insert it */ + PQueueDelete(queue, node, oldgain); + return PQueueInsert(queue, node, newgain); + } + else { /* Heap Priority Queue */ + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] != -1); + ASSERT(heap[locator[node]].val == node); + ASSERT(heap[locator[node]].key == oldgain); + ASSERT(CheckHeap(queue)); + + i = locator[node]; + + if (oldgain < newgain) { /* Filter-up */ + while (i > 0) { + j = (i-1)>>1; + if (heap[j].key < newgain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + else { /* Filter down */ + while ((j=2*i+1) < queue->nnodes) { + if (heap[j].key > newgain) { + if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key) + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else if (j+1 < queue->nnodes && heap[j+1].key > newgain) { + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + } + + heap[i].key = newgain; + heap[i].val = node; + locator[node] = i; + + ASSERT(CheckHeap(queue)); + } + + return 0; +} + + + +/************************************************************************* +* This function deletes a node from a partition and reinserts it with +* an updated gain +**************************************************************************/ +void PQueueUpdateUp(PQueueType *queue, int node, int oldgain, int newgain) +{ + int i, j; + idxtype *locator; + ListNodeType *newnode, **buckets; + KeyValueType *heap; + + if (oldgain == newgain) + return; + + if (queue->type == 1) { + ASSERT(oldgain >= -queue->ngainspan && oldgain <= queue->pgainspan); + ASSERT(newgain >= -queue->ngainspan && newgain <= queue->pgainspan); + ASSERT(queue->nnodes > 0); + + buckets = queue->buckets; + newnode = queue->nodes+node; + + /* First delete the node */ + if (newnode->prev != NULL) + newnode->prev->next = newnode->next; + else + buckets[oldgain] = newnode->next; + if (newnode->next != NULL) + newnode->next->prev = newnode->prev; + + /* Attach this node in the doubly-linked list */ + newnode->next = buckets[newgain]; + newnode->prev = NULL; + if (newnode->next != NULL) + newnode->next->prev = newnode; + buckets[newgain] = newnode; + + if (queue->maxgain < newgain) + queue->maxgain = newgain; + } + else { /* Heap Priority Queue */ + heap = queue->heap; + locator = queue->locator; + + ASSERT(locator[node] != -1); + ASSERT(heap[locator[node]].val == node); + ASSERT(heap[locator[node]].key == oldgain); + ASSERT(CheckHeap(queue)); + + + /* Here we are just filtering up since the newgain is greater than the oldgain */ + i = locator[node]; + while (i > 0) { + j = (i-1)>>1; + if (heap[j].key < newgain) { + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + + heap[i].key = newgain; + heap[i].val = node; + locator[node] = i; + + ASSERT(CheckHeap(queue)); + } + +} + + +/************************************************************************* +* This function returns the vertex with the largest gain from a partition +* and removes the node from the bucket list +**************************************************************************/ +int PQueueGetMax(PQueueType *queue) +{ + int vtx, i, j, gain, node; + idxtype *locator; + ListNodeType *tptr; + KeyValueType *heap; + + if (queue->nnodes == 0) + return -1; + + queue->nnodes--; + + if (queue->type == 1) { + tptr = queue->buckets[queue->maxgain]; + queue->buckets[queue->maxgain] = tptr->next; + if (tptr->next != NULL) { + tptr->next->prev = NULL; + } + else { + if (queue->nnodes == 0) { + queue->maxgain = -queue->ngainspan; + } + else + for (; queue->buckets[queue->maxgain]==NULL; queue->maxgain--); + } + + return tptr->id; + } + else { + heap = queue->heap; + locator = queue->locator; + + vtx = heap[0].val; + locator[vtx] = -1; + + if ((i = queue->nnodes) > 0) { + gain = heap[i].key; + node = heap[i].val; + i = 0; + while ((j=2*i+1) < queue->nnodes) { + if (heap[j].key > gain) { + if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key) + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else if (j+1 < queue->nnodes && heap[j+1].key > gain) { + j = j+1; + heap[i] = heap[j]; + locator[heap[i].val] = i; + i = j; + } + else + break; + } + + heap[i].key = gain; + heap[i].val = node; + locator[node] = i; + } + + ASSERT(CheckHeap(queue)); + return vtx; + } +} + + +/************************************************************************* +* This function returns the vertex with the largest gain from a partition +**************************************************************************/ +int PQueueSeeMax(PQueueType *queue) +{ + int vtx; + + if (queue->nnodes == 0) + return -1; + + if (queue->type == 1) + vtx = queue->buckets[queue->maxgain]->id; + else + vtx = queue->heap[0].val; + + return vtx; +} + + +/************************************************************************* +* This function returns the vertex with the largest gain from a partition +**************************************************************************/ +int PQueueGetKey(PQueueType *queue) +{ + int key; + + if (queue->nnodes == 0) + return -1; + + if (queue->type == 1) + key = queue->maxgain; + else + key = queue->heap[0].key; + + return key; +} + + + + +/************************************************************************* +* This functions checks the consistency of the heap +**************************************************************************/ +int CheckHeap(PQueueType *queue) +{ + int i, j, nnodes; + idxtype *locator; + KeyValueType *heap; + + heap = queue->heap; + locator = queue->locator; + nnodes = queue->nnodes; + + if (nnodes == 0) + return 1; + + ASSERT(locator[heap[0].val] == 0); + for (i=1; i<nnodes; i++) { + ASSERTP(locator[heap[i].val] == i, ("%d %d %d %d\n", nnodes, i, heap[i].val, locator[heap[i].val])); + ASSERTP(heap[i].key <= heap[(i-1)/2].key, ("%d %d %d %d %d\n", i, (i-1)/2, nnodes, heap[i].key, heap[(i-1)/2].key)); + } + for (i=1; i<nnodes; i++) + ASSERT(heap[i].key <= heap[0].key); + + for (j=i=0; i<queue->maxnodes; i++) { + if (locator[i] != -1) + j++; + } + ASSERTP(j == nnodes, ("%d %d\n", j, nnodes)); + + return 1; +} diff --git a/Metis/proto.h b/Metis/proto.h new file mode 100644 index 0000000000..a82e7c9fa5 --- /dev/null +++ b/Metis/proto.h @@ -0,0 +1,505 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * proto.h + * + * This file contains header files + * + * Started 10/19/95 + * George + * + * $Id: proto.h,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +/* balance.c */ +void Balance2Way(CtrlType *, GraphType *, int *, float); +void Bnd2WayBalance(CtrlType *, GraphType *, int *); +void General2WayBalance(CtrlType *, GraphType *, int *); + +/* bucketsort.c */ +void BucketSortKeysInc(int, int, idxtype *, idxtype *, idxtype *); + +/* ccgraph.c */ +void CreateCoarseGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *); +void CreateCoarseGraphNoMask(CtrlType *, GraphType *, int, idxtype *, idxtype *); +void CreateCoarseGraph_NVW(CtrlType *, GraphType *, int, idxtype *, idxtype *); +GraphType *SetUpCoarseGraph(GraphType *, int, int); +void ReAdjustMemory(GraphType *, GraphType *, int); + +/* coarsen.c */ +GraphType *Coarsen2Way(CtrlType *, GraphType *); + +/* compress.c */ +void CompressGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *, idxtype *, idxtype *); +void PruneGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *, idxtype *, float); + +/* debug.c */ +int ComputeCut(GraphType *, idxtype *); +int CheckBnd(GraphType *); +int CheckBnd2(GraphType *); +int CheckNodeBnd(GraphType *, int); +int CheckRInfo(RInfoType *); +int CheckNodePartitionParams(GraphType *); +int IsSeparable(GraphType *); + +/* estmem.c */ +void METIS_EstimateMemory(int *, idxtype *, idxtype *, int *, int *, int *); +void EstimateCFraction(int, idxtype *, idxtype *, float *, float *); +int ComputeCoarseGraphSize(int, idxtype *, idxtype *, int, idxtype *, idxtype *, idxtype *); + +/* fm.c */ +void FM_2WayEdgeRefine(CtrlType *, GraphType *, int *, int); + +/* fortran.c */ +void Change2CNumbering(int, idxtype *, idxtype *); +void Change2FNumbering(int, idxtype *, idxtype *, idxtype *); +void Change2FNumbering2(int, idxtype *, idxtype *); +void Change2FNumberingOrder(int, idxtype *, idxtype *, idxtype *, idxtype *); +void ChangeMesh2CNumbering(int, idxtype *); +void ChangeMesh2FNumbering(int, idxtype *, int, idxtype *, idxtype *); +void ChangeMesh2FNumbering2(int, idxtype *, int, int, idxtype *, idxtype *); + +/* frename.c */ +void METIS_PARTGRAPHRECURSIVE(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphrecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphrecursive_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphrecursive__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPARTGRAPHRECURSIVE(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphrecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphrecursive_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphrecursive__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_PARTGRAPHKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPARTGRAPHKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_EDGEND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_edgend(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_edgend_(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_edgend__(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NODEND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodend(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodend_(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodend__(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NODEWND(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodewnd(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodewnd_(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_nodewnd__(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_PARTMESHNODAL(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshnodal(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshnodal_(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshnodal__(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void METIS_PARTMESHDUAL(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshdual(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshdual_(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void metis_partmeshdual__(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void METIS_MESHTONODAL(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtonodal(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtonodal_(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtonodal__(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_MESHTODUAL(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtodual(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtodual_(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void metis_meshtodual__(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_ESTIMATEMEMORY(int *, idxtype *, idxtype *, int *, int *, int *); +void metis_estimatememory(int *, idxtype *, idxtype *, int *, int *, int *); +void metis_estimatememory_(int *, idxtype *, idxtype *, int *, int *, int *); +void metis_estimatememory__(int *, idxtype *, idxtype *, int *, int *, int *); +void METIS_MCPARTGRAPHRECURSIVE(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_mcpartgraphrecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_mcpartgraphrecursive_(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_mcpartgraphrecursive__(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_MCPARTGRAPHKWAY(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_mcpartgraphkway(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_mcpartgraphkway_(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_mcpartgraphkway__(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_PARTGRAPHVKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphvkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphvkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void metis_partgraphvkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPARTGRAPHVKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphvkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphvkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void metis_wpartgraphvkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); + +/* graph.c */ +void SetUpGraph(GraphType *, int, int, int, idxtype *, idxtype *, idxtype *, idxtype *, int); +void SetUpGraphKway(GraphType *, int, idxtype *, idxtype *); +void SetUpGraph2(GraphType *, int, int, idxtype *, idxtype *, float *, idxtype *); +void VolSetUpGraph(GraphType *, int, int, int, idxtype *, idxtype *, idxtype *, idxtype *, int); +void RandomizeGraph(GraphType *); +int IsConnectedSubdomain(CtrlType *, GraphType *, int, int); +int IsConnected(CtrlType *, GraphType *, int); +int IsConnected2(GraphType *, int); +int FindComponents(CtrlType *, GraphType *, idxtype *, idxtype *); + +/* initpart.c */ +void Init2WayPartition(CtrlType *, GraphType *, int *, float); +void InitSeparator(CtrlType *, GraphType *, float); +void GrowBisection(CtrlType *, GraphType *, int *, float); +void GrowBisectionNode(CtrlType *, GraphType *, float); +void RandomBisection(CtrlType *, GraphType *, int *, float); + +/* kmetis.c */ +void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MlevelKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *, float); + +/* kvmetis.c */ +void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MlevelVolKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *, float); + +/* kwayfm.c */ +void Random_KWayEdgeRefine(CtrlType *, GraphType *, int, float *, float, int, int); +void Greedy_KWayEdgeRefine(CtrlType *, GraphType *, int, float *, float, int); +void Greedy_KWayEdgeBalance(CtrlType *, GraphType *, int, float *, float, int); + +/* kwayrefine.c */ +void RefineKWay(CtrlType *, GraphType *, GraphType *, int, float *, float); +void AllocateKWayPartitionMemory(CtrlType *, GraphType *, int); +void ComputeKWayPartitionParams(CtrlType *, GraphType *, int); +void ProjectKWayPartition(CtrlType *, GraphType *, int); +int IsBalanced(idxtype *, int, float *, float); +void ComputeKWayBoundary(CtrlType *, GraphType *, int); +void ComputeKWayBalanceBoundary(CtrlType *, GraphType *, int); + +/* kwayvolfm.c */ +void Random_KWayVolRefine(CtrlType *, GraphType *, int, float *, float, int, int); +void Random_KWayVolRefineMConn(CtrlType *, GraphType *, int, float *, float, int, int); +void Greedy_KWayVolBalance(CtrlType *, GraphType *, int, float *, float, int); +void Greedy_KWayVolBalanceMConn(CtrlType *, GraphType *, int, float *, float, int); +void KWayVolUpdate(CtrlType *, GraphType *, int, int, int, idxtype *, idxtype *, idxtype *); +void ComputeKWayVolume(GraphType *, int, idxtype *, idxtype *, idxtype *); +int ComputeVolume(GraphType *, idxtype *); +void CheckVolKWayPartitionParams(CtrlType *, GraphType *, int); +void ComputeVolSubDomainGraph(GraphType *, int, idxtype *, idxtype *); +void EliminateVolSubDomainEdges(CtrlType *, GraphType *, int, float *); +void EliminateVolComponents(CtrlType *, GraphType *, int, float *, float); + +/* kwayvolrefine.c */ +void RefineVolKWay(CtrlType *, GraphType *, GraphType *, int, float *, float); +void AllocateVolKWayPartitionMemory(CtrlType *, GraphType *, int); +void ComputeVolKWayPartitionParams(CtrlType *, GraphType *, int); +void ComputeKWayVolGains(CtrlType *, GraphType *, int); +void ProjectVolKWayPartition(CtrlType *, GraphType *, int); +void ComputeVolKWayBoundary(CtrlType *, GraphType *, int); +void ComputeVolKWayBalanceBoundary(CtrlType *, GraphType *, int); + +/* match.c */ +void Match_RM(CtrlType *, GraphType *); +void Match_RM_NVW(CtrlType *, GraphType *); +void Match_HEM(CtrlType *, GraphType *); +void Match_SHEM(CtrlType *, GraphType *); + +/* mbalance.c */ +void MocBalance2Way(CtrlType *, GraphType *, float *, float); +void MocGeneral2WayBalance(CtrlType *, GraphType *, float *, float); + +/* mbalance2.c */ +void MocBalance2Way2(CtrlType *, GraphType *, float *, float *); +void MocGeneral2WayBalance2(CtrlType *, GraphType *, float *, float *); +void SelectQueue3(int, float *, float *, int *, int *, PQueueType [MAXNCON][2], float *); + +/* mcoarsen.c */ +GraphType *MCCoarsen2Way(CtrlType *, GraphType *); + +/* memory.c */ +void AllocateWorkSpace(CtrlType *, GraphType *, int); +void FreeWorkSpace(CtrlType *, GraphType *); +int WspaceAvail(CtrlType *); +idxtype *idxwspacemalloc(CtrlType *, int); +void idxwspacefree(CtrlType *, int); +float *fwspacemalloc(CtrlType *, int); +void fwspacefree(CtrlType *, int); +GraphType *CreateGraph(void); +void InitGraph(GraphType *); +void FreeGraph(GraphType *); + +/* mesh.c */ +void METIS_MeshToDual(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_MeshToNodal(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *); +void GENDUALMETIS(int, int, int, idxtype *, idxtype *, idxtype *adjncy); +void TRINODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); +void TETNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); +void HEXNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); +void QUADNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy); + +/* meshpart.c */ +void METIS_PartMeshNodal(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); +void METIS_PartMeshDual(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *); + +/* mfm.c */ +void MocFM_2WayEdgeRefine(CtrlType *, GraphType *, float *, int); +void SelectQueue(int, float *, float *, int *, int *, PQueueType [MAXNCON][2]); +int BetterBalance(int, float *, float *, float *); +float Compute2WayHLoadImbalance(int, float *, float *); +void Compute2WayHLoadImbalanceVec(int, float *, float *, float *); + +/* mfm2.c */ +void MocFM_2WayEdgeRefine2(CtrlType *, GraphType *, float *, float *, int); +void SelectQueue2(int, float *, float *, int *, int *, PQueueType [MAXNCON][2], float *); +int IsBetter2wayBalance(int, float *, float *, float *); + +/* mincover.o */ +void MinCover(idxtype *, idxtype *, int, int, idxtype *, int *); +int MinCover_Augment(idxtype *, idxtype *, int, idxtype *, idxtype *, idxtype *, int); +void MinCover_Decompose(idxtype *, idxtype *, int, int, idxtype *, idxtype *, int *); +void MinCover_ColDFS(idxtype *, idxtype *, int, idxtype *, idxtype *, int); +void MinCover_RowDFS(idxtype *, idxtype *, int, idxtype *, idxtype *, int); + +/* minitpart.c */ +void MocInit2WayPartition(CtrlType *, GraphType *, float *, float); +void MocGrowBisection(CtrlType *, GraphType *, float *, float); +void MocRandomBisection(CtrlType *, GraphType *, float *, float); +void MocInit2WayBalance(CtrlType *, GraphType *, float *); +int SelectQueueoneWay(int, float *, float *, int, PQueueType [MAXNCON][2]); + +/* minitpart2.c */ +void MocInit2WayPartition2(CtrlType *, GraphType *, float *, float *); +void MocGrowBisection2(CtrlType *, GraphType *, float *, float *); +void MocGrowBisectionNew2(CtrlType *, GraphType *, float *, float *); +void MocInit2WayBalance2(CtrlType *, GraphType *, float *, float *); +int SelectQueueOneWay2(int, float *, PQueueType [MAXNCON][2], float *); + +/* mkmetis.c */ +void METIS_mCPartGraphKway(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MCMlevelKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *); + +/* mkwayfmh.c */ +void MCRandom_KWayEdgeRefineHorizontal(CtrlType *, GraphType *, int, float *, int); +void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *, GraphType *, int, float *, int); +int AreAllHVwgtsBelow(int, float, float *, float, float *, float *); +int AreAllHVwgtsAbove(int, float, float *, float, float *, float *); +void ComputeHKWayLoadImbalance(int, int, float *, float *); +int MocIsHBalanced(int, int, float *, float *); +int IsHBalanceBetterFT(int, int, float *, float *, float *, float *); +int IsHBalanceBetterTT(int, int, float *, float *, float *, float *); + +/* mkwayrefine.c */ +void MocRefineKWayHorizontal(CtrlType *, GraphType *, GraphType *, int, float *); +void MocAllocateKWayPartitionMemory(CtrlType *, GraphType *, int); +void MocComputeKWayPartitionParams(CtrlType *, GraphType *, int); +void MocProjectKWayPartition(CtrlType *, GraphType *, int); +void MocComputeKWayBalanceBoundary(CtrlType *, GraphType *, int); + +/* mmatch.c */ +void MCMatch_RM(CtrlType *, GraphType *); +void MCMatch_HEM(CtrlType *, GraphType *); +void MCMatch_SHEM(CtrlType *, GraphType *); +void MCMatch_SHEBM(CtrlType *, GraphType *, int); +void MCMatch_SBHEM(CtrlType *, GraphType *, int); +float BetterVBalance(int, int, float *, float *, float *); +int AreAllVwgtsBelowFast(int, float *, float *, float); + +/* mmd.c */ +void genmmd(int, idxtype *, idxtype *, idxtype *, idxtype *, int , idxtype *, idxtype *, idxtype *, idxtype *, int, int *); +void mmdelm(int, idxtype *xadj, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int); +int mmdint(int, idxtype *xadj, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *); +void mmdnum(int, idxtype *, idxtype *, idxtype *); +void mmdupd(int, int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int *tag); + +/* mpmetis.c */ +void METIS_mCPartGraphRecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_mCHPartGraphRecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_mCPartGraphRecursiveInternal(int *, int *, idxtype *, idxtype *, float *, idxtype *, int *, int *, int *, idxtype *); +void METIS_mCHPartGraphRecursiveInternal(int *, int *, idxtype *, idxtype *, float *, idxtype *, int *, float *, int *, int *, idxtype *); +int MCMlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float, int); +int MCHMlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float *, int); +void MCMlevelEdgeBisection(CtrlType *, GraphType *, float *, float); +void MCHMlevelEdgeBisection(CtrlType *, GraphType *, float *, float *); + +/* mrefine.c */ +void MocRefine2Way(CtrlType *, GraphType *, GraphType *, float *, float); +void MocAllocate2WayPartitionMemory(CtrlType *, GraphType *); +void MocCompute2WayPartitionParams(CtrlType *, GraphType *); +void MocProject2WayPartition(CtrlType *, GraphType *); + +/* mrefine2.c */ +void MocRefine2Way2(CtrlType *, GraphType *, GraphType *, float *, float *); + +/* mutil.c */ +int AreAllVwgtsBelow(int, float, float *, float, float *, float); +int AreAnyVwgtsBelow(int, float, float *, float, float *, float); +int AreAllVwgtsAbove(int, float, float *, float, float *, float); +float ComputeLoadImbalance(int, int, float *, float *); +int AreAllBelow(int, float *, float *); + +/* myqsort.c */ +void iidxsort(int, idxtype *); +void iintsort(int, int *); +void ikeysort(int, KeyValueType *); +void ikeyvalsort(int, KeyValueType *); + +/* ometis.c */ +void METIS_EdgeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NodeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void METIS_NodeWND(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *); +void MlevelNestedDissection(CtrlType *, GraphType *, idxtype *, float, int); +void MlevelNestedDissectionCC(CtrlType *, GraphType *, idxtype *, float, int); +void MlevelNodeBisectionMultiple(CtrlType *, GraphType *, int *, float); +void MlevelNodeBisection(CtrlType *, GraphType *, int *, float); +void SplitGraphOrder(CtrlType *, GraphType *, GraphType *, GraphType *); +void MMDOrder(CtrlType *, GraphType *, idxtype *, int); +int SplitGraphOrderCC(CtrlType *, GraphType *, GraphType *, int, idxtype *, idxtype *); + +/* parmetis.c */ +void METIS_PartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +void METIS_NodeNDP(int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *); +void MlevelNestedDissectionP(CtrlType *, GraphType *, idxtype *, int, int, int, idxtype *); +void METIS_NodeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *); +void METIS_EdgeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *); + +/* pmetis.c */ +void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); +void METIS_WPartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *); +int MlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float *, float, int); +void MlevelEdgeBisection(CtrlType *, GraphType *, int *, float); +void SplitGraphPart(CtrlType *, GraphType *, GraphType *, GraphType *); +void SetUpSplitGraph(GraphType *, GraphType *, int, int); + +/* pqueue.c */ +void PQueueInit(CtrlType *ctrl, PQueueType *, int, int); +void PQueueReset(PQueueType *); +void PQueueFree(CtrlType *ctrl, PQueueType *); +int PQueueGetSize(PQueueType *); +int PQueueInsert(PQueueType *, int, int); +int PQueueDelete(PQueueType *, int, int); +int PQueueUpdate(PQueueType *, int, int, int); +void PQueueUpdateUp(PQueueType *, int, int, int); +int PQueueGetMax(PQueueType *); +int PQueueSeeMax(PQueueType *); +int PQueueGetKey(PQueueType *); +int CheckHeap(PQueueType *); + +/* refine.c */ +void Refine2Way(CtrlType *, GraphType *, GraphType *, int *, float ubfactor); +void Allocate2WayPartitionMemory(CtrlType *, GraphType *); +void Compute2WayPartitionParams(CtrlType *, GraphType *); +void Project2WayPartition(CtrlType *, GraphType *); + +/* separator.c */ +void ConstructSeparator(CtrlType *, GraphType *, float); +void ConstructMinCoverSeparator0(CtrlType *, GraphType *, float); +void ConstructMinCoverSeparator(CtrlType *, GraphType *, float); + +/* sfm.c */ +void FM_2WayNodeRefine(CtrlType *, GraphType *, float, int); +void FM_2WayNodeRefineEqWgt(CtrlType *, GraphType *, int); +void FM_2WayNodeRefine_OneSided(CtrlType *, GraphType *, float, int); +void FM_2WayNodeBalance(CtrlType *, GraphType *, float); +int ComputeMaxNodeGain(int, idxtype *, idxtype *, idxtype *); + +/* srefine.c */ +void Refine2WayNode(CtrlType *, GraphType *, GraphType *, float); +void Allocate2WayNodePartitionMemory(CtrlType *, GraphType *); +void Compute2WayNodePartitionParams(CtrlType *, GraphType *); +void Project2WayNodePartition(CtrlType *, GraphType *); + +/* stat.c */ +void ComputePartitionInfo(GraphType *, int, idxtype *); +void ComputePartitionInfoBipartite(GraphType *, int, idxtype *); +void ComputePartitionBalance(GraphType *, int, idxtype *, float *); +float ComputeElementBalance(int, int, idxtype *); + +/* subdomains.c */ +void Random_KWayEdgeRefineMConn(CtrlType *, GraphType *, int, float *, float, int, int); +void Greedy_KWayEdgeBalanceMConn(CtrlType *, GraphType *, int, float *, float, int); +void PrintSubDomainGraph(GraphType *, int, idxtype *); +void ComputeSubDomainGraph(GraphType *, int, idxtype *, idxtype *); +void EliminateSubDomainEdges(CtrlType *, GraphType *, int, float *); +void MoveGroupMConn(CtrlType *, GraphType *, idxtype *, idxtype *, int, int, int, idxtype *); +void EliminateComponents(CtrlType *, GraphType *, int, float *, float); +void MoveGroup(CtrlType *, GraphType *, int, int, int, idxtype *, idxtype *); + +/* timing.c */ +void InitTimers(CtrlType *); +void PrintTimers(CtrlType *); +double seconds(void); + +/* util.c */ +void errexit(char *,...); +#ifndef DMALLOC +int *imalloc(int, char *); +idxtype *idxmalloc(int, char *); +float *fmalloc(int, char *); +int *ismalloc(int, int, char *); +idxtype *idxsmalloc(int, idxtype, char *); +void *GKmalloc(int, char *); +#endif +/*void GKfree(void **,...); */ +int *iset(int n, int val, int *x); +idxtype *idxset(int n, idxtype val, idxtype *x); +float *sset(int n, float val, float *x); +int iamax(int, int *); +int idxamax(int, idxtype *); +int idxamax_strd(int, idxtype *, int); +int samax(int, float *); +int samax2(int, float *); +int idxamin(int, idxtype *); +int samin(int, float *); +int idxsum(int, idxtype *); +int idxsum_strd(int, idxtype *, int); +void idxadd(int, idxtype *, idxtype *); +int charsum(int, char *); +int isum(int, int *); +float ssum(int, float *); +float ssum_strd(int n, float *x, int); +void sscale(int n, float, float *x); +float snorm2(int, float *); +float sdot(int n, float *, float *); +void saxpy(int, float, float *, int, float *, int); +void RandomPermute(int, idxtype *, int); +double drand48(); +void srand48(long); +int ispow2(int); +void InitRandom(int); +//int log2(int); + + + + + + + + + + +/*************************************************************** +* Programs Directory +****************************************************************/ + +/* io.c */ +void ReadGraph(GraphType *, char *, int *); +void WritePartition(char *, idxtype *, int, int); +void WriteMeshPartition(char *, int, int, idxtype *, int, idxtype *); +void WritePermutation(char *, idxtype *, int); +int CheckGraph(GraphType *); +idxtype *ReadMesh(char *, int *, int *, int *); +void WriteGraph(char *, int, idxtype *, idxtype *); + +/* smbfactor.c */ +void ComputeFillIn(GraphType *, idxtype *); +idxtype ComputeFillIn2(GraphType *, idxtype *); +int smbfct(int, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int *, idxtype *, idxtype *, int *); + + +/*************************************************************** +* Test Directory +****************************************************************/ +void Test_PartGraph(int, idxtype *, idxtype *); +int VerifyPart(int, idxtype *, idxtype *, idxtype *, idxtype *, int, int, idxtype *); +int VerifyWPart(int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *); +void Test_PartGraphV(int, idxtype *, idxtype *); +int VerifyPartV(int, idxtype *, idxtype *, idxtype *, idxtype *, int, int, idxtype *); +int VerifyWPartV(int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *); +void Test_PartGraphmC(int, idxtype *, idxtype *); +int VerifyPartmC(int, int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *); +void Test_ND(int, idxtype *, idxtype *); +int VerifyND(int, idxtype *, idxtype *); + diff --git a/Metis/refine.c b/Metis/refine.c new file mode 100644 index 0000000000..314ec21aaf --- /dev/null +++ b/Metis/refine.c @@ -0,0 +1,204 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * refine.c + * + * This file contains the driving routines for multilevel refinement + * + * Started 7/24/97 + * George + * + * $Id: refine.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of refinement +**************************************************************************/ +void Refine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int *tpwgts, float ubfactor) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + /* Compute the parameters of the coarsest graph */ + Compute2WayPartitionParams(ctrl, graph); + + for (;;) { + ASSERT(CheckBnd(graph)); + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + switch (ctrl->RType) { + case 1: + Balance2Way(ctrl, graph, tpwgts, ubfactor); + FM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); + break; + default: + errexit("Unknown refinement type: %d\n", ctrl->RType); + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + Project2WayPartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for 2-way edge refinement +**************************************************************************/ +void Allocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph) +{ + int nvtxs; + + nvtxs = graph->nvtxs; + + graph->rdata = idxmalloc(5*nvtxs+2, "Allocate2WayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + 2; + graph->id = graph->rdata + nvtxs + 2; + graph->ed = graph->rdata + 2*nvtxs + 2; + graph->bndptr = graph->rdata + 3*nvtxs + 2; + graph->bndind = graph->rdata + 4*nvtxs + 2; +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void Compute2WayPartitionParams(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, l, nvtxs, nbnd, mincut; + idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts; + idxtype *id, *ed, *where; + idxtype *bndptr, *bndind; + int me, other; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = idxset(2, 0, graph->pwgts); + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /*------------------------------------------------------------ + / Compute now the id/ed degrees + /------------------------------------------------------------*/ + nbnd = mincut = 0; + for (i=0; i<nvtxs; i++) { + ASSERT(where[i] >= 0 && where[i] <= 1); + me = where[i]; + pwgts[me] += vwgt[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me == where[adjncy[j]]) + id[i] += adjwgt[j]; + else + ed[i] += adjwgt[j]; + } + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + mincut += ed[i]; + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + + graph->mincut = mincut/2; + graph->nbnd = nbnd; + + ASSERT(pwgts[0]+pwgts[1] == idxsum(nvtxs, vwgt)); +} + + + +/************************************************************************* +* This function projects a partition, and at the same time computes the +* parameters for refinement. +**************************************************************************/ +void Project2WayPartition(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, nvtxs, nbnd, me; + idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; + idxtype *cmap, *where, *id, *ed, *bndptr, *bndind; + idxtype *cwhere, *cid, *ced, *cbndptr; + GraphType *cgraph; + + cgraph = graph->coarser; + cwhere = cgraph->where; + cid = cgraph->id; + ced = cgraph->ed; + cbndptr = cgraph->bndptr; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + adjwgtsum = graph->adjwgtsum; + + Allocate2WayPartitionMemory(ctrl, graph); + + where = graph->where; + id = idxset(nvtxs, 0, graph->id); + ed = idxset(nvtxs, 0, graph->ed); + bndptr = idxset(nvtxs, -1, graph->bndptr); + bndind = graph->bndind; + + + /* Go through and project partition and compute id/ed for the nodes */ + for (i=0; i<nvtxs; i++) { + k = cmap[i]; + where[i] = cwhere[k]; + cmap[i] = cbndptr[k]; + } + + for (nbnd=0, i=0; i<nvtxs; i++) { + me = where[i]; + + id[i] = adjwgtsum[i]; + + if (xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + else { + if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (me != where[adjncy[j]]) + ed[i] += adjwgt[j]; + } + id[i] -= ed[i]; + + if (ed[i] > 0 || xadj[i] == xadj[i+1]) { + bndptr[i] = nbnd; + bndind[nbnd++] = i; + } + } + } + } + + graph->mincut = cgraph->mincut; + graph->nbnd = nbnd; + idxcopy(2, cgraph->pwgts, graph->pwgts); + + FreeGraph(graph->coarser); + graph->coarser = NULL; + +} + diff --git a/Metis/rename.h b/Metis/rename.h new file mode 100644 index 0000000000..74534511a4 --- /dev/null +++ b/Metis/rename.h @@ -0,0 +1,418 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * rename.h + * + * This file contains header files + * + * Started 10/2/97 + * George + * + * $Id: rename.h,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +/* balance.c */ +#define Balance2Way __Balance2Way +#define Bnd2WayBalance __Bnd2WayBalance +#define General2WayBalance __General2WayBalance + + +/* bucketsort.c */ +#define BucketSortKeysInc __BucketSortKeysInc + + +/* ccgraph.c */ +#define CreateCoarseGraph __CreateCoarseGraph +#define CreateCoarseGraphNoMask __CreateCoarseGraphNoMask +#define CreateCoarseGraph_NVW __CreateCoarseGraph_NVW +#define SetUpCoarseGraph __SetUpCoarseGraph +#define ReAdjustMemory __ReAdjustMemory + + +/* coarsen.c */ +#define Coarsen2Way __Coarsen2Way + + +/* compress.c */ +#define CompressGraph __CompressGraph +#define PruneGraph __PruneGraph + + +/* debug.c */ +#define ComputeCut __ComputeCut +#define CheckBnd __CheckBnd +#define CheckBnd2 __CheckBnd2 +#define CheckNodeBnd __CheckNodeBnd +#define CheckRInfo __CheckRInfo +#define CheckNodePartitionParams __CheckNodePartitionParams +#define IsSeparable __IsSeparable + + +/* estmem.c */ +#define EstimateCFraction __EstimateCFraction +#define ComputeCoarseGraphSize __ComputeCoarseGraphSize + + +/* fm.c */ +#define FM_2WayEdgeRefine __FM_2WayEdgeRefine + + +/* fortran.c */ +#define Change2CNumbering __Change2CNumbering +#define Change2FNumbering __Change2FNumbering +#define Change2FNumbering2 __Change2FNumbering2 +#define Change2FNumberingOrder __Change2FNumberingOrder +#define ChangeMesh2CNumbering __ChangeMesh2CNumbering +#define ChangeMesh2FNumbering __ChangeMesh2FNumbering +#define ChangeMesh2FNumbering2 __ChangeMesh2FNumbering2 + + +/* graph.c */ +#define SetUpGraph __SetUpGraph +#define SetUpGraphKway __SetUpGraphKway +#define SetUpGraph2 __SetUpGraph2 +#define VolSetUpGraph __VolSetUpGraph +#define RandomizeGraph __RandomizeGraph +#define IsConnectedSubdomain __IsConnectedSubdomain +#define IsConnected __IsConnected +#define IsConnected2 __IsConnected2 +#define FindComponents __FindComponents + + +/* initpart.c */ +#define Init2WayPartition __Init2WayPartition +#define InitSeparator __InitSeparator +#define GrowBisection __GrowBisection +#define GrowBisectionNode __GrowBisectionNode +#define RandomBisection __RandomBisection + + +/* kmetis.c */ +#define MlevelKWayPartitioning __MlevelKWayPartitioning + + +/* kvmetis.c */ +#define MlevelVolKWayPartitioning __MlevelVolKWayPartitioning + + +/* kwayfm.c */ +#define Random_KWayEdgeRefine __Random_KWayEdgeRefine +#define Greedy_KWayEdgeRefine __Greedy_KWayEdgeRefine +#define Greedy_KWayEdgeBalance __Greedy_KWayEdgeBalance + + +/* kwayrefine.c */ +#define RefineKWay __RefineKWay +#define AllocateKWayPartitionMemory __AllocateKWayPartitionMemory +#define ComputeKWayPartitionParams __ComputeKWayPartitionParams +#define ProjectKWayPartition __ProjectKWayPartition +#define IsBalanced __IsBalanced +#define ComputeKWayBoundary __ComputeKWayBoundary +#define ComputeKWayBalanceBoundary __ComputeKWayBalanceBoundary + + +/* kwayvolfm.c */ +#define Random_KWayVolRefine __Random_KWayVolRefine +#define Random_KWayVolRefineMConn __Random_KWayVolRefineMConn +#define Greedy_KWayVolBalance __Greedy_KWayVolBalance +#define Greedy_KWayVolBalanceMConn __Greedy_KWayVolBalanceMConn +#define KWayVolUpdate __KWayVolUpdate +#define ComputeKWayVolume __ComputeKWayVolume +#define ComputeVolume __ComputeVolume +#define CheckVolKWayPartitionParams __CheckVolKWayPartitionParams +#define ComputeVolSubDomainGraph __ComputeVolSubDomainGraph +#define EliminateVolSubDomainEdges __EliminateVolSubDomainEdges + + +/* kwayvolrefine.c */ +#define RefineVolKWay __RefineVolKWay +#define AllocateVolKWayPartitionMemory __AllocateVolKWayPartitionMemory +#define ComputeVolKWayPartitionParams __ComputeVolKWayPartitionParams +#define ComputeKWayVolGains __ComputeKWayVolGains +#define ProjectVolKWayPartition __ProjectVolKWayPartition +#define ComputeVolKWayBoundary __ComputeVolKWayBoundary +#define ComputeVolKWayBalanceBoundary __ComputeVolKWayBalanceBoundary + + +/* match.c */ +#define Match_RM __Match_RM +#define Match_RM_NVW __Match_RM_NVW +#define Match_HEM __Match_HEM +#define Match_SHEM __Match_SHEM + + +/* mbalance.c */ +#define MocBalance2Way __MocBalance2Way +#define MocGeneral2WayBalance __MocGeneral2WayBalance + + +/* mbalance2.c */ +#define MocBalance2Way2 __MocBalance2Way2 +#define MocGeneral2WayBalance2 __MocGeneral2WayBalance2 +#define SelectQueue3 __SelectQueue3 + + +/* mcoarsen.c */ +#define MCCoarsen2Way __MCCoarsen2Way + + +/* memory.c */ +#define AllocateWorkSpace __AllocateWorkSpace +#define FreeWorkSpace __FreeWorkSpace +#define WspaceAvail __WspaceAvail +#define idxwspacemalloc __idxwspacemalloc +#define idxwspacefree __idxwspacefree +#define fwspacemalloc __fwspacemalloc +#define CreateGraph __CreateGraph +#define InitGraph __InitGraph +#define FreeGraph __FreeGraph + + +/* mesh.c */ +#define TRIDUALMETIS __TRIDUALMETIS +#define TETDUALMETIS __TETDUALMETIS +#define HEXDUALMETIS __HEXDUALMETIS +#define TRINODALMETIS __TRINODALMETIS +#define TETNODALMETIS __TETNODALMETIS +#define HEXNODALMETIS __HEXNODALMETIS + + +/* mfm.c */ +#define MocFM_2WayEdgeRefine __MocFM_2WayEdgeRefine +#define SelectQueue __SelectQueue +#define BetterBalance __BetterBalance +#define Compute2WayHLoadImbalance __Compute2WayHLoadImbalance +#define Compute2WayHLoadImbalanceVec __Compute2WayHLoadImbalanceVec + + +/* mfm2.c */ +#define MocFM_2WayEdgeRefine2 __MocFM_2WayEdgeRefine2 +#define SelectQueue2 __SelectQueue2 +#define IsBetter2wayBalance __IsBetter2wayBalance + + +/* mincover.c */ +#define MinCover __MinCover +#define MinCover_Augment __MinCover_Augment +#define MinCover_Decompose __MinCover_Decompose +#define MinCover_ColDFS __MinCover_ColDFS +#define MinCover_RowDFS __MinCover_RowDFS + + +/* minitpart.c */ +#define MocInit2WayPartition __MocInit2WayPartition +#define MocGrowBisection __MocGrowBisection +#define MocRandomBisection __MocRandomBisection +#define MocInit2WayBalance __MocInit2WayBalance +#define SelectQueueoneWay __SelectQueueoneWay + + +/* minitpart2.c */ +#define MocInit2WayPartition2 __MocInit2WayPartition2 +#define MocGrowBisection2 __MocGrowBisection2 +#define MocGrowBisectionNew2 __MocGrowBisectionNew2 +#define MocInit2WayBalance2 __MocInit2WayBalance2 +#define SelectQueueOneWay2 __SelectQueueOneWay2 + + +/* mkmetis.c */ +#define MCMlevelKWayPartitioning __MCMlevelKWayPartitioning + + +/* mkwayfmh.c */ +#define MCRandom_KWayEdgeRefineHorizontal __MCRandom_KWayEdgeRefineHorizontal +#define MCGreedy_KWayEdgeBalanceHorizontal __MCGreedy_KWayEdgeBalanceHorizontal +#define AreAllHVwgtsBelow __AreAllHVwgtsBelow +#define AreAllHVwgtsAbove __AreAllHVwgtsAbove +#define ComputeHKWayLoadImbalance __ComputeHKWayLoadImbalance +#define MocIsHBalanced __MocIsHBalanced +#define IsHBalanceBetterFT __IsHBalanceBetterFT +#define IsHBalanceBetterTT __IsHBalanceBetterTT + + +/* mkwayrefine.c */ +#define MocRefineKWayHorizontal __MocRefineKWayHorizontal +#define MocAllocateKWayPartitionMemory __MocAllocateKWayPartitionMemory +#define MocComputeKWayPartitionParams __MocComputeKWayPartitionParams +#define MocProjectKWayPartition __MocProjectKWayPartition +#define MocComputeKWayBalanceBoundary __MocComputeKWayBalanceBoundary + + +/* mmatch.c */ +#define MCMatch_RM __MCMatch_RM +#define MCMatch_HEM __MCMatch_HEM +#define MCMatch_SHEM __MCMatch_SHEM +#define MCMatch_SHEBM __MCMatch_SHEBM +#define MCMatch_SBHEM __MCMatch_SBHEM +#define BetterVBalance __BetterVBalance +#define AreAllVwgtsBelowFast __AreAllVwgtsBelowFast + + +/* mmd.c */ +#define genmmd __genmmd +#define mmdelm __mmdelm +#define mmdint __mmdint +#define mmdnum __mmdnum +#define mmdupd __mmdupd + + +/* mpmetis.c */ +#define MCMlevelRecursiveBisection __MCMlevelRecursiveBisection +#define MCHMlevelRecursiveBisection __MCHMlevelRecursiveBisection +#define MCMlevelEdgeBisection __MCMlevelEdgeBisection +#define MCHMlevelEdgeBisection __MCHMlevelEdgeBisection + + +/* mrefine.c */ +#define MocRefine2Way __MocRefine2Way +#define MocAllocate2WayPartitionMemory __MocAllocate2WayPartitionMemory +#define MocCompute2WayPartitionParams __MocCompute2WayPartitionParams +#define MocProject2WayPartition __MocProject2WayPartition + + +/* mrefine2.c */ +#define MocRefine2Way2 __MocRefine2Way2 + + +/* mutil.c */ +#define AreAllVwgtsBelow __AreAllVwgtsBelow +#define AreAnyVwgtsBelow __AreAnyVwgtsBelow +#define AreAllVwgtsAbove __AreAllVwgtsAbove +#define ComputeLoadImbalance __ComputeLoadImbalance +#define AreAllBelow __AreAllBelow + + +/* myqsort.c */ +#define iidxsort __iidxsort +#define iintsort __iintsort +#define ikeysort __ikeysort +#define ikeyvalsort __ikeyvalsort + + +/* ometis.c */ +#define MlevelNestedDissection __MlevelNestedDissection +#define MlevelNestedDissectionCC __MlevelNestedDissectionCC +#define MlevelNodeBisectionMultiple __MlevelNodeBisectionMultiple +#define MlevelNodeBisection __MlevelNodeBisection +#define SplitGraphOrder __SplitGraphOrder +#define MMDOrder __MMDOrder +#define SplitGraphOrderCC __SplitGraphOrderCC + + +/* parmetis.c */ +#define MlevelNestedDissectionP __MlevelNestedDissectionP + + +/* pmetis.c */ +#define MlevelRecursiveBisection __MlevelRecursiveBisection +#define MlevelEdgeBisection __MlevelEdgeBisection +#define SplitGraphPart __SplitGraphPart +#define SetUpSplitGraph __SetUpSplitGraph + + +/* pqueue.c */ +#define PQueueInit __PQueueInit +#define PQueueReset __PQueueReset +#define PQueueFree __PQueueFree +#define PQueueInsert __PQueueInsert +#define PQueueDelete __PQueueDelete +#define PQueueUpdate __PQueueUpdate +#define PQueueUpdateUp __PQueueUpdateUp +#define PQueueGetMax __PQueueGetMax +#define PQueueSeeMax __PQueueSeeMax +#define CheckHeap __CheckHeap + + +/* refine.c */ +#define Refine2Way __Refine2Way +#define Allocate2WayPartitionMemory __Allocate2WayPartitionMemory +#define Compute2WayPartitionParams __Compute2WayPartitionParams +#define Project2WayPartition __Project2WayPartition + + +/* separator.c */ +#define ConstructSeparator __ConstructSeparator +#define ConstructMinCoverSeparator0 __ConstructMinCoverSeparator0 +#define ConstructMinCoverSeparator __ConstructMinCoverSeparator + + +/* sfm.c */ +#define FM_2WayNodeRefine __FM_2WayNodeRefine +#define FM_2WayNodeRefineEqWgt __FM_2WayNodeRefineEqWgt +#define FM_2WayNodeRefine_OneSided __FM_2WayNodeRefine_OneSided +#define FM_2WayNodeBalance __FM_2WayNodeBalance +#define ComputeMaxNodeGain __ComputeMaxNodeGain + + +/* srefine.c */ +#define Refine2WayNode __Refine2WayNode +#define Allocate2WayNodePartitionMemory __Allocate2WayNodePartitionMemory +#define Compute2WayNodePartitionParams __Compute2WayNodePartitionParams +#define Project2WayNodePartition __Project2WayNodePartition + + +/* stat.c */ +#define ComputePartitionInfo __ComputePartitionInfo +#define ComputePartitionBalance __ComputePartitionBalance +#define ComputeElementBalance __ComputeElementBalance + + +/* subdomains.c */ +#define Random_KWayEdgeRefineMConn __Random_KWayEdgeRefineMConn +#define Greedy_KWayEdgeBalanceMConn __Greedy_KWayEdgeBalanceMConn +#define PrintSubDomainGraph __PrintSubDomainGraph +#define ComputeSubDomainGraph __ComputeSubDomainGraph +#define EliminateSubDomainEdges __EliminateSubDomainEdges +#define MoveGroupMConn __MoveGroupMConn +#define EliminateComponents __EliminateComponents +#define MoveGroup __MoveGroup + + +/* timing.c */ +#define InitTimers __InitTimers +#define PrintTimers __PrintTimers +#define seconds __seconds + + +/* util.c */ +#define errexit __errexit +#define GKfree __GKfree +#ifndef DMALLOC +#define imalloc __imalloc +#define idxmalloc __idxmalloc +#define fmalloc __fmalloc +#define ismalloc __ismalloc +#define idxsmalloc __idxsmalloc +#define GKmalloc __GKmalloc +#endif +#define iset __iset +#define idxset __idxset +#define sset __sset +#define iamax __iamax +#define idxamax __idxamax +#define idxamax_strd __idxamax_strd +#define samax __samax +#define samax2 __samax2 +#define idxamin __idxamin +#define samin __samin +#define idxsum __idxsum +#define idxsum_strd __idxsum_strd +#define idxadd __idxadd +#define charsum __charsum +#define isum __isum +#define ssum __ssum +#define ssum_strd __ssum_strd +#define sscale __sscale +#define snorm2 __snorm2 +#define sdot __sdot +#define saxpy __saxpy +#define RandomPermute __RandomPermute +#define ispow2 __ispow2 +#define InitRandom __InitRandom +#define log2 __log2 + + + + + diff --git a/Metis/separator.c b/Metis/separator.c new file mode 100644 index 0000000000..cbabeacb7f --- /dev/null +++ b/Metis/separator.c @@ -0,0 +1,284 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * separator.c + * + * This file contains code for separator extraction + * + * Started 8/1/97 + * George + * + * $Id: separator.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + +/************************************************************************* +* This function takes a bisection and constructs a minimum weight vertex +* separator out of it. It uses the node-based separator refinement for it. +**************************************************************************/ +void ConstructSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, j, k, nvtxs, nbnd; + idxtype *xadj, *where, *bndind; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + nbnd = graph->nbnd; + bndind = graph->bndind; + + where = idxcopy(nvtxs, graph->where, idxwspacemalloc(ctrl, nvtxs)); + + /* Put the nodes in the boundary into the separator */ + for (i=0; i<nbnd; i++) { + j = bndind[i]; + if (xadj[j+1]-xadj[j] > 0) /* Ignore islands */ + where[j] = 2; + } + + GKfree(&graph->rdata, LTERM); + Allocate2WayNodePartitionMemory(ctrl, graph); + idxcopy(nvtxs, where, graph->where); + idxwspacefree(ctrl, nvtxs); + + ASSERT(IsSeparable(graph)); + + Compute2WayNodePartitionParams(ctrl, graph); + + ASSERT(CheckNodePartitionParams(graph)); + + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + + ASSERT(IsSeparable(graph)); +} + + + +/************************************************************************* +* This function takes a bisection and constructs a minimum weight vertex +* separator out of it. It uses an unweighted minimum-cover algorithm +* followed by node-based separator refinement. +**************************************************************************/ +void ConstructMinCoverSeparator0(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize; + idxtype *xadj, *adjncy, *bxadj, *badjncy; + idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + nbnd = graph->nbnd; + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + + vmap = idxwspacemalloc(ctrl, nvtxs); + ivmap = idxwspacemalloc(ctrl, nbnd); + cover = idxwspacemalloc(ctrl, nbnd); + + if (nbnd > 0) { + /* Go through the boundary and determine the sizes of the bipartite graph */ + bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0; + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + bnvtxs[k]++; + bnedges[k] += xadj[j+1]-xadj[j]; + } + } + + bnvtxs[2] = bnvtxs[0]+bnvtxs[1]; + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + + bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj"); + badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy"); + + /* Construct the ivmap and vmap */ + ASSERT(idxset(nvtxs, -1, vmap) == vmap); + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + vmap[j] = bnvtxs[k]; + ivmap[bnvtxs[k]++] = j; + } + } + + /* OK, go through and put the vertices of each part starting from 0 */ + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + bxadj[0] = l = 0; + for (k=0; k<2; k++) { + for (ii=0; ii<nbnd; ii++) { + i = bndind[ii]; + if (where[i] == k && xadj[i] < xadj[i+1]) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + jj = adjncy[j]; + if (where[jj] != k) { + ASSERT(bndptr[jj] != -1); + ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj])); + badjncy[l++] = vmap[jj]; + } + } + bxadj[++bnvtxs[k]] = l; + } + } + } + + ASSERT(l <= bnedges[0]+bnedges[1]); + + MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize)); + + for (i=0; i<csize; i++) { + j = ivmap[cover[i]]; + where[j] = 2; + } + + GKfree(&bxadj, &badjncy, LTERM); + + for (i=0; i<nbnd; i++) + bndptr[bndind[i]] = -1; + for (nbnd=i=0; i<nvtxs; i++) { + if (where[i] == 2) { + bndind[nbnd] = i; + bndptr[i] = nbnd++; + } + } + } + else { + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0)); + } + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, graph->nbnd); + idxwspacefree(ctrl, graph->nbnd); + graph->nbnd = nbnd; + + + ASSERT(IsSeparable(graph)); +} + + + +/************************************************************************* +* This function takes a bisection and constructs a minimum weight vertex +* separator out of it. It uses an unweighted minimum-cover algorithm +* followed by node-based separator refinement. +**************************************************************************/ +void ConstructMinCoverSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize; + idxtype *xadj, *adjncy, *bxadj, *badjncy; + idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover; + + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + nbnd = graph->nbnd; + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + + vmap = idxwspacemalloc(ctrl, nvtxs); + ivmap = idxwspacemalloc(ctrl, nbnd); + cover = idxwspacemalloc(ctrl, nbnd); + + if (nbnd > 0) { + /* Go through the boundary and determine the sizes of the bipartite graph */ + bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0; + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + bnvtxs[k]++; + bnedges[k] += xadj[j+1]-xadj[j]; + } + } + + bnvtxs[2] = bnvtxs[0]+bnvtxs[1]; + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + + bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj"); + badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy"); + + /* Construct the ivmap and vmap */ + ASSERT(idxset(nvtxs, -1, vmap) == vmap); + for (i=0; i<nbnd; i++) { + j = bndind[i]; + k = where[j]; + if (xadj[j+1]-xadj[j] > 0) { + vmap[j] = bnvtxs[k]; + ivmap[bnvtxs[k]++] = j; + } + } + + /* OK, go through and put the vertices of each part starting from 0 */ + bnvtxs[1] = bnvtxs[0]; + bnvtxs[0] = 0; + bxadj[0] = l = 0; + for (k=0; k<2; k++) { + for (ii=0; ii<nbnd; ii++) { + i = bndind[ii]; + if (where[i] == k && xadj[i] < xadj[i+1]) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + jj = adjncy[j]; + if (where[jj] != k) { + ASSERT(bndptr[jj] != -1); + ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj])); + badjncy[l++] = vmap[jj]; + } + } + bxadj[++bnvtxs[k]] = l; + } + } + } + + ASSERT(l <= bnedges[0]+bnedges[1]); + + MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize); + + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize)); + + for (i=0; i<csize; i++) { + j = ivmap[cover[i]]; + where[j] = 2; + } + + GKfree(&bxadj, &badjncy, LTERM); + } + else { + IFSET(ctrl->dbglvl, DBG_SEPINFO, + printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0)); + } + + /* Prepare to refine the vertex separator */ + idxcopy(nvtxs, graph->where, vmap); + GKfree(&graph->rdata, LTERM); + + Allocate2WayNodePartitionMemory(ctrl, graph); + idxcopy(nvtxs, vmap, graph->where); + idxwspacefree(ctrl, nvtxs+2*graph->nbnd); + + Compute2WayNodePartitionParams(ctrl, graph); + + ASSERT(CheckNodePartitionParams(graph)); + + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 6); + + ASSERT(IsSeparable(graph)); +} + diff --git a/Metis/sfm.c b/Metis/sfm.c new file mode 100644 index 0000000000..28f1acb874 --- /dev/null +++ b/Metis/sfm.c @@ -0,0 +1,1069 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * sfm.c + * + * This file contains code that implementes an FM-based separator refinement + * + * Started 8/1/97 + * George + * + * $Id: sfm.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeRefine(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *moved, *swaps, *perm; + PQueueType parts[2]; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int badmaxpwgt, mindiff, newdiff; + int u[2], g[2]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + + i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); + PQueueInit(ctrl, &parts[0], nvtxs, i); + PQueueInit(ctrl, &parts[1], nvtxs, i); + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs+1); + mind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); + + for (pass=0; pass<npasses; pass++) { + idxset(nvtxs, -1, moved); + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]); + PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + to = (pwgts[0] < pwgts[1] ? 0 : 1); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + u[0] = PQueueSeeMax(&parts[0]); + u[1] = PQueueSeeMax(&parts[1]); + if (u[0] != -1 && u[1] != -1) { + g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1]; + g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0]; + + to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); + /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */ + + if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) + to = (to+1)%2; + } + else if (u[0] == -1 && u[1] == -1) { + break; + } + else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) { + to = 0; + } + else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) { + to = 1; + } + else + break; + + other = (to+1)%2; + + higain = PQueueGetMax(&parts[to]); + if (moved[higain] == -1) /* Delete if it was in the separator originally */ + PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + oldgain = vwgt[k]-rinfo[k].edegrees[to]; + rinfo[k].edegrees[to] += vwgt[higain]; + if (moved[k] == -1 || moved[k] == -(2+other)) + PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]); + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + if (moved[kk] == -1 || moved[kk] == -(2+to)) + PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Only one side! */ + if (moved[k] == -1) { + PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]); + moved[k] = -(2+to); + } + } + } + mptr[nswaps+1] = nmind; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + + to = where[higain]; + other = (to+1)%2; + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut >= initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeRefine2(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *moved, *swaps, *perm; + PQueueType parts[2]; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int badmaxpwgt, mindiff, newdiff; + int u[2], g[2]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + + i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); + PQueueInit(ctrl, &parts[0], nvtxs, i); + PQueueInit(ctrl, &parts[1], nvtxs, i); + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs+1); + mind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); + + for (pass=0; pass<npasses; pass++) { + idxset(nvtxs, -1, moved); + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]); + PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + to = (pwgts[0] < pwgts[1] ? 0 : 1); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2]/2)/2); + + u[0] = PQueueSeeMax(&parts[0]); + u[1] = PQueueSeeMax(&parts[1]); + if (u[0] != -1 && u[1] != -1) { + g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1]; + g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0]; + + to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); + /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */ + + if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) + to = (to+1)%2; + } + else if (u[0] == -1 && u[1] == -1) { + break; + } + else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) { + to = 0; + } + else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) { + to = 1; + } + else + break; + + other = (to+1)%2; + + higain = PQueueGetMax(&parts[to]); + if (moved[higain] == -1) /* Delete if it was in the separator originally */ + PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + oldgain = vwgt[k]-rinfo[k].edegrees[to]; + rinfo[k].edegrees[to] += vwgt[higain]; + if (moved[k] == -1 || moved[k] == -(2+other)) + PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]); + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + if (moved[kk] == -1 || moved[kk] == -(2+to)) + PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Only one side! */ + if (moved[k] == -1) { + PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]); + moved[k] = -(2+to); + } + } + } + mptr[nswaps+1] = nmind; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + + to = where[higain]; + other = (to+1)%2; + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut >= initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeRefineEqWgt(CtrlType *ctrl, GraphType *graph, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *moved, *swaps, *perm; + PQueueType parts[2]; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int mindiff, newdiff; + int u[2], g[2]; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + + i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); + PQueueInit(ctrl, &parts[0], nvtxs, i); + PQueueInit(ctrl, &parts[1], nvtxs, i); + + moved = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs+1); + mind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + idxset(nvtxs, -1, moved); + PQueueReset(&parts[0]); + PQueueReset(&parts[1]); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]); + PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + to = (pwgts[0] < pwgts[1] ? 0 : 1); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + to = (pwgts[0] < pwgts[1] ? 0 : 1); + + if (pwgts[0] == pwgts[1]) { + u[0] = PQueueSeeMax(&parts[0]); + u[1] = PQueueSeeMax(&parts[1]); + if (u[0] != -1 && u[1] != -1) { + g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1]; + g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0]; + + to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); + } + } + other = (to+1)%2; + + if ((higain = PQueueGetMax(&parts[to])) == -1) + break; + + if (moved[higain] == -1) /* Delete if it was in the separator originally */ + PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + moved[higain] = nswaps; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + oldgain = vwgt[k]-rinfo[k].edegrees[to]; + rinfo[k].edegrees[to] += vwgt[higain]; + if (moved[k] == -1 || moved[k] == -(2+other)) + PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]); + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + if (moved[kk] == -1 || moved[kk] == -(2+to)) + PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Only one side! */ + if (moved[k] == -1) { + PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]); + moved[k] = -(2+to); + } + } + } + mptr[nswaps+1] = nmind; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + + to = where[higain]; + other = (to+1)%2; + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (mincutorder == -1 || mincut >= initcut) + break; + } + + PQueueFree(ctrl, &parts[0]); + PQueueFree(ctrl, &parts[1]); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function performs a node-based FM refinement. This is the +* one-way version +**************************************************************************/ +void FM_2WayNodeRefine_OneSided(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *mptr, *mind, *swaps, *perm; + PQueueType parts; + NRInfoType *rinfo; + int higain, oldgain, mincut, initcut, mincutorder; + int pass, to, other, limit; + int badmaxpwgt, mindiff, newdiff; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt)); + + perm = idxwspacemalloc(ctrl, nvtxs); + swaps = idxwspacemalloc(ctrl, nvtxs); + mptr = idxwspacemalloc(ctrl, nvtxs); + mind = idxwspacemalloc(ctrl, nvtxs+1); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions-N1: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); + + to = (pwgts[0] < pwgts[1] ? 1 : 0); + for (pass=0; pass<npasses; pass++) { + other = to; + to = (to+1)%2; + + PQueueReset(&parts); + + mincutorder = -1; + initcut = mincut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + mptr[0] = nmind = 0; + mindiff = abs(pwgts[0]-pwgts[1]); + for (nswaps=0; nswaps<nvtxs; nswaps++) { + + if ((higain = PQueueGetMax(&parts)) == -1) + break; + + ASSERT(bndptr[higain] != -1); + + if (pwgts[to]+vwgt[higain] > badmaxpwgt) + break; /* No point going any further. Balance will be bad */ + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); + if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { + mincut = pwgts[2]; + mincutorder = nswaps; + mindiff = newdiff; + } + else { + if (nswaps - mincutorder > limit) { + pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); + break; /* No further improvement, break out */ + } + } + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + swaps[nswaps] = higain; + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + rinfo[k].edegrees[to] += vwgt[higain]; + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + mind[nmind++] = k; /* Keep track for rollback */ + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + + /* Since the moves are one-sided this vertex has not been moved yet */ + PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue. Safe due to one-sided moves */ + PQueueInsert(&parts, k, vwgt[k]-edegrees[other]); + } + } + mptr[nswaps+1] = nmind; + + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %5d [%5d] \t[%5d %5d %5d] [%3d %2d]\n", + higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit)); + + } + + + /**************************************************************** + * Roll back computation + *****************************************************************/ + for (nswaps--; nswaps>mincutorder; nswaps--) { + higain = swaps[nswaps]; + + ASSERT(CheckNodePartitionParams(graph)); + ASSERT(where[higain] == to); + + INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); + where[higain] = 2; + BNDInsert(nbnd, bndind, bndptr, higain); + + edegrees = rinfo[higain].edegrees; + edegrees[0] = edegrees[1] = 0; + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) + rinfo[k].edegrees[to] -= vwgt[higain]; + else + edegrees[where[k]] += vwgt[k]; + } + + /* Push nodes out of the separator */ + for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { + k = mind[j]; + ASSERT(where[k] == 2); + where[k] = other; + INC_DEC(pwgts[other], pwgts[2], vwgt[k]); + BNDDelete(nbnd, bndind, bndptr, k); + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] == 2) + rinfo[kk].edegrees[other] += vwgt[k]; + } + } + } + + ASSERT(mincut == pwgts[2]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = mincut; + graph->nbnd = nbnd; + + if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut)) + break; + } + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs+1); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs a node-based FM refinement +**************************************************************************/ +void FM_2WayNodeBalance(CtrlType *ctrl, GraphType *graph, float ubfactor) +{ + int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps; + idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; + idxtype *perm, *moved; + PQueueType parts; + NRInfoType *rinfo; + int higain, oldgain; + int pass, to, other; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + where = graph->where; + pwgts = graph->pwgts; + rinfo = graph->nrinfo; + + if (abs(pwgts[0]-pwgts[1]) < (int)((ubfactor-1.0)*(pwgts[0]+pwgts[1]))) + return; + if (abs(pwgts[0]-pwgts[1]) < 3*idxsum(nvtxs, vwgt)/nvtxs) + return; + + to = (pwgts[0] < pwgts[1] ? 0 : 1); + other = (to+1)%2; + + PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt)); + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxset(nvtxs, -1, idxwspacemalloc(ctrl, nvtxs)); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d [B]\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); + + nbnd = graph->nbnd; + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + ASSERT(where[i] == 2); + PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]); + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + ASSERT(CheckNodePartitionParams(graph)); + + /****************************************************** + * Get into the FM loop + *******************************************************/ + for (nswaps=0; nswaps<nvtxs; nswaps++) { + if ((higain = PQueueGetMax(&parts)) == -1) + break; + + moved[higain] = 1; + + if (pwgts[other] - rinfo[higain].edegrees[other] < (pwgts[0]+pwgts[1])/2) + continue; +#ifdef XXX + if (pwgts[other] - rinfo[higain].edegrees[other] < pwgts[to]+vwgt[higain]) + break; +#endif + + ASSERT(bndptr[higain] != -1); + + pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); + + BNDDelete(nbnd, bndind, bndptr, higain); + pwgts[to] += vwgt[higain]; + where[higain] = to; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, + printf("Moved %6d to %3d, Gain: %3d, \t[%5d %5d %5d]\n", higain, to, vwgt[higain]-rinfo[higain].edegrees[other], pwgts[0], pwgts[1], pwgts[2])); + + + /********************************************************** + * Update the degrees of the affected nodes + ***********************************************************/ + for (j=xadj[higain]; j<xadj[higain+1]; j++) { + k = adjncy[j]; + if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ + rinfo[k].edegrees[to] += vwgt[higain]; + } + else if (where[k] == other) { /* This vertex is pulled into the separator */ + ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k])); + BNDInsert(nbnd, bndind, bndptr, k); + + where[k] = 2; + pwgts[other] -= vwgt[k]; + + edegrees = rinfo[k].edegrees; + edegrees[0] = edegrees[1] = 0; + for (jj=xadj[k]; jj<xadj[k+1]; jj++) { + kk = adjncy[jj]; + if (where[kk] != 2) + edegrees[where[kk]] += vwgt[kk]; + else { + ASSERT(bndptr[kk] != -1); + oldgain = vwgt[kk]-rinfo[kk].edegrees[other]; + rinfo[kk].edegrees[other] -= vwgt[k]; + + if (moved[kk] == -1) + PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]); + } + } + + /* Insert the new vertex into the priority queue */ + PQueueInsert(&parts, k, vwgt[k]-edegrees[other]); + } + } + + if (pwgts[to] > pwgts[other]) + break; + } + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\tBalanced sep: %6d at %4d, PWGTS: [%6d %6d], NBND: %6d\n", pwgts[2], nswaps, pwgts[0], pwgts[1], nbnd)); + + graph->mincut = pwgts[2]; + graph->nbnd = nbnd; + + + PQueueFree(ctrl, &parts); + + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); +} + + +/************************************************************************* +* This function computes the maximum possible gain for a vertex +**************************************************************************/ +int ComputeMaxNodeGain(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt) +{ + int i, j, k, max; + + max = 0; + for (j=xadj[0]; j<xadj[1]; j++) + max += vwgt[adjncy[j]]; + + for (i=1; i<nvtxs; i++) { + for (k=0, j=xadj[i]; j<xadj[i+1]; j++) + k += vwgt[adjncy[j]]; + if (max < k) + max = k; + } + + return max; +} + + diff --git a/Metis/srefine.c b/Metis/srefine.c new file mode 100644 index 0000000000..a0cf88d101 --- /dev/null +++ b/Metis/srefine.c @@ -0,0 +1,169 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * srefine.c + * + * This file contains code for the separator refinement algortihms + * + * Started 8/1/97 + * George + * + * $Id: srefine.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function is the entry point of the separator refinement +**************************************************************************/ +void Refine2WayNode(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float ubfactor) +{ + + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); + + for (;;) { + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); + if (ctrl->RType != 15) + FM_2WayNodeBalance(ctrl, graph, ubfactor); + + switch (ctrl->RType) { + case 1: + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + break; + case 2: + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8); + break; + case 3: + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8); + break; + case 4: + FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8); + FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); + break; + case 5: + FM_2WayNodeRefineEqWgt(ctrl, graph, 8); + break; + } + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); + + if (graph == orggraph) + break; + + graph = graph->finer; + IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); + Project2WayNodePartition(ctrl, graph); + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); + } + + IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); +} + + +/************************************************************************* +* This function allocates memory for 2-way edge refinement +**************************************************************************/ +void Allocate2WayNodePartitionMemory(CtrlType *ctrl, GraphType *graph) +{ + int nvtxs, pad64; + + nvtxs = graph->nvtxs; + + pad64 = (3*nvtxs+3)%2; + + graph->rdata = idxmalloc(3*nvtxs+3+(sizeof(NRInfoType)/sizeof(idxtype))*nvtxs+pad64, "Allocate2WayPartitionMemory: rdata"); + graph->pwgts = graph->rdata; + graph->where = graph->rdata + 3; + graph->bndptr = graph->rdata + nvtxs + 3; + graph->bndind = graph->rdata + 2*nvtxs + 3; + graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3 + pad64); +} + + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void Compute2WayNodePartitionParams(CtrlType *ctrl, GraphType *graph) +{ + int i, j, k, l, nvtxs, nbnd; + idxtype *xadj, *adjncy, *adjwgt, *vwgt; + idxtype *where, *pwgts, *bndind, *bndptr, *edegrees; + NRInfoType *rinfo; + int me, other; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + rinfo = graph->nrinfo; + pwgts = idxset(3, 0, graph->pwgts); + bndind = graph->bndind; + bndptr = idxset(nvtxs, -1, graph->bndptr); + + + /*------------------------------------------------------------ + / Compute now the separator external degrees + /------------------------------------------------------------*/ + nbnd = 0; + for (i=0; i<nvtxs; i++) { + me = where[i]; + pwgts[me] += vwgt[i]; + + ASSERT(me >=0 && me <= 2); + + if (me == 2) { /* If it is on the separator do some computations */ + BNDInsert(nbnd, bndind, bndptr, i); + + edegrees = rinfo[i].edegrees; + edegrees[0] = edegrees[1] = 0; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + other = where[adjncy[j]]; + if (other != 2) + edegrees[other] += vwgt[adjncy[j]]; + } + } + } + + ASSERT(CheckNodeBnd(graph, nbnd)); + + graph->mincut = pwgts[2]; + graph->nbnd = nbnd; +} + + +/************************************************************************* +* This function computes the initial id/ed +**************************************************************************/ +void Project2WayNodePartition(CtrlType *ctrl, GraphType *graph) +{ + int i, j, nvtxs; + idxtype *cmap, *where, *cwhere; + GraphType *cgraph; + + cgraph = graph->coarser; + cwhere = cgraph->where; + + nvtxs = graph->nvtxs; + cmap = graph->cmap; + + Allocate2WayNodePartitionMemory(ctrl, graph); + where = graph->where; + + /* Project the partition */ + for (i=0; i<nvtxs; i++) { + where[i] = cwhere[cmap[i]]; + ASSERTP(where[i] >= 0 && where[i] <= 2, ("%d %d %d %d\n", i, cmap[i], where[i], cwhere[cmap[i]])); + } + + FreeGraph(graph->coarser); + graph->coarser = NULL; + + Compute2WayNodePartitionParams(ctrl, graph); +} diff --git a/Metis/stat.c b/Metis/stat.c new file mode 100644 index 0000000000..74d22e9989 --- /dev/null +++ b/Metis/stat.c @@ -0,0 +1,287 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * stat.c + * + * This file computes various statistics + * + * Started 7/25/97 + * George + * + * $Id: stat.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function computes cuts and balance information +**************************************************************************/ +void ComputePartitionInfo(GraphType *graph, int nparts, idxtype *where) +{ + int i, j, k, nvtxs, ncon, mustfree=0; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *kpwgts, *tmpptr; + idxtype *padjncy, *padjwgt, *padjcut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + if (vwgt == NULL) { + vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt"); + mustfree = 1; + } + if (adjwgt == NULL) { + adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt"); + mustfree += 2; + } + + printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where)); + + /* Compute balance information */ + kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j]; + } + + if (ncon == 1) { + printf("\tBalance: %5.3f out of %5.3f\n", + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), + 1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts))); + } + else { + printf("\tBalance:"); + for (j=0; j<ncon; j++) + printf(" (%5.3f out of %5.3f)", + 1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)), + 1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon))); + printf("\n"); + } + + + /* Compute p-adjncy information */ + padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy"); + padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + + idxset(nparts, 0, kpwgts); + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) { + padjncy[where[i]*nparts+where[adjncy[j]]] = 1; + padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j]; + if (kpwgts[where[adjncy[j]]] == 0) { + padjwgt[where[i]*nparts+where[adjncy[j]]]++; + kpwgts[where[adjncy[j]]] = 1; + } + } + } + for (j=xadj[i]; j<xadj[i+1]; j++) + kpwgts[where[adjncy[j]]] = 0; + } + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjncy+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5.2f %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], + 1.0*idxsum(nparts, kpwgts)/(1.0*nparts), + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjcut+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjwgt+i*nparts); + printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs)); + + tmpptr = graph->where; + graph->where = where; + for (i=0; i<nparts; i++) + IsConnectedSubdomain(NULL, graph, i, 1); + graph->where = tmpptr; + + if (mustfree == 1 || mustfree == 3) { + free(vwgt); + graph->vwgt = NULL; + } + if (mustfree == 2 || mustfree == 3) { + free(adjwgt); + graph->adjwgt = NULL; + } + + GKfree(&kpwgts, &padjncy, &padjwgt, &padjcut, LTERM); +} + + +/************************************************************************* +* This function computes cuts and balance information +**************************************************************************/ +void ComputePartitionInfoBipartite(GraphType *graph, int nparts, idxtype *where) +{ + int i, j, k, nvtxs, ncon, mustfree=0; + idxtype *xadj, *adjncy, *vwgt, *vsize, *adjwgt, *kpwgts, *tmpptr; + idxtype *padjncy, *padjwgt, *padjcut; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + vsize = graph->vsize; + adjwgt = graph->adjwgt; + + if (vwgt == NULL) { + vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt"); + mustfree = 1; + } + if (adjwgt == NULL) { + adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt"); + mustfree += 2; + } + + printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where)); + + /* Compute balance information */ + kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts"); + + for (i=0; i<nvtxs; i++) { + for (j=0; j<ncon; j++) + kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j]; + } + + if (ncon == 1) { + printf("\tBalance: %5.3f out of %5.3f\n", + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), + 1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts))); + } + else { + printf("\tBalance:"); + for (j=0; j<ncon; j++) + printf(" (%5.3f out of %5.3f)", + 1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)), + 1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon))); + printf("\n"); + } + + + /* Compute p-adjncy information */ + padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy"); + padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt"); + + idxset(nparts, 0, kpwgts); + for (i=0; i<nvtxs; i++) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[i] != where[adjncy[j]]) { + padjncy[where[i]*nparts+where[adjncy[j]]] = 1; + padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j]; + if (kpwgts[where[adjncy[j]]] == 0) { + padjwgt[where[i]*nparts+where[adjncy[j]]] += vsize[i]; + kpwgts[where[adjncy[j]]] = 1; + } + } + } + for (j=xadj[i]; j<xadj[i+1]; j++) + kpwgts[where[adjncy[j]]] = 0; + } + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjncy+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5d %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjcut+i*nparts); + printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts))); + + for (i=0; i<nparts; i++) + kpwgts[i] = idxsum(nparts, padjwgt+i*nparts); + printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n", + kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts, + 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs)); + + + if (mustfree == 1 || mustfree == 3) { + free(vwgt); + graph->vwgt = NULL; + } + if (mustfree == 2 || mustfree == 3) { + free(adjwgt); + graph->adjwgt = NULL; + } + + GKfree(&kpwgts, &padjncy, &padjwgt, &padjcut, LTERM); +} + + + +/************************************************************************* +* This function computes the balance of the partitioning +**************************************************************************/ +void ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec) +{ + int i, j, nvtxs, ncon; + idxtype *kpwgts, *vwgt; + float balance; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + vwgt = graph->vwgt; + + kpwgts = idxsmalloc(nparts, 0, "ComputePartitionInfo: kpwgts"); + + if (vwgt == NULL) { + for (i=0; i<nvtxs; i++) + kpwgts[where[i]]++; + ubvec[0] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*nvtxs); + } + else { + for (j=0; j<ncon; j++) { + idxset(nparts, 0, kpwgts); + for (i=0; i<graph->nvtxs; i++) + kpwgts[where[i]] += vwgt[i*ncon+j]; + + ubvec[j] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)); + } + } + + free(kpwgts); + +} + + +/************************************************************************* +* This function computes the balance of the element partitioning +**************************************************************************/ +float ComputeElementBalance(int ne, int nparts, idxtype *where) +{ + int i; + idxtype *kpwgts; + float balance; + + kpwgts = idxsmalloc(nparts, 0, "ComputeElementBalance: kpwgts"); + + for (i=0; i<ne; i++) + kpwgts[where[i]]++; + + balance = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)); + + free(kpwgts); + + return balance; + +} diff --git a/Metis/struct.h b/Metis/struct.h new file mode 100644 index 0000000000..e5ba553e9a --- /dev/null +++ b/Metis/struct.h @@ -0,0 +1,251 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * struct.h + * + * This file contains data structures for ILU routines. + * + * Started 9/26/95 + * George + * + * $Id: struct.h,v 1.1 2005-09-07 14:36:46 remacle Exp $ + */ + +/* Undefine the following #define in order to use short int as the idxtype */ +#define IDXTYPE_INT + +/* Indexes are as long as integers for now */ +#ifdef IDXTYPE_INT +typedef int idxtype; +#else +typedef short idxtype; +#endif + +#define MAXIDX (1<<8*sizeof(idxtype)-2) + + +/************************************************************************* +* The following data structure stores key-value pair +**************************************************************************/ +struct KeyValueType { + idxtype key; + idxtype val; +}; + +typedef struct KeyValueType KeyValueType; + + +/************************************************************************* +* The following data structure will hold a node of a doubly-linked list. +**************************************************************************/ +struct ListNodeType { + int id; /* The id value of the node */ + struct ListNodeType *prev, *next; /* It's a doubly-linked list */ +}; + +typedef struct ListNodeType ListNodeType; + + + +/************************************************************************* +* The following data structure is used to store the buckets for the +* refinment algorithms +**************************************************************************/ +struct PQueueType { + int type; /* The type of the representation used */ + int nnodes; + int maxnodes; + int mustfree; + + /* Linear array version of the data structures */ + int pgainspan, ngainspan; /* plus and negative gain span */ + int maxgain; + ListNodeType *nodes; + ListNodeType **buckets; + + /* Heap version of the data structure */ + KeyValueType *heap; + idxtype *locator; +}; + +typedef struct PQueueType PQueueType; + + +/************************************************************************* +* The following data structure stores an edge +**************************************************************************/ +struct edegreedef { + idxtype pid; + idxtype ed; +}; +typedef struct edegreedef EDegreeType; + + +/************************************************************************* +* The following data structure stores an edge for vol +**************************************************************************/ +struct vedegreedef { + idxtype pid; + idxtype ed, ned; + idxtype gv; +}; +typedef struct vedegreedef VEDegreeType; + + +/************************************************************************* +* This data structure holds various working space data +**************************************************************************/ +struct workspacedef { + idxtype *core; /* Where pairs, indices, and degrees are coming from */ + int maxcore, ccore; + + EDegreeType *edegrees; + VEDegreeType *vedegrees; + int cdegree; + + idxtype *auxcore; /* This points to the memory of the edegrees */ + + idxtype *pmat; /* An array of k^2 used for eliminating domain + connectivity in k-way refinement */ +}; + +typedef struct workspacedef WorkSpaceType; + + +/************************************************************************* +* The following data structure holds information on degrees for k-way +* partition +**************************************************************************/ +struct rinfodef { + int id, ed; /* ID/ED of nodes */ + int ndegrees; /* The number of different ext-degrees */ + EDegreeType *edegrees; /* List of edges */ +}; + +typedef struct rinfodef RInfoType; + + +/************************************************************************* +* The following data structure holds information on degrees for k-way +* vol-based partition +**************************************************************************/ +struct vrinfodef { + int id, ed, nid; /* ID/ED of nodes */ + int gv; /* IV/EV of nodes */ + int ndegrees; /* The number of different ext-degrees */ + VEDegreeType *edegrees; /* List of edges */ +}; + +typedef struct vrinfodef VRInfoType; + + +/************************************************************************* +* The following data structure holds information on degrees for k-way +* partition +**************************************************************************/ +struct nrinfodef { + idxtype edegrees[2]; +}; + +typedef struct nrinfodef NRInfoType; + + +/************************************************************************* +* This data structure holds the input graph +**************************************************************************/ +struct graphdef { + idxtype *gdata, *rdata; /* Memory pools for graph and refinement data. + This is where memory is allocated and used + the rest of the fields in this structure */ + + int nvtxs, nedges; /* The # of vertices and edges in the graph */ + idxtype *xadj; /* Pointers to the locally stored vertices */ + idxtype *vwgt; /* Vertex weights */ + idxtype *vsize; /* Vertex sizes for min-volume formulation */ + idxtype *adjncy; /* Array that stores the adjacency lists of nvtxs */ + idxtype *adjwgt; /* Array that stores the weights of the adjacency lists */ + + idxtype *adjwgtsum; /* The sum of the adjacency weight of each vertex */ + + idxtype *label; + + idxtype *cmap; + + /* Partition parameters */ + int mincut, minvol; + idxtype *where, *pwgts; + int nbnd; + idxtype *bndptr, *bndind; + + /* Bisection refinement parameters */ + idxtype *id, *ed; + + /* K-way refinement parameters */ + RInfoType *rinfo; + + /* K-way volume refinement parameters */ + VRInfoType *vrinfo; + + /* Node refinement information */ + NRInfoType *nrinfo; + + + /* Additional info needed by the MOC routines */ + int ncon; /* The # of constrains */ + float *nvwgt; /* Normalized vertex weights */ + float *npwgts; /* The normalized partition weights */ + + struct graphdef *coarser, *finer; +}; + +typedef struct graphdef GraphType; + + + +/************************************************************************* +* The following data type implements a timer +**************************************************************************/ +typedef double timer; + + +/************************************************************************* +* The following structure stores information used by Metis +**************************************************************************/ +struct controldef { + int CoarsenTo; /* The # of vertices in the coarsest graph */ + int dbglvl; /* Controls the debuging output of the program */ + int CType; /* The type of coarsening */ + int IType; /* The type of initial partitioning */ + int RType; /* The type of refinement */ + int maxvwgt; /* The maximum allowed weight for a vertex */ + float nmaxvwgt; /* The maximum allowed weight for a vertex for each constrain */ + int optype; /* Type of operation */ + int pfactor; /* .1*prunning factor */ + int nseps; /* The number of separators to be found during multiple bisections */ + int oflags; + + WorkSpaceType wspace; /* Work Space Informations */ + + /* Various Timers */ + timer TotalTmr, InitPartTmr, MatchTmr, ContractTmr, CoarsenTmr, UncoarsenTmr, + SepTmr, RefTmr, ProjectTmr, SplitTmr, AuxTmr1, AuxTmr2, AuxTmr3, AuxTmr4, AuxTmr5, AuxTmr6; + +}; + +typedef struct controldef CtrlType; + + +/************************************************************************* +* The following data structure stores max-partition weight info for +* Vertical MOC k-way refinement +**************************************************************************/ +struct vpwgtdef { + float max[2][MAXNCON]; + int imax[2][MAXNCON]; +}; + +typedef struct vpwgtdef VPInfoType; + + + + diff --git a/Metis/subdomains.c b/Metis/subdomains.c new file mode 100644 index 0000000000..ec6ef674da --- /dev/null +++ b/Metis/subdomains.c @@ -0,0 +1,1295 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * subdomains.c + * + * This file contains functions that deal with prunning the number of + * adjacent subdomains in KMETIS + * + * Started 7/15/98 + * George + * + * $Id: subdomains.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Random_KWayEdgeRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees; + int from, me, to, oldcut, vwgt, gain; + int maxndoms, nadd; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; + idxtype *phtable, *pmat, *pmatptr, *ndoms; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndptr = graph->bndptr; + bndind = graph->bndind; + + where = graph->where; + pwgts = graph->pwgts; + + pmat = ctrl->wspace.pmat; + phtable = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeSubDomainGraph(graph, nparts, pmat, ndoms); + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (nmoves=iii=0; iii<graph->nbnd; iii++) { + ii = perm[iii]; + if (ii >= nbnd) + continue; + i = bndind[ii]; + + myrinfo = graph->rinfo+i; + + if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ + from = where[i]; + vwgt = graph->vwgt[i]; + + if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + if (nadd == 0) + phtable[to] = 2; + } + + /* Find the first valid move */ + j = myrinfo->id; + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ + if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to]) + continue; + if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || + (myedegrees[j].ed == myedegrees[k].ed && + itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) + k = j; + } + + to = myedegrees[k].pid; + + j = 0; + if (myedegrees[k].ed-myrinfo->id > 0) + j = 1; + else if (myedegrees[k].ed-myrinfo->id == 0) { + if (/*(iii&7) == 0 ||*/ phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + j = 1; + } + if (j == 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + + } + nmoves++; + } + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %5d, Vol: %5d, %d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, + graph->mincut, ComputeVolume(graph, where), idxsum(nparts, ndoms))); + + if (graph->mincut == oldcut) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); +} + + + +/************************************************************************* +* This function performs k-way refinement +**************************************************************************/ +void Greedy_KWayEdgeBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) +{ + int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves; + int from, me, to, oldcut, vwgt, maxndoms, nadd; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; + idxtype *phtable, *pmat, *pmatptr, *ndoms; + EDegreeType *myedegrees; + RInfoType *myrinfo; + PQueueType queue; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + pmat = ctrl->wspace.pmat; + phtable = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + + ComputeSubDomainGraph(graph, nparts, pmat, ndoms); + + + /* Setup the weight intervals of the various subdomains */ + minwgt = idxwspacemalloc(ctrl, nparts); + maxwgt = idxwspacemalloc(ctrl, nparts); + itpwgts = idxwspacemalloc(ctrl, nparts); + tvwgt = idxsum(nparts, pwgts); + ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); + + for (i=0; i<nparts; i++) { + itpwgts[i] = tpwgts[i]*tvwgt; + maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; + minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); + } + + perm = idxwspacemalloc(ctrl, nvtxs); + moved = idxwspacemalloc(ctrl, nvtxs); + + PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, + graph->mincut)); + + for (pass=0; pass<npasses; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts; i++) { + if (pwgts[i] > maxwgt[i]) + break; + } + if (i == nparts) /* Things are balanced. Return right away */ + break; + + PQueueReset(&queue); + idxset(nvtxs, -1, moved); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + + RandomPermute(nbnd, perm, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); + moved[i] = 2; + } + + maxndoms = ndoms[idxamax(nparts, ndoms)]; + + for (nmoves=0;;) { + if ((i = PQueueGetMax(&queue)) == -1) + break; + moved[i] = 1; + + myrinfo = graph->rinfo+i; + from = where[i]; + vwgt = graph->vwgt[i]; + + if (pwgts[from]-vwgt < minwgt[from]) + continue; /* This cannot be moved! */ + + myedegrees = myrinfo->edegrees; + myndegrees = myrinfo->ndegrees; + + /* Determine the valid domains */ + for (j=0; j<myndegrees; j++) { + to = myedegrees[j].pid; + phtable[to] = 1; + pmatptr = pmat + to*nparts; + for (nadd=0, k=0; k<myndegrees; k++) { + if (k == j) + continue; + + l = myedegrees[k].pid; + if (pmatptr[l] == 0) { + if (ndoms[l] > maxndoms-1) { + phtable[to] = 0; + nadd = maxndoms; + break; + } + nadd++; + } + } + if (ndoms[to]+nadd > maxndoms) + phtable[to] = 0; + } + + for (k=0; k<myndegrees; k++) { + to = myedegrees[k].pid; + if (!phtable[to]) + continue; + if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + break; + } + if (k == myndegrees) + continue; /* break out if you did not find a candidate */ + + for (j=k+1; j<myndegrees; j++) { + to = myedegrees[j].pid; + if (!phtable[to]) + continue; + if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) + k = j; + } + + to = myedegrees[k].pid; + + if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0) + continue; + + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[to*nparts+from] == 0) { + ndoms[to]--; + if (ndoms[to]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt); + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed == 0) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + oldgain = (myrinfo->ed-myrinfo->id); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed > 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed == 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) { + ndoms[me]--; + if (ndoms[me]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + if (pmat[from*nparts+me] == 0) { + ndoms[from]--; + if (ndoms[from]+1 == maxndoms) + maxndoms = ndoms[idxamax(nparts, ndoms)]; + } + + if (pmat[me*nparts+to] == 0) { + ndoms[me]++; + if (ndoms[me] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms); + maxndoms = ndoms[me]; + } + } + if (pmat[to*nparts+me] == 0) { + ndoms[to]++; + if (ndoms[to] > maxndoms) { + printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms); + maxndoms = ndoms[to]; + } + } + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + + /* Update the queue */ + if (me == to || me == from) { + gain = myrinfo->ed-myrinfo->id; + if (moved[ii] == 2) { + if (myrinfo->ed > 0) + PQueueUpdate(&queue, ii, oldgain, gain); + else { + PQueueDelete(&queue, ii, oldgain); + moved[ii] = -1; + } + } + else if (moved[ii] == -1 && myrinfo->ed > 0) { + PQueueInsert(&queue, ii, gain); + moved[ii] = 2; + } + } + + ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); + ASSERT(CheckRInfo(myrinfo)); + } + nmoves++; + } + + graph->nbnd = nbnd; + + IFSET(ctrl->dbglvl, DBG_REFINE, + printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, %d\n", + pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], + 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,idxsum(nparts, ndoms))); + } + + PQueueFree(ctrl, &queue); + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void PrintSubDomainGraph(GraphType *graph, int nparts, idxtype *where) +{ + int i, j, k, me, nvtxs, total, max; + idxtype *xadj, *adjncy, *adjwgt, *pmat; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + pmat = idxsmalloc(nparts*nparts, 0, "ComputeSubDomainGraph: pmat"); + + for (i=0; i<nvtxs; i++) { + me = where[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] != me) + pmat[me*nparts+where[k]] += adjwgt[j]; + } + } + + /* printf("Subdomain Info\n"); */ + total = max = 0; + for (i=0; i<nparts; i++) { + for (k=0, j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + k++; + } + total += k; + + if (k > max) + max = k; +/* + printf("%2d -> %2d ", i, k); + for (j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + printf("[%2d %4d] ", j, pmat[i*nparts+j]); + } + printf("\n"); +*/ + } + printf("Total adjacent subdomains: %d, Max: %d\n", total, max); + + free(pmat); +} + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void ComputeSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms) +{ + int i, j, k, me, nvtxs, ndegrees; + idxtype *xadj, *adjncy, *adjwgt, *where; + RInfoType *rinfo; + EDegreeType *edegrees; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + where = graph->where; + rinfo = graph->rinfo; + + idxset(nparts*nparts, 0, pmat); + + for (i=0; i<nvtxs; i++) { + if (rinfo[i].ed > 0) { + me = where[i]; + ndegrees = rinfo[i].ndegrees; + edegrees = rinfo[i].edegrees; + + k = me*nparts; + for (j=0; j<ndegrees; j++) + pmat[k+edegrees[j].pid] += edegrees[j].ed; + } + } + + for (i=0; i<nparts; i++) { + ndoms[i] = 0; + for (j=0; j<nparts; j++) { + if (pmat[i*nparts+j] > 0) + ndoms[i]++; + } + } + +} + + + + + +/************************************************************************* +* This function computes the subdomain graph +**************************************************************************/ +void EliminateSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts) +{ + int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd; + int min, move, cpwgt, tvwgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind; + KeyValueType *cand, *cand2; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = graph->pwgts; /* We assume that this is properly initialized */ + + maxpwgt = idxwspacemalloc(ctrl, nparts); + ndoms = idxwspacemalloc(ctrl, nparts); + otherpmat = idxwspacemalloc(ctrl, nparts); + ind = idxwspacemalloc(ctrl, nvtxs); + pmat = ctrl->wspace.pmat; + + cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand"); + + /* Compute the pmat matrix and ndoms */ + ComputeSubDomainGraph(graph, nparts, pmat, ndoms); + + + /* Compute the maximum allowed weight for each domain */ + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = 1.25*tpwgts[i]*tvwgt; + + + /* Get into the loop eliminating subdomain connections */ + for (;;) { + total = idxsum(nparts, ndoms); + avg = total/nparts; + max = ndoms[idxamax(nparts, ndoms)]; + + /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d [%5d]\n", total, max, avg, idxsum(nparts*nparts, pmat)); */ + + if (max < 1.4*avg) + break; + + me = idxamax(nparts, ndoms); + mypmat = pmat + me*nparts; + totalout = idxsum(nparts, mypmat); + + /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/ + + /* Sort the connections according to their cut */ + for (ncand2=0, i=0; i<nparts; i++) { + if (mypmat[i] > 0) { + cand2[ncand2].key = mypmat[i]; + cand2[ncand2++].val = i; + } + } + ikeysort(ncand2, cand2); + + move = 0; + for (min=0; min<ncand2; min++) { + if (cand2[min].key > totalout/(2*ndoms[me])) + break; + + other = cand2[min].val; + + /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/ + + idxset(nparts, 0, otherpmat); + + /* Go and find the vertices in 'other' that are connected in 'me' */ + for (nind=0, i=0; i<nvtxs; i++) { + if (where[i] == other) { + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (where[adjncy[j]] == me) { + ind[nind++] = i; + break; + } + } + } + } + + /* Go and construct the otherpmat to see where these nind vertices are connected to */ + for (cpwgt=0, ii=0; ii<nind; ii++) { + i = ind[ii]; + cpwgt += vwgt[i]; + + for (j=xadj[i]; j<xadj[i+1]; j++) + otherpmat[where[adjncy[j]]] += adjwgt[j]; + } + otherpmat[other] = 0; + + for (ncand=0, i=0; i<nparts; i++) { + if (otherpmat[i] > 0) { + cand[ncand].key = -otherpmat[i]; + cand[ncand++].val = i; + } + } + ikeysort(ncand, cand); + + /* + * Go through and the select the first domain that is common with 'me', and + * does not increase the ndoms[target] higher than my ndoms, subject to the + * maxpwgt constraint. Traversal is done from the mostly connected to the least. + */ + target = target2 = -1; + for (i=0; i<ncand; i++) { + k = cand[i].val; + + if (mypmat[k] > 0) { + if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */ + continue; + + for (j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0) + break; + } + if (j == nparts) { /* No bad second level effects */ + for (nadd=0, j=0; j<nparts; j++) { + if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0) + nadd++; + } + + /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/ + if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) { + target2 = k; + } + if (nadd == 0) { + target = k; + break; + } + } + } + } + if (target == -1 && target2 != -1) + target = target2; + + if (target == -1) { + /* printf("\t\tCould not make the move\n");*/ + continue; + } + + /*printf("\t\tMoving to %d\n", target);*/ + + /* Update the partition weights */ + INC_DEC(pwgts[target], pwgts[other], cpwgt); + + MoveGroupMConn(ctrl, graph, ndoms, pmat, nparts, target, nind, ind); + + move = 1; + break; + } + + if (move == 0) + break; + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + + GKfree(&cand, &cand2, LTERM); +} + + +/************************************************************************* +* This function moves a collection of vertices and updates their rinfo +**************************************************************************/ +void MoveGroupMConn(CtrlType *ctrl, GraphType *graph, idxtype *ndoms, idxtype *pmat, + int nparts, int to, int nind, idxtype *ind) +{ + int i, ii, iii, j, jj, k, l, nvtxs, nbnd, myndegrees; + int from, me; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *bndptr, *bndind; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + nbnd = graph->nbnd; + + for (iii=0; iii<nind; iii++) { + i = ind[iii]; + from = where[i]; + + myrinfo = graph->rinfo+i; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + myrinfo->ndegrees = 0; + } + myedegrees = myrinfo->edegrees; + + /* find the location of 'to' in myrinfo or create it if it is not there */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) + break; + } + if (k == myrinfo->ndegrees) { + myedegrees[k].pid = to; + myedegrees[k].ed = 0; + myrinfo->ndegrees++; + } + + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + /* Update pmat to reflect the move of 'i' */ + pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed); + pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed); + if (pmat[from*nparts+to] == 0) + ndoms[from]--; + if (pmat[to*nparts+from] == 0) + ndoms[to]--; + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[i] != -1) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */ + if (me != from && me != to) { + pmat[me*nparts+from] -= adjwgt[j]; + pmat[from*nparts+me] -= adjwgt[j]; + if (pmat[me*nparts+from] == 0) + ndoms[me]--; + if (pmat[from*nparts+me] == 0) + ndoms[from]--; + + if (pmat[me*nparts+to] == 0) + ndoms[me]++; + if (pmat[to*nparts+me] == 0) + ndoms[to]++; + + pmat[me*nparts+to] += adjwgt[j]; + pmat[to*nparts+me] += adjwgt[j]; + } + + ASSERT(CheckRInfo(myrinfo)); + } + + ASSERT(CheckRInfo(graph->rinfo+i)); + } + + graph->nbnd = nbnd; + +} + + + + +/************************************************************************* +* This function finds all the connected components induced by the +* partitioning vector in wgraph->where and tries to push them around to +* remove some of them +**************************************************************************/ +void EliminateComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor) +{ + int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, other, target, deltawgt; + idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt; + idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + where = graph->where; + pwgts = graph->pwgts; + + touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs)); + cptr = idxwspacemalloc(ctrl, nvtxs); + cind = idxwspacemalloc(ctrl, nvtxs); + perm = idxwspacemalloc(ctrl, nvtxs); + todo = idxwspacemalloc(ctrl, nvtxs); + maxpwgt = idxwspacemalloc(ctrl, nparts); + cpvec = idxwspacemalloc(ctrl, nparts); + npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts)); + + for (i=0; i<nvtxs; i++) + perm[i] = todo[i] = i; + + /* Find the connected componends induced by the partition */ + ncmps = -1; + first = last = 0; + nleft = nvtxs; + while (nleft > 0) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; + ASSERT(touched[todo[0]] == 0); + i = todo[0]; + cind[last++] = i; + touched[i] = 1; + me = where[i]; + npcmps[me]++; + } + + i = cind[first++]; + k = perm[i]; + j = todo[k] = todo[--nleft]; + perm[j] = k; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == me && !touched[k]) { + cind[last++] = k; + touched[k] = 1; + } + } + } + cptr[++ncmps] = first; + + /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */ + + if (ncmps > nparts) { /* There are more components than processors */ + /* First determine the max allowed load imbalance */ + tvwgt = idxsum(nparts, pwgts); + for (i=0; i<nparts; i++) + maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt; + + deltawgt = 5; + + for (i=0; i<ncmps; i++) { + me = where[cind[cptr[i]]]; /* Get the domain of this component */ + if (npcmps[me] == 1) + continue; /* Skip it because it is contigous */ + + /*printf("Trying to move %d from %d\n", i, me); */ + + /* Determine the weight of the block to be moved and abort if too high */ + for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++) + cwgt += vwgt[cind[j]]; + + if (cwgt > .30*pwgts[me]) + continue; /* Skip the component if it is over 30% of the weight */ + + /* Determine the connectivity */ + idxset(nparts, 0, cpvec); + for (j=cptr[i]; j<cptr[i+1]; j++) { + ii = cind[j]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) + cpvec[where[adjncy[jj]]] += adjwgt[jj]; + } + cpvec[me] = 0; + + target = -1; + for (j=0; j<nparts; j++) { + if (cpvec[j] > 0 && (cwgt < deltawgt || pwgts[j] + cwgt < maxpwgt[j])) { + if (target == -1 || cpvec[target] < cpvec[j]) + target = j; + } + } + + /* printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/ + + if (target != -1) { + /* Assign all the vertices of 'me' to 'target' and update data structures */ + INC_DEC(pwgts[target], pwgts[me], cwgt); + npcmps[me]--; + + MoveGroup(ctrl, graph, nparts, target, i, cptr, cind); + } + } + + } + + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nparts); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + idxwspacefree(ctrl, nvtxs); + +} + + +/************************************************************************* +* This function moves a collection of vertices and updates their rinfo +**************************************************************************/ +void MoveGroup(CtrlType *ctrl, GraphType *graph, int nparts, int to, int gid, idxtype *ptr, idxtype *ind) +{ + int i, ii, iii, j, jj, k, l, nvtxs, nbnd, myndegrees; + int from, me; + idxtype *xadj, *adjncy, *adjwgt; + idxtype *where, *bndptr, *bndind; + EDegreeType *myedegrees; + RInfoType *myrinfo; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + where = graph->where; + bndptr = graph->bndptr; + bndind = graph->bndind; + + nbnd = graph->nbnd; + + for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) { + i = ind[iii]; + from = where[i]; + + myrinfo = graph->rinfo+i; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; + myrinfo->ndegrees = 0; + } + myedegrees = myrinfo->edegrees; + + /* find the location of 'to' in myrinfo or create it if it is not there */ + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) + break; + } + if (k == myrinfo->ndegrees) { + myedegrees[k].pid = to; + myedegrees[k].ed = 0; + myrinfo->ndegrees++; + } + + graph->mincut -= myedegrees[k].ed-myrinfo->id; + + + /* Update where, weight, and ID/ED information of the vertex you moved */ + where[i] = to; + myrinfo->ed += myrinfo->id-myedegrees[k].ed; + SWAP(myrinfo->id, myedegrees[k].ed, j); + if (myedegrees[k].ed == 0) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].pid = from; + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[i] != -1) + BNDDelete(nbnd, bndind, bndptr, i); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + + myrinfo = graph->rinfo+ii; + if (myrinfo->edegrees == NULL) { + myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; + ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; + } + myedegrees = myrinfo->edegrees; + + ASSERT(CheckRInfo(myrinfo)); + + if (me == from) { + INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) + BNDInsert(nbnd, bndind, bndptr, ii); + } + else if (me == to) { + INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); + + if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) + BNDDelete(nbnd, bndind, bndptr, ii); + } + + /* Remove contribution from the .ed of 'from' */ + if (me != from) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == from) { + if (myedegrees[k].ed == adjwgt[j]) + myedegrees[k] = myedegrees[--myrinfo->ndegrees]; + else + myedegrees[k].ed -= adjwgt[j]; + break; + } + } + } + + /* Add contribution to the .ed of 'to' */ + if (me != to) { + for (k=0; k<myrinfo->ndegrees; k++) { + if (myedegrees[k].pid == to) { + myedegrees[k].ed += adjwgt[j]; + break; + } + } + if (k == myrinfo->ndegrees) { + myedegrees[myrinfo->ndegrees].pid = to; + myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; + } + } + + ASSERT(CheckRInfo(myrinfo)); + } + + ASSERT(CheckRInfo(graph->rinfo+i)); + } + + graph->nbnd = nbnd; + +} + diff --git a/Metis/timing.c b/Metis/timing.c new file mode 100644 index 0000000000..5495f92732 --- /dev/null +++ b/Metis/timing.c @@ -0,0 +1,74 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * timing.c + * + * This file contains routines that deal with timing Metis + * + * Started 7/24/97 + * George + * + * $Id: timing.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + * + */ + +#include <metis.h> + + +/************************************************************************* +* This function clears the timers +**************************************************************************/ +void InitTimers(CtrlType *ctrl) +{ + cleartimer(ctrl->TotalTmr); + cleartimer(ctrl->InitPartTmr); + cleartimer(ctrl->MatchTmr); + cleartimer(ctrl->ContractTmr); + cleartimer(ctrl->CoarsenTmr); + cleartimer(ctrl->UncoarsenTmr); + cleartimer(ctrl->RefTmr); + cleartimer(ctrl->ProjectTmr); + cleartimer(ctrl->SplitTmr); + cleartimer(ctrl->SepTmr); + cleartimer(ctrl->AuxTmr1); + cleartimer(ctrl->AuxTmr2); + cleartimer(ctrl->AuxTmr3); + cleartimer(ctrl->AuxTmr4); + cleartimer(ctrl->AuxTmr5); + cleartimer(ctrl->AuxTmr6); +} + + + +/************************************************************************* +* This function prints the various timers +**************************************************************************/ +void PrintTimers(CtrlType *ctrl) +{ + printf("\nTiming Information -------------------------------------------------"); + printf("\n Multilevel: \t\t %7.3f", gettimer(ctrl->TotalTmr)); + printf("\n Coarsening: \t\t %7.3f", gettimer(ctrl->CoarsenTmr)); + printf("\n Matching: \t\t\t %7.3f", gettimer(ctrl->MatchTmr)); + printf("\n Contract: \t\t\t %7.3f", gettimer(ctrl->ContractTmr)); + printf("\n Initial Partition: \t %7.3f", gettimer(ctrl->InitPartTmr)); + printf("\n Construct Separator: \t %7.3f", gettimer(ctrl->SepTmr)); + printf("\n Uncoarsening: \t\t %7.3f", gettimer(ctrl->UncoarsenTmr)); + printf("\n Refinement: \t\t\t %7.3f", gettimer(ctrl->RefTmr)); + printf("\n Projection: \t\t\t %7.3f", gettimer(ctrl->ProjectTmr)); + printf("\n Splitting: \t\t %7.3f", gettimer(ctrl->SplitTmr)); + printf("\n AUX1: \t\t %7.3f", gettimer(ctrl->AuxTmr1)); + printf("\n AUX2: \t\t %7.3f", gettimer(ctrl->AuxTmr2)); + printf("\n AUX3: \t\t %7.3f", gettimer(ctrl->AuxTmr3)); + printf("\n********************************************************************\n"); +} + + +/************************************************************************* +* This function returns the seconds +**************************************************************************/ +double seconds(void) +{ + return((double) clock()/CLOCKS_PER_SEC); +} + + diff --git a/Metis/util.c b/Metis/util.c new file mode 100644 index 0000000000..36eef2f938 --- /dev/null +++ b/Metis/util.c @@ -0,0 +1,519 @@ +/* + * Copyright 1997, Regents of the University of Minnesota + * + * util.c + * + * This function contains various utility routines + * + * Started 9/28/95 + * George + * + * $Id: util.c,v 1.1 2005-09-07 14:36:46 remacle Exp $ + */ + +#include <metis.h> + + +/************************************************************************* +* This function prints an error message and exits +**************************************************************************/ +void errexit(char *f_str,...) +{ + va_list argp; + char out1[256], out2[256]; + + va_start(argp, f_str); + vsprintf(out1, f_str, argp); + va_end(argp); + + sprintf(out2, "Error! %s", out1); + + fprintf(stdout, out2); + fflush(stdout); + + abort(); +} + + + +#ifndef DMALLOC +/************************************************************************* +* The following function allocates an array of integers +**************************************************************************/ +int *imalloc(int n, char *msg) +{ + if (n == 0) + return NULL; + + return (int *)GKmalloc(sizeof(int)*n, msg); +} + + +/************************************************************************* +* The following function allocates an array of integers +**************************************************************************/ +idxtype *idxmalloc(int n, char *msg) +{ + if (n == 0) + return NULL; + + return (idxtype *)GKmalloc(sizeof(idxtype)*n, msg); +} + + +/************************************************************************* +* The following function allocates an array of float +**************************************************************************/ +float *fmalloc(int n, char *msg) +{ + if (n == 0) + return NULL; + + return (float *)GKmalloc(sizeof(float)*n, msg); +} + + +/************************************************************************* +* The follwoing function allocates an array of integers +**************************************************************************/ +int *ismalloc(int n, int ival, char *msg) +{ + if (n == 0) + return NULL; + + return iset(n, ival, (int *)GKmalloc(sizeof(int)*n, msg)); +} + + + +/************************************************************************* +* The follwoing function allocates an array of integers +**************************************************************************/ +idxtype *idxsmalloc(int n, idxtype ival, char *msg) +{ + if (n == 0) + return NULL; + + return idxset(n, ival, (idxtype *)GKmalloc(sizeof(idxtype)*n, msg)); +} + + +/************************************************************************* +* This function is my wrapper around malloc +**************************************************************************/ +void *GKmalloc(int nbytes, char *msg) +{ + void *ptr; + + if (nbytes == 0) + return NULL; + + ptr = (void *)malloc(nbytes); + if (ptr == NULL) + errexit("***Memory allocation failed for %s. Requested size: %d bytes", msg, nbytes); + + return ptr; +} +#endif + +/************************************************************************* +* This function is my wrapper around free, allows multiple pointers +**************************************************************************/ +void GKfree(void **ptr1,...) +{ + va_list plist; + void **ptr; + + if (*ptr1 != NULL) + free(*ptr1); + *ptr1 = NULL; + + va_start(plist, ptr1); + + /* while ((int)(ptr = va_arg(plist, void **)) != -1) { */ + while ((ptr = va_arg(plist, void **)) != LTERM) { + if (*ptr != NULL) + free(*ptr); + *ptr = NULL; + } + + va_end(plist); +} + + +/************************************************************************* +* These functions set the values of a vector +**************************************************************************/ +int *iset(int n, int val, int *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] = val; + + return x; +} + + +/************************************************************************* +* These functions set the values of a vector +**************************************************************************/ +idxtype *idxset(int n, idxtype val, idxtype *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] = val; + + return x; +} + + +/************************************************************************* +* These functions set the values of a vector +**************************************************************************/ +float *sset(int n, float val, float *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] = val; + + return x; +} + + + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int iamax(int n, int *x) +{ + int i, max=0; + + for (i=1; i<n; i++) + max = (x[i] > x[max] ? i : max); + + return max; +} + + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int idxamax(int n, idxtype *x) +{ + int i, max=0; + + for (i=1; i<n; i++) + max = (x[i] > x[max] ? i : max); + + return max; +} + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int idxamax_strd(int n, idxtype *x, int incx) +{ + int i, max=0; + + n *= incx; + for (i=incx; i<n; i+=incx) + max = (x[i] > x[max] ? i : max); + + return max/incx; +} + + + +/************************************************************************* +* These functions return the index of the maximum element in a vector +**************************************************************************/ +int samax(int n, float *x) +{ + int i, max=0; + + for (i=1; i<n; i++) + max = (x[i] > x[max] ? i : max); + + return max; +} + +/************************************************************************* +* These functions return the index of the almost maximum element in a vector +**************************************************************************/ +int samax2(int n, float *x) +{ + int i, max1, max2; + + if (x[0] > x[1]) { + max1 = 0; + max2 = 1; + } + else { + max1 = 1; + max2 = 0; + } + + for (i=2; i<n; i++) { + if (x[i] > x[max1]) { + max2 = max1; + max1 = i; + } + else if (x[i] > x[max2]) + max2 = i; + } + + return max2; +} + + +/************************************************************************* +* These functions return the index of the minimum element in a vector +**************************************************************************/ +int idxamin(int n, idxtype *x) +{ + int i, min=0; + + for (i=1; i<n; i++) + min = (x[i] < x[min] ? i : min); + + return min; +} + + +/************************************************************************* +* These functions return the index of the minimum element in a vector +**************************************************************************/ +int samin(int n, float *x) +{ + int i, min=0; + + for (i=1; i<n; i++) + min = (x[i] < x[min] ? i : min); + + return min; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int idxsum(int n, idxtype *x) +{ + int i, sum = 0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int idxsum_strd(int n, idxtype *x, int incx) +{ + int i, sum = 0; + + for (i=0; i<n; i++, x+=incx) { + sum += *x; + } + + return sum; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +void idxadd(int n, idxtype *x, idxtype *y) +{ + for (n--; n>=0; n--) + y[n] += x[n]; +} + + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int charsum(int n, char *x) +{ + int i, sum = 0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +int isum(int n, int *x) +{ + int i, sum = 0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +float ssum(int n, float *x) +{ + int i; + float sum = 0.0; + + for (i=0; i<n; i++) + sum += x[i]; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +float ssum_strd(int n, float *x, int incx) +{ + int i; + float sum = 0.0; + + for (i=0; i<n; i++, x+=incx) + sum += *x; + + return sum; +} + +/************************************************************************* +* This function sums the entries in an array +**************************************************************************/ +void sscale(int n, float alpha, float *x) +{ + int i; + + for (i=0; i<n; i++) + x[i] *= alpha; +} + + +/************************************************************************* +* This function computes a 2-norm +**************************************************************************/ +float snorm2(int n, float *v) +{ + int i; + float partial = 0; + + for (i = 0; i<n; i++) + partial += v[i] * v[i]; + + return sqrt(partial); +} + + + +/************************************************************************* +* This function computes a 2-norm +**************************************************************************/ +float sdot(int n, float *x, float *y) +{ + int i; + float partial = 0; + + for (i = 0; i<n; i++) + partial += x[i] * y[i]; + + return partial; +} + + +/************************************************************************* +* This function computes a 2-norm +**************************************************************************/ +void saxpy(int n, float alpha, float *x, int incx, float *y, int incy) +{ + int i; + + for (i=0; i<n; i++, x+=incx, y+=incy) + *y += alpha*(*x); +} + + + + +/************************************************************************* +* This file randomly permutes the contents of an array. +* flag == 0, don't initialize perm +* flag == 1, set p[i] = i +**************************************************************************/ +void RandomPermute(int n, idxtype *p, int flag) +{ + int i, u, v; + idxtype tmp; + + if (flag == 1) { + for (i=0; i<n; i++) + p[i] = i; + } + + if (n <= 4) + return; + + for (i=0; i<n; i+=16) { + u = RandomInRangeFast(n-4); + v = RandomInRangeFast(n-4); + SWAP(p[v], p[u], tmp); + SWAP(p[v+1], p[u+1], tmp); + SWAP(p[v+2], p[u+2], tmp); + SWAP(p[v+3], p[u+3], tmp); + } +} + + + +/************************************************************************* +* This function returns true if the a is a power of 2 +**************************************************************************/ +int ispow2(int a) +{ + for (; a%2 != 1; a = a>>1); + return (a > 1 ? 0 : 1); +} + + +/************************************************************************* +* This function initializes the random number generator +**************************************************************************/ +void InitRandom(int seed) +{ + if (seed == -1) { +#ifndef __VC__ + srand48(7654321L); +#endif + srand(4321); + } + else { +#ifndef __VC__ + srand48(seed); +#endif + srand(seed); + } +} + +/************************************************************************* +* This function returns the log2(x) +**************************************************************************/ +int log2(int a) +{ + int i; + + for (i=1; a > 1; i++, a = a>>1); + return i-1; +} + diff --git a/Parser/OpenFile.cpp b/Parser/OpenFile.cpp index e1915ab7e6..24a7cd0f4c 100644 --- a/Parser/OpenFile.cpp +++ b/Parser/OpenFile.cpp @@ -1,4 +1,4 @@ -// $Id: OpenFile.cpp,v 1.81 2005-07-04 15:07:41 remacle Exp $ +// $Id: OpenFile.cpp,v 1.82 2005-09-07 14:36:46 remacle Exp $ // // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle // @@ -50,6 +50,7 @@ extern Mesh *THEM, M; extern Context_T CTX; extern void BDS_To_Mesh(Mesh *m); +extern void BDS_To_Mesh_2(Mesh *m); void FixRelativePath(char *in, char *out){ if(in[0] == '/' || in[0] == '\\' || (strlen(in)>2 && in[1] == ':')){ diff --git a/configure b/configure index 872d69f195..c63e65b069 100755 --- a/configure +++ b/configure @@ -855,6 +855,7 @@ Optional Features: --enable-triangle compile Triangle if available (default=yes) --enable-netgen compile Netgen if available (default=yes) --enable-ann compile ANN if available (default=yes) + --enable-metis compile METIS if available (default=yes) --enable-tetgen compile Tetgen if available (default=yes) --enable-matheval compile MathEval if available (default=yes) --enable-jpeg enable JPEG support (default=yes) @@ -1388,6 +1389,11 @@ fi; if test "${enable_ann+set}" = set; then enableval="$enable_ann" +fi; +# Check whether --enable-metis or --disable-metis was given. +if test "${enable_metis+set}" = set; then + enableval="$enable_metis" + fi; # Check whether --enable-tetgen or --disable-tetgen was given. if test "${enable_tetgen+set}" = set; then @@ -3839,6 +3845,54 @@ else fi fi +echo "$as_me:$LINENO: checking for ./Metis/metis.h" >&5 +echo $ECHO_N "checking for ./Metis/metis.h... $ECHO_C" >&6 +if test "${ac_cv_file___Metis_metis_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + test "$cross_compiling" = yes && + { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 +echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} + { (exit 1); exit 1; }; } +if test -r "./Metis/metis.h"; then + ac_cv_file___Metis_metis_h=yes +else + ac_cv_file___Metis_metis_h=no +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_file___Metis_metis_h" >&5 +echo "${ECHO_T}$ac_cv_file___Metis_metis_h" >&6 +if test $ac_cv_file___Metis_metis_h = yes; then + METIS="yes" +else + METIS="no" +fi + +if test "x${METIS}" = "xyes"; then + if test "x$enable_metis" != "xno"; then + GMSH_DIRS="${GMSH_DIRS} Metis" + GMSH_LIBS="${GMSH_LIBS} -lGmshMetis" + FLAGS="-DHAVE_METIS ${FLAGS}" + echo "********************************************************************" + echo "You are building a version of Gmsh that contains METIS, the" + echo "Serial Graph Partitioner." + echo "Please note that by doing so, you agree with METIS's licensing" + echo "requirements stated in ./Metis/Doc/manual.ps." + echo "To disable METIS, run configure again with the --disable-metis" + echo "option." + echo "********************************************************************" + fi +else + if test "x$enable-metis" != "xno"; then + echo "********************************************************************" + echo "If you want to use METIS for doing mesh partitioning, please download METIS from the" + echo "author's web site at http://www-users.cs.umn.edu/~karypis/metis/" + echo "unpack the archive and copy the Lib Directory in the" + echo "./Metis subdirectory. Then run ./configure again." + echo "********************************************************************" + fi +fi + echo "$as_me:$LINENO: checking for ./Netgen/libsrc/meshing/meshclass.cpp" >&5 echo $ECHO_N "checking for ./Netgen/libsrc/meshing/meshclass.cpp... $ECHO_C" >&6 if test "${ac_cv_file___Netgen_libsrc_meshing_meshclass_cpp+set}" = set; then diff --git a/configure.in b/configure.in index fd75e21f05..d4da309bf3 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl $Id: configure.in,v 1.77 2005-08-31 22:03:26 geuzaine Exp $ +dnl $Id: configure.in,v 1.78 2005-09-07 14:36:44 remacle Exp $ dnl dnl Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle dnl @@ -72,6 +72,9 @@ AC_ARG_ENABLE(netgen, AC_ARG_ENABLE(ann, AC_HELP_STRING([--enable-ann], [compile ANN if available (default=yes)])) +AC_ARG_ENABLE(metis, + AC_HELP_STRING([--enable-metis], + [compile METIS if available (default=yes)])) AC_ARG_ENABLE(tetgen, AC_HELP_STRING([--enable-tetgen], [compile Tetgen if available (default=yes)])) @@ -283,6 +286,33 @@ else fi fi +dnl Check if METIS is installed +AC_CHECK_FILE(./Metis/metis.h, METIS="yes", METIS="no") +if test "x${METIS}" = "xyes"; then + if test "x$enable_metis" != "xno"; then + GMSH_DIRS="${GMSH_DIRS} Metis" + GMSH_LIBS="${GMSH_LIBS} -lGmshMetis" + FLAGS="-DHAVE_METIS ${FLAGS}" + echo "********************************************************************" + echo "You are building a version of Gmsh that contains METIS, the" + echo "Serial Graph Partitioner." + echo "Please note that by doing so, you agree with METIS's licensing" + echo "requirements stated in ./Metis/Doc/manual.ps." + echo "To disable METIS, run configure again with the --disable-metis" + echo "option." + echo "********************************************************************" + fi +else + if test "x$enable-metis" != "xno"; then + echo "********************************************************************" + echo "If you want to use METIS for doing mesh partitioning, please download METIS from the" + echo "author's web site at http://www-users.cs.umn.edu/~karypis/metis/" + echo "unpack the archive and copy the Lib Directory in the" + echo "./Metis subdirectory. Then run ./configure again." + echo "********************************************************************" + fi +fi + dnl Check if Netgen is installed AC_CHECK_FILE(./Netgen/libsrc/meshing/meshclass.cpp, NETGEN="yes", NETGEN="no") if test "x${NETGEN}" = "xyes"; then -- GitLab