code: def local_upcast_elemwise_constant_inputs(fgraph, node):
      """This explicitly upcasts constant inputs to elemwise Ops, when
      those Ops do implicit upcasting anyway.
  
      Rationale: it helps merge things like (1-x) and (1.0 - x).
  
      """
      if len(node.outputs) > 1:
          return
      try:
          shape_i = fgraph.shape_feature.shape_i
      except AttributeError:
          shape_i = None
      if isinstance(node.op, Elemwise):
          scalar_op = node.op.scalar_op
          # print "aa", scalar_op.output_types_preference
          if getattr(scalar_op, "output_types_preference", None) in (
              ps.upgrade_to_float,
              ps.upcast_out,
          ):
              # this is the kind of op that we can screw with the input
              # dtypes by upcasting explicitly
              output_dtype = node.outputs[0].type.dtype
              new_inputs = []
              for i in node.inputs:
                  if i.type.dtype == output_dtype:
                      new_inputs.append(i)
                  else:
                      try:
                          # works only for scalars
                          cval_i = get_underlying_scalar_constant_value(
                              i, only_process_constants=True
                          )
                          if all(i.broadcastable):
                              new_inputs.append(
                                  shape_padleft(
                                      cast(cval_i, output_dtype), i.ndim
                                  )
                              )
                          else:
                              if shape_i is None:
                                  return
                              new_inputs.append(
                                  alloc(
                                      cast(cval_i, output_dtype),
                                      *[
                                          shape_i(d)(i)
                                          for d in range(i.ndim)
                                      ],
                                  )
                              )
                              # print >> sys.stderr, "AAA",
                              # *[Shape_i(d)(i) for d in range(i.ndim)]
                      except NotScalarConstantError:
                          # for the case of a non-scalar
                          if isinstance(i, TensorConstant):
                              new_inputs.append(cast(i, output_dtype))
                          else:
                              new_inputs.append(i)
  
              if new_inputs != node.inputs:
                  rval = [node.op(*new_inputs)]
                  if not node.outputs[0].type.is_super(rval[0].type):
                      # This can happen for example when floatX=float32
                      # and we do the true division between and int64
                      # and a constant that will get typed as int8.
  
                      # As this is just to allow merging more case, if
                      # the upcast don't work, we can just skip it.
                      return
  
                  # Copy over output stacktrace from before upcasting
                  copy_stack_trace(node.outputs[0], rval)
                  return rval
  
imports: import sys
  from collections import defaultdict, deque
  from collections.abc import Generator
  from functools import cache
  from typing import TypeVar
  from warnings import warn
  import pytensor
  import pytensor.scalar.basic
  from pytensor import clone_replace, compile
  from pytensor.compile.mode import get_target_language
  from pytensor.configdefaults import config
  from pytensor.graph import FunctionGraph
  from pytensor.graph.basic import Apply, Constant, Variable, ancestors, io_toposort
  from pytensor.graph.features import ReplaceValidate
  from pytensor.graph.fg import ApplyOrOutput
  from pytensor.graph.rewriting.basic import EquilibriumGraphRewriter, GraphRewriter, copy_stack_trace, in2out, node_rewriter
  from pytensor.graph.rewriting.db import SequenceDB
  from pytensor.graph.utils import InconsistencyError, MethodNotDefined
  from pytensor.scalar.loop import ScalarLoop
  from pytensor.scalar.math import Grad2F1Loop, _grad_2f1_loop
  from pytensor.tensor.basic import MakeVector, alloc, cast, get_underlying_scalar_constant_value
  from pytensor.tensor.elemwise import CAReduce, DimShuffle, Elemwise
  from pytensor.tensor.exceptions import NotScalarConstantError
  from pytensor.tensor.math import exp
  from pytensor.tensor.rewriting.basic import alloc_like, register_canonicalize, register_specialize
  from pytensor.tensor.shape import shape_padleft
  from pytensor.tensor.variable import TensorConstant, get_unique_constant_value
label_desc: Use image node_id 5 for calling a global function with example usage: local_upcast_elemwise_constant_inputs(fgraph, node) and returns: rval