예제 #1
0
    def __init__(self,
                 col,
                 row,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorToeplitz"):
        r"""Initialize a `LinearOperatorToeplitz`.

    Args:
      col: Shape `[B1,...,Bb, N]` `Tensor` with `b >= 0` `N >= 0`.
        The first column of the operator. Allowed dtypes: `float16`, `float32`,
          `float64`, `complex64`, `complex128`. Note that the first entry of
          `col` is assumed to be the same as the first entry of `row`.
      row: Shape `[B1,...,Bb, N]` `Tensor` with `b >= 0` `N >= 0`.
        The first row of the operator. Allowed dtypes: `float16`, `float32`,
          `float64`, `complex64`, `complex128`. Note that the first entry of
          `row` is assumed to be the same as the first entry of `col`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  If `diag.dtype` is real, this is auto-set to `True`.
      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`.
    """
        parameters = dict(col=col,
                          row=row,
                          is_non_singular=is_non_singular,
                          is_self_adjoint=is_self_adjoint,
                          is_positive_definite=is_positive_definite,
                          is_square=is_square,
                          name=name)

        with ops.name_scope(name, values=[row, col]):
            self._row = linear_operator_util.convert_nonref_to_tensor(
                row, name="row")
            self._col = linear_operator_util.convert_nonref_to_tensor(
                col, name="col")
            self._check_row_col(self._row, self._col)

            if is_square is False:  # pylint:disable=g-bool-id-comparison
                raise ValueError(
                    "Only square Toeplitz operators currently supported.")
            is_square = True

            super(LinearOperatorToeplitz,
                  self).__init__(dtype=self._row.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)

            self._set_graph_parents([self._row, self._col])
  def __init__(self,
               tril,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               is_square=None,
               name="LinearOperatorLowerTriangular"):
    r"""Initialize a `LinearOperatorLowerTriangular`.

    Args:
      tril:  Shape `[B1,...,Bb, N, N]` with `b >= 0`, `N >= 0`.
        The lower triangular part of `tril` defines this operator.  The strictly
        upper triangle is ignored.
      is_non_singular:  Expect that this operator is non-singular.
        This operator is non-singular if and only if its diagonal elements are
        all non-zero.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  This operator is self-adjoint only if it is diagonal with
        real-valued diagonal entries.  In this case it is advised to use
        `LinearOperatorDiag`.
      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`.

    Raises:
      ValueError:  If `is_square` is `False`.
    """
    parameters = dict(
        tril=tril,
        is_non_singular=is_non_singular,
        is_self_adjoint=is_self_adjoint,
        is_positive_definite=is_positive_definite,
        is_square=is_square,
        name=name
    )

    if is_square is False:
      raise ValueError(
          "Only square lower triangular operators supported at this time.")
    is_square = True

    with ops.name_scope(name, values=[tril]):
      self._tril = linear_operator_util.convert_nonref_to_tensor(tril,
                                                                 name="tril")
      self._check_tril(self._tril)

      super(LinearOperatorLowerTriangular, self).__init__(
          dtype=self._tril.dtype,
          graph_parents=None,
          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)
      self._set_graph_parents([self._tril])
    def __init__(self,
                 perm,
                 dtype=dtypes.float32,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorPermutation"):
        r"""Initialize a `LinearOperatorPermutation`.

    Args:
      perm:  Shape `[B1,...,Bb, N]` Integer `Tensor` with `b >= 0`
        `N >= 0`. An integer vector that represents the permutation to apply.
        Note that this argument is same as `tf.transpose`. However, this
        permutation is applied on the rows, while the permutation in
        `tf.transpose` is applied on the dimensions of the `Tensor`. `perm`
        is required to have unique entries from `{0, 1, ... N-1}`.
      dtype: The `dtype` of arguments to this operator. Default: `float32`.
        Allowed dtypes: `float16`, `float32`, `float64`, `complex64`,
        `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  This is autoset to true
      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
        This is autoset to false.
      is_square:  Expect that this operator acts like square [batch] matrices.
        This is autoset to true.
      name: A name for this `LinearOperator`.

    Raises:
      ValueError:  `is_self_adjoint` is not `True`, `is_positive_definite` is
        not `False` or `is_square` is not `True`.
    """

        with ops.name_scope(name, values=[perm]):
            self._perm = linear_operator_util.convert_nonref_to_tensor(
                perm, name="perm")
            self._check_perm(self._perm)

            # Check and auto-set hints.
            if is_non_singular is False:  # pylint:disable=g-bool-id-comparison
                raise ValueError(
                    "A Permutation operator is always non-singular.")

            if is_square is False:  # pylint:disable=g-bool-id-comparison
                raise ValueError("A Permutation operator is always square.")
            is_square = True

            super(LinearOperatorPermutation,
                  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,
                                 name=name)
예제 #4
0
    def __init__(self,
                 diag,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorDiag"):
        r"""Initialize a `LinearOperatorDiag`.

    Args:
      diag:  Shape `[B1,...,Bb, N]` `Tensor` with `b >= 0` `N >= 0`.
        The diagonal of the operator.  Allowed dtypes: `float16`, `float32`,
          `float64`, `complex64`, `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  If `diag.dtype` is real, this is auto-set to `True`.
      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`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
      ValueError:  If `diag.dtype` is real, and `is_self_adjoint` is not `True`.
    """

        with ops.name_scope(name, values=[diag]):
            self._diag = linear_operator_util.convert_nonref_to_tensor(
                diag, name="diag")
            self._check_diag(self._diag)

            # Check and auto-set hints.
            if not self._diag.dtype.is_complex:
                if is_self_adjoint is False:
                    raise ValueError(
                        "A real diagonal operator is always self adjoint.")
                else:
                    is_self_adjoint = True

            if is_square is False:
                raise ValueError(
                    "Only square diagonal operators currently supported.")
            is_square = True

            super(LinearOperatorDiag,
                  self).__init__(dtype=self._diag.dtype,
                                 graph_parents=None,
                                 is_non_singular=is_non_singular,
                                 is_self_adjoint=is_self_adjoint,
                                 is_positive_definite=is_positive_definite,
                                 is_square=is_square,
                                 name=name)
            # TODO(b/143910018) Remove graph_parents in V3.
            self._set_graph_parents([self._diag])
예제 #5
0
    def _check_spectrum_and_return_tensor(self, spectrum):
        """Static check of spectrum.  Then return `Tensor` version."""
        spectrum = linear_operator_util.convert_nonref_to_tensor(
            spectrum, name="spectrum")

        if spectrum.shape.ndims is not None:
            if spectrum.shape.ndims < self.block_depth:
                raise ValueError(
                    "Argument spectrum must have at least %d dimensions.  Found: %s"
                    % (self.block_depth, spectrum))
        return spectrum
예제 #6
0
    def _check_spectrum_and_return_tensor(self, spectrum):
        """Static check of spectrum.  Then return `Tensor` version."""
        spectrum = linear_operator_util.convert_nonref_to_tensor(
            spectrum, name="spectrum")

        if spectrum.shape.ndims is not None:
            if spectrum.shape.ndims < self.block_depth:
                raise ValueError(
                    f"Argument `spectrum` must have at least {self.block_depth} "
                    f"dimensions. Received: {spectrum}.")
        return spectrum
예제 #7
0
  def __init__(self,
               matrix,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               is_square=None,
               name="LinearOperatorFullMatrix"):
    r"""Initialize a `LinearOperatorFullMatrix`.

    Args:
      matrix:  Shape `[B1,...,Bb, M, N]` with `b >= 0`, `M, N >= 0`.
        Allowed dtypes: `float16`, `float32`, `float64`, `complex64`,
        `complex128`.
      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`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
    """
    parameters = dict(
        matrix=matrix,
        is_non_singular=is_non_singular,
        is_self_adjoint=is_self_adjoint,
        is_positive_definite=is_positive_definite,
        is_square=is_square,
        name=name
    )

    with ops.name_scope(name, values=[matrix]):
      self._matrix = linear_operator_util.convert_nonref_to_tensor(
          matrix, name="matrix")
      self._check_matrix(self._matrix)

      super(LinearOperatorFullMatrix, self).__init__(
          dtype=self._matrix.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)
      # TODO(b/143910018) Remove graph_parents in V3.
      self._set_graph_parents([self._matrix])
예제 #8
0
  def __init__(self,
               diagonals,
               diagonals_format=_COMPACT,
               is_non_singular=None,
               is_self_adjoint=None,
               is_positive_definite=None,
               is_square=None,
               name='LinearOperatorTridiag'):
    r"""Initialize a `LinearOperatorTridiag`.

    Args:
      diagonals: `Tensor` or list of `Tensor`s depending on `diagonals_format`.

        If `diagonals_format=sequence`, this is a list of three `Tensor`'s each
        with shape `[B1, ..., Bb, N]`, `b >= 0, N >= 0`, representing the
        superdiagonal, diagonal and subdiagonal in that order. Note the
        superdiagonal is padded with an element in the last position, and the
        subdiagonal is padded with an element in the front.

        If `diagonals_format=matrix` this is a `[B1, ... Bb, N, N]` shaped
        `Tensor` representing the full tridiagonal matrix.

        If `diagonals_format=compact` this is a `[B1, ... Bb, 3, N]` shaped
        `Tensor` with the second to last dimension indexing the
        superdiagonal, diagonal and subdiagonal in that order. Note the
        superdiagonal is padded with an element in the last position, and the
        subdiagonal is padded with an element in the front.

        In every case, these `Tensor`s are all floating dtype.
      diagonals_format: one of `matrix`, `sequence`, or `compact`. Default is
        `compact`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  If `diag.dtype` is real, this is auto-set to `True`.
      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`.

    Raises:
      TypeError:  If `diag.dtype` is not an allowed type.
      ValueError:  If `diag.dtype` is real, and `is_self_adjoint` is not `True`.
    """
    parameters = dict(
        diagonals=diagonals,
        diagonals_format=diagonals_format,
        is_non_singular=is_non_singular,
        is_self_adjoint=is_self_adjoint,
        is_positive_definite=is_positive_definite,
        is_square=is_square,
        name=name
    )

    with ops.name_scope(name, values=[diagonals]):
      if diagonals_format not in _DIAGONAL_FORMATS:
        raise ValueError(
            f'Argument `diagonals_format` must be one of compact, matrix, or '
            f'sequence. Received : {diagonals_format}.')
      if diagonals_format == _SEQUENCE:
        self._diagonals = [linear_operator_util.convert_nonref_to_tensor(
            d, name='diag_{}'.format(i)) for i, d in enumerate(diagonals)]
        dtype = self._diagonals[0].dtype
      else:
        self._diagonals = linear_operator_util.convert_nonref_to_tensor(
            diagonals, name='diagonals')
        dtype = self._diagonals.dtype
      self._diagonals_format = diagonals_format

      super(LinearOperatorTridiag, 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)
    def __init__(self,
                 num_rows,
                 multiplier,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=True,
                 assert_proper_shapes=False,
                 name="LinearOperatorScaledIdentity"):
        r"""Initialize a `LinearOperatorScaledIdentity`.

    The `LinearOperatorScaledIdentity` is initialized with `num_rows`, which
    determines the size of each identity matrix, and a `multiplier`,
    which defines `dtype`, batch shape, and scale of each matrix.

    This operator is able to broadcast the leading (batch) dimensions.

    Args:
      num_rows:  Scalar non-negative integer `Tensor`.  Number of rows in the
        corresponding identity matrix.
      multiplier:  `Tensor` of shape `[B1,...,Bb]`, or `[]` (a scalar).
      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.
      assert_proper_shapes:  Python `bool`.  If `False`, only perform static
        checks that initialization and method arguments have proper shape.
        If `True`, and static checks are inconclusive, add asserts to the graph.
      name: A name for this `LinearOperator`

    Raises:
      ValueError:  If `num_rows` is determined statically to be non-scalar, or
        negative.
    """
        parameters = dict(num_rows=num_rows,
                          multiplier=multiplier,
                          is_non_singular=is_non_singular,
                          is_self_adjoint=is_self_adjoint,
                          is_positive_definite=is_positive_definite,
                          is_square=is_square,
                          assert_proper_shapes=assert_proper_shapes,
                          name=name)

        self._assert_proper_shapes = assert_proper_shapes

        with ops.name_scope(name, values=[multiplier, num_rows]):
            self._multiplier = linear_operator_util.convert_nonref_to_tensor(
                multiplier, name="multiplier")

            # Check and auto-set hints.
            if not self._multiplier.dtype.is_complex:
                if is_self_adjoint is False:  # pylint: disable=g-bool-id-comparison
                    raise ValueError(
                        "A real diagonal operator is always self adjoint.")
                else:
                    is_self_adjoint = True

            if not is_square:
                raise ValueError("A ScaledIdentity operator is always square.")

            linear_operator_util.assert_not_ref_type(num_rows, "num_rows")

            super(LinearOperatorScaledIdentity,
                  self).__init__(dtype=self._multiplier.dtype.base_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)

            self._num_rows = linear_operator_util.shape_tensor(num_rows,
                                                               name="num_rows")
            self._num_rows_static = tensor_util.constant_value(self._num_rows)
            self._check_num_rows_possibly_add_asserts()
            self._num_rows_cast_to_dtype = math_ops.cast(
                self._num_rows, self.dtype)
            self._num_rows_cast_to_real_dtype = math_ops.cast(
                self._num_rows, self.dtype.real_dtype)
예제 #10
0
    def __init__(self,
                 base_operator,
                 u,
                 diag_update=None,
                 v=None,
                 is_diag_update_positive=None,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorLowRankUpdate"):
        """Initialize a `LinearOperatorLowRankUpdate`.

    This creates a `LinearOperator` of the form `A = L + U D V^H`, with
    `L` a `LinearOperator`, `U, V` both [batch] matrices, and `D` a [batch]
    diagonal matrix.

    If `L` is non-singular, solves and determinants are available.
    Solves/determinants both involve a solve/determinant of a `K x K` system.
    In the event that L and D are self-adjoint positive-definite, and U = V,
    this can be done using a Cholesky factorization.  The user should set the
    `is_X` matrix property hints, which will trigger the appropriate code path.

    Args:
      base_operator:  Shape `[B1,...,Bb, M, N]`.
      u:  Shape `[B1,...,Bb, M, K]` `Tensor` of same `dtype` as `base_operator`.
        This is `U` above.
      diag_update:  Optional shape `[B1,...,Bb, K]` `Tensor` with same `dtype`
        as `base_operator`.  This is the diagonal of `D` above.
         Defaults to `D` being the identity operator.
      v:  Optional `Tensor` of same `dtype` as `u` and shape `[B1,...,Bb, N, K]`
         Defaults to `v = u`, in which case the perturbation is symmetric.
         If `M != N`, then `v` must be set since the perturbation is not square.
      is_diag_update_positive:  Python `bool`.
        If `True`, expect `diag_update > 0`.
      is_non_singular:  Expect that this operator is non-singular.
        Default is `None`, unless `is_positive_definite` is auto-set to be
        `True` (see below).
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  Default is `None`, unless `base_operator` is self-adjoint
        and `v = None` (meaning `u=v`), in which case this defaults to `True`.
      is_positive_definite:  Expect that this operator is positive definite.
        Default is `None`, unless `base_operator` is positive-definite
        `v = None` (meaning `u=v`), and `is_diag_update_positive`, in which case
        this defaults to `True`.
        Note that we say an operator is positive definite when the quadratic
        form `x^H A x` has positive real part for all nonzero `x`.
      is_square:  Expect that this operator acts like square [batch] matrices.
      name: A name for this `LinearOperator`.

    Raises:
      ValueError:  If `is_X` flags are set in an inconsistent way.
    """
        parameters = dict(base_operator=base_operator,
                          u=u,
                          diag_update=diag_update,
                          v=v,
                          is_diag_update_positive=is_diag_update_positive,
                          is_non_singular=is_non_singular,
                          is_self_adjoint=is_self_adjoint,
                          is_positive_definite=is_positive_definite,
                          is_square=is_square,
                          name=name)
        dtype = base_operator.dtype

        if diag_update is not None:
            if is_diag_update_positive and dtype.is_complex:
                logging.warn(
                    "Note: setting is_diag_update_positive with a complex "
                    "dtype means that diagonal is real and positive.")

        if diag_update is None:
            if is_diag_update_positive is False:
                raise ValueError(
                    "Default diagonal is the identity, which is positive.  However, "
                    "user set 'is_diag_update_positive' to False.")
            is_diag_update_positive = True

        # In this case, we can use a Cholesky decomposition to help us solve/det.
        self._use_cholesky = (base_operator.is_positive_definite
                              and base_operator.is_self_adjoint
                              and is_diag_update_positive and v is None)

        # Possibly auto-set some characteristic flags from None to True.
        # If the Flags were set (by the user) incorrectly to False, then raise.
        if base_operator.is_self_adjoint and v is None and not dtype.is_complex:
            if is_self_adjoint is False:
                raise ValueError(
                    "A = L + UDU^H, with L self-adjoint and D real diagonal.  Since"
                    " UDU^H is self-adjoint, this must be a self-adjoint operator."
                )
            is_self_adjoint = True

        # The condition for using a cholesky is sufficient for SPD, and
        # we no weaker choice of these hints leads to SPD.  Therefore,
        # the following line reads "if hints indicate SPD..."
        if self._use_cholesky:
            if (is_positive_definite is False or is_self_adjoint is False
                    or is_non_singular is False):
                raise ValueError(
                    "Arguments imply this is self-adjoint positive-definite operator."
                )
            is_positive_definite = True
            is_self_adjoint = True

        values = base_operator.graph_parents + [u, diag_update, v]
        with ops.name_scope(name, values=values):

            # Create U and V.
            self._u = linear_operator_util.convert_nonref_to_tensor(u,
                                                                    name="u")
            if v is None:
                self._v = self._u
            else:
                self._v = linear_operator_util.convert_nonref_to_tensor(
                    v, name="v")

            if diag_update is None:
                self._diag_update = None
            else:
                self._diag_update = linear_operator_util.convert_nonref_to_tensor(
                    diag_update, name="diag_update")

            # Create base_operator L.
            self._base_operator = base_operator
            graph_parents = base_operator.graph_parents + [
                self.u, self._diag_update, self.v
            ]
            graph_parents = [p for p in graph_parents if p is not None]

            super(LinearOperatorLowRankUpdate,
                  self).__init__(dtype=self._base_operator.dtype,
                                 graph_parents=None,
                                 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)
            self._set_graph_parents(graph_parents)

            # Create the diagonal operator D.
            self._set_diag_operators(diag_update, is_diag_update_positive)
            self._is_diag_update_positive = is_diag_update_positive

            self._check_shapes()
    def __init__(self,
                 reflection_axis,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorHouseholder"):
        r"""Initialize a `LinearOperatorHouseholder`.

    Args:
      reflection_axis:  Shape `[B1,...,Bb, N]` `Tensor` with `b >= 0` `N >= 0`.
        The vector defining the hyperplane to reflect about.
        Allowed dtypes: `float16`, `float32`, `float64`, `complex64`,
        `complex128`.
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  This is autoset to true
      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
        This is autoset to false.
      is_square:  Expect that this operator acts like square [batch] matrices.
        This is autoset to true.
      name: A name for this `LinearOperator`.

    Raises:
      ValueError:  `is_self_adjoint` is not `True`, `is_positive_definite` is
        not `False` or `is_square` is not `True`.
    """

        with ops.name_scope(name, values=[reflection_axis]):
            self._reflection_axis = linear_operator_util.convert_nonref_to_tensor(
                reflection_axis, name="reflection_axis")
            self._check_reflection_axis(self._reflection_axis)

            # Check and auto-set hints.
            if is_self_adjoint is False:  # pylint:disable=g-bool-id-comparison
                raise ValueError(
                    "A Householder operator is always self adjoint.")
            else:
                is_self_adjoint = True

            if is_positive_definite is True:  # pylint:disable=g-bool-id-comparison
                raise ValueError(
                    "A Householder operator is always non-positive definite.")
            else:
                is_positive_definite = False

            if is_square is False:  # pylint:disable=g-bool-id-comparison
                raise ValueError("A Householder operator is always square.")
            is_square = True

            super(LinearOperatorHouseholder,
                  self).__init__(dtype=self._reflection_axis.dtype,
                                 graph_parents=None,
                                 is_non_singular=is_non_singular,
                                 is_self_adjoint=is_self_adjoint,
                                 is_positive_definite=is_positive_definite,
                                 is_square=is_square,
                                 name=name)
            # TODO(b/143910018) Remove graph_parents in V3.
            self._set_graph_parents([self._reflection_axis])