code: def discrete_action_preprocessing(
      df, actions: List[str], multi_steps: Optional[int] = None
  ):
      """
      Inputted actions and possible_actions are strings, which isn't supported
          for PyTorch Tensors. Here, we represent them with LongType.
          (a) action and next_action are strings, so simply return their position
              in the action_space (as given by argument actions).
          (b) possible_actions and possible_next_actions are list of strs, so
              return an existence bitvector of length len(actions), where ith
              index is true iff actions[i] was in the list.
  
      By-product: output not_terminal from preprocessing actions.
      """
  
      # turn string actions into indices
      where_udf = make_where_udf(actions)
      df = df.withColumn("action", where_udf("action"))
      next_long_udf = make_next_udf(multi_steps, LongType())
      df = df.withColumn(
          "next_action", where_udf(next_long_udf("next_action"))
      )
  
      def make_not_terminal_udf(actions: List[str]):
          """Return true iff next_action is terminal (i.e. idx = len(actions))."""
  
          def get_not_terminal(next_action):
              return next_action < len(actions)
  
          return udf(get_not_terminal, BooleanType())
  
      not_terminal_udf = make_not_terminal_udf(actions)
      df = df.withColumn(
          "not_terminal", not_terminal_udf("next_action")
      )
  
      # turn List[str] possible_actions into existence bitvectors
      next_long_arr_udf = make_next_udf(
          multi_steps, ArrayType(LongType())
      )
      existence_bitvector_udf = make_existence_bitvector_udf(actions)
      df = df.withColumn(
          "possible_actions_mask",
          existence_bitvector_udf("possible_actions"),
      )
      df = df.withColumn(
          "possible_next_actions_mask",
          existence_bitvector_udf(
              next_long_arr_udf("possible_next_actions")
          ),
      )
      return df
  
imports: import logging
  from typing import List, Optional, Tuple
  from pyspark.sql.functions import col, crc32, explode, map_keys, udf
  from pyspark.sql.types import ArrayType, BooleanType, FloatType, LongType, MapType, StructField, StructType
  from reagent.data.data_fetcher import DataFetcher
  from reagent.data.spark_utils import get_spark_session, get_table_url
  from reagent.workflow.types import Dataset, TableSpec
label_desc: Use image node_id 12 for calling a global function with example usage: discrete_action_preprocessing(df, actions, multi_steps) and returns: df, udf, unknown