class_docstr: PipelineEngine class that computes each term independently.
  
  Parameters
  ----------
  get_loader : callable
      A function that is given a loadable term and returns a PipelineLoader
      to use to retrieve raw data for that term.
  calendar : DatetimeIndex
      Array of dates to consider as trading days when computing a range
      between a fixed start and end.
  asset_finder : catalyst.assets.AssetFinder
      An AssetFinder instance.  We depend on the AssetFinder to determine
      which assets are in the top-level universe at any point in time.
  populate_initial_workspace : callable, optional
      A function which will be used to populate the initial workspace when
      computing a pipeline. See
      :func:`catalyst.pipeline.engine.default_populate_initial_workspace`
      for more info.
  
  See Also
  --------
  :func:`catalyst.pipeline.engine.default_populate_initial_workspace`
docstr: Compute a lifetimes matrix from our AssetFinder, then drop columns that
  didn't exist at all during the query dates.
  
  Parameters
  ----------
  start_date : pd.Timestamp
      Base start date for the matrix.
  end_date : pd.Timestamp
      End date for the matrix.
  extra_rows : int
      Number of extra rows to compute before `start_date`.
      Extra rows are needed by terms like moving averages that require a
      trailing window of data.
  
  Returns
  -------
  lifetimes : pd.DataFrame
      Frame of dtype `bool` containing dates from `extra_rows` days
      before `start_date`, continuing through to `end_date`.  The
      returned frame contains as columns all assets in our AssetFinder
      that existed for at least one day between `start_date` and
      `end_date`.
docstr_tok: ["Compute","a","lifetimes","matrix","from","our","AssetFinder",",","then","drop","columns","that","did","n't","exist","at","all","during","the","query","dates",".","Parameters","--","--","--","--","--","start_date",":","pd.Timestamp","Base","start","date","for","the","matrix",".","end_date",":","pd.Timestamp","End","date","for","the","matrix",".","extra_rows",":","int","Number","of","extra","rows","to","compute","before","`","start_date","`",".","Extra","rows","are","needed","by","terms","like","moving","averages","that","require","a","trailing","window","of","data",".","Returns","--","--","--","-","lifetimes",":","pd.DataFrame","Frame","of","dtype","`","bool","`","containing","dates","from","`","extra_rows","`","days","before","`","start_date","`",",","continuing","through","to","`","end_date","`",".","The","returned","frame","contains","as","columns","all","assets","in","our","AssetFinder","that","existed","for","at","least","one","day","between","`","start_date","`","and","`","end_date","`","."]
code: def _compute_root_mask(self, start_date, end_date, extra_rows):
      """
      Compute a lifetimes matrix from our AssetFinder, then drop columns that
      didn't exist at all during the query dates.
  
      Parameters
      ----------
      start_date : pd.Timestamp
          Base start date for the matrix.
      end_date : pd.Timestamp
          End date for the matrix.
      extra_rows : int
          Number of extra rows to compute before `start_date`.
          Extra rows are needed by terms like moving averages that require a
          trailing window of data.
  
      Returns
      -------
      lifetimes : pd.DataFrame
          Frame of dtype `bool` containing dates from `extra_rows` days
          before `start_date`, continuing through to `end_date`.  The
          returned frame contains as columns all assets in our AssetFinder
          that existed for at least one day between `start_date` and
          `end_date`.
      """
      calendar = self._calendar
      finder = self._finder
      start_idx, end_idx = self._calendar.slice_locs(
          start_date, end_date
      )
      if start_idx < extra_rows:
          raise NoFurtherDataError.from_lookback_window(
              initial_message="Insufficient data to compute Pipeline:",
              first_date=calendar[0],
              lookback_start=start_date,
              lookback_length=extra_rows,
          )
  
      # Build lifetimes matrix reaching back to `extra_rows` days before
      # `start_date.`
      lifetimes = finder.lifetimes(
          calendar[start_idx - extra_rows : end_idx],
          include_start_date=False,
      )
  
      assert lifetimes.index[extra_rows] == start_date
      assert lifetimes.index[-1] == end_date
      if not lifetimes.columns.unique:
          columns = lifetimes.columns
          duplicated = columns[columns.duplicated()].unique()
          raise AssertionError("Duplicated sids: %d" % duplicated)
  
      # Filter out columns that didn't exist between the requested start and
      # end dates.
      existed = lifetimes.iloc[extra_rows:].any()
      ret = lifetimes.loc[:, existed]
      shape = ret.shape
      assert shape[0] * shape[1] != 0, "root mask cannot be empty"
      return ret
  
imports: from abc import ABCMeta, abstractmethod
  from uuid import uuid4
  import six
  from six import iteritems, with_metaclass
  from numpy import array
  from pandas import DataFrame, MultiIndex
  from toolz import groupby, juxt
  from toolz.curried.operator import getitem
  from catalyst.lib.adjusted_array import ensure_adjusted_array, ensure_ndarray
  from catalyst.errors import NoFurtherDataError
  from catalyst.utils.numpy_utils import as_column, repeat_first_axis, repeat_last_axis
  from catalyst.utils.pandas_utils import explode
  from .term import AssetExists, InputDates, LoadableTerm
  from catalyst.utils.date_utils import compute_date_range_chunks
  from catalyst.utils.pandas_utils import categorical_df_concat
  from catalyst.utils.sharedoc import copydoc
label_desc: Use image node_id 4 for calling the SimplePipelineEngine obj's underlying member method code with example usage: obj._compute_root_mask(start_date, end_date, extra_rows) and returns: ret