class_docstr: Kronecker product between two `LinearOperators`.
  
  This operator composes one or more linear operators `[op1,...,opJ]`,
  building a new `LinearOperator` representing the Kronecker product:
  `op1 x op2 x .. opJ` (we omit parentheses as the Kronecker product is
  associative).
  
  If `opj` has shape `batch_shape_j + [M_j, N_j]`, then the composed operator
  will have shape equal to `broadcast_batch_shape + [prod M_j, prod N_j]`,
  where the product is over all operators.
  
  ```python
  # Create a 4 x 4 linear operator composed of two 2 x 2 operators.
  operator_1 = LinearOperatorFullMatrix([[1., 2.], [3., 4.]])
  operator_2 = LinearOperatorFullMatrix([[1., 0.], [2., 1.]])
  operator = LinearOperatorKronecker([operator_1, operator_2])
  
  operator.to_dense()
  ==> [[1., 0., 2., 0.],
       [2., 1., 4., 2.],
       [3., 0., 4., 0.],
       [6., 3., 8., 4.]]
  
  operator.shape
  ==> [4, 4]
  
  operator.log_abs_determinant()
  ==> scalar Tensor
  
  x = ... Shape [4, 2] Tensor
  operator.matmul(x)
  ==> Shape [4, 2] Tensor
  
  # Create a [2, 3] batch of 4 x 5 linear operators.
  matrix_45 = tf.random.normal(shape=[2, 3, 4, 5])
  operator_45 = LinearOperatorFullMatrix(matrix)
  
  # Create a [2, 3] batch of 5 x 6 linear operators.
  matrix_56 = tf.random.normal(shape=[2, 3, 5, 6])
  operator_56 = LinearOperatorFullMatrix(matrix_56)
  
  # Compose to create a [2, 3] batch of 20 x 30 operators.
  operator_large = LinearOperatorKronecker([operator_45, operator_56])
  
  # Create a shape [2, 3, 20, 2] vector.
  x = tf.random.normal(shape=[2, 3, 6, 2])
  operator_large.matmul(x)
  ==> Shape [2, 3, 30, 2] Tensor
  ```
  
  #### Performance
  
  The performance of `LinearOperatorKronecker` on any operation is equal to
  the sum of the individual operators' operations.
  
  #### Matrix property hints
  
  This `LinearOperator` is initialized with boolean flags of the form `is_X`,
  for `X = non_singular, self_adjoint, positive_definite, square`.
  These have the following meaning:
  
  * If `is_X == True`, callers should expect the operator to have the
    property `X`.  This is a promise that should be fulfilled, but is *not* a
    runtime assert.  For example, finite floating point precision may result
    in these promises being violated.
  * If `is_X == False`, callers should expect the operator to not have `X`.
  * If `is_X == None` (the default), callers should have no expectation either
    way.
docstr: Initialize a `LinearOperatorKronecker`.
  
  `LinearOperatorKronecker` is initialized with a list of operators
  `[op_1,...,op_J]`.
  
  Args:
    operators:  Iterable of `LinearOperator` objects, each with
      the same `dtype` and composable shape, representing the Kronecker
      factors.
    is_non_singular:  Expect that this operator is non-singular.
    is_self_adjoint:  Expect that this operator is equal to its hermitian
      transpose.
    is_positive_definite:  Expect that this operator is positive definite,
      meaning the quadratic form `x^H A x` has positive real part for all
      nonzero `x`.  Note that we do not require the operator to be
      self-adjoint to be positive-definite.  See:
      https://en.wikipedia.org/wiki/Positive-definite_matrix\
          #Extension_for_non_symmetric_matrices
    is_square:  Expect that this operator acts like square [batch] matrices.
    name: A name for this `LinearOperator`.  Default is the individual
      operators names joined with `_x_`.
  
  Raises:
    TypeError:  If all operators do not have the same `dtype`.
    ValueError:  If `operators` is empty.
docstr_tok: ["Initialize","a","`","LinearOperatorKronecker","`",".","`","LinearOperatorKronecker","`","is","initialized","with","a","list","of","operators","`","[","op_1",",","...",",","op_J","]","`",".","Args",":","operators",":","Iterable","of","`","LinearOperator","`","objects",",","each","with","the","same","`","dtype","`","and","composable","shape",",","representing","the","Kronecker","factors",".","is_non_singular",":","Expect","that","this","operator","is","non-singular",".","is_self_adjoint",":","Expect","that","this","operator","is","equal","to","its","hermitian","transpose",".","is_positive_definite",":","Expect","that","this","operator","is","positive","definite",",","meaning","the","quadratic","form","`","x^H","A","x","`","has","positive","real","part","for","all","nonzero","`","x","`",".","Note","that","we","do","not","require","the","operator","to","be","self-adjoint","to","be","positive-definite",".","See",":","https",":","\/\/en.wikipedia.org\/wiki\/Positive-definite_matrix\\","#","Extension_for_non_symmetric_matrices","is_square",":","Expect","that","this","operator","acts","like","square","[","batch","]","matrices",".","name",":","A","name","for","this","`","LinearOperator","`",".","Default","is","the","individual","operators","names","joined","with","`","_x_","`",".","Raises",":","TypeError",":","If","all","operators","do","not","have","the","same","`","dtype","`",".","ValueError",":","If","`","operators","`","is","empty","."]
code: def __init__(
      self,
      operators,
      is_non_singular=None,
      is_self_adjoint=None,
      is_positive_definite=None,
      is_square=None,
      name=None,
  ):
      r"""Initialize a `LinearOperatorKronecker`.
  
      `LinearOperatorKronecker` is initialized with a list of operators
      `[op_1,...,op_J]`.
  
      Args:
        operators:  Iterable of `LinearOperator` objects, each with
          the same `dtype` and composable shape, representing the Kronecker
          factors.
        is_non_singular:  Expect that this operator is non-singular.
        is_self_adjoint:  Expect that this operator is equal to its hermitian
          transpose.
        is_positive_definite:  Expect that this operator is positive definite,
          meaning the quadratic form `x^H A x` has positive real part for all
          nonzero `x`.  Note that we do not require the operator to be
          self-adjoint to be positive-definite.  See:
          https://en.wikipedia.org/wiki/Positive-definite_matrix\
              #Extension_for_non_symmetric_matrices
        is_square:  Expect that this operator acts like square [batch] matrices.
        name: A name for this `LinearOperator`.  Default is the individual
          operators names joined with `_x_`.
  
      Raises:
        TypeError:  If all operators do not have the same `dtype`.
        ValueError:  If `operators` is empty.
      """
      parameters = dict(
          operators=operators,
          is_non_singular=is_non_singular,
          is_self_adjoint=is_self_adjoint,
          is_positive_definite=is_positive_definite,
          is_square=is_square,
          name=name,
      )
  
      # Validate operators.
      check_ops.assert_proper_iterable(operators)
      operators = list(operators)
      if not operators:
          raise ValueError(
              f"Argument `operators` must be a list of >=1 operators. "
              f"Received: {operators}."
          )
      self._operators = operators
  
      # Validate dtype.
      dtype = operators[0].dtype
      for operator in operators:
          if operator.dtype != dtype:
              name_type = (str((o.name, o.dtype)) for o in operators)
              raise TypeError(
                  f"Expected every operation in argument `operators` to have the "
                  f"same dtype. Received {list(name_type)}."
              )
  
      # Auto-set and check hints.
      # A Kronecker product is invertible, if and only if all factors are
      # invertible.
      if all(operator.is_non_singular for operator in operators):
          if is_non_singular is False:
              raise ValueError(
                  f"The Kronecker product of non-singular operators is always "
                  f"non-singular. Expected argument `is_non_singular` to be True. "
                  f"Received: {is_non_singular}."
              )
          is_non_singular = True
  
      if all(operator.is_self_adjoint for operator in operators):
          if is_self_adjoint is False:
              raise ValueError(
                  f"The Kronecker product of self-adjoint operators is always "
                  f"self-adjoint. Expected argument `is_self_adjoint` to be True. "
                  f"Received: {is_self_adjoint}."
              )
          is_self_adjoint = True
  
      # The eigenvalues of a Kronecker product are equal to the products of eigen
      # values of the corresponding factors.
      if all(operator.is_positive_definite for operator in operators):
          if is_positive_definite is False:
              raise ValueError(
                  f"The Kronecker product of positive-definite operators is always "
                  f"positive-definite. Expected argument `is_positive_definite` to "
                  f"be True. Received: {is_positive_definite}."
              )
          is_positive_definite = True
  
      if name is None:
          name = operators[0].name
          for operator in operators[1:]:
              name += "_x_" + operator.name
      with ops.name_scope(name):
          super(LinearOperatorKronecker, self).__init__(
              dtype=dtype,
              is_non_singular=is_non_singular,
              is_self_adjoint=is_self_adjoint,
              is_positive_definite=is_positive_definite,
              is_square=is_square,
              parameters=parameters,
              name=name,
          )
  
imports: from tensorflow.python.framework import common_shapes
  from tensorflow.python.framework import dtypes
  from tensorflow.python.framework import errors
  from tensorflow.python.framework import ops
  from tensorflow.python.framework import tensor_shape
  from tensorflow.python.framework import tensor_util
  from tensorflow.python.ops import array_ops
  from tensorflow.python.ops import check_ops
  from tensorflow.python.ops import control_flow_ops
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops.linalg import linalg_impl
  from tensorflow.python.ops.linalg import linear_operator
  from tensorflow.python.util.tf_export import tf_export
label_desc: Use image node_id 1 to create a new LinearOperatorKronecker object from inherited base classes: linear_operator with example: obj = LinearOperatorKronecker(operators, is_non_singular, is__adjoint, is_positive_definite, is_square, name)