code: def unpack_feature(
      byte_arr: bytearray,
  ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
      """Unpack the flatten feature (in byte array format) from c++
  
      Parameters
      ----------
      byte_arr: bytearray
          The two-dimensional feature vector in serialized byte array format
  
      Returns
      -------
      features: np.ndarray
          Feature vectors
      normalized_throughputs: np.ndarray
          Normalized throughputs
      task_ids: np.ndarray
          Task ids
  
      Note
      ----
      For faster data copy between c++ and python, the c++ part returns features in a single
      flatten array using a packed format. The python part then unpacks the flatten array.
  
      The packed format for n records is:
      {
        int   n;
        int   sizes[n+2];           // The sizes for the following arrays
  
        float features_0[size[0]];  // The features for record 0
        float features_1[size[1]];  // The features for record 1
        ...
        float features_i[size[i]];  // The features for record i
        ... // until i == n - 1
  
        float throughputs[sizes[n]];  // The normalized throughputs for n records
        int   task_ids[size[n+1]];    // The task ids for n records
  
      }
      To implement this format, we also store int as float, so we can store all numbers
      into a single float array.
      """
      vec_len = DEFAULT_FEATURE_VEC_LEN
  
      # unpack sizes
      offset = 0
      n = struct.unpack_from("1i", byte_arr, offset=offset)[0]
      offset += SIZE_OF_INT32
  
      sizes = struct.unpack_from(f"{n + 2}i", byte_arr, offset=offset)
      offset += SIZE_OF_INT32 * (n + 2)
  
      # unpack features
      features = []
      for size in sizes[:-2]:
          row = []
  
          # Now, we need to unpack the feature for multiple statements.
          # The format is:
          # {
          #   int   n_stage;                        // The number of stages
          #   float feature_vecs[n_stage][vec_len]  // The feature vector for each stage
          # }
          # where vec_len can be calculated by `(size - 1) / n_stmts`
  
          if size == 0:
              # failed during lowering
              features.append(np.zeros((1, vec_len)))
          else:
              n_stmts = struct.unpack_from("f", byte_arr, offset=offset)
              offset += SIZE_OF_FLOAT32
  
              n_stmts = int(n_stmts[0] + 0.5)
              tmp_vec_len = (size - 1) // n_stmts
              assert (
                  tmp_vec_len == vec_len
              ), f"The length of feature vector is wrong. Expected {vec_len} but got {tmp_vec_len}."
              assert tmp_vec_len * n_stmts == size - 1
              for _ in range(n_stmts):
                  x = struct.unpack_from(
                      f"{vec_len}f", byte_arr, offset=offset
                  )
                  offset += vec_len * SIZE_OF_FLOAT32
                  row.append(x)
  
              features.append(np.array(row))
  
      # unpack normalized_throughputs
      m = sizes[-2]
      normalized_throughputs = struct.unpack_from(
          f"{m}f", byte_arr, offset=offset
      )
      offset += m * SIZE_OF_FLOAT32
  
      # unpack task_ids
      m = sizes[-1]
      task_ids = struct.unpack_from(f"{m}i", byte_arr, offset=offset)
      offset += m * SIZE_OF_INT32
  
      assert offset == len(byte_arr), f"{offset} vs {len(byte_arr)}"
      return (
          np.array(features, dtype=object),
          np.array(normalized_throughputs),
          np.array(task_ids),
      )
  
file_path: tvm/python/tvm/auto_scheduler/feature.py
imports: from typing import List, Tuple, Union, Optional, Dict
  import struct
  import numpy
  from .loop_state import State, StateObject
  from .measure import MeasureInput, MeasureResult
  from .None import _ffi_api
  from ..tir import PrimFunc
label_desc: Use image node_id 1 for calling a global function with example usage: unpack_feature(byte_arr) and returns: np,  np,  np