class_docstr: Like :py:class:`SingleCounter`, but bootstrap capable.
  
  **Attributes**:
  
  - ``logZ``, ``logZerr``, ``logVolremaining``: main estimator
    ``logZerr`` is probably not reliable, because it needs ``nlive``
    to convert ``H`` to ``logZerr``.
  - ``Lmax``: highest loglikelihood currently known
  - ``logZ_bs``, ``logZerr_bs``: bootstrapped logZ estimate
  - ``logZremain``, ``remainder_ratio``: weight and fraction of the unexplored remainder
  
  Each of the following has as many entries as number of iterations:
  
  - ``all_H``, ``all_logZ``, ``all_logVolremaining``, ``logweights``:
    information for all instances
    first entry is the main estimator, i.e., not bootstrapped
  - ``istail``: whether that node was a leaf.
  - ``nlive``: number of parallel arcs ("live points")
class_docstr_tok: ["Like",":","py",":","class",":","`","SingleCounter","`",",","but","bootstrap","capable",".","*","*","Attributes","*","*",":","-","``","logZ","``",",","``","logZerr","``",",","``","logVolremaining","``",":","main","estimator","``","logZerr","``","is","probably","not","reliable",",","because","it","needs","``","nlive","``","to","convert","``","H","``","to","``","logZerr","``",".","-","``","Lmax","``",":","highest","loglikelihood","currently","known","-","``","logZ_bs","``",",","``","logZerr_bs","``",":","bootstrapped","logZ","estimate","-","``","logZremain","``",",","``","remainder_ratio","``",":","weight","and","fraction","of","the","unexplored","remainder","Each","of","the","following","has","as","many","entries","as","number","of","iterations",":","-","``","all_H","``",",","``","all_logZ","``",",","``","all_logVolremaining","``",",","``","logweights","``",":","information","for","all","instances","first","entry","is","the","main","estimator",",","i.e.",",","not","bootstrapped","-","``","istail","``",":","whether","that","node","was","a","leaf",".","-","``","nlive","``",":","number","of","parallel","arcs","(","``","live","points","''",")"]
docstr: Accumulate node to the integration.
  
  Breadth-first removed `node` and nodes active next to node (`parallel_nodes`).
  rootid and rootids are needed to identify which bootstrap instance
  should accumulate.
  
  Parameters
  ----------
  rootid: :py:class:`TreeNode`
      root node this `node` is from.
  node: :py:class:`TreeNode`
      node being processed.
  rootids: array of ints
      for each parallel node, which root it belongs to.
  parallel_values: float array
      loglikelihood values of nodes passing `node`.
docstr_tok: ["Accumulate","node","to","the","integration",".","Breadth-first","removed","`","node","`","and","nodes","active","next","to","node","(","`","parallel_nodes","`",")",".","rootid","and","rootids","are","needed","to","identify","which","bootstrap","instance","should","accumulate",".","Parameters","--","--","--","--","--","rootid",":",":","py",":","class",":","`","TreeNode","`","root","node","this","`","node","`","is","from",".","node",":",":","py",":","class",":","`","TreeNode","`","node","being","processed",".","rootids",":","array","of","ints","for","each","parallel","node",",","which","root","it","belongs","to",".","parallel_values",":","float","array","loglikelihood","values","of","nodes","passing","`","node","`","."]
code: def passing_node(self, rootid, node, rootids, parallel_values):
      """Accumulate node to the integration.
  
      Breadth-first removed `node` and nodes active next to node (`parallel_nodes`).
      rootid and rootids are needed to identify which bootstrap instance
      should accumulate.
  
      Parameters
      ----------
      rootid: :py:class:`TreeNode`
          root node this `node` is from.
      node: :py:class:`TreeNode`
          node being processed.
      rootids: array of ints
          for each parallel node, which root it belongs to.
      parallel_values: float array
          loglikelihood values of nodes passing `node`.
  
      """
      # node is being consumed
      # we have parallel arcs to parallel_nodes
  
      assert not isinstance(rootid, float)
      nchildren = len(node.children)
      Li = node.value
      # in which bootstraps is rootid?
      active = self.rootids[:, rootid]
      # how many live points does each bootstrap have?
      nlive = self.rootids[:, rootids].sum(axis=1)
      nlive0 = nlive[0]
  
      if nchildren >= 1:
          # one arc terminates, another is spawned
  
          # weight is the size of the slice off the volume
          if self.random:
              randompoint = np.random.beta(
                  1, nlive, size=self.ncounters
              )
              logleft = log(randompoint)
              logright = log1p(-randompoint)
              logleft[0] = log1p(-exp(-1.0 / nlive0))
              logright[0] = -1.0 / nlive0
          else:
              logleft = log1p(-exp(-1.0 / nlive))
              logright = -1.0 / nlive
  
          logwidth = logleft + self.all_logVolremaining
          logwidth[~active] = -np.inf
          wi = logwidth[active] + Li
          self.logweights.append(logwidth)
          self.istail.append(False)
  
          # print("updating continuation...", Li)
          assert active[0], (active, rootid)
          logZ = self.all_logZ[active]
          logZnew = logaddexp(logZ, wi)
          H = (
              exp(wi - logZnew) * Li
              + exp(logZ - logZnew) * (self.all_H[active] + logZ)
              - logZnew
          )
          first_setting = np.isnan(H)
          # print()
          # print("Hnext:", H[0], first_setting[0])
          assert np.isfinite(H[~first_setting]).all(), (
              first_setting,
              self.all_H[active][~first_setting],
              H,
              wi,
              logZnew,
              Li,
              logZ,
          )
          self.all_logZ[active] = np.where(first_setting, wi, logZnew)
          # print("logZ:", self.all_logZ[0])
          if first_setting[0]:
              assert np.all(np.isfinite(Li - wi)), (Li, wi)
          else:
              assert np.isfinite(self.all_H[0]), self.all_H[0]
              assert np.isfinite(H[0]), (
                  first_setting[0],
                  H[0],
                  self.all_H[0],
                  wi[0],
                  logZnew[0],
                  Li,
                  logZ[0],
              )
          self.all_H[active] = np.where(
              first_setting, -logwidth[active], H
          )
          # print("H:", self.all_H)
          assert np.isfinite(self.all_H[active]).all(), (
              self.all_H[active],
              first_setting[0],
              H[0],
              self.all_H[0],
              wi[0],
              logZnew[0],
              Li,
              logZ[0],
          )
          # assert np.all(np.isfinite(self.all_H[active])), (H, self.all_H[active], wi, logZnew, Li, logZ)
          self.logZ = self.all_logZ[0]
          assert np.all(
              np.isfinite(self.all_logZ[active])
          ), self.all_logZ[active]
  
          # self.Lmax = max((n.value for n in parallel_nodes))
          # print("L=%.1f N=%d V=%.2e logw=%.2e logZ=%.1f logZremain=%.1f" % (
          #  Li, nlive[0], self.logVolremaining, wi[0], self.logZ, logZremain))
          # print("L=%.1f N=%d V=%.2e logw=%.2e logZ=%.1f logZremain=%.1f" % (
          #  Li, nlive[0], self.all_logVolremaining[0], (logwidth + Li)[0], self.all_logZ[0], logZremain))
          # print("L=%.1f N=%d V=%.2e logw=%.2e logZ=<%.1f logZremain=%.1f" % (
          #  Li, nlive[1], self.all_logVolremaining[1], (logwidth + Li)[1], self.all_logZ[1], logZremain))
  
          if self.all_H[0] > 0:
              # TODO: this needs to change if nlive varies
              self.logZerr = (self.all_H[0] / nlive0) ** 0.5
          # assert np.all(np.isfinite(self.logZerr)), (self.logZerr, self.all_H[0], nlive)
  
          # volume is reduced by exp(-1/N)
          self.all_logVolremaining[active] += logright[active]
          self.logVolremaining = self.all_logVolremaining[0]
  
          if self.check_insertion_order and len(
              np.unique(parallel_values)
          ) == len(parallel_values):
              acc = self.insertion_order_accumulator
              parallel_values_here = parallel_values[
                  self.rootids[0, rootids]
              ]
              for child in node.children:
                  # rootids is 400 ints pointing to the root id where each parallel_values is from
                  # self.rootids[i] says which rootids belong to this bootstrap
                  # need which of the parallel_values are active here
                  acc.add(
                      (parallel_values_here < child.value).sum(), nlive0
                  )
                  if abs(acc.zscore) > self.insertion_order_threshold:
                      self.insertion_order_runs.append(len(acc))
                      acc.reset()
  
      else:
          # contracting!
          # print("contracting...", Li)
  
          # weight is simply volume / Nlive
          logwidth = -np.inf * np.ones(self.ncounters)
          logwidth[active] = self.all_logVolremaining[active] - log(
              nlive[active]
          )
          wi = logwidth + Li
  
          self.logweights.append(logwidth)
          self.istail.append(True)
          self.all_logZ[active] = logaddexp(
              self.all_logZ[active], wi[active]
          )
          self.logZ = self.all_logZ[0]
  
          # print("L=%.1f N=%d V=%.2e logw=%.2e logZ=%.1f" % (Li, nlive, self.logVolremaining, wi, self.logZ))
  
          # the volume shrinks by (N - 1) / N
          # self.logVolremaining += log(1 - exp(-1. / nlive))
          # if nlive = 1, we are removing the last point, so remaining
          # volume is zero (leads to log of -inf, as expected)
          with np.errstate(divide="ignore"):
              self.all_logVolremaining[active] += log1p(
                  -1.0 / nlive[active]
              )
          self.logVolremaining = self.all_logVolremaining[0]
  
      V = self.all_logVolremaining - log(nlive0)
      Lmax = np.max(parallel_values)
      self.all_logZremain = (
          V + log(np.sum(exp(parallel_values - Lmax))) + Lmax
      )
      self.logZremainMax = self.all_logZremain.max()
      self.logZremain = self.all_logZremain[0]
      with np.errstate(over="ignore", under="ignore"):
          self.remainder_ratio = exp(self.logZremain - self.logZ)
          self.remainder_fraction = 1.0 / (
              1 + exp(self.logZ - self.logZremain)
          )
  
imports: import numpy
  from numpy import log, log1p, exp, logaddexp
  import math
  import sys
  from .utils import resample_equal
  from .ordertest import UniformOrderAccumulator
label_desc: Use image node_id 7 for calling the MultiCounter obj's underlying member method code with example usage: obj.passing_node(rootid, node, rootids, parallel_values) without return types