code: def test_separate_independent_mof() -> None:
      """
      Same test as above but we use different (i.e. separate) inducing inducing
      for each of the output dimensions.
      """
      np.random.seed(0)
  
      # Model 1 (INefficient)
      q_mu_1 = np.random.randn(Data.M * Data.P, 1)
      q_sqrt_1 = np.tril(
          np.random.randn(Data.M * Data.P, Data.M * Data.P)
      )[
          None, ...
      ]  # 1 x MP x MP
  
      kernel_1 = mk.SharedIndependent(
          SquaredExponential(variance=0.5, lengthscales=1.2), Data.P
      )
      inducing_variable_1 = InducingPoints(Data.X[: Data.M, ...])
      model_1 = SVGP(
          kernel_1,
          Gaussian(),
          inducing_variable_1,
          q_mu=q_mu_1,
          q_sqrt=q_sqrt_1,
      )
      set_trainable(model_1, False)
      set_trainable(model_1.q_sqrt, True)
      set_trainable(model_1.q_mu, True)
  
      gpflow.optimizers.Scipy().minimize(
          model_1.training_loss_closure(Data.data),
          variables=model_1.trainable_variables,
          method="BFGS",
          compile=True,
      )
  
      # Model 2 (efficient)
      q_mu_2 = np.random.randn(Data.M, Data.P)
      q_sqrt_2: AnyNDArray = np.array(
          [
              np.tril(np.random.randn(Data.M, Data.M))
              for _ in range(Data.P)
          ]
      )  # P x M x M
      kernel_2 = mk.SharedIndependent(
          SquaredExponential(variance=0.5, lengthscales=1.2), Data.P
      )
      inducing_variable_list_2 = [
          InducingPoints(Data.X[: Data.M, ...]) for _ in range(Data.P)
      ]
      inducing_variable_2 = mf.SeparateIndependentInducingVariables(
          inducing_variable_list_2
      )
      model_2 = SVGP(
          kernel_2,
          Gaussian(),
          inducing_variable_2,
          q_mu=q_mu_2,
          q_sqrt=q_sqrt_2,
      )
      set_trainable(model_2, False)
      set_trainable(model_2.q_sqrt, True)
      set_trainable(model_2.q_mu, True)
  
      gpflow.optimizers.Scipy().minimize(
          model_2.training_loss_closure(Data.data),
          variables=model_2.trainable_variables,
          method="BFGS",
          compile=True,
      )
  
      # Model 3 (Inefficient): an idenitical inducing variable is used P times,
      # and treated as a separate one.
      q_mu_3 = np.random.randn(Data.M, Data.P)
      q_sqrt_3: AnyNDArray = np.array(
          [
              np.tril(np.random.randn(Data.M, Data.M))
              for _ in range(Data.P)
          ]
      )  # P x M x M
      kern_list = [
          SquaredExponential(variance=0.5, lengthscales=1.2)
          for _ in range(Data.P)
      ]
      kernel_3 = mk.SeparateIndependent(kern_list)
      inducing_variable_list_3 = [
          InducingPoints(Data.X[: Data.M, ...]) for _ in range(Data.P)
      ]
      inducing_variable_3 = mf.SeparateIndependentInducingVariables(
          inducing_variable_list_3
      )
      model_3 = SVGP(
          kernel_3,
          Gaussian(),
          inducing_variable_3,
          q_mu=q_mu_3,
          q_sqrt=q_sqrt_3,
      )
      set_trainable(model_3, False)
      set_trainable(model_3.q_sqrt, True)
      set_trainable(model_3.q_mu, True)
  
      gpflow.optimizers.Scipy().minimize(
          model_3.training_loss_closure(Data.data),
          variables=model_3.trainable_variables,
          method="BFGS",
          compile=True,
      )
  
      check_equality_predictions(Data.data, [model_1, model_2, model_3])
  
imports: from typing import Callable, List, Sequence, Tuple, cast
  import numpy
  import pytest
  import scipy
  import tensorflow
  from _pytest.fixtures import SubRequest
  from check_shapes import ShapeChecker, check_shapes
  import gpflow
  import gpflow.inducing_variables.multioutput
  import gpflow.kernels.multioutput
  from gpflow import set_trainable
  from gpflow.base import AnyNDArray, RegressionData
  from gpflow.conditionals import sample_conditional
  from gpflow.conditionals.util import fully_correlated_conditional, fully_correlated_conditional_repeat, independent_interdomain_conditional, sample_mvn
  from gpflow.config import default_float, default_jitter
  from gpflow.inducing_variables import InducingPoints
  from gpflow.kernels import SquaredExponential
  from gpflow.likelihoods import Gaussian
  from gpflow.models import SVGP
label_desc: Use image node_id 17 for calling a global function with example usage: test_separate_independent_mof() without return types