def matrix(self, x1, x2):
with self._name_scope(self._name, values=[x1, x2]):<EOL><INDENT>x1 = tf.convert_to_tensor(value=x1, name='<STR_LIT>')<EOL>x2 = tf.convert_to_tensor(value=x2, name='<STR_LIT>')<EOL>x1 = tf.expand_dims(x1, -(self.feature_ndims + <NUM_LIT:1>))<EOL>x2 = tf.expand_dims(x2, -(self.feature_ndims + <NUM_LIT:2>))<EOL>return self._apply(x1, x2, param_expansion_ndims=<NUM_LIT:2>)<EOL><DEDENT>
Construct (batched) matrices from (batches of) collections of inputs.

        Args:
          x1: `Tensor` input to the first positional parameter of the kernel, of
            shape `[b1, ..., bB, e1, f1, ..., fF]`, where `B` may be zero (ie, no
            batching), e1 is an integer greater than zero, and `F` (number of
            feature dimensions) must equal the kernel's `feature_ndims` property.
            Batch shape must broadcast with the batch shape of `x2` and with the
            kernel's parameters *after* parameter expansion (see
            `param_expansion_ndims` argument).
          x2: `Tensor` input to the second positional parameter of the kernel,
            shape `[c1, ..., cC, e2, f1, ..., fF]`, where `C` may be zero (ie, no
            batching), e2 is an integer greater than zero,  and `F` (number of
            feature dimensions) must equal the kernel's `feature_ndims` property.
            Batch shape must broadcast with the batch shape of `x1` and with the
            kernel's parameters *after* parameter expansion (see
            `param_expansion_ndims` argument).

        Returns:
          `Tensor containing (batch of) matrices of kernel applications to pairs
          from inputs `x1` and `x2`. If the kernel parameters' batch shape is
          `[k1, ..., kK]`, then the shape of the resulting `Tensor` is
          `broadcast([b1, ..., bB], [c1, ..., cC], [k1, ..., kK]) + [e1, e2]`.

        Given inputs `x1` and `x2` of shapes

        ```none
        [b1, ..., bB, e1, f1, ..., fF]
        ```

        and

        ```none
        [c1, ..., cC, e2, f1, ..., fF]
        ```

        This method computes the batch of `e1 x e2` matrices resulting from applying
        the kernel function to all pairs of inputs from `x1` and `x2`. The shape
        of the batch of matrices is the result of broadcasting the batch shapes of
        `x1`, `x2`, and the kernel parameters (see examples below). As such, it's
        required that these shapes all be broadcast compatible. However, the kernel
        parameter batch shapes need not broadcast against the 'example shapes' (`e1`
        and `e2` above).

        When the two inputs are the (batches of) identical collections, the
        resulting matrix is the so-called Gram (or Gramian) matrix
        (https://en.wikipedia.org/wiki/Gramian_matrix).

        N.B., this method can only be used to compute the pairwise application of
        the kernel function on rank-1 collections. E.g., it *does* support inputs of
        shape `[e1, f]` and `[e2, f]`, yielding a matrix of shape `[e1, e2]`. It
        *does not* support inputs of shape `[e1, e2, f]` and `[e3, e4, f]`, yielding
        a `Tensor` of shape `[e1, e2, e3, e4]`. To do this, one should instead
        reshape the inputs and pass them to `apply`, e.g.:

        ```python
        k = tfpk.SomeKernel()
        t1 = tf.placeholder([4, 4, 3], tf.float32)
        t2 = tf.placeholder([5, 5, 3], tf.float32)
        k.apply(
            tf.reshape(t1, [4, 4, 1, 1, 3]),
            tf.reshape(t2, [1, 1, 5, 5, 3])).shape
        # ==> [4, 4, 5, 5, 3]
        ```

        `matrix` is a special case of the above, where there is only one example
        dimension; indeed, its implementation looks almost exactly like the above
        (reshaped inputs passed to the private version of `_apply`).

        #### Examples

        First, consider a kernel with a single scalar parameter.

        ```python
        import tensorflow_probability as tfp

        scalar_kernel = tfp.positive_semidefinite_kernels.SomeKernel(param=.5)
        scalar_kernel.batch_shape
        # ==> []

        # Our inputs are two lists of 3-D vectors
        x = np.ones([5, 3], np.float32)
        y = np.ones([4, 3], np.float32)
        scalar_kernel.matrix(x, y).shape
        # ==> [5, 4]
        ```

        The result comes from applying the kernel to the entries in `x` and `y`
        pairwise, across all pairs:

          ```none
          | k(x[0], y[0])    k(x[0], y[1])  ...  k(x[0], y[3]) |
          | k(x[1], y[0])    k(x[1], y[1])  ...  k(x[1], y[3]) |
          |      ...              ...                 ...      |
          | k(x[4], y[0])    k(x[4], y[1])  ...  k(x[4], y[3]) |
          ```

        Now consider a kernel with batched parameters with the same inputs

        ```python
        batch_kernel = tfp.positive_semidefinite_kernels.SomeKernel(param=[1., .5])
        batch_kernel.batch_shape
        # ==> [2]

        batch_kernel.matrix(x, y).shape
        # ==> [2, 5, 4]
        ```

        This results in a batch of 2 matrices, one computed from the kernel with
        `param = 1.` and the other with `param = .5`.

        We also support batching of the inputs. First, let's look at that with
        the scalar kernel again.

        ```python
        # Batch of 10 lists of 5 vectors of dimension 3
        x = np.ones([10, 5, 3], np.float32)

        # Batch of 10 lists of 4 vectors of dimension 3
        y = np.ones([10, 4, 3], np.float32)

        scalar_kernel.matrix(x, y).shape
        # ==> [10, 5, 4]
        ```

        The result is a batch of 10 matrices built from the batch of 10 lists of
        input vectors. These batch shapes have to be broadcastable. The following
        will *not* work:

        ```python
        x = np.ones([10, 5, 3], np.float32)
        y = np.ones([20, 4, 3], np.float32)
        scalar_kernel.matrix(x, y).shape
        # ==> Error! [10] and [20] can't broadcast.
        ```

        Now let's consider batches of inputs in conjunction with batches of kernel
        parameters. We require that the input batch shapes be broadcastable with
        the kernel parameter batch shapes, otherwise we get an error:

        ```python
        x = np.ones([10, 5, 3], np.float32)
        y = np.ones([10, 4, 3], np.float32)

        batch_kernel = tfp.positive_semidefinite_kernels.SomeKernel(params=[1., .5])
        batch_kernel.batch_shape
        # ==> [2]
        batch_kernel.matrix(x, y).shape
        # ==> Error! [2] and [10] can't broadcast.
        ```

        The fix is to make the kernel parameter shape broadcastable with `[10]` (or
        reshape the inputs to be broadcastable!):

        ```python
        x = np.ones([10, 5, 3], np.float32)
        y = np.ones([10, 4, 3], np.float32)

        batch_kernel = tfp.positive_semidefinite_kernels.SomeKernel(
            params=[[1.], [.5]])
        batch_kernel.batch_shape
        # ==> [2, 1]
        batch_kernel.matrix(x, y).shape
        # ==> [2, 10, 5, 4]

        # Or, make the inputs broadcastable:
        x = np.ones([10, 1, 5, 3], np.float32)
        y = np.ones([10, 1, 4, 3], np.float32)

        batch_kernel = tfp.positive_semidefinite_kernels.SomeKernel(
            params=[1., .5])
        batch_kernel.batch_shape
        # ==> [2]
        batch_kernel.matrix(x, y).shape
        # ==> [10, 2, 5, 4]

        ```

        Here, we have the result of applying the kernel, with 2 different
        parameters, to each of a batch of 10 pairs of input lists.