# LostTech.TensorFlow : API Documentation

Type LinearOperatorCirculant2D

Namespace tensorflow.linalg

Interfaces ILinearOperatorCirculant2D

`LinearOperator` acting like a block circulant matrix.

This operator acts like a block circulant matrix `A` with shape `[B1,...,Bb, N, N]` for some `b >= 0`. The first `b` indices index a batch member. For every batch index `(i1,...,ib)`, `A[i1,...,ib, : :]` is an `N x N` matrix. This matrix `A` is not materialized, but for purposes of broadcasting this shape will be relevant.

#### Description in terms of block circulant matrices

If `A` is block circulant, with block sizes `N0, N1` (`N0 * N1 = N`): `A` has a block circulant structure, composed of `N0 x N0` blocks, with each block an `N1 x N1` circulant matrix.

For example, with `W`, `X`, `Y`, `Z` each circulant,

``` A = |W Z Y X| |X W Z Y| |Y X W Z| |Z Y X W| ```

Note that `A` itself will not in general be circulant.

#### Description in terms of the frequency spectrum

There is an equivalent description in terms of the [batch] spectrum `H` and Fourier transforms. Here we consider `A.shape = [N, N]` and ignore batch dimensions.

If `H.shape = [N0, N1]`, (`N0 * N1 = N`): Loosely speaking, matrix multiplication is equal to the action of a Fourier multiplier: `A u = IDFT2[ H DFT2[u] ]`. Precisely speaking, given `[N, R]` matrix `u`, let `DFT2[u]` be the `[N0, N1, R]` `Tensor` defined by re-shaping `u` to `[N0, N1, R]` and taking a two dimensional DFT across the first two dimensions. Let `IDFT2` be the inverse of `DFT2`. Matrix multiplication may be expressed columnwise:

```(A u)_r = IDFT2[ H * (DFT2[u])_r ]```

#### Operator properties deduced from the spectrum.

* This operator is positive definite if and only if `Real{H} > 0`.

A general property of Fourier transforms is the correspondence between Hermitian functions and real valued transforms.

Suppose `H.shape = [B1,...,Bb, N0, N1]`, we say that `H` is a Hermitian spectrum if, with `%` indicating modulus division,

``` H[..., n0 % N0, n1 % N1] = ComplexConjugate[ H[..., (-n0) % N0, (-n1) % N1 ]. ```

* This operator corresponds to a real matrix if and only if `H` is Hermitian. * This operator is self-adjoint if and only if `H` is real.

See e.g. "Discrete-Time Signal Processing", Oppenheim and Schafer.

### Example of a self-adjoint positive definite operator #### Example of defining in terms of a real convolution kernel, #### Performance

Suppose `operator` is a `LinearOperatorCirculant` of shape `[N, N]`, and `x.shape = [N, R]`. Then

* `operator.matmul(x)` is `O(R*N*Log[N])` * `operator.solve(x)` is `O(R*N*Log[N])` * `operator.determinant()` involves a size `N` `reduce_prod`.

If instead `operator` and `x` have shape `[B1,...,Bb, N, N]` and `[B1,...,Bb, N, R]`, every operation increases in complexity by `B1*...*Bb`.

#### 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.
Show Example
```# spectrum is real ==> operator is self-adjoint
# spectrum is positive ==> operator is positive definite
spectrum = [[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]]  operator = LinearOperatorCirculant2D(spectrum)  # IFFT[spectrum]
operator.convolution_kernel()
==> [[5.0+0.0j, -0.5-.3j, -0.5+.3j],
[-1.5-.9j,        0,        0],
[-1.5+.9j,        0,        0]]  operator.to_dense()
==> Complex self adjoint 9 x 9 matrix. ```

### Public instance methods

#### Tensormatvec(ValueTuple<PythonClassContainer, PythonClassContainer> x, bool adjoint, string name)

Transform [batch] vector `x` with left multiplication: `x --> Ax`.
##### Parameters
`ValueTuple<PythonClassContainer, PythonClassContainer>` x
`Tensor` with compatible shape and same `dtype` as `self`. `x` is treated as a [batch] vector meaning for every set of leading dimensions, the last dimension defines a vector. See class docstring for definition of compatibility.
`bool` adjoint
Python `bool`. If `True`, left multiply by the adjoint: `A^H x`.
`string` name
A name for this `Op`.
##### Returns
`Tensor`
A `Tensor` with shape `[..., M]` and same `dtype` as `self`.
Show Example
```# Make an operator acting like batch matric A.  Assume A.shape = [..., M, N]
operator = LinearOperator(...)  X =... # shape [..., N], batch vector  Y = operator.matvec(X)
Y.shape
==> [..., M]  Y[..., :] = sum_j A[..., :, j] X[..., j] ```

#### Tensormatvec(IndexedSlices x, bool adjoint, string name)

Transform [batch] vector `x` with left multiplication: `x --> Ax`.
##### Parameters
`IndexedSlices` x
`Tensor` with compatible shape and same `dtype` as `self`. `x` is treated as a [batch] vector meaning for every set of leading dimensions, the last dimension defines a vector. See class docstring for definition of compatibility.
`bool` adjoint
Python `bool`. If `True`, left multiply by the adjoint: `A^H x`.
`string` name
A name for this `Op`.
##### Returns
`Tensor`
A `Tensor` with shape `[..., M]` and same `dtype` as `self`.
Show Example
```# Make an operator acting like batch matric A.  Assume A.shape = [..., M, N]
operator = LinearOperator(...)  X =... # shape [..., N], batch vector  Y = operator.matvec(X)
Y.shape
==> [..., M]  Y[..., :] = sum_j A[..., :, j] X[..., j] ```

#### Tensormatvec(IGraphNodeBase x, bool adjoint, string name)

Transform [batch] vector `x` with left multiplication: `x --> Ax`.
##### Parameters
`IGraphNodeBase` x
`Tensor` with compatible shape and same `dtype` as `self`. `x` is treated as a [batch] vector meaning for every set of leading dimensions, the last dimension defines a vector. See class docstring for definition of compatibility.
`bool` adjoint
Python `bool`. If `True`, left multiply by the adjoint: `A^H x`.
`string` name
A name for this `Op`.
##### Returns
`Tensor`
A `Tensor` with shape `[..., M]` and same `dtype` as `self`.
Show Example
```# Make an operator acting like batch matric A.  Assume A.shape = [..., M, N]
operator = LinearOperator(...)  X =... # shape [..., N], batch vector  Y = operator.matvec(X)
Y.shape
==> [..., M]  Y[..., :] = sum_j A[..., :, j] X[..., j] ```

#### objectmatvec_dyn(object x, ImplicitContainer<T> adjoint, ImplicitContainer<T> name)

Transform [batch] vector `x` with left multiplication: `x --> Ax`.
##### Parameters
`object` x
`Tensor` with compatible shape and same `dtype` as `self`. `x` is treated as a [batch] vector meaning for every set of leading dimensions, the last dimension defines a vector. See class docstring for definition of compatibility.
`ImplicitContainer<T>` adjoint
Python `bool`. If `True`, left multiply by the adjoint: `A^H x`.
`ImplicitContainer<T>` name
A name for this `Op`.
##### Returns
`object`
A `Tensor` with shape `[..., M]` and same `dtype` as `self`.
Show Example
```# Make an operator acting like batch matric A.  Assume A.shape = [..., M, N]
operator = LinearOperator(...)  X =... # shape [..., N], batch vector  Y = operator.matvec(X)
Y.shape
==> [..., M]  Y[..., :] = sum_j A[..., :, j] X[..., j] ```

#### objectto_dense_dyn(ImplicitContainer<T> name)

Return a dense (batch) matrix representing this operator.