class_docstr: - Shared: we use the same kernel for each latent GP
  - Independent: Latents are uncorrelated a priori.
  
  .. warning::
     This class is created only for testing and comparison purposes.
     Use `gpflow.kernels` instead for more efficient code.
class_docstr_tok: ["-","Shared",":","we","use","the","same","kernel","for","each","latent","GP","-","Independent",":","Latents","are","uncorrelated","a","priori",".","..","warning",":",":","This","class","is","created","only","for","testing","and","comparison","purposes",".","Use","`","gpflow.kernels","`","instead","for","more","efficient","code","."]
code: def K(
      self,
      X: TensorType,
      X2: Optional[TensorType] = None,
      full_output_cov: bool = True,
  ) -> tf.Tensor:
      K = self.kernel.K(X, X2)
      rank = tf.rank(X) - 1
      if X2 is None:
          cs(K, "[batch..., N, N]")
          ones = tf.ones((rank,), dtype=tf.int32)
          if full_output_cov:
              multiples = tf.concat([ones, [1, self.output_dim]], 0)
              Ks = cs(
                  tf.tile(K[..., None], multiples),
                  "[batch..., N, N, P]",
              )
              perm = tf.concat(
                  [
                      tf.range(rank),
                      [rank + 1, rank, rank + 2],
                  ],
                  0,
              )
              return cs(
                  tf.transpose(tf.linalg.diag(Ks), perm),
                  "[batch..., N, P, N, P]",
              )
          else:
              multiples = tf.concat([[self.output_dim], ones, [1]], 0)
              return cs(
                  tf.tile(K[None, ...], multiples),
                  "[P, batch..., N, N]",
              )
  
      else:
          cs(K, "[batch..., N, batch2..., N2]")
          rank2 = tf.rank(X2) - 1
          ones12 = tf.ones((rank + rank2,), dtype=tf.int32)
          if full_output_cov:
              multiples = tf.concat([ones12, [self.output_dim]], 0)
              Ks = cs(
                  tf.tile(K[..., None], multiples),
                  "[batch..., N, batch2..., N2, P]",
              )
              perm = tf.concat(
                  [
                      tf.range(rank),
                      [rank + rank2],
                      rank + tf.range(rank2),
                      [rank + rank2 + 1],
                  ],
                  0,
              )
              return cs(
                  tf.transpose(tf.linalg.diag(Ks), perm),
                  "[batch..., N, P, batch2..., N2, P]",
              )
          else:
              multiples = tf.concat([[self.output_dim], ones12], 0)
              return cs(
                  tf.tile(K[None, ...], multiples),
                  "[P, batch..., N, batch2..., N2]",
              )
  
imports: import abc
  from typing import Optional, Sequence, Tuple
  import tensorflow
  from check_shapes import check_shape
  from check_shapes import check_shapes, inherit_check_shapes
  from ...base import Parameter, TensorType
  from ..base import Combination, Kernel
label_desc: Use image node_id 4 for calling the SharedIndependent obj's underlying member method code with example usage: obj.K(X, X2, full_output_cov) and returns: cs, cs, cs, cs