docstr: Remove `existing_ops` (list[Operation]) that must be pre-existing in
  the block. Error if any other op in the block uses output Vars of
  `existing_ops`
docstr_tok: ["Remove","`","existing_ops","`","(","list","[","Operation","]",")","that","must","be","pre-existing","in","the","block",".","Error","if","any","other","op","in","the","block","uses","output","Vars","of","`","existing_ops","`"]
code: def remove_ops(self, existing_ops):
      """
      Remove `existing_ops` (list[Operation]) that must be pre-existing in
      the block. Error if any other op in the block uses output Vars of
      `existing_ops`
      """
      self.validate()
      idxs = [-1] * len(existing_ops)
      existing_ops_set = set(existing_ops)
      for i, op in enumerate(self.operations):
          if op in existing_ops_set:
              idxs[existing_ops.index(op)] = i
      if -1 in idxs:
          not_found = []
          for i, op in zip(idxs, existing_ops):
              if i == -1:
                  not_found.append(op.name)
          raise ValueError(
              "Ops {} not found in block {}".format(
                  not_found, self.name
              )
          )
  
      # Remove ops in reverse topological order
      pairs = list(zip(idxs, existing_ops))
      pairs.sort(key=lambda x: x[0], reverse=True)
  
      for idx, op in pairs:
          for i, v in enumerate(op.outputs):
              # Check that no ops depend on op's outputs
              if len(v.child_ops) > 0:
                  child_op_names = [s.name for s in v.child_ops]
                  msg = (
                      "Cannot delete op '{}' with active output at id {}: '{}' "
                      + "used by ops {}"
                  )
                  raise ValueError(
                      msg.format(op.name, i, v.name, child_op_names)
                  )
              # Check that the output Var isn't block's output
              if v in self._outputs:
                  msg = (
                      "cannot delete op {} with output {}: {} "
                      + "that's block {}'s output"
                  )
                  raise ValueError(
                      msg.format(op.name, i, v.name, self.name)
                  )
  
          for b in op.blocks:
              b.set_outputs([])
              b.remove_ops(b.operations)
  
          # remove the op (in reverse topological order)
          self.operations.pop(idx)
          op.enclosing_block = None
  
          for v in op.inputs.values():
              if isinstance(v, (tuple, list)):
                  for vv in v:
                      vv.remove_child_op(op)
              else:
                  v.remove_child_op(op)
  
imports: from collections import Counter, OrderedDict
  import copy
  import logging
  import numpy
  from six import string_types
  from .None import SPACES, types
  from .var import Var, InternalVar, ListVar
  from .visitors.dot_visitor import DotVisitor
  from .types.symbolic import k_used_symbols, k_num_internal_syms, any_symbolic, is_symbolic
  from .input_type import TupleInputType
label_desc: Use image node_id 17 for calling the Block obj's underlying member method code with example usage: obj.remove_ops(existing_ops) without return types