Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 4e3ce547 authored by hhakim's avatar hhakim
Browse files

Update lazylinop jupyter notebook.

parent 71857df5
No related branches found
No related tags found
No related merge requests found
......@@ -13975,6 +13975,7 @@ a.anchor-link {
<p>Starting from a <code>numpy</code> array, a <code>scipy</code> matrix, a <code>Faust</code> object, or potentially many other compatible linear operators with efficient implementatons, this class follows the <em>lazy evaluation paradigm</em>.</p>
<p>In short, one can <em>aggregate low-level <code>LazyLinearOp</code> objects into higher-level ones</em> using classical operations (addition, concatenation, adjoint, real part, slicing, etc.), without actually building arrays. The actual effect of these operations is delayed until the resulting linear operator is actually applied to a vector (or to a collection of vectors, seen as a matrix).</p>
<p>The main interest of this paradigm is to enable the construction of processing pipelines that exploit as building blocks efficient implementations of ``low-level'' linear operators.</p>
<p>LazyLinearOperators are complementary to other “lazy” objects such as LazyTensors in <a href="https://www.kernel-operations.io/keops/_auto_tutorials/a_LazyTensors/plot_lazytensors_a.html">Kheops</a>, or the ones of <a href="https://lazyarray.readthedocs.io/en/latest/index.html">lazyarray</a>, <a href="https://www.weld.rs/weldnumpy/]">WeldNumpy</a> libraries, which, to the best of our knowledge, primarily provide compact descriptions of arrays which entries can be evaluated efficiently on the fly.</p>
<h2 id="This-notebook">This notebook<a class="anchor-link" href="#This-notebook">&#182;</a></h2><p>In this notebook we shall see how to create a <code>LazyLinearOp</code> instance, create more complex instances using various lazy operations, and finally how to apply the resulting instance on vectors or matrices. We assume the reader is familiar with at least <code>numpy</code> arrays and their operations.</p>
 
</div>
......@@ -14267,8 +14268,8 @@ Let us mention most importantly:</p>
 
 
<div class="jp-RenderedText jp-OutputArea-output jp-OutputArea-executeResult" data-mime-type="text/plain">
<pre>array([-2.63467895e+11+0.j, -1.82512222e+11+0.j, -3.24855445e+11+0.j, ...,
-2.18234934e+11+0.j, -1.40949814e+11+0.j, -2.27929503e+11+0.j])</pre>
<pre>array([-2.43516666e+11, -5.23268916e+11, -4.19169965e+11, ...,
-2.58653991e+11, -3.34532139e+11, -6.53673371e+11])</pre>
</div>
 
</div>
......@@ -14357,13 +14358,13 @@ Let us mention most importantly:</p>
 
 
<div class="jp-RenderedText jp-OutputArea-output jp-OutputArea-executeResult" data-mime-type="text/plain">
<pre>array([[-21912992.26312142+0.j],
[-15180144.64900897+0.j],
[-27019233.94555141+0.j],
<pre>array([[-19787814.52565873],
[-42520196.99833652],
[-34061613.02022415],
...,
[-18151408.88322322+0.j],
[-11723135.21816526+0.j],
[-18957276.86080584+0.j]])</pre>
[-21018083.96961382],
[-27184057.67527183],
[-53118164.47840539]])</pre>
</div>
 
</div>
......@@ -14387,7 +14388,7 @@ Let us mention most importantly:</p>
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[10]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[11]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="o">%</span><span class="k">timeit</span> lFs@M
......@@ -14414,33 +14415,9 @@ Let us mention most importantly:</p>
 
 
<div class="jp-RenderedText jp-OutputArea-output" data-mime-type="text/plain">
<pre>2.47 s ± 192 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
</pre>
</div>
</div>
<div class="jp-OutputArea-child">
<div class="jp-OutputPrompt jp-OutputArea-prompt"></div>
<div class="jp-RenderedText jp-OutputArea-output" data-mime-type="application/vnd.jupyter.stderr">
<pre>/home/hinria/faust2/build/wrapper/python/pyfaust/__init__.py:1232: UserWarning: The numpy array to multiply is not F_CONTIGUOUS, costly conversion on the fly. Please use np.asfortranarray by yourself.
w = lambda: warnings.warn(&#34;The numpy array to multiply is not &#34;
</pre>
</div>
</div>
<div class="jp-OutputArea-child">
<div class="jp-OutputPrompt jp-OutputArea-prompt"></div>
<div class="jp-RenderedText jp-OutputArea-output" data-mime-type="text/plain">
<pre>1.16 s ± 75.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
4.51 s ± 543 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
<pre>2 s ± 86.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
880 ms ± 44.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.51 s ± 69.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
consistent results: True
</pre>
</div>
......@@ -14471,7 +14448,7 @@ consistent results: True
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[11]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[12]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="kn">from</span> <span class="nn">scipy.sparse.linalg</span> <span class="kn">import</span> <span class="n">svds</span>
......@@ -14494,7 +14471,7 @@ consistent results: True
<div class="jp-OutputArea-child">
 
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[11]:</div>
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[12]:</div>
 
 
 
......@@ -14519,7 +14496,7 @@ consistent results: True
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[12]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[13]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="kn">from</span> <span class="nn">pyfaust.lazylinop</span> <span class="kn">import</span> <span class="n">kron</span> <span class="k">as</span> <span class="n">lkron</span>
......@@ -14546,7 +14523,7 @@ consistent results: True
<div class="jp-OutputArea-child">
 
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[12]:</div>
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[13]:</div>
 
 
 
......@@ -14570,7 +14547,7 @@ consistent results: True
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[13]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[14]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="o">%</span><span class="k">timeit</span> AxB @ x
......@@ -14593,7 +14570,7 @@ consistent results: True
 
 
<div class="jp-RenderedText jp-OutputArea-output" data-mime-type="text/plain">
<pre>42.6 ms ± 2.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
<pre>38.4 ms ± 967 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
</pre>
</div>
</div>
......@@ -14605,7 +14582,7 @@ consistent results: True
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[14]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[15]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="o">%</span><span class="k">timeit</span> lAxB @ x
......@@ -14628,7 +14605,7 @@ consistent results: True
 
 
<div class="jp-RenderedText jp-OutputArea-output" data-mime-type="text/plain">
<pre>2.76 ms ± 282 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
<pre>816 µs ± 110 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
</pre>
</div>
</div>
......@@ -14647,7 +14624,7 @@ consistent results: True
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell jp-mod-noOutputs ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[15]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[16]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="kn">from</span> <span class="nn">pyfaust</span> <span class="kn">import</span> <span class="n">dft</span>
......@@ -14674,7 +14651,7 @@ The operator can totally be applied on matrices too. So, since we choose to appl
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell jp-mod-noOutputs ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[16]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[17]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="n">F</span> <span class="o">=</span> <span class="n">dft</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">normed</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
......@@ -14695,7 +14672,7 @@ The operator can totally be applied on matrices too. So, since we choose to appl
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[17]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[18]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
......@@ -14715,7 +14692,7 @@ The operator can totally be applied on matrices too. So, since we choose to appl
<div class="jp-OutputArea-child">
 
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[17]:</div>
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[18]:</div>
 
 
 
......@@ -14740,7 +14717,7 @@ The operator can totally be applied on matrices too. So, since we choose to appl
</div><div class="jp-Cell jp-CodeCell jp-Notebook-cell ">
<div class="jp-Cell-inputWrapper">
<div class="jp-InputArea jp-Cell-inputArea">
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[18]:</div>
<div class="jp-InputPrompt jp-InputArea-prompt">In&nbsp;[19]:</div>
<div class="jp-CodeMirrorEditor jp-Editor jp-InputArea-editor" data-type="inline">
<div class="CodeMirror cm-s-jupyter">
<div class=" highlight hl-ipython3"><pre><span></span><span class="n">pf</span><span class="o">.</span><span class="n">version</span><span class="p">()</span>
......@@ -14759,13 +14736,13 @@ The operator can totally be applied on matrices too. So, since we choose to appl
<div class="jp-OutputArea-child">
 
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[18]:</div>
<div class="jp-OutputPrompt jp-OutputArea-prompt">Out[19]:</div>
 
 
 
 
<div class="jp-RenderedText jp-OutputArea-output jp-OutputArea-executeResult" data-mime-type="text/plain">
<pre>&#39;3.35.13&#39;</pre>
<pre>&#39;3.35.15&#39;</pre>
</div>
 
</div>
......
%% Cell type:markdown id: tags:
# Using LazyLinearOp-s
The ``LazyLinearOp`` class defines a kind of linear operator extending the scipy [LinearOperator](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.LinearOperator.html) class.
Starting from a ``numpy`` array, a ``scipy`` matrix, a ``Faust`` object, or potentially many other compatible linear operators with efficient implementatons, this class follows the *lazy evaluation paradigm*.
In short, one can *aggregate low-level ``LazyLinearOp`` objects into higher-level ones* using classical operations (addition, concatenation, adjoint, real part, slicing, etc.), without actually building arrays. The actual effect of these operations is delayed until the resulting linear operator is actually applied to a vector (or to a collection of vectors, seen as a matrix).
The main interest of this paradigm is to enable the construction of processing pipelines that exploit as building blocks efficient implementations of ``low-level'' linear operators.
LazyLinearOperators are complementary to other “lazy” objects such as LazyTensors in [Kheops](https://www.kernel-operations.io/keops/_auto_tutorials/a_LazyTensors/plot_lazytensors_a.html), or the ones of [lazyarray](https://lazyarray.readthedocs.io/en/latest/index.html), [WeldNumpy](https://www.weld.rs/weldnumpy/]) libraries, which, to the best of our knowledge, primarily provide compact descriptions of arrays which entries can be evaluated efficiently on the fly.
## This notebook
In this notebook we shall see how to create a ``LazyLinearOp`` instance, create more complex instances using various lazy operations, and finally how to apply the resulting instance on vectors or matrices. We assume the reader is familiar with at least ``numpy`` arrays and their operations.
%% Cell type:markdown id: tags:
### 1. How to create and use a LazyLinearOp
In order to create this kind of object, you simply need to use the ``aslazylinearoperator`` function. This function receives an object that represents a linear operator, for instance a ``Faust`` (but it can also be a ``numpy`` array or a ``scipy`` matrix). Besides, note that there is another way to create a LazyLinearOp using the kind of functions we call matmat or matvec as explained in 4.3 with the FFT use case.
In the example below, the function ``aslazylinearoperator`` allows us to instantiate a ``LazyLinearOp`` that encapsulates a ``Faust``.
%% Cell type:code id: tags:
``` python
from pyfaust.lazylinop import aslazylinearoperator
import pyfaust as pf
import numpy as np
n = 3000
# create a random Faust
F = pf.rand(n, n, density=.001)
# create a LazyLinearOp upon it
lF = aslazylinearoperator(F)
print(lF)
```
%% Cell type:markdown id: tags:
As said earlier, it is also possible to create ``LazyLinearOp`` operators based on ``numpy`` arrays or ``scipy`` matrices.
%% Cell type:code id: tags:
``` python
from scipy.sparse import random
from numpy.random import rand
S = random(n, n, .2, format='csc') # scipy matrix
lS = aslazylinearoperator(S)
M = rand(n, n) + rand(n,n)*1j # numpy complex array
lM = aslazylinearoperator(M)
```
%% Cell type:markdown id: tags:
It's worth noting that a ``LazyLinearOp`` must have two dimensions. Trying to instantiate a ``LazyLinearOp`` from a vector (defined with one dimension) would raise an exception, as the example below shows.
%% Cell type:code id: tags:
``` python
try:
lMSF_imag@aslazylinearoperator(np.random.rand(n))
except:
print("A LazyLinearOp must have two dimensions")
```
%% Cell type:markdown id: tags:
As a matter of fact, vectors can be interpreted as matrices but there is always an ambiguity whether this matrix has a single row or a single column.
%% Cell type:markdown id: tags:
Then we can start to build more complex ``LazyLinearOp`` objects using various operations. For example, let's multiply ``lF`` by a scalar:
%% Cell type:code id: tags:
``` python
lF = 2 * lF
print(lF)
```
%% Cell type:markdown id: tags:
As you can see the result is still a ``LazyLinearOp`` after the scalar multiplication. That's the principle of the lazy evaluation we mentioned in the beginning of this notebook. No operation is really computed, only the track of the operations is kept in a new ``LazyLinearOp`` object.
Let's continue with other possible operations. For example, a matrix multiplication and then a concatenation.
%% Cell type:code id: tags:
``` python
import pyfaust.lazylinop as lp
lFs = lF @ lF
print("lF shape before concatenation:", lFs.shape)
lFc = lp.vstack((lFs, lFs))
print("lF shape after concatenation:", lFc.shape)
```
%% Cell type:markdown id: tags:
Note that we know the ``shape`` of the resulting LazyLinearOp without the need to evaluate it.
Let's try other operations with ``lM`` and ``lS``, all ``LazyLinearOp`` are compatible with each other provided their ``shape``s are compatible.
%% Cell type:code id: tags:
``` python
lMSF = lFc[:n, :] @ (2 * lM.conj().T @ lS)
# then get back the imaginary part of the LazyLinearOp
lMSF_imag = lMSF.imag
```
%% Cell type:markdown id: tags:
For a tour of all supported operations on ``LazyLinearOp`` objects please take a look at : [LazyLinearOp reference](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1lazylinop_1_1LazyLinearOp.html).
Let us mention most importantly:
* lazy scalar multiplication
* lazy addition
* lazy operator multiplication
* lazy operator concatenation
* lazy slicing
* lazy real/imaginary part
* lazy operator tranpose / conjugate / transconjugate
%% Cell type:markdown id: tags:
### 2. Applying a LazyLinearOp to a vector or a matrix
Now that we've seen how to create and operate a ``LazyLinearOp`` let's see how to apply it to a vector or a matrix, represented by a ``numpy`` array.
%% Cell type:code id: tags:
``` python
import numpy as np
v = np.arange(n)
lMSF_imag@v
```
%% Cell type:markdown id: tags:
Note the difference with the lazy multiplication by the another random vector taken as A ``LazyLinearOp``.
%% Cell type:code id: tags:
``` python
lMSF_imag@aslazylinearoperator(np.random.rand(n,1))
```
%% Cell type:markdown id: tags:
Instead of computing the resulting vector it gives another ``LazyLinearOp``.
The vector doesn't have to be dense, a sparse one can totally be used in the multiplication.
%% Cell type:code id: tags:
``` python
from scipy.sparse import random as srand
s = srand(n,1, density=0.25)
lMSF_imag@s
```
%% Cell type:markdown id: tags:
One can also simply *convert* a ``LazyLinearOp`` to an equivalent numpy array using ``LazyLinearOp.toarray``. An example will come next when we compare the resulting computation times.
%% Cell type:markdown id: tags:
### 3. Comparing computation times
As a last step in this notebook, we shall verify how much computation time it takes to use a ``LazyLinearOp`` compared to a numpy array. Of course it depends on the underlying objects used behind (in the operations encoded in the ``LazyLinearOp``). Here we make the measurement on ``lFs`` which was initialized before upon a Faust object.
%% Cell type:code id: tags:
``` python
%timeit lFs@M
%timeit lFs.toarray()
FD = lFs.toarray() # FD is a numpy array
%timeit FD@M
print("consistent results:", np.allclose(lFs@M, FD@M))
```
%% Cell type:markdown id: tags:
Great! As expected ``lFs`` is faster to apply than its numpy array counterpart ``FD``.
%% Cell type:markdown id: tags:
### 4. Higher-level operations on LazyLinearOp
%% Cell type:markdown id: tags:
Because a ``LazyLinearOp`` is a kind of scipy ``LinearOperator``, it is straightforward to use many operations provided by scipy on this type of object.
#### 4.1 The SVD
For example, let's try a SVD decomposition on a ``LazyLinearOp`` in one hand and on a numpy array on the other hand.
%% Cell type:code id: tags:
``` python
from scipy.sparse.linalg import svds
lF = aslazylinearoperator(pf.rand(25, 25))
U1, S1, Vh1 = svds(lF)
U2, S2, Vh2 = svds(lF.toarray())
np.allclose(U1 @ np.diag(S1) @ Vh1, U2 @ np.diag(S2) @ Vh2, atol=1e-8)
```
%% Cell type:markdown id: tags:
It works the same!
#### 4.2 The Kronecker product
Another operation we can try is the Kronecker product. This time we will use the ``numpy.kron`` function on A and B numpy arrays and we will compare this function to the ``pyfaust.lazylinop.kron`` which computes the Kronecker product too but as a ``LazyLinearOp``. Precisely, we compare these functions on the multiplication of the Kronecker product by a vector.
%% Cell type:code id: tags:
``` python
from pyfaust.lazylinop import kron as lkron
import numpy as np
from pyfaust import rand
A = np.random.rand(100, 100)
B = np.random.rand(100, 100)
AxB = np.kron(A,B)
lAxB = lkron(A, B)
x = np.random.rand(AxB.shape[1], 1)
np.allclose(AxB@x, lAxB@x)
```
%% Cell type:markdown id: tags:
The two versions of kron give the same result. Now let's compare the computation times.
%% Cell type:code id: tags:
``` python
%timeit AxB @ x
```
%% Cell type:code id: tags:
``` python
%timeit lAxB @ x
```
%% Cell type:markdown id: tags:
The LazyLinearOp kron function is much faster! Indeed, it is optimized for ``LazyLinearOp-s``.
#### 4.3 The FFT and its inverse as a LazyLinearOp
Now let's explain how it is possible to create a ``LazyLinearOp`` not using a pre-defined operator like a Faust or a numpy array but a function that defines how to apply the operator on a vector (the kind of function we name matvec) or on a matrix (in which case the function is named matmat). Actually, this process mimics the scipy [LinearOperator](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.LinearOperator.html) constructor, so it works pretty the same for a ``LazyLinearOp`` as we show in the example below for an operator that represents the FFT.
%% Cell type:code id: tags:
``` python
from pyfaust import dft
from pyfaust.lazylinop import LazyLinearOperator, aslazylinearoperator
import numpy as np
from scipy.fft import fft, ifft
n = 1024
lfft = LazyLinearOperator(matvec=lambda x: fft(x, axis=0), rmatvec=lambda x: n * ifft(x, axis=0), shape=(n, n))
```
%% Cell type:markdown id: tags:
Hence, ``lfft`` is a ``LazyLinearOp`` defined upon the scipy ``fft`` and ``ifft`` functions. Here ``fft`` is the matvec function, it defines how to apply the ``lfft`` operator to a vector. Likewise, the ``ifft``, as a ``rmatvec`` function, defines how to apply the inverse of the lfft operator to a vector.
The operator can totally be applied on matrices too. So, since we choose to apply the 1D FFT on columns instead of rows we set the axis argument of scipy fft to 0. The reason of the scaling by n of the ``ifft`` is to find on the scipy documentation [fft doc.](https://docs.scipy.org/doc/scipy/reference/generated/scipy.fft.fft.html#scipy.fft.fft) (look at the norm argument). For more details about the ``LazyLinearOperator`` constructor, please look at the [API documentation](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1lazylinop.html).
We can compare this ``lfft`` operator to the equivalent operator based this time on the DFT Faust.
%% Cell type:code id: tags:
``` python
F = dft(n, normed=False)
lF = aslazylinearoperator(F)
```
%% Cell type:markdown id: tags:
The two operators give the same results when applying them to a vector.
%% Cell type:code id: tags:
``` python
x = np.random.rand(n)
np.allclose(lfft @ x, lF @ x)
```
%% Cell type:markdown id: tags:
This notebook comes to its end. We've seen quickly how to create and evaluate ``LazyLinearOp`` objects based on numpy arrays, scipy matrices, or a Faust objects. We've also seen how to define them upon ``matmat`` and ``matvec`` functions. We've tried a bunch of operations we can call on this kind of objects. For more information about ``LazyLinearOp`` objects you can take a look to the API documentation [here](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1lazylinop.html).
**NOTE**: this notebook was executed using the pyfaust version:
%% Cell type:code id: tags:
``` python
pf.version()
```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment