def _StopOps(from_ops, stop_gradient_ops, pending_count):
  """The set of ops that terminate the gradient computation.

  This computes the frontier of the forward graph *before* which backprop
  should stop. Operations in the returned set will not be differentiated.
  This set is defined as the subset of `from_ops` containing ops that have
  no predecessor in `from_ops`. `pending_count` is the result of
  `_PendingCount(g, xs, from_ops)`. An 'op' has predecessors in `from_ops`
  iff pending_count[op._id] > 0.

  In addition, none of `stop_gradient_ops` will be differentiated.

  Args:
    from_ops: list of Operations.
    stop_gradient_ops: list of Operations never to backprop through.
    pending_count: List of integers, indexed by operation id.

  Returns:
    The set of operations.
  """
  stop_ops = set()
  for op in from_ops:
    is_stop_op = True
    for inp in op.inputs:
      if pending_count[inp.op._id] > 0:
        is_stop_op = False
        break
    if is_stop_op:
      stop_ops.add(op._id)
  stop_ops.update(op._id for op in stop_gradient_ops)  # pylint: disable=protected-access
  return stop_ops