input: Write a function to decode a LibSVM input string into tensors using TensorFlow. The function should be named `decode_libsvm` and should take the following arguments: `input` (a Tensor of type string), `num_features` (an int that is `>= 1`), `dtype` (an optional tf.DType from: `tf.float32, tf.float64, tf.int32, tf.int64`. Defaults to `tf.float32`), `label_dtype` (an optional tf.DType from: `tf.float32, tf.float64, 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 1:1 2:2"], 2, tf.float32, tf.int64, "example")==(tf.constant([1], dtype=tf.int64), tf.constant([[0, 0], [0, 1]], dtype=tf.int64), tf.constant([1.0, 2.0], dtype=tf.float32), tf.constant([2], dtype=tf.int64))
  assert decode_libsvm(["2 1:3 2:4"], 2, tf.float32, tf.int64, "example")==(tf.constant([2], dtype=tf.int64), tf.constant([[0, 0], [0, 1]], dtype=tf.int64), tf.constant([3.0, 4.0], dtype=tf.float32), tf.constant([2], dtype=tf.int64))
  assert decode_libsvm(["1 1:5"], 1, tf.float32, tf.int64, "example")==(tf.constant([1], dtype=tf.int64), tf.constant([[0, 0]], dtype=tf.int64), tf.constant([5.0], dtype=tf.float32), tf.constant([1], dtype=tf.int64))
  assert decode_libsvm(["3 1:6 2:7 3:8"], 3, tf.float32, tf.int64, "example")==(tf.constant([3], dtype=tf.int64), tf.constant([[0, 0], [0, 1], [0, 2]], dtype=tf.int64), tf.constant([6.0, 7.0, 8.0], dtype=tf.float32), tf.constant([3], dtype=tf.int64))
  assert decode_libsvm(["0"], 1, tf.float32, tf.int64, "example")==(tf.constant([0], dtype=tf.int64), tf.constant([], dtype=tf.int64), tf.constant([], dtype=tf.float32), tf.constant([0], dtype=tf.int64))
output: def decode_libsvm(input, num_features, dtype=tf.float32, label_dtype=tf.int64, name=None):
      def _parse_line(line):
          parts = tf.strings.split(line, ' ')
          label = tf.strings.to_number(parts[0], out_type=label_dtype)
          indices = []
          values = []
          for part in parts[1:]:
              index, value = tf.strings.split(part, ':')
              indices.append([0, tf.strings.to_number(index, out_type=tf.int64) - 1])
              values.append(tf.strings.to_number(value, out_type=dtype))
          return label, tf.stack(indices), tf.stack(values), tf.constant([num_features], dtype=tf.int64)
  
      labels, indices, values, shapes = tf.map_fn(
          _parse_line,
          input,
          dtype=(label_dtype, tf.int64, dtype, tf.int64),
          name=name
      )
      return labels, indices, values, shapes