code: def transform_values(
      fgraph: FunctionGraph, node: Apply
  ) -> Optional[list[Apply]]:
      """Apply transforms to value variables.
  
      It is assumed that the input value variables correspond to forward
      transformations, usually chosen in such a way that the values are
      unconstrained on the real line.
  
      For example, if ``Y = halfnormal(...)``, we assume the respective value
      variable is specified on the log scale and back-transform it to obtain
      ``Y`` on the natural scale.
      """
  
      rv_map_feature: Optional[PreserveRVMappings] = getattr(
          fgraph, "preserve_rv_mappings", None
      )
      values_to_transforms: Optional[TransformValuesMapping] = getattr(
          fgraph, "values_to_transforms", None
      )
  
      if rv_map_feature is None or values_to_transforms is None:
          return None  # pragma: no cover
  
      rv_vars = []
      value_vars = []
  
      for out in node.outputs:
          value = rv_map_feature.rv_values.get(out, None)
          if value is None:
              continue
          rv_vars.append(out)
          value_vars.append(value)
  
      if not value_vars:
          return None
  
      transforms = [
          values_to_transforms.get(value_var, None)
          for value_var in value_vars
      ]
  
      if all(transform is None for transform in transforms):
          return None
  
      transformed_rv_op = TransformedValueRV(transforms)
      # Clone outputs so that rewrite doesn't reference original variables circularly
      cloned_outputs = node.clone().outputs
      transformed_rv_node = transformed_rv_op.make_node(*cloned_outputs)
  
      # We now assume that the old value variable represents the *transformed space*.
      # This means that we need to replace all instance of the old value variable
      # with "inversely/un-" transformed versions of itself.
      for rv_var, value_var, transform in zip(
          rv_vars, value_vars, transforms
      ):
          rv_var_out_idx = node.outputs.index(rv_var)
  
          if transform is None:
              continue
  
          new_value_var = transformed_value(
              transform.backward(value_var, *node.inputs),
              value_var,
          )
  
          if value_var.name and getattr(transform, "name", None):
              new_value_var.name = f"{value_var.name}_{transform.name}"
  
          rv_map_feature.update_rv_maps(
              rv_var,
              new_value_var,
              transformed_rv_node.outputs[rv_var_out_idx],
          )
  
      return transformed_rv_node.outputs
  
imports: from typing import Dict, Optional, Sequence, Union
  import numpy
  from pytensor.gradient import DisconnectedType
  from pytensor.graph import Apply, Op
  from pytensor.graph.features import AlreadyThere, Feature
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.replace import clone_replace
  from pytensor.graph.rewriting.basic import GraphRewriter, in2out, node_rewriter
  from pytensor.scan.op import Scan
  from pytensor.tensor.variable import TensorVariable
  from pymc.logprob.abstract import MeasurableVariable, _logprob
  from pymc.logprob.rewriting import PreserveRVMappings, cleanup_ir_rewrites_db
  from pymc.logprob.transforms import Transform
label_desc: Use image node_id 2 for calling a global function with example usage: transform_values(fgraph, node) and returns: transformed_rv_node, None, None, None