Date: 2013-07-02T14:47:11+00:00

Actual source code: lowstretch.cpp
petsc-3.4.2 2013-07-02

      1: #define PETSCKSP_DLL

      3: #include <math.h>
      4: #include <queue>
      5: #include <petsc-private/pcimpl.h>   /*I "petscpc.h" I*/
      6: #include <boost/graph/adjacency_list.hpp>
      7: #include <boost/graph/subgraph.hpp>

      9: using namespace boost;

     11: /*
     12:   Boost Graph type definitions
     13: */

     15: enum edge_length_t { edge_length };
     16: enum edge_keep_t { edge_keep };
     17: enum vertex_parent_t { vertex_parent };
     18: enum vertex_children_t { vertex_children };
     19: enum vertex_depth_t { vertex_depth };
     20: namespace boost {
     21:   BOOST_INSTALL_PROPERTY(edge, length);
     22:   BOOST_INSTALL_PROPERTY(edge, keep);
     23:   BOOST_INSTALL_PROPERTY(vertex, parent);
     24:   BOOST_INSTALL_PROPERTY(vertex, children);
     25:   BOOST_INSTALL_PROPERTY(vertex, depth);
     26: }

     29: typedef property<vertex_parent_t, PetscInt,
     30:                  property<vertex_children_t, std::vector<PetscInt>,
     31:                           property<vertex_depth_t, PetscScalar,
     32:                                    property<vertex_index_t, PetscInt> > > > VertexProperty;
     33: typedef property<edge_length_t, PetscScalar,
     34:                  property<edge_keep_t, PetscBool,
     35:                           property<edge_index_t, PetscInt> > >  EdgeProperty2;
     36: typedef property<edge_weight_t, PetscScalar, EdgeProperty2> EdgeProperty;
     37: // I wish I knew a better way to make a convenient edge property constructor
     38: #define EDGE_PROPERTY(WEIGHT,LENGTH,KEEP) EdgeProperty(WEIGHT,EdgeProperty2(LENGTH,KEEP))

     40: typedef subgraph<adjacency_list<vecS, vecS, undirectedS, VertexProperty, EdgeProperty> > Graph;
     41: typedef graph_traits<Graph>::edge_descriptor Edge;

     43: typedef property_map<Graph, edge_weight_t>::type EdgeWeight;
     44: typedef property_map<Graph, edge_length_t>::type EdgeLength;
     45: typedef property_map<Graph, edge_keep_t>::type EdgeKeep;
     46: typedef property_map<Graph, edge_index_t>::type EdgeIndex;
     47: typedef property_map<Graph, vertex_parent_t>::type VertexParent;
     48: typedef property_map<Graph, vertex_children_t>::type VertexChildren;
     49: typedef property_map<Graph, vertex_depth_t>::type VertexDepth;

     51: typedef std::pair<PetscInt,PetscInt> PetscIntPair;
     52: struct Component {
     53:   //  static PetscInt next_id;
     54:   //static PetscInt max_id;

     56:   //PetscInt id;
     57:   std::vector<PetscInt> vertices; /* ordered s.t. root is first; parent precedes child */
     58:   /*
     59:   Component() {
     60:     id = next_id++;
     61:   }
     62:   */

     64: };
     65: struct ComponentPair {
     66:   Component *first;
     67:   Component *second;
     68:   std::vector<Edge> edges; // pointing from first to second
     69:   std::vector<std::pair<PetscScalar,PetscScalar> > lengthBelow;
     70:   std::pair<PetscScalar,PetscScalar> rootLengthBelow;
     71:   std::pair<PetscScalar,PetscScalar> rootCongestion;

     73:   ComponentPair() {
     74:     first = NULL;
     75:     second = NULL;
     76:   }

     78:   int getIndex(Component *c) {
     79:     if (first == c)
     80:       return 0;
     81:     else if (second == c)
     82:       return 1;
     83:     else
     84:       return -1;
     85:   }

     87:   Component* get(int i) {
     88:     return (i==0)?first:second;
     89:   }

     91:   void put(int i,Component *c) {
     92:     if (i==0)
     93:       first=c;
     94:     else
     95:       second=c;
     96:   }

     98:   bool match(Component *c1, Component *c2) {
     99:     return (first == c1 && second == c2) || (first == c2 && second == c1);
    100:   }
    101: };

    103: /* ShortestPathPriorityQueue is a priority queue in which each node (PQNode)
    104:    represents a potential shortest path to a vertex.  Each node stores
    105:    the terminal vertex, the distance along the path, and (optionally)
    106:    the vertex (pred) adjacent to the terminal vertex.
    107:    The top node of the queue is the shortest path in the queue.
    108: */

    110: struct PQNode {
    111:   PetscInt vertex;
    112:   PetscInt pred;
    113:   PetscReal dist;

    115:   PQNode() {}

    117:   PQNode(const PetscInt v,const PetscReal d) {
    118:     vertex = v;
    119:     dist = d;
    120:   }

    122:   PQNode(const PetscInt v,const PetscInt p,const PetscReal d) {
    123:     vertex = v;
    124:     pred = p;
    125:     dist = d;
    126:   }

    128:   bool operator<( const PQNode &a ) const {
    129:     return dist > a.dist;
    130:   }
    131: };
    132: typedef std::priority_queue<PQNode> ShortestPathPriorityQueue;

    134: /*
    135:   Function headers
    136: */
    137: PetscErrorCode LowStretchSpanningTree(Mat mat,Mat *pre,
    138:                                       PetscReal tol,PetscReal& maxCong);
    139: PetscErrorCode AugmentedLowStretchSpanningTree(Mat mat,Mat *pre,PetscBool augment,
    140:                                                PetscReal tol,PetscReal& maxCong);
    141: PetscErrorCode LowStretchSpanningTreeHelper(Graph& g,const PetscInt root,const PetscScalar alpha,PetscInt perm[]);
    142: PetscErrorCode StarDecomp(const Graph g,const PetscInt root,const PetscScalar delta,const PetscScalar epsilon,
    143:                           PetscInt& k,std::vector<PetscInt>& size,std::vector<std::vector<PetscInt> >& idx,
    144:                           std::vector<PetscInt>& x,std::vector<PetscInt>& y);
    145: PetscErrorCode AugmentSpanningTree(Graph& g,const PetscInt root,PetscScalar& maxCong);
    146: PetscErrorCode DecomposeSpanningTree(Graph& g,const PetscInt root,
    147:                                      const PetscScalar maxInternalStretch,
    148:                                      const PetscScalar maxExternalWeight,
    149:                                      std::vector<Component*>& componentList,
    150:                                      std::vector<ComponentPair>& edgeComponentMap);
    151: PetscErrorCode DecomposeSubTree(Graph& g,const PetscInt root,
    152:                                 const PetscScalar maxInternalStretch,
    153:                                 const PetscScalar maxExternalWeight,
    154:                                 std::vector<Component*>& componentList,
    155:                                 std::vector<ComponentPair>& edgeComponentMap,
    156:                                 Component*& currComponent,
    157:                                 PetscScalar& currInternalStretch,
    158:                                 PetscScalar& currExternalWeight);
    159: PetscErrorCode AddBridges(Graph& g,
    160:                           std::vector<Component*>& componentList,
    161:                           std::vector<ComponentPair>& edgeComponentMap,
    162:                           PetscScalar& maxCong);

    165: /* -------------------------------------------------------------------------- */
    166: /*
    167:    LowStretchSpanningTree - Applies EEST algorithm to construct
    168:                             low-stretch spanning tree preconditioner
    169:

    171:    Input Parameters:
    172: .  mat - input matrix

    174:    Output Parameter:
    175: .  pre - preconditioner matrix with cholesky factorization precomputed in place
    176:  */
    179: PetscErrorCode LowStretchSpanningTree(Mat mat,Mat *prefact,
    180:                                       PetscReal tol,PetscReal& maxCong)
    181: {
    182:   PetscErrorCode    ierr;

    186:   AugmentedLowStretchSpanningTree(mat,prefact,PETSC_FALSE,tol,maxCong);

    188:   return(0);
    189: }
    190: /* -------------------------------------------------------------------------- */
    191: /*
    192:    AugmentedLowStretchSpanningTree - Applies EEST algorithm to construct
    193:                                      low-stretch spanning tree preconditioner;
    194:                                      then augments tree with additional edges
    195:

    197:    Input Parameters:
    198: .  mat - input matrix
    199: .  augment - augmenting options

    201:    Output Parameter:
    202: .  pre - preconditioner matrix with cholesky factorization precomputed in place
    203:  */
    206: PetscErrorCode AugmentedLowStretchSpanningTree(Mat mat,Mat *prefact,PetscBool augment,
    207:                                                PetscReal tol,PetscReal& maxCong)
    208: {
    209: #ifndef PETSC_USE_COMPLEX
    210:   PetscInt          *idx;
    211:   PetscInt          start,end,ncols,i,j,k;
    212:   MatFactorInfo     info;
    213:   // IS                perm, iperm;
    214:   const PetscInt    *cols_c;
    215:   const PetscScalar *vals_c;
    216:   PetscInt          *rows, *cols, *dnz, *onz;
    217:   PetscScalar       *vals, *diag, absval;
    218:   Mat               *pre;
    219:   graph_traits<Graph>::out_edge_iterator e, e_end;
    220:   const PetscInt    root = 0;
    221: #endif
    222:   PetscInt          n;
    223:   PetscErrorCode    ierr;

    226:   MatGetSize(mat,NULL,&n);

    228:   Graph g(n);

    230:   EdgeKeep edge_keep_g = get(edge_keep_t(),g);

    232: #ifdef PETSC_USE_COMPLEX
    233:   SETERRQ(((PetscObject) mat)->comm, PETSC_ERR_SUP, "Complex numbers not supported for support graph PC");
    234: #else
    235:   PetscMalloc3(n,PetscScalar,&diag,n,PetscInt,&dnz,n,PetscInt,&onz);
    236:   PetscMemzero(dnz, n * sizeof(PetscInt));
    237:   PetscMemzero(onz, n * sizeof(PetscInt));
    238:   MatGetOwnershipRange(mat, &start, &end);
    239:   for (i=0; i<n; i++) {
    240:     MatGetRow(mat,i,&ncols,&cols_c,&vals_c);
    241:     diag[i] = 0;
    242:     for (k=0; k<ncols; k++) {
    243:       if (cols_c[k] == i) {
    244:         diag[i] += vals_c[k];
    245:       } else if (vals_c[k] != 0) {
    246:         absval = vals_c[k]>0?vals_c[k]:-vals_c[k];
    247:         diag[i] -= absval;
    248:         if (cols_c[k] > i && absval > tol) {
    249:           // we set edge_weight = absval; edge_length = 1.0/absval; edge_keep = PETSC_FALSE
    250:           add_edge(i,cols_c[k],EDGE_PROPERTY(absval,1.0/absval,PETSC_FALSE),g);
    251:         }
    252:       }
    253:     }
    254:     MatRestoreRow(mat,i,&ncols,&cols_c,&vals_c);
    255:   }

    257:   PetscMalloc(n*sizeof(PetscInt),&idx);
    258:   put(get(vertex_depth_t(),g),root,0);
    259:   LowStretchSpanningTreeHelper(g,root,log(4.0/3.0)/(2.0*log((double)n)),idx);

    261:   if (augment) {
    262:     AugmentSpanningTree(g,root,maxCong);
    263:   }

    265:   pre = prefact;
    266:   MatCreate(PETSC_COMM_WORLD,pre);
    267:   MatSetSizes(*pre,PETSC_DECIDE,PETSC_DECIDE,n,n);
    268:   MatSetType(*pre,MATAIJ);

    270:   PetscMalloc3(1,PetscInt,&rows,n,PetscInt,&cols,n,PetscScalar,&vals);
    271:   for (i=0; i<n; i++) {
    272:     for (tie(e, e_end) = out_edges(i,g); e != e_end; e++) {
    273:       if (get(edge_keep_g,*e)) {
    274:         const PetscInt col =  target(*e,g);

    276:         if (col >= start && col < end) {
    277:           dnz[i]++;
    278:         } else {
    279:           onz[i]++;
    280:         }
    281:       }
    282:     }
    283:   }
    284:   MatSeqAIJSetPreallocation(*pre, 0, dnz);
    285:   MatMPIAIJSetPreallocation(*pre, 0, dnz, 0, onz);
    286:   for (i=0; i<n; i++) {
    287:     rows[0] = i;
    288:     k = 0;
    289:     for (tie(e, e_end) = out_edges(i,g); e != e_end; e++) {
    290:       if (get(edge_keep_g,*e)) {
    291:         cols[k++] = target(*e,g);
    292:       }
    293:     }
    294:     MatGetValues(mat,1,rows,k,cols,vals);
    295:     for (j=0; j<k; j++) {
    296:       absval = vals[j]>0?vals[j]:-vals[j];
    297:       diag[i] += absval;
    298:     }
    299:     cols[k] = i;
    300:     vals[k] = diag[i];
    301:     MatSetValues(*pre,1,rows,k+1,cols,vals,INSERT_VALUES);
    302:   }
    303:   PetscFree3(rows,cols,vals);
    304:   PetscFree3(diag,dnz,onz);

    306:   MatAssemblyBegin(*pre,MAT_FINAL_ASSEMBLY);
    307:   MatAssemblyEnd(*pre,MAT_FINAL_ASSEMBLY);

    309:   /*
    310:     ISCreateGeneral(PETSC_COMM_WORLD,n,idx,&perm);
    311:     ISSetPermutation(perm);
    312:     ISInvertPermutation(perm,PETSC_DECIDE,&iperm);
    313:     PetscFree(idx);
    314:     ISView(perm,PETSC_VIEWER_STDOUT_SELF);
    315:   */
    316:   IS rperm, cperm;
    317:   MatGetOrdering(*pre,MATORDERINGQMD,&rperm,&cperm);

    319:   MatFactorInfoInitialize(&info);
    320:   /*
    321:   MatCholeskyFactorSymbolic(*pre,iperm,&info,prefact);
    322:   MatCholeskyFactorNumeric(*pre,&info,prefact);
    323:   MatDestroy(*pre);
    324:   ISDestroy(perm);
    325:   ISDestroy(iperm);
    326:   */
    327:   MatLUFactor(*pre,rperm,cperm,&info);
    328:   ISDestroy(&rperm);
    329:   ISDestroy(&cperm);
    330: #endif
    331:   return(0);
    332: }

    334: /* -------------------------------------------------------------------------- */
    335: /*
    336:    LowStretchSpanningTreeHelper

    338:    Input Parameters:
    339: .  g - input graph; all edges have edge_keep = PETSC_FALSE;
    340:                     root has vertex_depth set to distance from global root
    341: .  root - root vertex
    342: .  alpha - parameter
    343: .  perm - preallocated array of size num_vertices(g) in which to store vertex ordering

    345:    Output Parameter:
    346: .  g - edges in low-stretch spanning tree are marked with edge_keep = PETSC_TRUE;
    347:        also vertex_parent and vertex_children are set (vertex_parent of global root is undefined)
    348:        and vertex_depth is set to be distance from global root (where weight on edge is inverse distance)
    349: .  perm - list of vertices in which a vertex precedes its parent (with vertices referred to by global index)
    350:  */
    353: PetscErrorCode LowStretchSpanningTreeHelper(Graph& g,const PetscInt root,const PetscScalar alpha,PetscInt perm[])
    354: {
    355:   PetscInt n,i,j,k;
    356:   std::vector<PetscInt> size,x,y;
    357:   std::vector<std::vector<PetscInt> > idx;

    362:   EdgeLength edge_length_g = get(edge_length_t(),g);
    363:   EdgeKeep edge_keep_g = get(edge_keep_t(),g);
    364:   VertexParent vertex_parent_g = get(vertex_parent_t(),g);
    365:   VertexChildren vertex_children_g = get(vertex_children_t(),g);
    366:   VertexDepth vertex_depth_g = get(vertex_depth_t(),g);
    367:   n = num_vertices(g);

    369:   if (n > 2) {
    370:     StarDecomp(g,root,1.0/3,alpha,k,size,idx,x,y);
    371:     j = n - size[0];
    372:     Graph& g1 = g.create_subgraph(idx[0].begin(),idx[0].end());
    373:     LowStretchSpanningTreeHelper(g1,g1.global_to_local(g.local_to_global(root)),alpha,perm+j);
    374:     for (i=1;i<=k;i++) {
    375:       Edge e = edge(x[i-1],y[i-1],g).first;
    376:       put(edge_keep_g,e,PETSC_TRUE);
    377:       put(vertex_parent_g,x[i-1],g.local_to_global(y[i-1]));
    378:       get(vertex_children_g,y[i-1]).push_back(g.local_to_global(x[i-1]));
    379:       put(vertex_depth_g,x[i-1],get(vertex_depth_g,y[i-1])+get(edge_length_g,e));

    381:       j -= size[i];
    382:       Graph& g1 = g.create_subgraph(idx[i].begin(),idx[i].end());
    383:       LowStretchSpanningTreeHelper(g1,g1.global_to_local(g.local_to_global(x[i-1])),alpha,perm+j);
    384:     }
    385:   } else if (n == 2) {
    386:     Edge e = *(out_edges(root,g).first);
    387:     PetscInt t = target(e,g);

    389:     put(edge_keep_g,e,PETSC_TRUE);
    390:     put(vertex_parent_g,t,g.local_to_global(root));
    391:     get(vertex_children_g,root).push_back(g.local_to_global(t));
    392:     put(vertex_depth_g,t,get(vertex_depth_g,root)+get(edge_length_g,e));

    394:     perm[0] = g.local_to_global(t);
    395:     perm[1] = g.local_to_global(root);
    396:   } else /* n == 1 */ {
    397:     perm[0] = g.local_to_global(root);
    398:   }

    400:   return(0);
    401: }

    405: /* -------------------------------------------------------------------------- */
    406: /*
    407:    StarDecomp - calculate a star decomposition of the graph

    409:    Input Parameters:
    410: .  g - input graph
    411: .  root - center of star decomposition
    412: .  delta, epsilon - parameters of star decomposition

    414:    Output Parameter:
    415: .  k - number of partitions, not-including central one.
    416: .  size[i] - number of vertices in partition i
    417: .  idx[i] - list of vertices in partition i; partition 0 contains root
    418: .  x[i-1] - "anchor" vertex of non-central partition i
    419: .  y[i-i] - vertex in partition 0 forming "bridge" with x[i-1]
    420:  */
    423: PetscErrorCode StarDecomp(Graph g,const PetscInt root,const PetscScalar delta,const PetscScalar epsilon,
    424:                           PetscInt& k,std::vector<PetscInt>& size,std::vector<std::vector<PetscInt> >& idx,
    425:                           std::vector<PetscInt>& x,std::vector<PetscInt>& y)
    426: {
    427: #ifndef PETSC_USE_COMPLEX
    428:   PetscInt n,m,edgesLeft;
    430:   ShortestPathPriorityQueue pq;
    431:   PetscScalar radius = 0;
    432:   PetscInt centerSize;
    433:   std::vector<PetscInt> centerIdx;
    434:   PQNode node;
    435: #endif

    438: #ifdef PETSC_USE_COMPLEX
    439:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Complex numbers not supported for support graph PC");
    440: #else
    441:   EdgeWeight edge_weight_g = get(edge_weight_t(),g);
    442:   EdgeLength edge_length_g = get(edge_length_t(),g);
    443:   n = num_vertices(g);
    444:   m = num_edges(g);
    445:   edgesLeft = m;

    447:   std::vector<PetscInt> pred(n,-1);
    448:   std::vector<PetscInt> *succ = new std::vector<PetscInt>[n];
    449:   std::vector<PetscInt>::iterator i;
    450:   PetscScalar *dist = new PetscScalar[n];
    451:   std::vector<PetscBool> taken(n,PETSC_FALSE);

    453:   /** form tree of shortest paths to root **/
    454:   graph_traits<Graph>::out_edge_iterator e, e_end;
    455:   for (tie(e,e_end)=out_edges(root,g); e!=e_end; e++) {
    456:     PetscInt t = target(*e,g);
    457:     pq.push(PQNode(t,root,get(edge_length_g,*e)));
    458:   }
    459:   pred[root] = root;
    460:   while (!pq.empty()) {
    461:     node = pq.top();pq.pop();
    462:     if (pred[node.vertex] == -1) {
    463:       succ[node.pred].push_back(node.vertex);
    464:       pred[node.vertex] = node.pred;
    465:       dist[node.vertex] = node.dist;
    466:       for (tie(e,e_end)=out_edges(node.vertex,g); e!=e_end; e++) {
    467:         PetscInt t = target(*e,g);
    468:         if (pred[t] == -1) {
    469:           pq.push(PQNode(t,node.vertex,node.dist+get(edge_length_g,*e)));
    470:         }
    471:       }
    472:       radius = node.dist;
    473:     }
    474:   }

    476:   /** BALL CUT **/
    477:   for (i=succ[root].begin();i!=succ[root].end();i++) {
    478:     pq.push(PQNode(*i,dist[*i]));
    479:   }
    480:   PetscScalar boundary = 0;
    481:   PetscInt edgeCount = 0;
    482:   centerIdx.push_back(g.local_to_global(root));
    483:   taken[root] = PETSC_TRUE;
    484:   centerSize = 1;
    485:   for (tie(e,e_end)=out_edges(root,g); e!=e_end; e++) {
    486:     boundary += get(edge_weight_g,*e);
    487:     edgeCount++;
    488:   }
    489:   const PetscScalar minRadius = delta*radius;
    490:   while (dist[pq.top().vertex] < minRadius) {
    491:     assert(!pq.empty());
    492:     node = pq.top();pq.pop();
    493:     centerIdx.push_back(g.local_to_global(node.vertex));
    494:     taken[node.vertex] = PETSC_TRUE;
    495:     centerSize++;
    496:     for (tie(e,e_end)=out_edges(node.vertex,g); e!=e_end; e++) {
    497:       if (taken[target(*e,g)]) {
    498:         boundary -= get(edge_weight_g,*e);
    499:       } else {
    500:         boundary += get(edge_weight_g,*e);
    501:         edgeCount++;
    502:       }
    503:     }
    504:     for (i=succ[node.vertex].begin();i!=succ[node.vertex].end();i++) {
    505:       pq.push(PQNode(*i,dist[*i]));
    506:     }
    507:   }
    508:   while (boundary > (edgeCount+1)*log((double)m)/(log(2.0)*(1.0-2.0*delta)*radius)) {
    509:     assert(!pq.empty());
    510:     node = pq.top();pq.pop();
    511:     centerIdx.push_back(g.local_to_global(node.vertex));
    512:     taken[node.vertex] = PETSC_TRUE;
    513:     centerSize++;
    514:     for (tie(e,e_end)=out_edges(node.vertex,g); e!=e_end; e++) {
    515:       if (taken[target(*e,g)]) {
    516:         boundary -= get(edge_weight_g,*e);
    517:       } else {
    518:         boundary += get(edge_weight_g,*e);
    519:         edgeCount++;
    520:       }
    521:     }
    522:     for (i=succ[node.vertex].begin();i!=succ[node.vertex].end();i++) {
    523:       pq.push(PQNode(*i,dist[*i]));
    524:     }
    525:   }
    526:   size.push_back(centerSize);
    527:   idx.push_back(centerIdx);
    528:   edgesLeft -= edgeCount;

    530:   k = 0;
    531:   assert(!pq.empty());
    532:   std::queue<PetscInt> anchor_q;
    533:   ShortestPathPriorityQueue cone_pq;
    534:   std::vector<PetscInt> *cone_succ = new std::vector<PetscInt>[n];
    535:   std::vector<PetscBool> cone_found(n,PETSC_FALSE);

    537:   /** form tree of shortest paths to an anchor **/
    538:   while (!pq.empty()) {
    539:     node = pq.top();pq.pop();
    540:     cone_found[node.vertex] = PETSC_TRUE;
    541:     anchor_q.push(node.vertex);
    542:     for (tie(e,e_end)=out_edges(node.vertex,g); e!=e_end; e++) {
    543:       PetscInt t = target(*e,g);
    544:       if (!taken[t]) {
    545:         cone_pq.push(PQNode(t,node.vertex,get(edge_length_g,*e)));
    546:       }
    547:     }
    548:   }
    549:   while (!cone_pq.empty()) {
    550:     node = cone_pq.top();cone_pq.pop();
    551:     if (!cone_found[node.vertex]) {
    552:       cone_succ[node.pred].push_back(node.vertex);
    553:       cone_found[node.vertex] = PETSC_TRUE;
    554:       for (tie(e,e_end)=out_edges(node.vertex,g); e!=e_end; e++) {
    555:         PetscInt t = target(*e,g);
    556:         if (!taken[t] && !cone_found[t]) {
    557:           cone_pq.push(PQNode(t,node.vertex,node.dist+get(edge_length_g,*e)));
    558:         }
    559:       }
    560:     }
    561:   }

    563:   while (!anchor_q.empty()) {
    564:     /** CONE CUT **/
    565:     PetscInt anchor = anchor_q.front();anchor_q.pop();
    566:     if (!taken[anchor]) {
    567:       PetscInt v;
    568:       PetscInt thisSize = 0;
    569:       std::vector<PetscInt> thisIdx;
    570:       std::queue<PetscInt> q;
    571:       ShortestPathPriorityQueue mycone_pq;
    572:       std::vector<PetscBool> mycone_taken(n,PETSC_FALSE);
    573:       PetscInt initialInternalConeEdges = 0;

    575:       boundary = 0;
    576:       edgeCount = 0;
    577:       q.push(anchor);
    578:       while (!q.empty()) {
    579:         v = q.front();q.pop();
    580:         taken[v] = PETSC_TRUE;
    581:         mycone_taken[v] = PETSC_TRUE;
    582:         thisIdx.push_back(g.local_to_global(v));
    583:         thisSize++;
    584:         for (i=cone_succ[v].begin();i!=cone_succ[v].end();i++) {
    585:           q.push(*i);
    586:         }
    587:         for (tie(e,e_end)=out_edges(v,g); e!=e_end; e++) {
    588:           PetscInt t = target(*e,g);
    589:           if (!taken[t]) {
    590:             mycone_pq.push(PQNode(t,v,get(edge_length_g,*e)));
    591:             boundary += get(edge_weight_g,*e);
    592:             edgeCount++;
    593:           } else if (mycone_taken[t]) {
    594:             boundary -= get(edge_weight_g,*e);
    595:             initialInternalConeEdges++;
    596:           }
    597:         }
    598:       }
    599:       if (initialInternalConeEdges < edgesLeft) {
    600:         while (initialInternalConeEdges == 0 ?
    601:                boundary > (edgeCount+1)*log((double)(edgesLeft+1))*2.0/(log(2.0)*epsilon*radius) :
    602:                boundary > (edgeCount)*log(edgesLeft*1.0/initialInternalConeEdges)*2.0/(log(2.0)*epsilon*radius))
    603:           {
    604:             assert(!mycone_pq.empty());
    605:             node = mycone_pq.top();mycone_pq.pop();
    606:             if (!mycone_taken[node.vertex]) {
    607:               q.push(node.vertex);
    608:               while (!q.empty()) {
    609:                 v = q.front();q.pop();
    610:                 taken[v] = PETSC_TRUE;
    611:                 mycone_taken[v] = PETSC_TRUE;
    612:                 thisIdx.push_back(g.local_to_global(v));
    613:                 thisSize++;
    614:                 for (i=cone_succ[v].begin();i!=cone_succ[v].end();i++) {
    615:                   q.push(*i);
    616:                 }
    617:                 for (tie(e,e_end)=out_edges(v,g); e!=e_end; e++) {
    618:                   PetscInt t = target(*e,g);
    619:                   if (!taken[t]) {
    620:                     mycone_pq.push(PQNode(t,v,node.dist+get(edge_length_g,*e)));
    621:                     boundary += get(edge_weight_g,*e);
    622:                     edgeCount++;
    623:                   } else if (mycone_taken[t]) {
    624:                     boundary -= get(edge_weight_g,*e);
    625:                   }
    626:                 }
    627:               }
    628:             }
    629:           }
    630:       }
    631:       edgesLeft -= edgeCount;
    632:       size.push_back(thisSize);
    633:       idx.push_back(thisIdx);
    634:       x.push_back(anchor);
    635:       y.push_back(pred[anchor]);
    636:       k++;
    637:     }
    638:   }
    639: #endif
    640:

    642:   /*
    643:   // pseudo cone cut
    644:   while (!pq.empty()) {
    645:     node = pq.top();pq.pop();

    647:     PetscInt thisSize = 1;
    648:     std::vector<PetscInt> thisIdx;
    649:     std::queue<PetscInt> q;

    651:     thisIdx.push_back(g.local_to_global(node.vertex));
    652:     for (i=succ[node.vertex].begin();i!=succ[node.vertex].end();i++) {
    653:       q.push(*i);
    654:     }

    656:     PetscInt v;
    657:     while (!q.empty()) {
    658:       v = q.front();q.pop();
    659:       thisSize++;
    660:       thisIdx.push_back(g.local_to_global(v));
    661:       for (i=succ[v].begin();i!=succ[v].end();i++) {
    662:         q.push(*i);
    663:       }
    664:     }
    665:     size.push_back(thisSize);
    666:     idx.push_back(thisIdx);
    667:     x.push_back(node.vertex);
    668:     y.push_back(pred[node.vertex]);
    669:     k++;
    670:   }
    671:   */
    672: #ifndef PETSC_USE_COMPLEX
    673:   delete [] succ;
    674:   delete [] dist;
    675:   delete [] cone_succ;
    676: #endif
    677:   return(0);
    678: }

    680: /* -------------------------------------------------------------------------- */
    681: /*
    682:    AugmentSpanningTree

    684:    Input Parameters:
    685: .  g - input graph with spanning tree defined by vertex_parent and vertex_children;
    686:        vertex_depth gives distance in tree from root
    687: .  maxCong - target upper bound on congestion

    689:    Output Parameter:
    690: .  g - edges in augmented spanning tree are marked with edge_keep = PETSC_TRUE
    691: .  maxCong - an actual upper bound on congestion
    692:  */
    695: PetscErrorCode AugmentSpanningTree(Graph& g,const PetscInt root,PetscScalar& maxCong)
    696: {
    697:   //  const PetscInt n = num_vertices(g);
    698:   const PetscInt m = num_edges(g);
    699:   //PetscInt i;
    701:   //PetscInt *component;  // maps each vertex to a vertex component
    702:   //std::vector<PetscScalar>
    703:   //  maxCongestion;       /* maps each edge component to an upper bound on the
    704:   //                            congestion through any of its edges */

    706:   //const EdgeIndex edge_index_g = get(edge_index_t(),g);

    710:   std::vector<Component*> componentList;
    711:   std::vector<ComponentPair> edgeComponentMap(m);

    713:   DecomposeSpanningTree(g,root,maxCong,maxCong,
    714:                                componentList,edgeComponentMap);
    715:   /*
    716:   PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"COMPONENTS:\n");
    717:   for (int i=0; i<componentList.size(); i++) {
    718:     for (int j=0; j<componentList[i]->vertices.size(); j++) {
    719:       PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"%d ",componentList[i]->vertices[j]);
    720:     }
    721:     PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"EDGES: ");

    723:     graph_traits<Graph>::edge_iterator e, e_end;
    724:     for (tie(e,e_end)=edges(g); e!=e_end; e++) {
    725:       if (edgeComponentMap[get(edge_index_g,*e)].getIndex(componentList[i]) != -1) {
    726:         PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"(%d,%d) ",source(*e,g),target(*e,g));
    727:       }
    728:     }
    729:     PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"\n");
    730:   }
    731:   PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"END COMPONENTS\n");
    732:   */
    733:   AddBridges(g,componentList,edgeComponentMap,maxCong);

    735:   return(0);
    736: }

    740: /* -------------------------------------------------------------------------- */
    741: /*
    742:    DecomposeSpanningTree

    744:    Input Parameters:
    745: .  g - input graph with spanning tree defined by vertex_parent and vertex_children;
    746:        vertex_depth gives distance in tree from root
    747: .  component - a preallocated array of length num_vertices(g)
    748: .  edgeComponent - a preallocated vector of length num_edges(g)

    750:    Output Parameter:
    751: .  component - a vector mapping each vertex to a component
    752:  */
    755: PetscErrorCode DecomposeSpanningTree(Graph& g,const PetscInt root,
    756:                                      const PetscScalar maxInternalStretch,
    757:                                      const PetscScalar maxExternalWeight,
    758:                                      std::vector<Component*>& componentList,
    759:                                      std::vector<ComponentPair>& edgeComponentMap)
    760: {

    765:   Component* currComponent;
    766:   PetscScalar currInternalStretch, currExternalWeight;

    768:   //Component::next_id = 0;
    769:   //Component::max_id = num_edges(g);
    770:   DecomposeSubTree(g,root,
    771:                           maxInternalStretch,maxExternalWeight,
    772:                           componentList,edgeComponentMap,
    773:                           currComponent,
    774:                           currInternalStretch,
    775:                           currExternalWeight);
    776:
    777:   componentList.push_back(currComponent);

    779:   return(0);
    780: }

    785: PetscErrorCode DecomposeSubTree(Graph& g,const PetscInt root,
    786:                                 const PetscScalar maxInternalStretch,
    787:                                 const PetscScalar maxExternalWeight,
    788:                                 std::vector<Component*>& componentList,
    789:                                 std::vector<ComponentPair>& edgeComponentMap,
    790:                                 Component*& currComponent,
    791:                                 PetscScalar& currInternalStretch,
    792:                                 PetscScalar& currExternalWeight)
    793: {
    794: #ifndef PETSC_USE_COMPLEX
    795:   const EdgeWeight edge_weight_g = get(edge_weight_t(),g);
    796:   const EdgeIndex edge_index_g = get(edge_index_t(),g);
    797:   const EdgeKeep edge_keep_g = get(edge_keep_t(),g);
    798:   //const VertexParent vertex_parent_g = get(vertex_parent_t(),g);
    799:   const VertexChildren vertex_children_g = get(vertex_children_t(),g);
    800:   const VertexDepth vertex_depth_g = get(vertex_depth_t(),g);
    801:   const PetscScalar rootDepth = get(vertex_depth_g,root);
    802:   std::vector<PetscInt>::const_iterator i,j;
    803:   graph_traits<Graph>::out_edge_iterator e, e_end;
    805:   PetscScalar newInternalStretch, newExternalWeight;
    806:   PetscInt v,w,edgeIndex,compIndex;
    807:   PetscScalar weight;
    808: #endif

    811: #ifdef PETSC_USE_COMPLEX
    812:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Complex numbers not supported for support graph PC");
    813: #else
    814:   currComponent = new Component();
    815:   currComponent->vertices.push_back(root);
    816:   currInternalStretch = 0;
    817:   currExternalWeight = 0;
    818:   // temporarily add all external edges to component, but may remove some at end
    819:   for (tie(e,e_end)=out_edges(root,g); e!=e_end; e++) {
    820:     if (!get(edge_keep_g,*e)) {
    821:       edgeIndex = get(edge_index_g,*e);
    822:
    823:       if (!edgeComponentMap[edgeIndex].get(0)) {
    824:         edgeComponentMap[edgeIndex].put(0,currComponent);
    825:       } else {
    826:         if (edgeComponentMap[edgeIndex].get(1)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"expected edgeComponentMap[edgeIndex].get(1) == NULL");
    827:         edgeComponentMap[edgeIndex].put(1,currComponent);
    828:       }
    829:     }
    830:   }

    832:   std::vector<PetscInt> children = get(vertex_children_g,root);

    834:   Component *childComponent;
    835:   PetscScalar childInternalStretch, childExternalWeight;
    836:   for (i=children.begin();i!=children.end();i++) {
    837:     PetscInt child = *i;
    838:     DecomposeSubTree(g,child,maxInternalStretch,maxExternalWeight,
    839:                             componentList,edgeComponentMap,
    840:                             childComponent,
    841:                             childInternalStretch,childExternalWeight);

    843:     newInternalStretch = currInternalStretch + childInternalStretch;
    844:     newExternalWeight = currExternalWeight;

    846:     for (j = childComponent->vertices.begin(), v = *j;
    847:          j != childComponent->vertices.end() && (newInternalStretch <= maxInternalStretch);
    848:          v = *(++j)) {
    849:       for (tie(e,e_end)=out_edges(v,g);
    850:            e!=e_end && (newInternalStretch <= maxInternalStretch);
    851:            e++) {
    852:         if (!get(edge_keep_g,*e)) {
    853:           w = target(*e,g);
    854:           edgeIndex = get(edge_index_g,*e);
    855:           compIndex = edgeComponentMap[edgeIndex].getIndex(childComponent);
    856:
    857:           if (compIndex != -1) {
    858:             weight = get(edge_weight_g,*e);
    859:
    860:             if (edgeComponentMap[edgeIndex].get(1-compIndex) == currComponent) {
    861:               newExternalWeight -= weight;
    862:               newInternalStretch +=
    863:                 (get(vertex_depth_g,v) + get(vertex_depth_g,w) - 2*rootDepth) * weight;
    864:             } else {
    865:               newExternalWeight += weight;
    866:             }
    867:           }
    868:         }
    869:       }
    870:     }

    872:     if (newInternalStretch <= maxInternalStretch && newExternalWeight <= maxExternalWeight) {
    873:       // merge the components

    875:       currInternalStretch = newInternalStretch;
    876:       currExternalWeight = newExternalWeight;

    878:       for (j = childComponent->vertices.begin(), v = *j;
    879:            j != childComponent->vertices.end();
    880:            v = *(++j)) {
    881:         currComponent->vertices.push_back(v);
    882:         for (tie(e,e_end)=out_edges(v,g); e!=e_end; e++) {
    883:           if (!get(edge_keep_g,*e)) {
    884:             edgeIndex = get(edge_index_g,*e);
    885:             if (edgeComponentMap[edgeIndex].get(0) == childComponent) {
    886:               edgeComponentMap[edgeIndex].put(0,currComponent);
    887:             }
    888:             if (edgeComponentMap[edgeIndex].get(1) == childComponent) {
    889:               edgeComponentMap[edgeIndex].put(1,currComponent);
    890:             }
    891:           }
    892:         }
    893:       }
    894:       delete childComponent;
    895:     } else {
    896:       componentList.push_back(childComponent);
    897:     }
    898:   }

    900:   const Component *origCurrComponent = currComponent;
    901:   for (tie(e,e_end)=out_edges(root,g); e!=e_end; e++) {
    902:     edgeIndex = get(edge_index_g,*e);
    903:     if (!get(edge_keep_g,*e)) {
    904:       if (edgeComponentMap[edgeIndex].get(0) == origCurrComponent) {
    905:         compIndex = 0;
    906:       } else {
    907:         assert(edgeComponentMap[edgeIndex].get(1) == origCurrComponent);
    908:         compIndex = 1;
    909:       }
    910:
    911:       if (edgeComponentMap[edgeIndex].get(1-compIndex) != origCurrComponent) {
    912:         weight = get(edge_weight_g,*e);
    913:         if (currExternalWeight + weight <= maxExternalWeight) {
    914:           currExternalWeight += weight;
    915:         } else {
    916:           componentList.push_back(currComponent);
    917:           currComponent = new Component();
    918:           currComponent->vertices.push_back(root);
    919:           currInternalStretch = 0;
    920:           currExternalWeight = 0;
    921:         }
    922:         edgeComponentMap[edgeIndex].put(compIndex,currComponent);
    923:       }
    924:     }
    925:   }
    926: #endif
    927:   return(0);
    928: }

    933: PetscErrorCode AddBridges(Graph& g,
    934:                           std::vector<Component*>& componentList,
    935:                           std::vector<ComponentPair>& edgeComponentMap,
    936:                           PetscScalar& maxCong) {

    938: #ifndef PETSC_USE_COMPLEX
    939:   const PetscInt m = num_edges(g);
    940:   std::vector<PetscBool> edgeSupported(m); // edgeSupported[i] if edge i's component pair has been bridged
    941:   const EdgeLength edge_length_g = get(edge_length_t(),g);
    942:   const EdgeWeight edge_weight_g = get(edge_weight_t(),g);
    943:   const EdgeIndex edge_index_g = get(edge_index_t(),g);
    944:   const EdgeKeep edge_keep_g = get(edge_keep_t(),g);
    945:   const VertexParent vertex_parent_g = get(vertex_parent_t(),g);
    946:   // const VertexChildren vertex_children_g = get(vertex_children_t(),g);
    947:   const VertexDepth vertex_depth_g = get(vertex_depth_t(),g);
    948:   PetscInt edgeIndex, eeIndex;
    949:   Component *comp1, *comp2;
    950:   PetscInt comp1size, comp2size, i, v, w, parent;
    951:   graph_traits<Graph>::edge_iterator e, e_end;
    952:   graph_traits<Graph>::out_edge_iterator ee, ee_end;
    953:   PetscScalar realMaxCong;
    954: #endif

    957: #ifdef PETSC_USE_COMPLEX
    958:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Complex numbers not supported for support graph PC");
    959: #else
    960:   realMaxCong = 0;

    962:   for (tie(e,e_end)=edges(g); e!=e_end; e++) {
    963:     if (!get(edge_keep_g,*e)) {
    964:       edgeIndex = get(edge_index_g,*e);
    965:       comp1 = edgeComponentMap[edgeIndex].get(0);
    966:       comp2 = edgeComponentMap[edgeIndex].get(1);
    967:       if ((comp1 != comp2) && !edgeSupported[edgeIndex]) {
    968:         comp1size = comp1->vertices.size();
    969:         comp2size = comp2->vertices.size();
    970:         std::map<PetscInt,PetscScalar> congestionBelow1,weightBelow1;
    971:         std::map<PetscInt,PetscScalar> congestionBelow2,weightBelow2;
    972:         for (i=0; i<comp1size; i++) {
    973:           congestionBelow1[comp1->vertices[i]] = 0;
    974:           weightBelow1[comp1->vertices[i]] = 0;
    975:         }
    976:         for (i=0; i<comp2size; i++) {
    977:           congestionBelow2[comp2->vertices[i]] = 0;
    978:           weightBelow2[comp2->vertices[i]] = 0;
    979:         }

    981:         for (i=comp1size-1; i>=0; i--) {
    982:           v = comp1->vertices[i];
    983:           for (tie(ee,ee_end)=out_edges(v,g); ee!=ee_end; ee++) {
    984:             if (!get(edge_keep_g,*ee)) {
    985:               eeIndex = get(edge_index_g,*ee);
    986:               if (edgeComponentMap[eeIndex].match(comp1,comp2) &&
    987:                   weightBelow2.count(target(*ee,g)) > 0) {
    988:                 edgeSupported[eeIndex] = PETSC_TRUE;
    989:                 weightBelow1[v] += get(edge_weight_g,*ee);
    990:               }
    991:             }
    992:           }
    993:           if (i>0) {
    994:             parent = get(vertex_parent_g,v);
    995:             weightBelow1[parent] += weightBelow1[v];
    996:             congestionBelow1[parent] +=
    997:               weightBelow1[v]*(get(vertex_depth_g,v)-get(vertex_depth_g,parent));
    998:           }
    999:         }
    1000:         for (i=1; i<comp1size; i++) {
    1001:           v = comp1->vertices[i];
    1002:           parent = get(vertex_parent_g,v);
    1003:           congestionBelow1[v] = congestionBelow1[parent] -
    1004:             (weightBelow1[comp1->vertices[0]] - 2*weightBelow1[v])*(get(vertex_depth_g,v)-get(vertex_depth_g,parent));
    1005:         }
    1006:
    1007:         for (i=comp2size-1; i>=0; i--) {
    1008:           v = comp2->vertices[i];
    1009:           for (tie(ee,ee_end)=out_edges(v,g); ee!=ee_end; ee++) {
    1010:             if (!get(edge_keep_g,*ee)) {
    1011:               eeIndex = get(edge_index_g,*ee);
    1012:               if (edgeComponentMap[eeIndex].match(comp1,comp2) &&
    1013:                   weightBelow1.count(target(*ee,g)) > 0) {
    1014:                 assert(edgeSupported[eeIndex] == PETSC_TRUE);
    1015:                 weightBelow2[v] += get(edge_weight_g,*ee);
    1016:               }
    1017:             }
    1018:           }
    1019:           if (i>0) {
    1020:             parent = get(vertex_parent_g,v);
    1021:             weightBelow2[parent] += weightBelow2[v];
    1022:             congestionBelow2[parent] +=
    1023:               weightBelow2[v]*(get(vertex_depth_g,v)-get(vertex_depth_g,parent));
    1024:           }
    1025:         }
    1026:         for (i=1; i<comp2size; i++) {
    1027:           v = comp2->vertices[i];
    1028:           parent = get(vertex_parent_g,v);
    1029:           congestionBelow2[v] = congestionBelow2[parent] -
    1030:             (weightBelow2[comp2->vertices[0]] - 2*weightBelow2[v])*(get(vertex_depth_g,v)-get(vertex_depth_g,parent));
    1031:         }
    1032:         /*
    1033:         for (std::map<PetscInt,PetscScalar>::iterator it = congestionBelow1.begin();
    1034:              it != congestionBelow1.end();
    1035:              it++) {
    1036:           PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"congestionBelow1[%d]=%f\n",(*it).first,(*it).second);
    1037:         }
    1038:         for (std::map<PetscInt,PetscScalar>::iterator it = weightBelow1.begin();
    1039:              it != weightBelow1.end();
    1040:              it++) {
    1041:           PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"weightBelow1[%d]=%f\n",(*it).first,(*it).second);
    1042:         }
    1043:         for (std::map<PetscInt,PetscScalar>::iterator it = congestionBelow2.begin();
    1044:              it != congestionBelow2.end();
    1045:              it++) {
    1046:           PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"congestionBelow2[%d]=%f\n",(*it).first,(*it).second);
    1047:         }
    1048:         for (std::map<PetscInt,PetscScalar>::iterator it = weightBelow2.begin();
    1049:              it != weightBelow2.end();
    1050:              it++) {
    1051:           PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"weightBelow2[%d]=%f\n",(*it).first,(*it).second);
    1052:         }
    1053:         */
    1054:         assert(weightBelow1[comp1->vertices[0]] - weightBelow2[comp2->vertices[0]] < 1e-9 &&
    1055:                weightBelow1[comp1->vertices[0]] - weightBelow2[comp2->vertices[0]] > -1e-9);

    1057:         Edge bestEdge;
    1058:         PetscScalar bestCongestion = -1;
    1059:         for (i=0; i<comp1size; i++) {
    1060:           v = comp1->vertices[i];
    1061:           for (tie(ee,ee_end)=out_edges(v,g); ee!=ee_end; ee++) {
    1062:             if (!get(edge_keep_g,*ee)) {
    1063:               eeIndex = get(edge_index_g,*ee);
    1064:               if (edgeComponentMap[eeIndex].match(comp1,comp2)) {
    1065:                 w = target(*ee,g);
    1066:                 PetscScalar newCongestion =
    1067:                   weightBelow1[comp1->vertices[0]] * get(edge_length_g,*ee) +
    1068:                   congestionBelow1[v] + congestionBelow2[w];
    1069:                 if (bestCongestion < 0 || newCongestion < bestCongestion) {
    1070:                   bestEdge = *ee;
    1071:                   bestCongestion = newCongestion;
    1072:                 }
    1073:               }
    1074:             }
    1075:           }
    1076:         }
    1077:         put(edge_keep_g,bestEdge,PETSC_TRUE);
    1078:         if (bestCongestion > realMaxCong)
    1079:           realMaxCong = bestCongestion;
    1080:       }
    1081:     }
    1082:   }
    1083:   maxCong = realMaxCong;
    1084: #endif
    1085:   return(0);
    1086: }