int order(const RCP<OrderingSolution<lno_t, gno_t> > &solution)
 {
   int ierr= 0;
 
   HELLO;
 
   lno_t *perm;
   perm = (lno_t *) (solution->getPermutation());
   if (perm==0){
     // Throw exception
     std::cerr << "perm is NULL" << std::endl;
     ierr = -1;
   }
 
   // Get local graph.
   const size_t nVtx = model->getLocalNumVertices();
   ArrayView<const gno_t> edgeIds;
   ArrayView<const lno_t> offsets;
   ArrayView<StridedData<lno_t, scalar_t> > wgts;
   model->getEdgeList(edgeIds, offsets, wgts);
 
   // Store degrees together with index so we can sort.
   Teuchos::Array<std::pair<lno_t, size_t> >  degrees(nVtx);
   for (lno_t i=0; i<(lno_t)nVtx; i++){
     degrees[i].first = i;
     degrees[i].second  = offsets[i+1] - offsets[i];
   }
 
   // Sort degrees.
   SortPairs<lno_t,size_t> zort;
   bool inc = true; // TODO: Add user parameter
   zort.sort(degrees, inc);
 
   // Copy permuted indices to perm.
   for (lno_t i=0; i<(lno_t)nVtx; i++){
     perm[i] = degrees[i].first;
   }
 
   solution->setHavePerm(true);
   return ierr;
 }
Example #2
0
  int order(
    const RCP<GraphModel<Adapter> > &model,
    const RCP<OrderingSolution<typename Adapter::gid_t,
  			     typename Adapter::lno_t> > &solution,
    const RCP<Teuchos::ParameterList> &pl,
    const RCP<Teuchos::Comm<int> > &comm
  )
  {
    int ierr= 0;
  
    HELLO;
  
    // Check size of communicator: serial only.
    // TODO: Remove this test when RCM works on local graph.
    if (comm->getSize() > 1){
      throw std::runtime_error("RCM currently only works in serial.");
    }
  
    // Get local graph.
    ArrayView<const gno_t> edgeIds;
    ArrayView<const lno_t> offsets;
    ArrayView<StridedData<lno_t, scalar_t> > wgts;
  
    // TODO: edgeIds should be of type lno_t for getLocalEdgeList. Needs revisit.
    //model->getLocalEdgeList(edgeIds, offsets, wgts); // BUGGY!
    // Use global graph for now. This only works in serial!
    ArrayView<const int> procIds;
    size_t numEdges = model->getEdgeList( edgeIds, procIds, offsets, wgts);
  
    //cout << "Debug: Local graph from getLocalEdgeList" << endl;
    //cout << "edgeIds: " << edgeIds << endl;
    //cout << "offsets: " << offsets << endl;
  
    const size_t nVtx = model->getLocalNumVertices();
    // RCM constructs invPerm, not perm
    ArrayRCP<lno_t> invPerm = solution->getPermutationRCP(true);
  
    // Check if there are actually edges to reorder.
    // If there are not, then just use the natural ordering.
    if (numEdges == 0) {
      for (size_t i = 0; i < nVtx; ++i) {
        invPerm[i] = i;
      }
      return 0;
    }
  
    // Set the label of each vertex to invalid.
    Tpetra::global_size_t INVALID = Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
    for (size_t i = 0; i < nVtx; ++i) {
      invPerm[i] = INVALID;
    }
  
    // Loop over all connected components.
    // Do BFS within each component.
    lno_t root;
    std::queue<lno_t> Q;
    size_t count = 0; // CM label, reversed later
    size_t next = 0;  // next unmarked vertex
    Teuchos::Array<std::pair<lno_t, size_t> >  children; // children and their degrees
  
    while (count < nVtx) {
  
      // Find suitable root vertex for this component.
      // First find an unmarked vertex, use to find root in next component.
      while ((next < nVtx) && (static_cast<Tpetra::global_size_t>(invPerm[next]) != INVALID)) next++;

      // Select root method. Pseudoperipheral usually gives the best
      // ordering, but the user may choose a faster method.
      std::string root_method = pl->get("root_method", "pseudoperipheral");
      if (root_method == string("first"))
        root = next;
      else if (root_method == string("smallest_degree"))
        root = findSmallestDegree(next, nVtx, edgeIds, offsets);
      else if (root_method == string("pseudoperipheral"))
        root = findPseudoPeripheral(next, nVtx, edgeIds, offsets);
      else {
        // This should never happen if pl was validated.
      }

      // Label connected component starting at root
      Q.push(root);
      //cout << "Debug: invPerm[" << root << "] = " << count << endl;
      invPerm[root] = count++;
  
      while (Q.size()){
        // Get a vertex from the queue
        lno_t v = Q.front();
        Q.pop();
        //cout << "Debug: v= " << v << ", offsets[v] = " << offsets[v] << endl;
  
        // Add unmarked children to list of pairs, to be added to queue.
        children.resize(0);
        for (lno_t ptr = offsets[v]; ptr < offsets[v+1]; ++ptr){
          lno_t child = edgeIds[ptr];
          if (static_cast<Tpetra::global_size_t>(invPerm[child]) == INVALID){
            // Not visited yet; add child to list of pairs.
            std::pair<lno_t,size_t> newchild;
            newchild.first = child;
            newchild.second = offsets[child+1] - offsets[child];
            children.push_back(newchild); 
          }
        }
        // Sort children by increasing degree
        // TODO: If edge weights, sort children by decreasing weight,
        SortPairs<lno_t,size_t> zort;
        zort.sort(children);

        typename Teuchos::Array<std::pair<lno_t,size_t> >::iterator it = children.begin ();
        for ( ; it != children.end(); ++it){
          // Push children on the queue in sorted order.
          lno_t child = it->first;
          invPerm[child] = count++; // Label as we push on Q
          Q.push(child);
          //cout << "Debug: invPerm[" << child << "] = " << count << endl;
        }
      }
    }
  
    // Reverse labels for RCM
    bool reverse = true; // TODO: Make parameter
    if (reverse) {
      lno_t temp;
      for (size_t i=0; i < nVtx/2; ++i) {
        // Swap (invPerm[i], invPerm[nVtx-i])
        temp = invPerm[i];
        invPerm[i] = invPerm[nVtx-1-i];
        invPerm[nVtx-1-i] = temp;
      }
    }
  
    solution->setHaveInverse(true);
    return ierr;
  }