"This notebook put the focus on the [``proj``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1proj.html) module of the pyfaust API. This module provides a bunch of projectors which are for instance necessary to implement proximal operators in [PALM](https://link.springer.com/article/10.1007/s10107-013-0701-9) algorithms. \n",
"A projector is basically a function defined from a matrix set to another (the image set is defined by a set of constraints to satisfy). \n",
"Each one of these projectors corresponds to a particular kind of constraint which can be of type ``ConstraintReal``, ``ConstraintInt`` or ``ConstraintMat``. \n",
"We will not address the constraints in this notebook however there is an important idea to keep in mind: a projector is defined by a specific configuration of one these constraints. \n",
"The reason why the constraints will not be introduced here, is because the use of projectors is quite straightforward and it is advised to use them instead of the ``ConstraintGen`` family objects. \n",
"Indeed these projectors matter in the parametrization of the [PALM4MSA](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1fact.html#a686e523273cf3e38b1b614a69f4b48af) and [hierarchical factorization](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1fact.html#a7ff9e21a4f0b4acd2107629d788c441c) algorithms, so let's maintain their configuration as simple as possible by using projectors!\n",
"\n",
"In the next we shall pass the projectors in review, starting from the integer projectors.\n",
"But first let's explain some generalities about projectors: \n",
"- They are all functor objects (objects that you can call as a function).\n",
"- They are all types defined by child classes of the parent abstract class [``proj_gen``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1proj__gen.html).\n",
"\n",
"The general pattern to use a projector unfolds in two steps: \n",
"1. Instantiate the projector passing the proper arguments. \n",
"2. Call this projector (again, as a function) on the matrix you're working on. This step is optional or for test purposes, because generally this is the algorithm implementation which calls the projectors. You just need to feed the algorithms (PALM4MSA for example) with them.\n",
"\n",
"Let's see how to define and use the projectors in the code. For the brief math definitions, I let you consult this [document](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/constraint.png).\n",
"Remember that the projector API is documented too, you'll find the link for each projector below.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Integer projectors\n",
"\n",
"The integer projectors constrains the integer sparsity of the image matrix.\n",
"\n",
"### The SP projector\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This projector governs the global sparsity of a matrix given an integer k.\n",
"The matrix $ A \\in \\mathbb{R}^{m \\times n }, A = (a_{ij})_{i \\in \\mathbb{N}^m, j \\in \\mathbb{N}^n}$ is projected to the matrix $ B = (b_{ij})_{i \\in \\mathbb{N}^m}$ such that $ k = \\#\\{b_{ij} = a_{ij} \\neq 0 \\} $ which implies , if $k < mn$, that some entries of A are kept in B and others are set to zero. The projector keeps the most k significant values (in term of absolute values or magnitude).\n",
"\n",
"Let's try on an example, here a random matrix."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from numpy.random import rand\n",
"A = rand(5,5)*100\n",
"print(\"A=\\n\", A)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pyfaust\n",
"from pyfaust.proj import sp\n",
"# 1. instantiate the projector\n",
"k = 2\n",
"p = sp(A.shape, k, normalized=False)\n",
"# 2. project the matrix through it\n",
"B = p(A)\n",
"print(\"B=\\n\", B)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The projector is simply defined by the input matrix shape and the k integer to specify the targeted sparsity. \n",
"As you noticed, the argument ``normalized`` is set to ``False`` in the projector definition, otherwise the image B would be normalized according to its 2-norm. \n",
"It is also possible to \"filter\" the negative entries of A by setting the [``pos``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1sp.html) argument of ``sp`` to ``True``."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The SPLIN and SPCOL projectors\n",
"\n",
"They are very similar to the ``sp`` projector except that ``splin`` governs the integer sparsity on a row basis and ``spcol`` does it by columns as the suffix name lets suppose. \n",
"Look at the two short examples, just to be sure."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pyfaust.proj import splin, spcol\n",
"pl = splin(A.shape, k, normalized=False)\n",
"pc = spcol(A.shape, k, normalized=False)\n",
"B1 = pl(A)\n",
"B2 = pc(A)\n",
"print(\"B1=\\n\", B1)\n",
"print(\"\\bB2=\\n\", B2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here again the most significant values are chosen (by rows for splin or by columns for spcol) and the image normalization is disabled."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The SPLINCOL projector"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The last integer projector is [``splincol``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1splincol.html). It tries to constrains the sparsity both by columns and by rows and I wrote it tries because there is not always a solution. The use is again the same."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pyfaust.proj import splincol\n",
"plc = splincol(A.shape, k, normalized=False)\n",
"print(plc(A))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The image matrix support is in fact the union set of the supports obtained through ``splin`` and ``spcol`` projectors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The Real projectors\n",
"\n",
"The pyfaust.proj modules provides two real constraint based projectors: ``normlin`` and ``normcol``. They look like the ``splin`` and ``spcol`` projectors we've seen before but here the constraint to define the matrix image set is based on the 2-norm of the rows for ``normlin`` and that of the columns for ``normcol``. \n",
"\n",
"Let's try them:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pyfaust.proj import normcol, normlin\n",
"from numpy.linalg import norm\n",
"pnl = normlin(A.shape, .2, normalized=False)\n",
"pnc = normcol(A.shape, .2, normalized=False)\n",
"# let's verify the norm for one column obtained by normlin\n",
"print(norm(pnl(A)[2,:]))\n",
"# and the same for normcol\n",
"print(norm(pnc(A)[:,2]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The Matrix projectors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The last kind of projectors to introduce are the matrix projectors. Unlike the previous projectors, they are defined by a matrix or a structure of matrix.\n",
"Let's describe two of them, for the others you can refer to the [API documentation](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1proj.html).\n",
"\n",
"### The SUPP projector\n",
"\n",
"The ``supp`` projector defines a matrix support for the arbitrary subset of entries you want to keep in a matrix. The others are set to zero."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pyfaust.proj import supp\n",
"from numpy import eye\n",
"# keep only the diagonal of A\n",
"ps = supp(eye(*A.shape))\n",
"print(ps(A))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The BLOCKDIAG projector\n",
"\n",
"Another matrix projector is the ``blockdiag`` projector. Contrary to the ``supp`` projector, for this kind of projector you don't pass a matrix as a definition but the structure of the image matrix.\n",
"The block-diagonal structure can be defined by the list of the upper-left corners of the block diagonal submatrices you want to keep from the input matrix into the output matrix. The list must be ended by passing the shape of the matrix as a last element.\n",
"This blockdiag projector above is defined in order to keep two blocks of the input matrix A, from the upper-left to the lower-right: the first block is the singleton block composed only from the single entry (0,0) and the second block from the next diagonal element to the last diagonal element of A."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As precised before, there are a few other matrix projectors, I invite you to refer to the documentation which always shows an example : [circ(culant)](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1circ.html), [hankel](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1hankel.html), [const(ant)](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1const.html), [toeplitz](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1toeplitz.html).\n",
"\n",
"----------------------"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Thanks** for reading this notebook, you'll find others on the [FAµST website](faust.inria.fr). Any feedback is welcome, all contact information is as well available on the website."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
%% Cell type:markdown id: tags:
# Using The FAµST Projectors API
This notebook put the focus on the [``proj``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1proj.html) module of the pyfaust API. This module provides a bunch of projectors which are for instance necessary to implement proximal operators in [PALM](https://link.springer.com/article/10.1007/s10107-013-0701-9) algorithms.
A projector is basically a function defined from a matrix set to another (the image set is defined by a set of constraints to satisfy).
Each one of these projectors corresponds to a particular kind of constraint which can be of type ``ConstraintReal``, ``ConstraintInt`` or ``ConstraintMat``.
We will not address the constraints in this notebook however there is an important idea to keep in mind: a projector is defined by a specific configuration of one these constraints.
The reason why the constraints will not be introduced here, is because the use of projectors is quite straightforward and it is advised to use them instead of the ``ConstraintGen`` family objects.
Indeed these projectors matter in the parametrization of the [PALM4MSA](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1fact.html#a686e523273cf3e38b1b614a69f4b48af) and [hierarchical factorization](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1fact.html#a7ff9e21a4f0b4acd2107629d788c441c) algorithms, so let's maintain their configuration as simple as possible by using projectors!
In the next we shall pass the projectors in review, starting from the integer projectors.
But first let's explain some generalities about projectors:
- They are all functor objects (objects that you can call as a function).
- They are all types defined by child classes of the parent abstract class [``proj_gen``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1proj__gen.html).
The general pattern to use a projector unfolds in two steps:
1. Instantiate the projector passing the proper arguments.
2. Call this projector (again, as a function) on the matrix you're working on. This step is optional or for test purposes, because generally this is the algorithm implementation which calls the projectors. You just need to feed the algorithms (PALM4MSA for example) with them.
Let's see how to define and use the projectors in the code. For the brief math definitions, I let you consult this [document](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/constraint.png).
Remember that the projector API is documented too, you'll find the link for each projector below.
%% Cell type:markdown id: tags:
## Integer projectors
The integer projectors constrains the integer sparsity of the image matrix.
### The SP projector
%% Cell type:markdown id: tags:
This projector governs the global sparsity of a matrix given an integer k.
The matrix $ A \in \mathbb{R}^{m \times n }, A = (a_{ij})_{i \in \mathbb{N}^m, j \in \mathbb{N}^n}$ is projected to the matrix $ B = (b_{ij})_{i \in \mathbb{N}^m}$ such that $ k = \#\{b_{ij} = a_{ij} \neq 0 \} $ which implies , if $k < mn$, that some entries of A are kept in B and others are set to zero. The projector keeps the most k significant values (in term of absolute values or magnitude).
Let's try on an example, here a random matrix.
%% Cell type:code id: tags:
``` python
fromnumpy.randomimportrand
A=rand(5,5)*100
print("A=\n",A)
```
%% Cell type:code id: tags:
``` python
importpyfaust
frompyfaust.projimportsp
# 1. instantiate the projector
k=2
p=sp(A.shape,k,normalized=False)
# 2. project the matrix through it
B=p(A)
print("B=\n",B)
```
%% Cell type:markdown id: tags:
The projector is simply defined by the input matrix shape and the k integer to specify the targeted sparsity.
As you noticed, the argument ``normalized`` is set to ``False`` in the projector definition, otherwise the image B would be normalized according to its 2-norm.
It is also possible to "filter" the negative entries of A by setting the [``pos``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1sp.html) argument of ``sp`` to ``True``.
%% Cell type:markdown id: tags:
### The SPLIN and SPCOL projectors
They are very similar to the ``sp`` projector except that ``splin`` governs the integer sparsity on a row basis and ``spcol`` does it by columns as the suffix name lets suppose.
Look at the two short examples, just to be sure.
%% Cell type:code id: tags:
``` python
frompyfaust.projimportsplin,spcol
pl=splin(A.shape,k,normalized=False)
pc=spcol(A.shape,k,normalized=False)
B1=pl(A)
B2=pc(A)
print("B1=\n",B1)
print("\bB2=\n",B2)
```
%% Cell type:markdown id: tags:
Here again the most significant values are chosen (by rows for splin or by columns for spcol) and the image normalization is disabled.
%% Cell type:markdown id: tags:
### The SPLINCOL projector
%% Cell type:markdown id: tags:
The last integer projector is [``splincol``](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1splincol.html). It tries to constrains the sparsity both by columns and by rows and I wrote it tries because there is not always a solution. The use is again the same.
%% Cell type:code id: tags:
``` python
frompyfaust.projimportsplincol
plc=splincol(A.shape,k,normalized=False)
print(plc(A))
```
%% Cell type:markdown id: tags:
The image matrix support is in fact the union set of the supports obtained through ``splin`` and ``spcol`` projectors
%% Cell type:markdown id: tags:
## The Real projectors
The pyfaust.proj modules provides two real constraint based projectors: ``normlin`` and ``normcol``. They look like the ``splin`` and ``spcol`` projectors we've seen before but here the constraint to define the matrix image set is based on the 2-norm of the rows for ``normlin`` and that of the columns for ``normcol``.
Let's try them:
%% Cell type:code id: tags:
``` python
frompyfaust.projimportnormcol,normlin
fromnumpy.linalgimportnorm
pnl=normlin(A.shape,.2,normalized=False)
pnc=normcol(A.shape,.2,normalized=False)
# let's verify the norm for one column obtained by normlin
print(norm(pnl(A)[2,:]))
# and the same for normcol
print(norm(pnc(A)[:,2]))
```
%% Cell type:markdown id: tags:
## The Matrix projectors
%% Cell type:markdown id: tags:
The last kind of projectors to introduce are the matrix projectors. Unlike the previous projectors, they are defined by a matrix or a structure of matrix.
Let's describe two of them, for the others you can refer to the [API documentation](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust_1_1proj.html).
### The SUPP projector
The ``supp`` projector defines a matrix support for the arbitrary subset of entries you want to keep in a matrix. The others are set to zero.
%% Cell type:code id: tags:
``` python
frompyfaust.projimportsupp
fromnumpyimporteye
# keep only the diagonal of A
ps=supp(eye(*A.shape))
print(ps(A))
```
%% Cell type:markdown id: tags:
### The BLOCKDIAG projector
Another matrix projector is the ``blockdiag`` projector. Contrary to the ``supp`` projector, for this kind of projector you don't pass a matrix as a definition but the structure of the image matrix.
The block-diagonal structure can be defined by the list of the upper-left corners of the block diagonal submatrices you want to keep from the input matrix into the output matrix. The list must be ended by passing the shape of the matrix as a last element.
This blockdiag projector above is defined in order to keep two blocks of the input matrix A, from the upper-left to the lower-right: the first block is the singleton block composed only from the single entry (0,0) and the second block from the next diagonal element to the last diagonal element of A.
%% Cell type:markdown id: tags:
As precised before, there are a few other matrix projectors, I invite you to refer to the documentation which always shows an example : [circ(culant)](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1circ.html), [hankel](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1hankel.html), [const(ant)](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1const.html), [toeplitz](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/classpyfaust_1_1proj_1_1toeplitz.html).
----------------------
%% Cell type:markdown id: tags:
**Thanks** for reading this notebook, you'll find others on the [FAµST website](faust.inria.fr). Any feedback is welcome, all contact information is as well available on the website.