input: Write a function to decode LibSVM input to tensors using TensorFlow. The function should be named `decode_libsvm` and take the following arguments: `input` (a `Tensor` of type `string`), `num_features` (an `int` that is `>= 1`), `dtype` (an optional `tf.DType` from: `tf.float64, tf.float32, tf.int32, tf.int64`. Defaults to `tf.float32`), `label_dtype` (an optional `tf.DType` from: `tf.float64, tf.float32, tf.int32, tf.int64`. Defaults to `tf.int64`), and `name` (a name for the operation, optional). The function should return a tuple of `Tensor` objects `(label, feature_indices, feature_values, feature_shape)`, where `label` is a `Tensor` of type `label_dtype`, `feature_indices` is a `Tensor` of type `int64`, `feature_values` is a `Tensor` of type `dtype`, and `feature_shape` is a `Tensor` of type `int64`.
  
  assert decode_libsvm(["1 2:3.4 5:6.7"], 5, dtype=tf.float32, label_dtype=tf.int32)==(tf.constant([1], dtype=tf.int32), tf.constant([[0, 1], [0, 4]], dtype=tf.int64), tf.constant([3.4, 6.7], dtype=tf.float32), tf.constant([1, 5], dtype=tf.int64))
  assert decode_libsvm(["2 1:1.1 3:3.3"], 5, dtype=tf.float32, label_dtype=tf.int64)==(tf.constant([2], dtype=tf.int64), tf.constant([[0, 0], [0, 2]], dtype=tf.int64), tf.constant([1.1, 3.3], dtype=tf.float32), tf.constant([1, 5], dtype=tf.int64))
  assert decode_libsvm(["3 4:4.4 6:6.6"], 10, dtype=tf.int32, label_dtype=tf.float64)==(tf.constant([3], dtype=tf.float64), tf.constant([[0, 3], [0, 5]], dtype=tf.int64), tf.constant([4, 6], dtype=tf.int32), tf.constant([1, 10], dtype=tf.int64))
  assert decode_libsvm(["4 2:2.2 3:3.3"], 5, dtype=tf.float64, label_dtype=tf.int32)==(tf.constant([4], dtype=tf.int32), tf.constant([[0, 1], [0, 2]], dtype=tf.int64), tf.constant([2.2, 3.3], dtype=tf.float64), tf.constant([1, 5], dtype=tf.int64))
  assert decode_libsvm([], 5, dtype=tf.float32, label_dtype=tf.int64)==(tf.constant([], dtype=tf.int64), tf.constant([], dtype=tf.int64), tf.constant([], dtype=tf.float32), tf.constant([0, 5], dtype=tf.int64))
output: 
  def decode_libsvm(input, num_features, dtype=tf.float32, label_dtype=tf.int64, name=None):
      def parse_libsvm(line):
          tokens = tf.strings.split([line], ' ')
          label = tf.strings.to_number(tokens[0], out_type=label_dtype)
          indices = []
          values = []
          for token in tokens[1:]:
              idx, val = tf.strings.split([token], ':')
              indices.append([0, tf.strings.to_number(idx, out_type=tf.int64) - 1])
              values.append(tf.strings.to_number(val, out_type=dtype))
          indices = tf.stack(indices)
          values = tf.stack(values)
          shape = tf.constant([1, num_features], dtype=tf.int64)
          return label, indices, values, shape
  
      labels, indices, values, shapes = tf.map_fn(
          parse_libsvm,
          input,
          dtype=(label_dtype, tf.int64, dtype, tf.int64),
          infer_shape=False
      )
  
      labels = tf.reshape(labels, [-1])
      indices = tf.reshape(indices, [-1, 2])
      values = tf.reshape(values, [-1])
      shapes = tf.reduce_max(shapes, axis=0)
  
      return labels, indices, values, shapes
  