docstr: A private API used by builder. Please use `builder.YOUR_OP(...,before_op)`.
  
  new_op's outputs are not used (not input to any other op) after
  this call. All inputs to new_op must be visible at or before
  the before_op (i.e., new_op must be added in topologically sorted
  order). Note that this is more restrictive than MIL, whose Block
  supports lexical scoping and thus an op can reference Var in enclosing
  scopes. new_op.name must be unique in the block.
  
  before_op=None to append new_op at the end of self.operations.
  
  Given:   %2 = op0(%1, %1)
           %4 = op2(%1)
           %6 = op3(%4, %4)
  
  Execute: insert_op_before(op1, before_op=op2),
           where %3 = op1(%1, %2)
  
  Result:  %2 = op0(%1, %1)
           %3 = op1(%1, %2)
           %4 = op2(%1)
           %6 = op3(%4, %4)
  
  Comment: We assume op1 has been constructed outside the block with
  %1, %2 as inputs. Typically it's builder's job to create an op and
  insert into the current block.
  
  Comment: insert_op_before(op1, before_op=op0) would error as %2 (an input to op1)
  is not visible before op0.
docstr_tok: ["A","private","API","used","by","builder",".","Please","use","`","builder.YOUR_OP","(","...",",","before_op",")","`",".","new_op","'s","outputs","are","not","used","(","not","input","to","any","other","op",")","after","this","call",".","All","inputs","to","new_op","must","be","visible","at","or","before","the","before_op","(","i.e.",",","new_op","must","be","added","in","topologically","sorted","order",")",".","Note","that","this","is","more","restrictive","than","MIL",",","whose","Block","supports","lexical","scoping","and","thus","an","op","can","reference","Var","in","enclosing","scopes",".","new_op.name","must","be","unique","in","the","block",".","before_op=None","to","append","new_op","at","the","end","of","self.operations",".","Given",":","%","2","=","op0","(","%","1",",","%","1",")","%","4","=","op2","(","%","1",")","%","6","=","op3","(","%","4",",","%","4",")","Execute",":","insert_op_before","(","op1",",","before_op=op2",")",",","where","%","3","=","op1","(","%","1",",","%","2",")","Result",":","%","2","=","op0","(","%","1",",","%","1",")","%","3","=","op1","(","%","1",",","%","2",")","%","4","=","op2","(","%","1",")","%","6","=","op3","(","%","4",",","%","4",")","Comment",":","We","assume","op1","has","been","constructed","outside","the","block","with","%","1",",","%","2","as","inputs",".","Typically","it","'s","builder","'s","job","to","create","an","op","and","insert","into","the","current","block",".","Comment",":","insert_op_before","(","op1",",","before_op=op0",")","would","error","as","%","2","(","an","input","to","op1",")","is","not","visible","before","op0","."]
code: def _insert_op_before(self, new_op, before_op=None):
      """
      A private API used by builder. Please use `builder.YOUR_OP(...,before_op)`.
  
      new_op's outputs are not used (not input to any other op) after
      this call. All inputs to new_op must be visible at or before
      the before_op (i.e., new_op must be added in topologically sorted
      order). Note that this is more restrictive than MIL, whose Block
      supports lexical scoping and thus an op can reference Var in enclosing
      scopes. new_op.name must be unique in the block.
  
      before_op=None to append new_op at the end of self.operations.
  
      Given:   %2 = op0(%1, %1)
               %4 = op2(%1)
               %6 = op3(%4, %4)
  
      Execute: insert_op_before(op1, before_op=op2),
               where %3 = op1(%1, %2)
  
      Result:  %2 = op0(%1, %1)
               %3 = op1(%1, %2)
               %4 = op2(%1)
               %6 = op3(%4, %4)
  
      Comment: We assume op1 has been constructed outside the block with
      %1, %2 as inputs. Typically it's builder's job to create an op and
      insert into the current block.
  
      Comment: insert_op_before(op1, before_op=op0) would error as %2 (an input to op1)
      is not visible before op0.
      """
      self.validate()
      visible_vars = self._visible_vars_from_enclosing_block()
      if before_op is not None:
          idx, visible_vars_in_block = self._visible_vars_in_block(
              before_op, inclusive=True
          )
          visible_vars.update(visible_vars_in_block)
      else:
          _, visible_vars_in_block = self._visible_vars_in_block()
          visible_vars.update(visible_vars_in_block)
  
      # check inputs are visible
      for k, v in new_op.inputs.items():
          if not isinstance(v, (Var, tuple)):
              continue
          if isinstance(v, Var):
              vs = [v]
          else:
              vs = v
          for s in vs:
              if s not in visible_vars:
                  before_op_name = (
                      before_op.name
                      if before_op is not None
                      else "None"
                  )
                  msg = "Op '{}' input {}={} is not in scope of {} before {}"
                  raise ValueError(
                      msg.format(
                          new_op.name,
                          k,
                          s.name,
                          self.name,
                          before_op_name,
                      )
                  )
  
      # add new_op
      if before_op is None:
          self.operations.append(new_op)
      else:
          self.operations.insert(idx, new_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 14 for calling the Block obj's underlying member method code with example usage: obj._insert_op_before(new_op, before_op) without return types