~daniele-bigoni/tensortoolbox/tt-docs

« back to all changes in this revision

Viewing changes to Docs/Sphinx/tw.rst

  • Committer: Daniele Bigoni
  • Date: 2015-01-19 11:10:20 UTC
  • Revision ID: dabi@dtu.dk-20150119111020-p0uckg4ab3xqzf47
merged with research

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Tensor Wrapper
 
2
--------------
 
3
 
 
4
The tensor wrapper is a data structure which mimics the behavior of a `numpy.ndarray <http://docs.scipy.org/doc/numpy/index.html>`_ and associates each item of the tensor with the evaluation of a user-defined function on the corresponding grid point.
 
5
 
 
6
Let for example :math:`\mathcal{X} = \times_{i=1}^d {\bf x}_i`, where :math:`{\bf x}_i` define the position of the grid points in the :math:`i`-th direction. Let us consider the function :math:`f:\mathcal{X}\rightarrow \mathbb{R}^{n_1\times \ldots \times n_m}`. Let us define the tensor valued tensor :math:`\mathcal{A}=f(\mathcal{X})`. Thus any entry :math:`\mathcal{A}[i_1,\ldots,i_d] = f({\bf x}_{i_1},\ldots,{\bf x}_{i_d})` is a tensor in :math:`\mathbb{R}^{n_1\times \ldots \times n_m}`. The storage of the whole tensor :math:`\mathcal{A}` can be problematic for big :math:`d` and :math:`m`, and not necessary if one is just willing to sample values from it. 
 
7
 
 
8
The :py:class:`~TensorToolbox.TensorWrapper` allows the access to the elements of :math:`\mathcal{A}` which however are not all allocated, but computed on-the-fly and stored in a hash-table data structure (a Python dictionary). The :py:class:`~TensorToolbox.TensorWrapper` can be reshaped and accessed as if it was a `numpy.ndarray <http://docs.scipy.org/doc/numpy/index.html>`_ (including slicing of indices). Additionally it allows the existence of multiple views of the tensor, sharing among them the allocated data, and it allows the *Quantics* folding used within the *Quantics Tensor Train* :cite:`Khoromskij2011,Khoromskij2010` routines :py:class:`~TensorToolbox.QTTvec`.
 
9
 
 
10
In the following we will use a simple example to show the capabilities of this data structure. We will let :math:`d=2` and :math:`f:\mathcal{X}\rightarrow \mathbb{R}`.
 
11
 
 
12
Construction
 
13
^^^^^^^^^^^^
 
14
 
 
15
In order to **construct** a :py:class:`~TensorToolbox.TensorWrapper` we need first to define a grid and a function.
 
16
 
 
17
.. doctest:: tw
 
18
 
 
19
   >>> import numpy as np
 
20
   >>> import itertools
 
21
   >>> import TensorToolbox as TT
 
22
   >>> d = 2
 
23
   >>> x_fine = np.linspace(-1,1,7)
 
24
   >>> params = {'k': 1.}
 
25
   >>> def f(X,params):
 
26
   >>>     return np.max(X) * params['k']
 
27
   >>> TW = TT.TensorWrapper( f, [ x_fine ]*d, params, dtype=float )
 
28
 
 
29
Access and data
 
30
^^^^^^^^^^^^^^^
 
31
 
 
32
The :py:class:`~TensorToolbox.TensorWrapper` can then be **accessed** as a `numpy.ndarray <http://docs.scipy.org/doc/numpy/index.html>`_:
 
33
 
 
34
.. doctest:: tw
 
35
 
 
36
   >>> TW[1,2]
 
37
   -0.33333333333333337
 
38
 
 
39
This access to the :py:class:`~TensorToolbox.TensorWrapper` has caused the evaluation of the function :math:`f` and the storage of the associated value. In order to check the **fill level** of the :py:class:`~TensorToolbox.TensorWrapper`, we do:
 
40
 
 
41
.. doctest:: tw
 
42
 
 
43
   >>> TW.get_fill_level()
 
44
   1
 
45
 
 
46
The **evaluation indices** at which the function has been evaluated can be retrived this way:
 
47
 
 
48
.. doctest:: tw
 
49
 
 
50
   >>> TW.get_fill_idxs()
 
51
   [(1, 2)]
 
52
 
 
53
The :py:class:`~TensorToolbox.TensorWrapper` can be accessed using also **slicing** along some of the coordinates:
 
54
 
 
55
.. doctest:: tw
 
56
 
 
57
   >>> TW[:,1:6:2]
 
58
   array([[-0.66666666666666674, 0.0, 0.66666666666666652],
 
59
       [-0.66666666666666674, 0.0, 0.66666666666666652],
 
60
       [-0.33333333333333337, 0.0, 0.66666666666666652],
 
61
       [0.0, 0.0, 0.66666666666666652],
 
62
       [0.33333333333333326, 0.33333333333333326, 0.66666666666666652],
 
63
       [0.66666666666666652, 0.66666666666666652, 0.66666666666666652],
 
64
       [1.0, 1.0, 1.0]], dtype=object)
 
65
 
 
66
The **data** already computed are stored in the dictionary :py:attr:`TensorWrapper.data`, which one can access and modify at his/her own risk. The data can be **erased** just by resetting the :py:attr:`TensorWrapper.data` field:
 
67
 
 
68
.. doctest:: tw
 
69
 
 
70
   >>> TW.data = {}
 
71
 
 
72
The constructed :py:class:`~TensorToolbox.TensorWrapper` to which has not been applied any of the view/extension/reshaping functions presented in the following, is called the **global** tensor wrapper. The shape informations regarding the global wrapper can be *always* accessed by:
 
73
 
 
74
.. doctest:: tw
 
75
 
 
76
   >>> TW.get_global_shape()
 
77
   (7, 7)
 
78
   >>> TW.get_global_ndim()
 
79
   2
 
80
   >>> TW.get_global_size()
 
81
   49
 
82
 
 
83
If no view/extension/reshaping has been applied to the :py:class:`~TensorToolbox.TensorWrapper`, then the same output is obtained by:
 
84
 
 
85
.. doctest:: tw
 
86
 
 
87
   >>> TW.get_shape()
 
88
   (7, 7)
 
89
   >>> TW.get_ndim()
 
90
   2
 
91
   >>> TW.get_size()
 
92
   49
 
93
 
 
94
or by 
 
95
 
 
96
.. doctest:: tw
 
97
 
 
98
   >>> TW.shape
 
99
   (7, 7)
 
100
   >>> TW.ndim
 
101
   2
 
102
   >>> TW.size
 
103
   49
 
104
 
 
105
.. note:: If any view/extension/reshape has been applied to the :py:class:`~TensorToolbox.TensorWrapper`, then the output of :py:meth:`TensorWrapper.get_global_shape` and :py:meth:`TensorWrapper.get_shape` will differ. Anyway :py:meth:`TensorWrapper.get_global_shape` will *always* return the information regarding the **global** tensor wrapper.
 
106
 
 
107
Views
 
108
^^^^^
 
109
 
 
110
The :py:class:`~TensorToolbox.TensorWrapper` allows the definition of multiple views over the defined tensor. The information regarding each view are contained in the dictionary :py:attr:`TensoWrapper.maps`. The main view is called ``full`` and is defined at construction time. Additional views can be defined through the function :py:meth:`TensorWrapper.set_view`. Let's continue the previous example, by adding a new view to the wrapper with a coarser grid.
 
111
 
 
112
.. doctest:: tw
 
113
 
 
114
   >>> x_coarse = np.linspace(-1,1,4)
 
115
   >>> TW.set_view( 'coarse', [x_coarse]*d )
 
116
 
 
117
.. note:: The grid of the ``full`` view must contain the grids associated to the new view.
 
118
 
 
119
The different views can be accessed separately, but they all refer to the same global data structure. In order to access the :py:class:`~TensorToolbox.TensorWrapper` through one of its views, the view must be **activated**:
 
120
 
 
121
.. doctest:: tw
 
122
 
 
123
   >>> TW.set_active_view('coarse')
 
124
   >>> TW[2,:]
 
125
   >>> TW.set_active_view('full')
 
126
   >>> TW[1,:]
 
127
   >>> TW[:,2]
 
128
 
 
129
The following figure shows the global grid as well as its two views, the ``full`` and the ``coarse`` views. The allocated indicies are also highlighted.
 
130
 
 
131
.. figure:: _static/Figures/TensorWrapperViews.*
 
132
 
 
133
   The global tensor and two of its views. The ``full`` view corresponds by default to the global tensor. The ``coarse`` is contained in the ``full`` view. The uniquely allocated values of the tensor are shown in the different views.
 
134
 
 
135
The shape characteristics of the active view can be accessed through :py:meth:`TensorWrapper.get_view_shape` and the corresponding commands for ``ndim`` and ``size``. For example:
 
136
 
 
137
.. doctest:: tw
 
138
 
 
139
   >>> TW.set_active_view('full')
 
140
   >>> TW.get_view_shape()
 
141
   (7,7)
 
142
   >>> TW.get_shape()
 
143
   (7,7)
 
144
   >>> TW.set_active_view('coarse')
 
145
   >>> TW.get_global_shape()
 
146
   (7,7)
 
147
   >>> TW.get_view_shape()
 
148
   (4,4)
 
149
   >>> TW.get_shape()
 
150
   (4,4)
 
151
   >>> TW.shape
 
152
   (4,4)
 
153
 
 
154
 
 
155
Quantics extension
 
156
^^^^^^^^^^^^^^^^^^
 
157
 
 
158
The quantics extension is used for extending the indices of the tesnor to the next power of ``Q``. The extension is performed so that the last coordinate point is appended to the coordinate points the necessary number of times. In order to apply the extension on a particular view, one needs to activate the view and then use the method :py:meth:`TensorWrapper.set_Q`.
 
159
 
 
160
.. doctest:: tw
 
161
 
 
162
   >>> TW.set_active_view('full')
 
163
   >>> TW.get_view_shape()
 
164
   (7,7)
 
165
   >>> TW.get_extended_shape()
 
166
   (7,7)
 
167
   >>> TW.set_Q(2)
 
168
   >>> TW.get_extended_shape()
 
169
   (8,8)
 
170
   >>> TW.get_shape()
 
171
   (8,8)
 
172
   >>> TW.shape
 
173
   (8,8)
 
174
 
 
175
We can see that :py:meth:`TensorWrapper.get_extended_shape` returns the same output of :py:meth:`TensorWrapper.get_viw_shape` if no quantics extension has been applied.
 
176
 
 
177
Using the following code we can investigate the content of the extended tensor wrapper and plot it as shown in the following figure.
 
178
 
 
179
>>> A = TW[:,:]
 
180
>>> import matplotlib.pyplot as plt
 
181
>>> plt.figure(figsize=(6,5))
 
182
>>> plt.imshow(A,interpolation='none')
 
183
>>> plt.tight_layout()
 
184
>>> plt.show(False)
 
185
 
 
186
.. figure:: _static/Figures/TensorWrapperQExtension.*
 
187
 
 
188
   The *Quantics* extension applied to the ``full`` view results in the repetition of its limit values in the tensor grid.
 
189
 
 
190
Reshape
 
191
^^^^^^^
 
192
 
 
193
The shape of each view can be changed as long as the size returned by :py:meth:`TensorWrapper.get_extended_size` is unchanged. This means that if *no quantics* extension has been applied, the size must correspond to :py:meth:`TensorWrapper.get_view_size`. If a *quantics* extension has been applied, the size must correspond to :py:meth:`TensorWrapper.get_extended_size`.
 
194
 
 
195
For example let us reshape the *quantics* extended ``full`` view of the tensor to the shape (4,16).
 
196
 
 
197
.. doctest:: tw
 
198
   
 
199
   >>> TW.set_active_view('full')
 
200
   >>> TW.reshape((4,16))
 
201
   >>> TW.get_extended_shape()
 
202
   (8,8)
 
203
   >>> TW.get_shape()
 
204
   (4,16)
 
205
   >>> TW.shape
 
206
   (4,16)
 
207
 
 
208
This results in the following reshaping of the tensor view:
 
209
 
 
210
>>> A = TW[:,:]
 
211
>>> import matplotlib.pyplot as plt
 
212
>>> plt.figure(figsize=(12,5))
 
213
>>> plt.imshow(A,interpolation='none')
 
214
>>> plt.tight_layout()
 
215
>>> plt.show(False)
 
216
 
 
217
.. figure:: _static/Figures/TensorWrapperReshape.*
 
218
 
 
219
   Reshaping of the *quantics* extended ``full`` view.
 
220
 
 
221
The *quantics* extension is used mainly to obtain a complete folding of base ``Q``. In this case this is obtained by:
 
222
 
 
223
.. doctest:: tw
 
224
 
 
225
   >>> TW.reshape([2,2,2,2,2,2])
 
226
   >>> TW.get_extended_shape()
 
227
   (8,8)
 
228
   >>> TW.get_shape()
 
229
   (2,2,2,2,2,2)
 
230
   >>> TW.shape
 
231
   (2,2,2,2,2,2)
 
232
 
 
233
Summary of shapes
 
234
^^^^^^^^^^^^^^^^^
 
235
 
 
236
Information regarding several shape transformations are always hold in the data structure. A hierarchy of shapes is used. The top shape is the **global** shape. In the following table we list the different shapes, their description and the main functions related and affecting them.
 
237
 
 
238
+-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
239
| **Shape**               | **Description**                                                                                                                                                                                                                       | **Functions**                                                                                                                                                                                                                                             |
 
240
+-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
241
| Global                  | This is the underlying shape of the :py:class:`~TensorToolbox.TensorWrapper`.                                                                                                                                                         | :py:meth:`~TensorWrapper.get_global_shape`, :py:meth:`~TensorWrapper.get_global_ndim`, :py:meth:`~TensorWrapper.get_global_size`, :py:meth:`~TensorWrapper.refine`                                                                                        |
 
242
+-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
243
| View                    | Multiple views can be defined for a :py:class:`~TensorToolbox.TensorWrapper`. The views are defined as nested grids into the global grid. The default view is called ``full`` and is defined automatically at construction time       | :py:meth:`~TensorWrapper.set_view`, :py:meth:`~TensorWrapper.set_active_view`, :py:meth:`~TensorWrapper.get_view_shape`, :py:meth:`~TensorWrapper.get_view_ndim`, :py:meth:`~TensorWrapper.get_view_size`, :py:meth:`~TensorWrapper.refine`               |
 
244
+-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
245
| Quantics Extended       | Each view can be extended to the next power of ``Q`` in order to allow the *quantics* folding :cite:`Khoromskij2011,Khoromskij2010` of the tensor.                                                                                    | :py:meth:`~TensorWrapper.set_Q`, :py:meth:`~TensorWrapper.get_extended_shape`, :py:meth:`~TensorWrapper.get_extended_ndim`, :py:meth:`~TensorWrapper.get_extended_size`                                                                                   |
 
246
+-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
247
| Reshape                 | This is the result of the reshape of the tensor. If any of the preceding shape transformations have been applied, then the reshape is applied to the lowest transformation.                                                           | :py:meth:`~TensorWrapper.reshape`, :py:meth:`~TensorWrapper.get_shape`, :py:meth:`~TensorWrapper.get_ndim`, :py:meth:`~TensorWrapper.get_size`, :py:attr:`~TensorWrapper.shape`, :py:attr:`~TensorWrapper.ndim`, :py:attr:`~TensorWrapper.size`           |
 
248
+-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
249
 
 
250
.. warning:: If a shape at any level is modified, every lower reshaping is automatically erased, due to possible inconsistency. For example, if a view is modified, any quantics extension and/or reshape of the view are reset.
 
251
 
 
252
.. note:: The :py:meth:`~TensorWrapper.refine` function erases all the quantics extensions and the reshapes of each view, but not the views themselves. Instead for each view, the :py:meth:`~TensorWrapper.refine` function updates the corresponding indices, fitting the old views to the new refinement.
 
253
 
 
254
Grid refinement
 
255
^^^^^^^^^^^^^^^
 
256
 
 
257
Storage
 
258
^^^^^^^