Basic operators

lazylinop.wip.basicops.anti_diag(v, k=0, extract_meth='canonical_vectors', extract_batch=1)

Extracts an antidiagonal or builds an antidiagonal LazyLinOp.

Args:
v: (compatible linear operator, 1D numpy.ndarray)
  • If v is a LazyLinOp or an array-like compatible object, returns a copy of its k-th antidiagonal.

  • If v is a 1D numpy array, returns a LazyLinOp with v on the k-th antidiagonal.

k: (int)

The index of antidiagonal, 0 for the main antidiagonal, k > 0 for upper antidiagonals, k < 0 for lower antidiagonals below (see anti_eye()).

extract_meth: (str)

The method used to extract the antidiagonal vector. The interest to have several methods resides in their difference of memory and execution time costs but also on the operator capabilities (e.g. not all of them support a CSC matrix as multiplication operand).

  • 'canonical_vectors': use canonical basis vectors \(e_i\) to extract each antidiagonal element of the operator. It takes an operator-vector multiplication to extract each antidiagonal element.

  • 'canonical_vectors_csc': The same as above but using scipy CSC matrices to encode the canonical vectors. The memory cost is even smaller than that of 'canonical_vectors'. However v must be compatible to CSC matrices multiplication.

  • 'slicing': extract antidiagonal elements by slicing rows and columns by blocks of shape (extract_batch, extract_batch).

  • 'toarray': use LazyLinOp.toarray() to extract the antidiagonal after a conversion to a whole numpy array.

extract_batch: (int)
  • The size of the batch used for partial antidiagonal extraction in 'canonical_vectors', 'canonical_vectors_csc' and 'slicing ' methods.

    This argument is ignored for 'toarray' method.

Antidiagonal extraction cost

Even though the 'toarray' method is generally faster if the operator is not extremely large it has an important memory cost (\(O(v.shape[0] \times v.shape[1])\)) . Hence the default method is canonical_vectors in order to avoid memory consumption. However note that this method allows to define a memory-time trade-off with the extract_batch argument. The larger is the batch, the faster should be the execution (provided enough memory is available).

Returns:

The extracted antidiagonal numpy vector or the constructed antidiagonal LazyLinOp.

Example: (antidiagonal LazyLinOp)
>>> import lazylinop.wip.basicops as lz
>>> import numpy as np
>>> v = np.arange(1, 6)
>>> v
array([1, 2, 3, 4, 5])
>>> ld1 = lz.anti_diag(v)
>>> ld1
<5x5 LazyLinOp with dtype=int64>
>>> ld1.toarray()
array([[0, 0, 0, 0, 1],
       [0, 0, 0, 2, 0],
       [0, 0, 3, 0, 0],
       [0, 4, 0, 0, 0],
       [5, 0, 0, 0, 0]])
>>> ld2 = lz.anti_diag(v, -2)
>>> ld2
<7x7 LazyLinOp with dtype=int64>
>>> ld2.toarray()
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 2, 0],
       [0, 0, 0, 0, 3, 0, 0],
       [0, 0, 0, 4, 0, 0, 0],
       [0, 0, 5, 0, 0, 0, 0]])
>>> ld3 = lz.anti_diag(v, 2)
>>> ld3
<7x7 LazyLinOp with dtype=int64>
>>> ld3.toarray()
array([[0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 2, 0, 0, 0],
       [0, 0, 3, 0, 0, 0, 0],
       [0, 4, 0, 0, 0, 0, 0],
       [5, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])
Example: (antidiagonal extraction)
>>> import lazylinop.wip.basicops as lz
>>> import numpy as np
>>> lD = aslazylinop(np.random.rand(10, 12))
>>> d = lz.anti_diag(lD, -2, extract_meth='toarray', extract_batch=3)
>>> # verify d is really the antidiagonal of index -2
>>> d_ = np.diag(np.fliplr(lD.toarray()), -2)
>>> np.allclose(d, d_)
True
lazylinop.wip.basicops.mean(op, axis=0, meth='ones')

Computes the arithmetic mean LazyLinOp of op along the specified axis.

Args:
op: LazyLinOp or compatible linear operator

The operator whose mean is computed.

axis: int, optional

Axis along which the mean is computed (0 or 1).

meth: str

The method used to compute the mean.

  • 'ones': op is multiplied by appropriate ones().

  • 'avg': average() is called with same weights for every columns/rows.

Returns:

LazyLinOp for mean of op.

Note

The returned LazyLinOp cannot be of integer dtype because the mean is never made with integer division (// is not supported by LazyLinOp class).

Example:
>>> import lazylinop
>>> import lazylinop.wip.basicops as lz
>>> lzo = lazylinop.ones((2, 3))
>>> lzo_m = lz.mean(lzo, axis=0)
>>> print(lzo_m)
<1x3 LazyLinOp with dtype=float64>
>>> print(lzo_m.toarray())
[[1. 1. 1.]]
>>> lzo2 = lzo * 2
>>> lzo_m2 = lz.mean(lzo2, axis=1)
>>> print(lzo_m2.toarray())
[[2.]
 [2.]]
lazylinop.wip.basicops.average(op, axis=0, weights=None)

Computes the weighted average LazyLinOp of op along the specified axis.

Args:
op: LazyLinOp or compatible linear operator

The operator whose average is computed.

axis: int, optional

Axis along which the average is computed (0 or 1).

weights: None or numpy.ndarray (vector of scalars), optional
  • weights[i] is the weight of the row i (resp. column i) if axis=0 (resp. if axis=1).

  • If None (default) all columns/rows have the same weight.

Returns:

LazyLinOp for mean of op.

Examples:
>>> import lazylinop as lz
>>> import lazylinop.wip.basicops as lzb
>>> lzo1 = lz.ones((2, 3), dtype='float') * 2
>>> lzo2 = lz.ones((2, 3), dtype='float') * 3
>>> lzo = lz.vstack((lzo1, lzo2))
>>> w0 = [1, .5, 1.5, 2]
>>> a1 = lzb.average(lzo, axis=0, weights=w0)
>>> print(a1)
<1x3 LazyLinOp with dtype=float64>
>>> print(a1.toarray())
[[2.7 2.7 2.7]]
>>> np_a1 = np.average(lzo.toarray(), axis=0, weights=w0)
>>> print(np.allclose(a1.toarray(), np_a1))
True
>>> w1 = [1, 2.2, 3]
>>> a2 = lzb.average(lzo, axis=1, weights=w1)
>>> print(a2.toarray())
[[2.]
 [2.]
 [3.]
 [3.]]
>>> np_a2 = np.average(lzo.toarray(), axis=1, weights=w1)
>>> print(np.allclose(a2.toarray().ravel(), np_a2))
True