code: def rename_variables(expression: Expression, renaming: Dict[str, str]) -> Expression:
      
      if isinstance(expression, Operation):
          if hasattr(expression, 'variable_name'):
              variable_name = renaming.get(expression.variable_name, expression.variable_name)
              return create_operation_expression(
                  expression, [rename_variables(o, renaming) for o in op_iter(expression)], variable_name=variable_name
              )
          operands = [rename_variables(o, renaming) for o in op_iter(expression)]
          return create_operation_expression(expression, operands)
      elif isinstance(expression, Expression):
          expression = expression.__copy__()
          expression.variable_name = renaming.get(expression.variable_name, expression.variable_name)
      return expression
docs: Rename the variables in the expression according to the given dictionary.
  
      Args:
          expression:
              The expression in which the variables are renamed.
          renaming:
              The renaming dictionary. Maps old variable names to new ones.
              Variable names not occuring in the dictionary are left unchanged.
  
      Returns:
          The expression with renamed variables.