void
diy::detail::KDTreeSamplingPartition<Block,Point>::
split_to_neighbors(Block* b, const diy::ReduceProxy& srp, int dim) const
{
    int         lid  = srp.master()->lid(srp.gid());
    RCLink*     link = static_cast<RCLink*>(srp.master()->link(lid));

    // determine split
    float split = find_split(link->core(), link->bounds());

    for (int i = 0; i < link->size(); ++i)
    {
        srp.enqueue(link->target(i), split);
        srp.enqueue(link->target(i), link->direction(i));
    }
}
Exemple #2
0
static hwloc_obj_t find_split(hwloc_topology_t topo, hwloc_obj_t obj)
{
    unsigned k;
    hwloc_obj_t nxt;

    if (1 < obj->arity) {
        return obj;
    }
    for (k=0; k < obj->arity; k++) {
        nxt = find_split(topo, obj->children[k]);
        if (NULL != nxt) {
            return nxt;
        }
    }
    return NULL;
}
Exemple #3
0
tree_t *convert_to_bst(int arr[], int start, int end)
{
	tree_t	*n = NULL;
	int	split;

	if (start > end) {
		return (NULL);
	}

	if (start == end) {
		n = create_new_node(arr[start]);
		return (n);
	}

	split = find_split(start, end);
	printf("convert_to_bst (start, end, split) : %d, %d, %d\n",
		start, end, split);
	n = create_new_node(arr[split]);
	n->right = convert_to_bst(arr, start, split - 1);
	n->left = convert_to_bst(arr, split + 1, end);
	return (n);
}
Exemple #4
0
/* recursively climb the topology, pruning procs beyond that allowed
 * by the given ppr
 */
static void prune(orte_jobid_t jobid,
                  orte_app_idx_t app_idx,
                  orte_node_t *node,
                  opal_hwloc_level_t *level,
                  orte_vpid_t *nmapped)
{
    hwloc_obj_t obj, top;
    unsigned int i, nobjs;
    hwloc_obj_type_t lvl;
    unsigned cache_level = 0, k;
    int nprocs;
    hwloc_cpuset_t avail, cpus, childcpus;
    int n, limit, nmax, nunder, idx, idxmax = 0;
    orte_proc_t *proc, *pptr, *procmax;
    opal_hwloc_level_t ll;
    char dang[64];
    hwloc_obj_t locale;

    opal_output_verbose(5, orte_rmaps_base_framework.framework_output,
                        "mca:rmaps:ppr: pruning level %d",
                        *level);

    /* convenience */
    ll = *level;

    /* convenience */
    lvl = opal_hwloc_levels[ll];
    limit = ppr[ll];

    if (0 == limit) {
        /* no limit at this level, so move up if necessary */
        if (0 == ll) {
            /* done */
            return;
        }
        --(*level);
        prune(jobid, app_idx, node, level, nmapped);
        return;
    }

    /* handle the darn cache thing again */
    if (OPAL_HWLOC_L3CACHE_LEVEL == ll) {
        cache_level = 3;
    } else if (OPAL_HWLOC_L2CACHE_LEVEL == ll) {
        cache_level = 2;
    } else if (OPAL_HWLOC_L1CACHE_LEVEL == ll) {
        cache_level = 1;
    }

    /* get the number of resources at this level on this node */
    nobjs = opal_hwloc_base_get_nbobjs_by_type(node->topology,
                                               lvl, cache_level,
                                               OPAL_HWLOC_AVAILABLE);

    /* for each resource, compute the number of procs sitting
     * underneath it and check against the limit
     */
    for (i=0; i < nobjs; i++) {
        obj = opal_hwloc_base_get_obj_by_type(node->topology,
                                              lvl, cache_level,
                                              i, OPAL_HWLOC_AVAILABLE);
        /* get the available cpuset */
        avail = opal_hwloc_base_get_available_cpus(node->topology, obj);

        /* look at the intersection of this object's cpuset and that
         * of each proc in the job/app - if they intersect, then count this proc
         * against the limit
         */
        nprocs = 0;
        for (n=0; n < node->procs->size; n++) {
            if (NULL == (proc = (orte_proc_t*)opal_pointer_array_get_item(node->procs, n))) {
                continue;
            }
            if (proc->name.jobid != jobid ||
                proc->app_idx != app_idx) {
                continue;
            }
            locale = NULL;
            if (orte_get_attribute(&proc->attributes, ORTE_PROC_HWLOC_LOCALE, (void**)&locale, OPAL_PTR)) {
                ORTE_ERROR_LOG(ORTE_ERR_NOT_FOUND);
                return;
            }
            cpus = opal_hwloc_base_get_available_cpus(node->topology, locale);
            if (hwloc_bitmap_intersects(avail, cpus)) {
                nprocs++;
            }
        }
        opal_output_verbose(5, orte_rmaps_base_framework.framework_output,
                            "mca:rmaps:ppr: found %d procs limit %d",
                            nprocs, limit);

        /* check against the limit */
        while (limit < nprocs) {
            /* need to remove procs - do this in a semi-intelligent
             * manner to provide a little load balancing by cycling
             * across the objects beneath this one, removing procs
             * in a round-robin fashion until the limit is satisfied
             *
             * NOTE: I'm sure someone more knowledgeable with hwloc
             * will come up with a more efficient way to do this, so
             * consider this is a starting point
             */

            /* find the first level that has more than
             * one child beneath it - if all levels
             * have only one child, then return this
             * object
             */
            top = find_split(node->topology, obj);
            hwloc_obj_type_snprintf(dang, 64, top, 1);
            opal_output_verbose(5, orte_rmaps_base_framework.framework_output,
                                "mca:rmaps:ppr: SPLIT AT LEVEL %s", dang);

            /* cycle across the children of this object */
            nmax = 0;
            procmax = NULL;
            idx = 0;
            /* find the child with the most procs underneath it */
            for (k=0; k < top->arity && limit < nprocs; k++) {
                /* get this object's available cpuset */
                childcpus = opal_hwloc_base_get_available_cpus(node->topology, top->children[k]);
                nunder = 0;
                pptr = NULL;
                for (n=0; n < node->procs->size; n++) {
                    if (NULL == (proc = (orte_proc_t*)opal_pointer_array_get_item(node->procs, n))) {
                        continue;
                    }
                    if (proc->name.jobid != jobid ||
                        proc->app_idx != app_idx) {
                        continue;
                    }
                    locale = NULL;
                    if (orte_get_attribute(&proc->attributes, ORTE_PROC_HWLOC_LOCALE, (void**)&locale, OPAL_PTR)) {
                        ORTE_ERROR_LOG(ORTE_ERR_NOT_FOUND);
                        return;
                    }
                    cpus = opal_hwloc_base_get_available_cpus(node->topology, locale);
                    if (hwloc_bitmap_intersects(childcpus, cpus)) {
                        nunder++;
                        if (NULL == pptr) {
                            /* save the location of the first proc under this object */
                            pptr = proc;
                            idx = n;
                        }
                    }
                }
                if (nmax < nunder) {
                    opal_output_verbose(5, orte_rmaps_base_framework.framework_output,
                                        "mca:rmaps:ppr: PROCS UNDER CHILD %d %d MAX %d",
                                        k, nunder, nmax);
                    nmax = nunder;
                    procmax = pptr;
                    idxmax = idx;
                }
            }
            if (NULL == procmax) {
                /* can't find anything to remove - error out */
                goto error;
            }
            /* remove it */
            opal_output_verbose(5, orte_rmaps_base_framework.framework_output,
                                "mca:rmaps:ppr: removing proc at posn %d",
                                idxmax);
            opal_pointer_array_set_item(node->procs, idxmax, NULL);
            node->num_procs--;
            node->slots_inuse--;
            if (node->slots_inuse < 0) {
                node->slots_inuse = 0;
            }
            nprocs--;
            *nmapped -= 1;
            OBJ_RELEASE(procmax);
        }
    }
    /* finished with this level - move up if necessary */
    if (0 == ll) {
        return;
    }
    --(*level);
    prune(jobid, app_idx, node, level, nmapped);
    return;

 error:
    opal_output(0, "INFINITE LOOP");
}
void
diy::detail::KDTreeSamplingPartition<Block,Point>::
update_links(Block* b, const diy::ReduceProxy& srp, int dim, int round, int rounds, bool wrap, const Bounds& domain) const
{
    auto        log  = get_logger();
    int         gid  = srp.gid();
    int         lid  = srp.master()->lid(gid);
    RCLink*     link = static_cast<RCLink*>(srp.master()->link(lid));

    // (gid, dir) -> i
    std::map<std::pair<int,diy::Direction>, int> link_map;
    for (int i = 0; i < link->size(); ++i)
        link_map[std::make_pair(link->target(i).gid, link->direction(i))] = i;

    // NB: srp.enqueue(..., ...) should match the link
    std::vector<float>  splits(link->size());
    for (int i = 0; i < link->size(); ++i)
    {
        float split; diy::Direction dir;

        int in_gid = link->target(i).gid;
        while(srp.incoming(in_gid))
        {
            srp.dequeue(in_gid, split);
            srp.dequeue(in_gid, dir);

            // reverse dir
            for (int j = 0; j < dim_; ++j)
                dir[j] = -dir[j];

            int k = link_map[std::make_pair(in_gid, dir)];
            log->trace("{} {} {} -> {}", in_gid, dir, split, k);
            splits[k] = split;
        }
    }

    RCLink      new_link(dim_, link->core(), link->core());

    bool lower = !(gid & (1 << (rounds - 1 - round)));

    // fill out the new link
    for (int i = 0; i < link->size(); ++i)
    {
        diy::Direction  dir = link->direction(i);
        //diy::Direction  wrap_dir = link->wrap(i);     // we don't use existing wrap, but restore it from scratch
        if (dir[dim] != 0)
        {
            if ((dir[dim] < 0 && lower) || (dir[dim] > 0 && !lower))
            {
                int nbr_gid = divide_gid(link->target(i).gid, !lower, round, rounds);
                diy::BlockID nbr = { nbr_gid, srp.assigner().rank(nbr_gid) };
                new_link.add_neighbor(nbr);

                new_link.add_direction(dir);

                Bounds bounds = link->bounds(i);
                update_neighbor_bounds(bounds, splits[i], dim, !lower);
                new_link.add_bounds(bounds);

                if (wrap)
                    new_link.add_wrap(find_wrap(new_link.bounds(), bounds, domain));
                else
                    new_link.add_wrap(diy::Direction());
            }
        } else // non-aligned side
        {
            for (int j = 0; j < 2; ++j)
            {
                int nbr_gid = divide_gid(link->target(i).gid, j == 0, round, rounds);

                Bounds  bounds  = link->bounds(i);
                update_neighbor_bounds(bounds, splits[i], dim, j == 0);

                if (intersects(bounds, new_link.bounds(), dim, wrap, domain))
                {
                    diy::BlockID nbr = { nbr_gid, srp.assigner().rank(nbr_gid) };
                    new_link.add_neighbor(nbr);
                    new_link.add_direction(dir);
                    new_link.add_bounds(bounds);

                    if (wrap)
                        new_link.add_wrap(find_wrap(new_link.bounds(), bounds, domain));
                    else
                        new_link.add_wrap(diy::Direction());
                }
            }
        }
    }

    // add link to the dual block
    int dual_gid = divide_gid(gid, !lower, round, rounds);
    diy::BlockID dual = { dual_gid, srp.assigner().rank(dual_gid) };
    new_link.add_neighbor(dual);

    Bounds nbr_bounds = link->bounds();     // old block bounds
    update_neighbor_bounds(nbr_bounds, find_split(new_link.bounds(), nbr_bounds), dim, !lower);
    new_link.add_bounds(nbr_bounds);

    new_link.add_wrap(diy::Direction());    // dual block cannot be wrapped

    if (lower)
    {
        diy::Direction right;
        right[dim] = 1;
        new_link.add_direction(right);
    } else
    {
        diy::Direction left;
        left[dim] = -1;
        new_link.add_direction(left);
    }

    // update the link; notice that this won't conflict with anything since
    // reduce is using its own notion of the link constructed through the
    // partners
    link->swap(new_link);
}
Exemple #6
0
/**
 * Parse XML transaction node and fill a ImportTransaction with results.
 *
 * \param transaction_node	XML transaction node to parse.
 */
void recuperation_donnees_gnucash_transaction ( xmlNodePtr transaction_node )
{
  struct ImportTransaction * transaction;
  struct ImportAccount * account = NULL;
  struct gnucash_split * split;
  gchar * date_string, *space, *tiers;
  GDate * date;
  xmlNodePtr splits, split_node, date_node;
  GSList * split_list = NULL;
  GsbReal total = { 0 , 0 };

  /* Transaction amount, category, account, etc.. */
  splits = get_child ( transaction_node, "splits" );
  split_node = splits -> children;

  while ( split_node )
    {
      struct ImportAccount * split_account = NULL;
      struct gnucash_category * categ = NULL;
      gint p_r = OPERATION_NORMALE;
      GsbReal amount;

      /**
       * Gnucash transactions are in fact "splits", much like grisbi's
       * splits of transactions.  We need to parse all splits and
       * see whether they are transfers to real accounts or transfers
       * to category accounts.  In that case, we only create one
       * transactions.  The other is discarded as grisbi is not a
       * double part financial engine.
       */
      if ( node_strcmp ( split_node, "split" ) )
	{
	  gchar * account_name = NULL, * categ_name = NULL;

	  split_account = find_imported_account_by_uid ( child_content ( split_node,
									"account" ) );
	  categ = find_imported_categ_by_uid ( child_content ( split_node, "account" ) );
	  amount = gnucash_value ( child_content(split_node, "value") );

	  if ( categ )
	    categ_name = categ -> name;
	  if ( split_account )
	    {
	      /* All of this stuff is here since we are dealing with
		 the account split, not the category one */
	      account_name = split_account -> nom_de_compte;
	      total = gsb_real_add ( total,
				     amount );
	      if ( strcmp(child_content(split_node, "reconciled-state"), "n") )
		p_r = OPERATION_RAPPROCHEE;
	    }

	  split = find_split ( split_list, amount, split_account, categ );
	  if ( split )
	    {
	      update_split ( split, amount, account_name, categ_name );
	    }
	  else
	    {
	      split = new_split ( amount, account_name, categ_name );
	      split_list = g_slist_append ( split_list, split );
	      split -> notes = child_content(split_node, "memo");
	    }
	  if ( p_r != OPERATION_NORMALE )
	      split -> p_r = p_r;
	}

      split_node = split_node -> next;
    }

  if ( ! split_list )
    return;

  /* Transaction date */
  date_node = get_child ( transaction_node, "date-posted" );
  date_string = child_content (date_node, "date");
  space = strchr ( date_string, ' ' );
  if ( space )
    *space = 0;
  date = g_date_new ();
  g_date_set_parse ( date, date_string );
  if ( !g_date_valid ( date ))
    fprintf ( stderr, "grisbi: Can't parse date %s\n", date_string );

  /* Tiers */
  tiers = child_content ( transaction_node, "description" );

  /* Create transaction */
  split = split_list -> data;
  transaction = new_transaction_from_split ( split, tiers, date );
  transaction -> operation_ventilee = 0;
  transaction -> ope_de_ventilation = 0;
  account = find_imported_account_by_name ( split -> account );
  if ( account )
    account -> operations_importees = g_slist_append ( account -> operations_importees, transaction );

  /** Splits of transactions are handled the same way, we process
      them if we find more than one split in transaction node. */
  if ( g_slist_length ( split_list ) > 1 )
    {
      transaction -> operation_ventilee = 1;
      transaction -> montant = total;

      while ( split_list )
	{
	  split = split_list -> data;
	  account = NULL;

	  transaction = new_transaction_from_split ( split, tiers, date );
	  transaction -> ope_de_ventilation = 1;

	  account = find_imported_account_by_name ( split -> account );
	  if ( account )
	    account -> operations_importees = g_slist_append ( account -> operations_importees, transaction );

	  split_list = split_list -> next;
	}
    }
}
void Search_Range::nearest_sphere_recurse( One_Tree *tree )
{
  Near_Workspace &ws = near_workspace;

  // debug
  const bool debug = false;
  assert(ws._num_calls <  num_nodes() );
  ++ws._num_calls;
  
  const size_t d = tree->_d;
  double x_lo, x_hi;
  old_lo_hi(d, x_lo, x_hi);

  // walk until the path to x_lo and x_hi diverge
  // this might update x_lo and x_hi with a new closest
  Tree_Node *n = find_split( tree, x_lo, x_hi, true );

  if (debug)
  {
    std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
    std::cout << "Diverges at node ";
    Range_Tree::print_single_node( n, tree );
    // std::cout << std::endl;
  }

  // never split, nothing is in range
  if (!n)
  {
    if (debug)
      std::cout << " no nearest sphere was in range." << std::endl;
    return;
  }

  // If n is a leaf, then immediately recurse by dimension on its subtree.
  // For efficiency we just check the distance immediately, since the result is the same.
  if (n->is_leaf())
  {
    if (debug)
      std::cout << " fathomed at leaf node." << std::endl;
    new_lo_hi( n->_sphere, d, x_lo, x_hi);
    return;
  }

  // go down right and left sides, checking subtrees
  // right
  {
    if (debug)
    {
      std::cout << "  Searching Right subtree " << std::endl;
    }
    Tree_Node * r = n->_right;
    while( r )
    {
      new_old_lo_hi( r->_sphere, d, x_lo, x_hi);

      const double &x = _spheres[ r->_sphere ][ d ];
      
      if ( r->is_leaf() )
        break;

      // discard right->right?
      if ( x > x_hi )
        r = r->_left;
      else
      {
        // recurse on left
        if (r->_left->_subtree)
        {
          if (debug) std::cout << "recursively searching left subtree. " << std::endl;
          nearest_sphere_recurse( r->_left->_subtree );
        }
        // fathomed at last dimension
        else
        {
          if (debug)
          {
            std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
            std::cout << " Nearest all leaves, left subtree, rooted at node ";
            print_single_node(r->_left, tree);
            std::cout << std::endl;
          }
          assert( last_dimension(tree) || r->_left->is_leaf() );
          // go down left (recurse) but with current dimension
          nearest_sphere_leaves( r->_left, d );
        }
        
        r = r->_right;
      }
    }
  }
  // left
  {
    if (debug)
    {
      std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
      std::cout << "Searching Left subtree " << std::endl;
    }
    Tree_Node * lft = n->_left;
    while( lft )
    {
      new_old_lo_hi( lft->_sphere, d, x_lo, x_hi);
      
      if (lft->is_leaf())
        break;

      const double &x = _spheres[ lft->_sphere ][ tree->_d ];
      if ( x_lo > x )
        lft = lft->_right;
      else
      {
        // right tree is (was) in the range
        if ( lft->_right )
        {
          if ( lft->_right->_subtree )
            nearest_sphere_recurse( lft->_right->_subtree );
          // fathomed at last dimension
          else
          {
            if (debug)
            {
              std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
              std::cout << " Nearest all leaves, right subtree, rooted at node ";
              print_single_node(lft->_right, tree);
              std::cout << std::endl;
            }
            assert( last_dimension(tree) || lft->_right->is_leaf() );
            // go down right (recurse) but with current dimension
            nearest_sphere_leaves( lft->_right, d );
          }
        }
        lft = lft->_left;
        // null if it was a leaf
      }
    }
  }
}
void Search_Range::trim_line_anchored_recurse( One_Tree *tree )
{

  // walk until the path to x_lo and x_hi diverge
  double x_lo, x_hi;
  Tree_Node *n = find_split( tree, x_lo, x_hi );

  // nothing was in range, no spheres near enough to possibly trim the line segment
  if (!n)
    return;

  // leaf, only one sphere in range, trim with it now
  if (n->is_leaf())
  {
    trim_leaf( n->_sphere );
    return;
  }

   // go down right and left sides
  // right
  {
    Tree_Node * r = n->_right;
    while( r )
    {
      assert( r->is_wellformed() );
      const double &x = _spheres[ r->_sphere ][ tree->_d ];
      if ( x_hi > x )
      {
        // left tree is in the range
        if ( r->_left )
        {
          assert( r->_left->is_wellformed() );
          if (r->_left->_subtree)
            trim_line_anchored_recurse( r->_left->_subtree );
          // fathomed at last dimension
          else
          {
            assert( last_dimension(tree)  );
            trim_all_leaves( r->_left );
            get_line_neighborhood( tree->_d, x_lo, x_hi );
          }
        }
        // leaf
        else
        {
          assert( r->is_leaf() );
          trim_leaf( r->_sphere );
          get_line_neighborhood( tree->_d, x_lo, x_hi );
        }
        r = r->_right;
        // null if it was a leaf
      }
      else
        r = r->_left;
        // if r == 0, then its parent was a leaf and out of range
    }
  }
  // left
  {
    Tree_Node * lft = n->_left;
    while( lft )
    {
      assert( lft->is_wellformed() );
      const double &x = _spheres[ lft->_sphere ][ tree->_d ];
      if ( x_lo <= x )
      {
        // right tree is in the range
        if ( lft->_right )
        {
          assert( lft->_right->is_wellformed() );
          if ( lft->_right->_subtree )
            trim_line_anchored_recurse( lft->_right->_subtree );
          // fathomed at last dimension
          else
          {
            assert( last_dimension(tree)  );
            trim_all_leaves( lft->_right );
            get_line_neighborhood( tree->_d, x_lo, x_hi );
          }
        }
        // leaf
        else
        {
          assert( lft->is_leaf() );
          trim_leaf( lft->_sphere );
          get_line_neighborhood( tree->_d, x_lo, x_hi );
        }
        lft = lft->_left; 
        // null if it was a leaf
      }
      else
      {
        lft = lft->_right;
        // if lft == 0, then its old value (parent) was a leaf and out of range
      }
    }
  }
}
bool Search_Range::no_near_spheres_recurse( One_Tree *tree ) 
{

  Near_Workspace &ws = near_workspace;

  // debug
  assert(ws._num_calls <= num_nodes() );
  ++ws._num_calls;
  
  double x_lo = ws._p[tree->_d] - ws._thresh;
  double x_hi = ws._p[tree->_d] + ws._thresh;

  // walk until the path to x_lo and x_hi diverge
  Tree_Node *n = find_split( tree, x_lo, x_hi);

  // nothing in range
  if (!n)
    return true;

  // only one sphere in range, check it now
  if (n->is_leaf())
    return no_near_leaf(n->_sphere);

  // go down right and left sides
  // right
  {
    Tree_Node * r = n->_right;
    while( r )
    {
      assert( r->is_wellformed() );
      const double &x = _spheres[ r->_sphere ][ tree->_d ];
      if ( x_hi > x )
      {
        // left tree is in the range
        if ( r->_left )
        {
          assert( r->_left->is_wellformed() );
          if (r->_left->_subtree)
          {
            if (!no_near_spheres_recurse( r->_left->_subtree ))
              return false;
          }
          // fathomed at last dimension
          else
          {
            assert( last_dimension(tree)  );
            // check entire subtree explicitly
            if (!no_near_leaves( r->_left ))
              return false;
          }
        }
        // leaf
        else
        {
          // check leaf sphere
          assert(r->is_leaf());
          if (!no_near_leaf( r->_sphere ))
            return false;
        }
        r = r->_right;
        // null if it was a leaf
      }
      else
        r = r->_left;
        // if r == 0, then its parent was a leaf and out of range
    }
  }
  // left
  {
    Tree_Node * lft = n->_left;
    while( lft )
    {
      assert( lft->is_wellformed() );
      const double &x = _spheres[ lft->_sphere ][ tree->_d ];
      if ( x_lo <= x )
      {
        // right tree is in the range
        if ( lft->_right )
        {
          assert( lft->is_wellformed() );
          if ( lft->_right->_subtree )
          {
            if (!no_near_spheres_recurse( lft->_right->_subtree ))
              return false;
          }
          // fathomed at last dimension
          else
          {
            assert( last_dimension(tree)  );
            if (!no_near_leaves( lft->_right ))
              return false;
          }
        }
        // leaf
        else
        {
          assert( lft->is_leaf() );
          if (!no_near_leaf( lft->_sphere ))
            return false;
        }
        lft = lft->_left; 
        // null if it was a leaf
      }
      else
      {
        lft = lft->_right;
        // if lft == 0, then its old value (parent) was a leaf and out of range
      }
    }
  }
  return true;
}
void Search_Range::all_near_spheres_recurse( One_Tree *tree )
{
  const bool debug = false;
  
  Near_Workspace &ws = near_workspace;

  // debug
  assert(ws._num_calls <  num_nodes() );
  ++ws._num_calls;
  
  const size_t d = tree->_d;
  double x_lo = ws._p[d] - ws._thresh;
  double x_hi = ws._p[d] + ws._thresh;

  // walk until the path to x_lo and x_hi diverge
  Tree_Node *n = find_split( tree, x_lo, x_hi );
  if (debug)
  {
    std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
    std::cout << "Diverges at node ";
    Range_Tree::print_single_node( n, tree );
    // std::cout << std::endl;
  }

  // never split, nothing is in range
  if (!n)
  {
    if (debug)
      std::cout << " no spheres were in range." << std::endl;
    return;
  }

  // If n is a leaf, then immediately recurse by dimension on its subtree.
  // For efficiency we just check the distance immediately, since the result is the same.
  if (n->is_leaf())
  {
    if (debug)
      std::cout << " fathomed at leaf node." << std::endl;
    add_leaf(n->_sphere);
    return;
  }

    // go down right and left sides, reporting subtrees
  // right
  {
    if (debug)
    {
      std::cout << "  Searching Right subtree " << std::endl;
    }
    Tree_Node * r = n->_right;
    while( r )
    {
      const double &x = _spheres[ r->_sphere ][ d ];
      if ( x_hi > x )
      {
        // left tree is in the range
        if ( r->_left )
        {
          if (r->_left->_subtree)
            all_near_spheres_recurse( r->_left->_subtree );
          // fathomed at last dimension
          else
          {
            if (debug)
            {
              std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
              std::cout << " Adding left subtree rooted at node ";
              print_single_node(r->_left, tree);
              std::cout << std::endl;
            }
            assert( last_dimension(tree) || r->_left->is_leaf() );
            add_all_leaves( r->_left );
          }
        }
        // leaf
        else
        {
          assert( r->is_leaf() );
          if (debug)
          {
            std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
            std::cout << " Adding leaf node ";
            print_single_node(r, tree);
            std::cout << std::endl;
          }
          add_leaf( r->_sphere );
        }
        r = r->_right;
        // null if it was a leaf
      }
      else
        r = r->_left;
        // if r == 0, then its parent was a leaf and out of range
    }
  }
  // left
  {
    if (debug)
    {
      std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
      std::cout << "Searching Left subtree " << std::endl;
    }
    Tree_Node * lft = n->_left;
    while( lft )
    {
      const double &x = _spheres[ lft->_sphere ][ tree->_d ];
      if ( x_lo <= x )
      {
        // right tree is in the range
        if ( lft->_right )
        {
          if ( lft->_right->_subtree )
            all_near_spheres_recurse( lft->_right->_subtree );
          // fathomed at last dimension
          else
          {
            if (debug)
            {
              std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
              std::cout << " Adding right subtree rooted at node ";
              print_single_node(lft->_right, tree);
              std::cout << std::endl;
            }
            assert( last_dimension(tree) || lft->_right->is_leaf() );
            add_all_leaves( lft->_right );
          }
        }
        // leaf
        else
        {
          assert( lft->is_leaf() );
          if (debug)
          {
            std::cout << "Search_Range [" << x_lo << ", " << x_hi << "] coordinate " << tree->_d << ". ";
            std::cout << " Adding leaf node ";
            print_single_node(lft, tree);
            std::cout << std::endl;
          }
          add_leaf( lft->_sphere );
        }
        lft = lft->_left; 
        // null if it was a leaf
      }
      else
      {
        lft = lft->_right;
        // if lft == 0, then its old value (parent) was a leaf and out of range
      }
    }
  }
}