class_docstr: Nested sampler with reactive exploration strategy.
  
  Storage & resume capable, optionally MPI parallelised.
class_docstr_tok: ["Nested","sampler","with","reactive","exploration","strategy",".","Storage","&","resume","capable",",","optionally","MPI","parallelised","."]
docstr: Ensure that at parents have `nnodes_needed` live points (parallel arcs).
  
  If not, fill up by sampling.
docstr_tok: ["Ensure","that","at","parents","have","`","nnodes_needed","`","live","points","(","parallel","arcs",")",".","If","not",",","fill","up","by","sampling","."]
code: def _widen_nodes(
      self,
      weighted_parents,
      weights,
      nnodes_needed,
      update_interval_ncall,
  ):
      """Ensure that at parents have `nnodes_needed` live points (parallel arcs).
  
      If not, fill up by sampling.
      """
      ndone = len(weighted_parents)
      if ndone == 0:
          if self.log:
              self.logger.info("No parents, so widening roots")
          self._widen_roots(nnodes_needed)
          return {}
  
      # select parents with weight 1/parent_weights
      p = 1.0 / np.array(weights)
      if (p == p[0]).all():
          parents = weighted_parents
      else:
          # preferentially select nodes with few parents, as those
          # have most weight
          i = np.random.choice(
              len(weighted_parents), size=nnodes_needed, p=p / p.sum()
          )
          if self.use_mpi:
              i = self.comm.bcast(i, root=0)
  
          parents = [weighted_parents[ii] for ii in i]
  
      del weighted_parents, weights
  
      # sort from low to high
      parents.sort(key=operator.attrgetter("value"))
      Lmin = parents[0].value
      if np.isinf(Lmin):
          # some of the parents were born by sampling from the entire
          # prior volume. So we can efficiently apply a solution:
          # expand the roots
          if self.log:
              self.logger.info(
                  "parent value is -inf, so widening roots"
              )
          self._widen_roots(nnodes_needed)
          return {}
  
      # double until we reach the necessary points
      # this is probably 1, from (2K - K) / K
      nsamples = int(np.ceil((nnodes_needed - ndone) / len(parents)))
  
      if self.log:
          self.logger.info(
              "Will add %d live points (x%d) at L=%.1g ...",
              nnodes_needed - ndone,
              nsamples,
              Lmin,
          )
  
      # add points where necessary (parents can have multiple entries)
      target_min_num_children = {}
      for n in parents:
          orign = target_min_num_children.get(n.id, len(n.children))
          target_min_num_children[n.id] = orign + nsamples
  
      return target_min_num_children
  
imports: from __future__ import print_function, division
  import os
  import sys
  import csv
  import json
  import operator
  import time
  import warnings
  from numpy import log, exp, logaddexp
  import numpy
  from .utils import create_logger, make_run_dir, resample_equal, vol_prefactor, vectorize, listify
  from .utils import is_affine_transform, normalised_kendall_tau_distance, distributed_work_chunk_size
  from ultranest.mlfriends import MLFriends, AffineLayer, ScalingLayer, find_nearby, WrappingEllipsoid, RobustEllipsoidRegion
  from .store import HDF5PointStore, TextPointStore, NullPointStore
  from .viz import get_default_viz_callback
  from .ordertest import UniformOrderAccumulator
  from .netiter import PointPile, SingleCounter, MultiCounter, BreadthFirstIterator, TreeNode, count_tree_between, find_nodes_before, logz_sequence
  from .netiter import dump_tree, combine_results
  from .hotstart import get_auxiliary_contbox_parameterization
label_desc: Use image node_id 5 for calling the ReactiveNestedSampler obj's underlying member method code with example usage: obj._widen_nodes(weighted_parents, weights, nnodes_needed, update_interval_ncall) and returns: target_min_num_children, dict, dict