code: def numba_funcify_Elemwise(op, node, **kwargs):
      # Creating a new scalar node is more involved and unnecessary
      # if the scalar_op is composite, as the fgraph already contains
      # all the necessary information.
      scalar_node = None
      if not isinstance(op.scalar_op, Composite):
          scalar_inputs = [
              scalar(dtype=input.dtype) for input in node.inputs
          ]
          scalar_node = op.scalar_op.make_node(*scalar_inputs)
  
      flags = {
          "arcp",  # Allow Reciprocal
          "contract",  # Allow floating-point contraction
          "afn",  # Approximate functions
          "reassoc",
          "nsz",  # TODO Do we want this one?
      }
  
      scalar_op_fn = numba_funcify(
          op.scalar_op,
          node=scalar_node,
          parent_node=node,
          fastmath=flags,
          **kwargs,
      )
  
      ndim = node.outputs[0].ndim
      output_bc_patterns = tuple(
          [(False,) * ndim for _ in node.outputs]
      )
      input_bc_patterns = tuple(
          [input_var.broadcastable for input_var in node.inputs]
      )
      output_dtypes = tuple(variable.dtype for variable in node.outputs)
      inplace_pattern = tuple(op.inplace_pattern.items())
  
      # numba doesn't support nested literals right now...
      input_bc_patterns_enc = base64.encodebytes(
          pickle.dumps(input_bc_patterns)
      ).decode()
      output_bc_patterns_enc = base64.encodebytes(
          pickle.dumps(output_bc_patterns)
      ).decode()
      output_dtypes_enc = base64.encodebytes(
          pickle.dumps(output_dtypes)
      ).decode()
      inplace_pattern_enc = base64.encodebytes(
          pickle.dumps(inplace_pattern)
      ).decode()
  
      def elemwise_wrapper(*inputs):
          return _vectorized(
              scalar_op_fn,
              input_bc_patterns_enc,
              output_bc_patterns_enc,
              output_dtypes_enc,
              inplace_pattern_enc,
              inputs,
          )
  
      # Pure python implementation, that will be used in tests
      def elemwise(*inputs):
          inputs = [np.asarray(input) for input in inputs]
          inputs_bc = np.broadcast_arrays(*inputs)
          shape = inputs[0].shape
          for input, bc in zip(inputs, input_bc_patterns):
              for length, allow_bc, iter_length in zip(
                  input.shape, bc, shape
              ):
                  if (
                      length == 1
                      and shape
                      and iter_length != 1
                      and not allow_bc
                  ):
                      raise ValueError("Broadcast not allowed.")
  
          outputs = []
          for dtype in output_dtypes:
              outputs.append(np.empty(shape, dtype=dtype))
  
          for idx in np.ndindex(shape):
              vals = [input[idx] for input in inputs_bc]
              outs = scalar_op_fn(*vals)
              if not isinstance(outs, tuple):
                  outs = (outs,)
              for out, out_val in zip(outputs, outs):
                  out[idx] = out_val
  
          outputs_summed = []
          for output, bc in zip(outputs, output_bc_patterns):
              axes = tuple(np.nonzero(bc)[0])
              outputs_summed.append(output.sum(axes, keepdims=True))
          if len(outputs_summed) != 1:
              return tuple(outputs_summed)
          return outputs_summed[0]
  
      @overload(elemwise)
      def ov_elemwise(*inputs):
          return elemwise_wrapper
  
      return elemwise
  
imports: import base64
  import pickle
  from functools import singledispatch
  from numbers import Number
  from textwrap import indent
  from typing import Any, Callable, Optional, Union
  import numba
  import numpy
  from numba import TypingError, types
  from numba.core import cgutils
  from numba.core.extending import overload
  from numba.np import arrayobj
  from numpy.core.numeric import normalize_axis_index, normalize_axis_tuple
  from pytensor import config
  from pytensor.graph.basic import Apply
  from pytensor.graph.op import Op
  from pytensor.link.numba.dispatch import basic
  from pytensor.link.numba.dispatch import elemwise_codegen
  from pytensor.link.numba.dispatch.basic import create_numba_signature, create_tuple_creator, numba_funcify, numba_njit, use_optimized_cheap_pass
  from pytensor.link.utils import compile_function_src, get_name_for_object
  from pytensor.scalar.basic import AND, OR, XOR, Add, Composite, IntDiv, Mean, Mul, ScalarMaximum, ScalarMinimum, Sub, TrueDiv, scalar_maximum
  from pytensor.scalar.basic import add
  from pytensor.tensor.elemwise import CAReduce, DimShuffle, Elemwise
  from pytensor.tensor.math import MaxAndArgmax, MulWithoutZeros, Sum
  from pytensor.tensor.special import LogSoftmax, Softmax, SoftmaxGrad
  from pytensor.tensor.type import scalar
label_desc: Use image node_id 20 for calling a global function with example usage: numba_funcify_Elemwise(op, node) and returns: elemwise, _vectorized, outputs_summed, elemwise_wrapper, tuple