def METHOD_NAME(self, X: tf.Tensor, X2: Optional[tf.Tensor] = None) -> tf.Tensor:
    cs(X, "[batch..., N, 1]  # The `ChangePoints` kernel requires a 1D input space.")
    rank = tf.rank(X) - 2
    batch = tf.shape(X)[:-2]
    N = tf.shape(X)[-2]
    Ncp = tf.shape(self.locations)[0]
    sig_X = cs(self._sigmoids(X), "[batch..., N, 1, Ncp]")
    if X2 is None:
        rank2 = 0
        batch2 = tf.constant([], dtype=tf.int32)
        N2 = N
        sig_X2 = sig_X
        sig_X = cs(
            tf.reshape(sig_X, tf.concat([batch, [N, 1, Ncp]], 0)), "[batch..., N, 1, Ncp]"
        )
        sig_X2 = cs(
            tf.reshape(sig_X2, tf.concat([batch, [1, N, Ncp]], 0)), "[batch..., 1, N, Ncp]"
        )
    else:
        rank2 = tf.rank(X2) - 2
        batch2 = tf.shape(X2)[:-2]
        N2 = tf.shape(X2)[-2]
        sig_X2 = cs(self._sigmoids(X2), "[batch2..., N2, 1, Ncp]")
        ones = tf.ones((rank,), dtype=tf.int32)
        ones2 = tf.ones((rank2,), dtype=tf.int32)
        sig_X = cs(
            tf.reshape(sig_X, tf.concat([batch, [N], ones2, [1, Ncp]], 0)),
            "[batch..., N, ..., 1, Ncp]",
        )
        sig_X2 = cs(
            tf.reshape(sig_X2, tf.concat([ones, [1], batch2, [N2, Ncp]], 0)),
            "[..., 1, batch2..., N2, Ncp]",
        )
    # `starters` are the sigmoids going from 0 -> 1, whilst `stoppers` go
    # from 1 -> 0.
    starters = cs(sig_X * sig_X2, "[batch..., N, batch2..., N2, Ncp]")
    stoppers = cs((1 - sig_X) * (1 - sig_X2), "[batch..., N, batch2..., N2, Ncp]")
    # prepend `starters` with ones and append ones to `stoppers` since the
    # first kernel has no start and the last kernel has no end
    ones = tf.ones(tf.concat([batch, [N], batch2, [N2, 1]], 0), dtype=X.dtype)
    starters = cs(tf.concat([ones, starters], axis=-1), "[batch..., N, batch2..., N2, Nkern]")
    stoppers = cs(tf.concat([stoppers, ones], axis=-1), "[batch..., N, batch2..., N2, Nkern]")
    # now combine with the underlying kernels
    kernel_stack = cs(
        tf.stack([k(X, X2) for k in self.kernels], axis=-1),
        "[batch..., N, batch2..., N2, Nkern]",
    )
    return tf.reduce_sum(kernel_stack * starters * stoppers, axis=-1)