input: 
  from typing import List
  
  
  def decode_libsvm(input: str, num_features: int, dtype=tf.float32, label_dtype=tf.int64, name=None) -> tuple:
      """Convert LibSVM input to tensors. The output consists of
  
      a label and a feature tensor. The shape of the label tensor
      is the same as input and the shape of the feature tensor is
      `[input_shape, num_features]`.
  
      >>> decode_libsvm("1 1:1 2:2", 2)
      (array([1], dtype=int64), array([[0, 1], [1, 2]], dtype=int64), array([1, 2], dtype=float32), array([2], dtype=int64))
      >>> decode_libsvm("2 1:1 2:2 3:3", 3, dtype=tf.float64, label_dtype=tf.int32)
      (array([2], dtype=int32), array([[0, 1], [1, 2], [2, 3]], dtype=int64), array([1, 2, 3], dtype=float64), array([3], dtype=int64))
      """
  
output:     
      lines = input.strip().split('\n')
      labels = []
      indices = []
      values = []
      max_index = 0
      
      for line in lines:
          parts = line.split()
          label = int(parts[0])
          labels.append(label)
          
          for feature in parts[1:]:
              index, value = feature.split(':')
              index = int(index)
              value = float(value)
              indices.append([len(labels) - 1, index - 1])
              values.append(value)
              if index > max_index:
                  max_index = index
      
      if max_index > num_features:
          raise ValueError("The number of features in the input exceeds the specified num_features.")
      
      labels_tensor = tf.constant(labels, dtype=label_dtype)
      indices_tensor = tf.constant(indices, dtype=tf.int64)
      values_tensor = tf.constant(values, dtype=dtype)
      shape_tensor = tf.constant([len(labels), num_features], dtype=tf.int64)
      
      return (labels_tensor, indices_tensor, values_tensor, shape_tensor)
  