class_docstr: This is an identity-like op with the side effect of enforcing a
  conditional breakpoint, inside an PyTensor function, based on a symbolic
  scalar condition. It automatically detects available debuggers and uses
  the first available in the following order: `pudb`, `ipdb`, or `pdb`.
  
  :type name: String
  :param name: name of the conditional breakpoint. To be printed when the
               breakpoint is activated.
  
  :note: WARNING. At least one of the outputs of the op must be used
                  otherwise the op will be removed from the PyTensor graph
                  due to its outputs being unused
  
  :note: WARNING. Employing the function inside an PyTensor graph can prevent
                  PyTensor from applying certain optimizations to improve
                  performance, reduce memory consumption and/or reduce
                  numerical instability.
  
          Detailed explanation:
          As of 2014-12-01 the PdbBreakpoint op is not known by any
          optimization. Setting a PdbBreakpoint op in the middle of a
          pattern that is usually optimized out will block the optimization.
  
  Example:
  
  .. code-block:: python
  
      import pytensor
      import pytensor.tensor as pt
      from pytensor.breakpoint import PdbBreakpoint
  
      input = pt.fvector()
      target = pt.fvector()
  
      # Mean squared error between input and target
      mse = (input - target) ** 2
  
      # Conditional breakpoint to be activated if the total MSE is higher
      # than 100. The breakpoint will monitor the inputs, targets as well
      # as the individual error values
      breakpointOp = PdbBreakpoint("MSE too high")
      condition = pt.gt(mse.sum(), 100)
      mse, monitored_input, monitored_target = breakpointOp(condition, mse,
                                                            input, target)
  
      # Compile the pytensor function
      fct = pytensor.function([input, target], mse)
  
      # Use the function
      print fct([10, 0], [10, 5]) # Will NOT activate the breakpoint
      print fct([0, 0], [10, 5]) # Will activate the breakpoint
class_docstr_tok: ["This","is","an","identity-like","op","with","the","side","effect","of","enforcing","a","conditional","breakpoint",",","inside","an","PyTensor","function",",","based","on","a","symbolic","scalar","condition",".","It","automatically","detects","available","debuggers","and","uses","the","first","available","in","the","following","order",":","`","pudb","`",",","`","ipdb","`",",","or","`","pdb","`",".",":","type","name",":","String",":","param","name",":","name","of","the","conditional","breakpoint",".","To","be","printed","when","the","breakpoint","is","activated",".",":","note",":","WARNING",".","At","least","one","of","the","outputs","of","the","op","must","be","used","otherwise","the","op","will","be","removed","from","the","PyTensor","graph","due","to","its","outputs","being","unused",":","note",":","WARNING",".","Employing","the","function","inside","an","PyTensor","graph","can","prevent","PyTensor","from","applying","certain","optimizations","to","improve","performance",",","reduce","memory","consumption","and\/or","reduce","numerical","instability",".","Detailed","explanation",":","As","of","2014-12-01","the","PdbBreakpoint","op","is","not","known","by","any","optimization",".","Setting","a","PdbBreakpoint","op","in","the","middle","of","a","pattern","that","is","usually","optimized","out","will","block","the","optimization",".","Example",":","..","code-block",":",":","python","import","pytensor","import","pytensor.tensor","as","pt","from","pytensor.breakpoint","import","PdbBreakpoint","input","=","pt.fvector","(",")","target","=","pt.fvector","(",")","#","Mean","squared","error","between","input","and","target","mse","=","(","input","-","target",")","*","*","2","#","Conditional","breakpoint","to","be","activated","if","the","total","MSE","is","higher","#","than","100",".","The","breakpoint","will","monitor","the","inputs",",","targets","as","well","#","as","the","individual","error","values","breakpointOp","=","PdbBreakpoint","(","``","MSE","too","high","''",")","condition","=","pt.gt","(","mse.sum","(",")",",","100",")","mse",",","monitored_input",",","monitored_target","=","breakpointOp","(","condition",",","mse",",","input",",","target",")","#","Compile","the","pytensor","function","fct","=","pytensor.function","(","[","input",",","target","]",",","mse",")","#","Use","the","function","print","fct","(","[","10",",","0","]",",","[","10",",","5","]",")","#","Will","NOT","activate","the","breakpoint","print","fct","(","[","0",",","0","]",",","[","10",",","5","]",")","#","Will","activate","the","breakpoint"]
code: def perform(self, node, inputs, output_storage):
      condition = inputs[0]
  
      if condition:
          try:
              monitored = [np.asarray(inp) for inp in inputs[1:]]
          except Exception:
              raise ValueError(
                  "Some of the inputs to the PdbBreakpoint op "
                  "'%s' could not be casted to NumPy arrays" % self.name
              )
  
          print("\n")
          print("-------------------------------------------------")
          print(f"Conditional breakpoint '{self.name}' activated\n")
          print("The monitored variables are stored, in order,")
          print("in the list variable 'monitored' as NumPy arrays.\n")
          print("Their contents can be altered and, when execution")
          print("resumes, the updated values will be used.")
          print("-------------------------------------------------")
  
          try:
              import pudb
  
              pudb.set_trace()
          except ImportError:
              try:
                  import ipdb
  
                  ipdb.set_trace()
              except ImportError:
                  import pdb
  
                  pdb.set_trace()
  
          # Take the new values in monitored, cast them back to their
          # original type and store them in the output_storage
          for i in range(len(output_storage)):
              output_storage[i][0] = self.inp_types[i].filter(
                  monitored[i]
              )
  
      else:
          # Simply return views on the monitored variables
          for i in range(len(output_storage)):
              output_storage[i][0] = inputs[i + 1]
  
file_path: pytensor/pytensor/breakpoint.py
imports: import numpy
  from pytensor.gradient import DisconnectedType
  from pytensor.graph.basic import Apply, Variable
  from pytensor.graph.op import Op
  from pytensor.tensor.basic import as_tensor_variable
label_desc: Use image node_id 3 for calling the PdbBreakpoint obj's underlying member method code with example usage: obj.perform(node, inputs, output_storage) without return types