nifty_core.py 136 KB
Newer Older
Marco Selig's avatar
Marco Selig committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
## NIFTY (Numerical Information Field Theory) has been developed at the
## Max-Planck-Institute for Astrophysics.
##
## Copyright (C) 2013 Max-Planck-Society
##
## Author: Marco Selig
## Project homepage: <http://www.mpa-garching.mpg.de/ift/nifty/>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.

"""
    ..                  __   ____   __
    ..                /__/ /   _/ /  /_
    ..      __ ___    __  /  /_  /   _/  __   __
    ..    /   _   | /  / /   _/ /  /   /  / /  /
    ..   /  / /  / /  / /  /   /  /_  /  /_/  /
    ..  /__/ /__/ /__/ /__/    \___/  \___   /  core
    ..                               /______/

    .. The NIFTY project homepage is http://www.mpa-garching.mpg.de/ift/nifty/

    NIFTY [#]_, "Numerical Information Field Theory", is a versatile
    library designed to enable the development of signal inference algorithms
    that operate regardless of the underlying spatial grid and its resolution.
    Its object-oriented framework is written in Python, although it accesses
    libraries written in Cython, C++, and C for efficiency.

    NIFTY offers a toolkit that abstracts discretized representations of
    continuous spaces, fields in these spaces, and operators acting on fields
    into classes. Thereby, the correct normalization of operations on fields is
    taken care of automatically without concerning the user. This allows for an
    abstract formulation and programming of inference algorithms, including
    those derived within information field theory. Thus, NIFTY permits its user
Marco Selig's avatar
Marco Selig committed
45
    to rapidly prototype algorithms in 1D and then apply the developed code in
Marco Selig's avatar
Marco Selig committed
46
47
48
49
50
    higher-dimensional settings of real world problems. The set of spaces on
    which NIFTY operates comprises point sets, n-dimensional regular grids,
    spherical spaces, their harmonic counterparts, and product spaces
    constructed as combinations of those.

51
52
53
54
55
56
57
    References
    ----------
    .. [#] Selig et al., "NIFTY -- Numerical Information Field Theory --
        a versatile Python library for signal inference",
        `A&A, vol. 554, id. A26 <http://dx.doi.org/10.1051/0004-6361/201321236>`_,
        2013; `arXiv:1301.4499 <http://www.arxiv.org/abs/1301.4499>`_

Marco Selig's avatar
Marco Selig committed
58
59
60
61
62
63
    Class & Feature Overview
    ------------------------
    The NIFTY library features three main classes: **spaces** that represent
    certain grids, **fields** that are defined on spaces, and **operators**
    that apply to fields.

64
65
    .. Overview of all (core) classes:
    ..
Marco Selig's avatar
Marco Selig committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    .. - switch
    .. - notification
    .. - _about
    .. - random
    .. - space
    ..     - point_space
    ..     - rg_space
    ..     - lm_space
    ..     - gl_space
    ..     - hp_space
    ..     - nested_space
    .. - field
    .. - operator
    ..     - diagonal_operator
    ..         - power_operator
    ..     - projection_operator
    ..     - vecvec_operator
    ..     - response_operator
    .. - probing
    ..     - trace_probing
    ..     - diagonal_probing

88
89
    Overview of the main classes and functions:

Marco Selig's avatar
Marco Selig committed
90
91
    .. automodule:: nifty

92
93
94
95
96
97
98
99
100
101
102
103
104
105
    - :py:class:`space`
        - :py:class:`point_space`
        - :py:class:`rg_space`
        - :py:class:`lm_space`
        - :py:class:`gl_space`
        - :py:class:`hp_space`
        - :py:class:`nested_space`
    - :py:class:`field`
    - :py:class:`operator`
        - :py:class:`diagonal_operator`
            - :py:class:`power_operator`
        - :py:class:`projection_operator`
        - :py:class:`vecvec_operator`
        - :py:class:`response_operator`
Marco Selig's avatar
Marco Selig committed
106

107
        .. currentmodule:: nifty.nifty_tools
Marco Selig's avatar
Marco Selig committed
108

109
110
        - :py:class:`invertible_operator`
        - :py:class:`propagator_operator`
Marco Selig's avatar
Marco Selig committed
111

112
        .. currentmodule:: nifty.nifty_explicit
Marco Selig's avatar
Marco Selig committed
113

114
        - :py:class:`explicit_operator`
Marco Selig's avatar
Marco Selig committed
115

116
    .. automodule:: nifty
Marco Selig's avatar
Marco Selig committed
117

118
119
120
    - :py:class:`probing`
        - :py:class:`trace_probing`
        - :py:class:`diagonal_probing`
Marco Selig's avatar
Marco Selig committed
121

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
        .. currentmodule:: nifty.nifty_explicit

        - :py:class:`explicit_probing`

    .. currentmodule:: nifty.nifty_tools

    - :py:class:`conjugate_gradient`
    - :py:class:`steepest_descent`

    .. currentmodule:: nifty.nifty_explicit

    - :py:func:`explicify`

    .. currentmodule:: nifty.nifty_power

    - :py:func:`weight_power`,
      :py:func:`smooth_power`,
      :py:func:`infer_power`,
      :py:func:`interpolate_power`
Marco Selig's avatar
Marco Selig committed
141
142
143
144

"""
from __future__ import division
import numpy as np
Marco Selig's avatar
Marco Selig committed
145
import pylab as pl
146
147
148
from nifty_paradict import space_paradict,\
                            point_space_paradict,\
                            nested_space_paradict
Ultimanet's avatar
Ultimanet committed
149
150
151

from nifty_about import about
from nifty_random import random
Marco Selig's avatar
Marco Selig committed
152

Marco Selig's avatar
Marco Selig committed
153

Marco Selig's avatar
Marco Selig committed
154
pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
155

Marco Selig's avatar
Marco Selig committed
156
157


Ultimanet's avatar
Ultimanet committed
158
159
160
161

##=============================================================================

class space(object):
Marco Selig's avatar
Marco Selig committed
162
    """
Ultimanet's avatar
Ultimanet committed
163
164
165
166
167
168
169
        ..     _______   ______    ____ __   _______   _______
        ..   /  _____/ /   _   | /   _   / /   ____/ /   __  /
        ..  /_____  / /  /_/  / /  /_/  / /  /____  /  /____/
        .. /_______/ /   ____/  \______|  \______/  \______/  class
        ..          /__/

        NIFTY base class for spaces and their discretizations.
Marco Selig's avatar
Marco Selig committed
170

Ultimanet's avatar
Ultimanet committed
171
172
173
        The base NIFTY space class is an abstract class from which other
        specific space subclasses, including those preimplemented in NIFTY
        (e.g. the regular grid class) must be derived.
Marco Selig's avatar
Marco Selig committed
174
175
176

        Parameters
        ----------
Ultimanet's avatar
Ultimanet committed
177
178
179
180
181
182
        para : {single object, list of objects}, *optional*
            This is a freeform list of parameters that derivatives of the space
            class can use (default: 0).
        datatype : numpy.dtype, *optional*
            Data type of the field values for a field defined on this space
            (default: numpy.float64).
Marco Selig's avatar
Marco Selig committed
183
184
185

        See Also
        --------
Ultimanet's avatar
Ultimanet committed
186
187
188
189
190
191
192
193
        point_space :  A class for unstructured lists of numbers.
        rg_space : A class for regular cartesian grids in arbitrary dimensions.
        hp_space : A class for the HEALPix discretization of the sphere
            [#]_.
        gl_space : A class for the Gauss-Legendre discretization of the sphere
            [#]_.
        lm_space : A class for spherical harmonic components.
        nested_space : A class for product spaces.
Marco Selig's avatar
Marco Selig committed
194

Ultimanet's avatar
Ultimanet committed
195
196
197
198
199
200
201
202
        References
        ----------
        .. [#] K.M. Gorski et al., 2005, "HEALPix: A Framework for
               High-Resolution Discretization and Fast Analysis of Data
               Distributed on the Sphere", *ApJ* 622..759G.
        .. [#] M. Reinecke and D. Sverre Seljebotn, 2013, "Libsharp - spherical
               harmonic transforms revisited";
               `arXiv:1303.4945 <http://www.arxiv.org/abs/1303.4945>`_
Marco Selig's avatar
Marco Selig committed
203
204
205

        Attributes
        ----------
Ultimanet's avatar
Ultimanet committed
206
207
208
209
210
211
212
213
214
215
        para : {single object, list of objects}
            This is a freeform list of parameters that derivatives of the space class can use.
        datatype : numpy.dtype
            Data type of the field values for a field defined on this space.
        discrete : bool
            Whether the space is inherently discrete (true) or a discretization
            of a continuous space (false).
        vol : numpy.ndarray
            An array of pixel volumes, only one component if the pixels all
            have the same volume.
Marco Selig's avatar
Marco Selig committed
216
    """
Ultimanet's avatar
Ultimanet committed
217
    def __init__(self,para=0,datatype=None):
Marco Selig's avatar
Marco Selig committed
218
        """
Ultimanet's avatar
Ultimanet committed
219
            Sets the attributes for a space class instance.
Marco Selig's avatar
Marco Selig committed
220
221
222

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
223
224
225
226
227
228
            para : {single object, list of objects}, *optional*
                This is a freeform list of parameters that derivatives of the
                space class can use (default: 0).
            datatype : numpy.dtype, *optional*
                Data type of the field values for a field defined on this space
                (default: numpy.float64).
Marco Selig's avatar
Marco Selig committed
229

Ultimanet's avatar
Ultimanet committed
230
231
232
            Returns
            -------
            None
Marco Selig's avatar
Marco Selig committed
233
        """
Ultimanet's avatar
Ultimanet committed
234
        self.paradict = space_paradict(default=para)        
Marco Selig's avatar
Marco Selig committed
235

Ultimanet's avatar
Ultimanet committed
236
237
238
239
240
241
242
        ## check data type
        if(datatype is None):
            datatype = np.float64
        elif(datatype not in [np.int8,np.int16,np.int32,np.int64,np.float16,np.float32,np.float64,np.complex64,np.complex128]):
            about.warnings.cprint("WARNING: data type set to default.")
            datatype = np.float64
        self.datatype = datatype
Marco Selig's avatar
Marco Selig committed
243

Ultimanet's avatar
Ultimanet committed
244
245
246
247
248
249
250
251
252
253
        self.discrete = True
        self.vol = np.real(np.array([1],dtype=self.datatype))
        
    @property
    def para(self):
        return self.paradict['default']
    
    @para.setter
    def para(self, x):
        self.paradict['default'] = x
Marco Selig's avatar
Marco Selig committed
254

Ultimanet's avatar
Ultimanet committed
255
256
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def _freeze_config(self, dictionary):
Marco Selig's avatar
Marco Selig committed
257
        """
Ultimanet's avatar
Ultimanet committed
258
259
260
261
            a helper function which forms a hashable identifying object from 
            a dictionary which can be used as key of a dict
        """        
        return frozenset(dictionary.items())
Marco Selig's avatar
Marco Selig committed
262
263
264
265



    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ultimanet's avatar
Ultimanet committed
266
267
268
269
    def getitem(self, data, key):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'getitem'."))
        
Marco Selig's avatar
Marco Selig committed
270

Ultimanet's avatar
Ultimanet committed
271
272
273
274
275
276
277
278
279
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def setitem(self, data, key):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'getitem'."))
        
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    def apply_scalar_function(self, x, function, inplace=False):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'apply_scalar_function'."))
Marco Selig's avatar
Marco Selig committed
280

Ultimanet's avatar
Ultimanet committed
281
282
283
284
285
286
287
288
289
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    def unary_operation(self, x, op=None):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'unary_operation'."))
    
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    def binary_operation(self, x, y, op=None):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'binary_operation'."))
Marco Selig's avatar
Marco Selig committed
290

Ultimanet's avatar
Ultimanet committed
291
292
293
294
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    def norm(self, x, q):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'norm'."))
Marco Selig's avatar
Marco Selig committed
295

Ultimanet's avatar
Ultimanet committed
296
297
298
    def shape(self):
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'shape'."))
Marco Selig's avatar
Marco Selig committed
299

Ultimanet's avatar
Ultimanet committed
300
301
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def dim(self,split=False):
Marco Selig's avatar
Marco Selig committed
302
        """
Ultimanet's avatar
Ultimanet committed
303
            Computes the dimension of the space, i.e.\  the number of pixels.
Marco Selig's avatar
Marco Selig committed
304
305
306

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
307
308
309
            split : bool, *optional*
                Whether to return the dimension split up, i.e. the numbers of
                pixels in each direction, or not (default: False).
Marco Selig's avatar
Marco Selig committed
310

Ultimanet's avatar
Ultimanet committed
311
312
313
314
            Returns
            -------
            dim : {int, numpy.ndarray}
                Dimension(s) of the space.
Marco Selig's avatar
Marco Selig committed
315
        """
Ultimanet's avatar
Ultimanet committed
316
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'dim'."))
Marco Selig's avatar
Marco Selig committed
317
318
319

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
320
    def dof(self):
Marco Selig's avatar
Marco Selig committed
321
        """
Ultimanet's avatar
Ultimanet committed
322
            Computes the number of degrees of freedom of the space.
Marco Selig's avatar
Marco Selig committed
323
324
325

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
326
327
            dof : int
                Number of degrees of freedom of the space.
Marco Selig's avatar
Marco Selig committed
328
        """
Ultimanet's avatar
Ultimanet committed
329
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'dof'."))
Marco Selig's avatar
Marco Selig committed
330
331
332

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
333
    def enforce_power(self,spec,**kwargs):
Marco Selig's avatar
Marco Selig committed
334
        """
Ultimanet's avatar
Ultimanet committed
335
            Provides a valid power spectrum array from a given object.
Marco Selig's avatar
Marco Selig committed
336
337
338

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
339
340
341
342
            spec : {scalar, list, numpy.ndarray, nifty.field, function}
                Fiducial power spectrum from which a valid power spectrum is to
                be calculated. Scalars are interpreted as constant power
                spectra.
Marco Selig's avatar
Marco Selig committed
343
344
345

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
            spec : numpy.ndarray
                Valid power spectrum.

            Other parameters
            ----------------
            size : int, *optional*
                Number of bands the power spectrum shall have (default: None).
            kindex : numpy.ndarray, *optional*
                Scale of each band.
            codomain : nifty.space, *optional*
                A compatible codomain for power indexing (default: None).
            log : bool, *optional*
                Flag specifying if the spectral binning is performed on logarithmic
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
            nbin : integer, *optional*
                Number of used spectral bins; if given `log` is set to ``False``;
                integers below the minimum of 3 induce an automatic setting;
                by default no binning is done (default: None).
            binbounds : {list, array}, *optional*
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
                Lower limit of the uniform distribution if ``random == "uni"``
                (default: 0).
Marco Selig's avatar
Marco Selig committed
372
373

        """
Ultimanet's avatar
Ultimanet committed
374
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'enforce_power'."))
Marco Selig's avatar
Marco Selig committed
375

Ultimanet's avatar
Ultimanet committed
376
377
378
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def set_power_indices(self,**kwargs):
Marco Selig's avatar
Marco Selig committed
379
        """
Ultimanet's avatar
Ultimanet committed
380
            Sets the (un)indexing objects for spectral indexing internally.
Marco Selig's avatar
Marco Selig committed
381
382
383

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
384
385
386
387
388
389
390
391
392
393
394
395
396
            log : bool
                Flag specifying if the binning is performed on logarithmic
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
            nbin : integer
                Number of used bins; if given `log` is set to ``False``;
                integers below the minimum of 3 induce an automatic setting;
                by default no binning is done (default: None).
            binbounds : {list, array}
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
                (default: None).
Marco Selig's avatar
Marco Selig committed
397
398
399
400
401

            Returns
            -------
            None

Ultimanet's avatar
Ultimanet committed
402
403
404
405
            See Also
            --------
            get_power_indices

Marco Selig's avatar
Marco Selig committed
406
        """
Ultimanet's avatar
Ultimanet committed
407
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'set_power_indices'."))
Marco Selig's avatar
Marco Selig committed
408

Ultimanet's avatar
Ultimanet committed
409
    def get_power_indices(self,**kwargs):
Marco Selig's avatar
Marco Selig committed
410
        """
Ultimanet's avatar
Ultimanet committed
411
412
413
414
415
416
            Provides the (un)indexing objects for spectral indexing.

            Provides one-dimensional arrays containing the scales of the
            spectral bands and the numbers of modes per scale, and an array
            giving for each component of a field the corresponding index of a
            power spectrum as well as an Unindexing array.
Marco Selig's avatar
Marco Selig committed
417
418
419

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
420
421
422
423
424
425
426
427
428
429
430
431
432
            log : bool
                Flag specifying if the binning is performed on logarithmic
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
            nbin : integer
                Number of used bins; if given `log` is set to ``False``;
                integers below the minimum of 3 induce an automatic setting;
                by default no binning is done (default: None).
            binbounds : {list, array}
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
                (default: None).
Marco Selig's avatar
Marco Selig committed
433
434
435

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
436
437
438
439
440
441
442
443
444
            kindex : numpy.ndarray
                Scale of each spectral band.
            rho : numpy.ndarray
                Number of modes per scale represented in the discretization.
            pindex : numpy.ndarray
                Indexing array giving the power spectrum index for each
                represented mode.
            pundex : numpy.ndarray
                Unindexing array undoing power spectrum indexing.
Marco Selig's avatar
Marco Selig committed
445

Ultimanet's avatar
Ultimanet committed
446
447
448
449
450
451
452
            Notes
            -----
            The ``kindex`` and ``rho`` are each one-dimensional arrays.
            The indexing array is of the same shape as a field living in this
            space and contains the indices of the associated bands.
            Indexing with the unindexing array undoes the indexing with the
            indexing array; i.e., ``power == power[pindex].flatten()[pundex]``.
Marco Selig's avatar
Marco Selig committed
453

Ultimanet's avatar
Ultimanet committed
454
455
456
            See Also
            --------
            set_power_indices
Marco Selig's avatar
Marco Selig committed
457
458

        """
Ultimanet's avatar
Ultimanet committed
459
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'get_power_indices'."))
Marco Selig's avatar
Marco Selig committed
460
461

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ultimanet's avatar
Ultimanet committed
462
463
    
    def cast(self, x, verbose=False):
Marco Selig's avatar
Marco Selig committed
464
        """
Ultimanet's avatar
Ultimanet committed
465
466
467
            Computes valid field values from a given object, trying
            to translate the given data into a valid form. Thereby it is as 
            benevolent as possible. 
Marco Selig's avatar
Marco Selig committed
468
469
470

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
471
472
            x : {float, numpy.ndarray, nifty.field}
                Object to be transformed into an array of valid field values.
Marco Selig's avatar
Marco Selig committed
473
474
475

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
476
477
478
            x : numpy.ndarray, distributed_data_object
                Array containing the field values, which are compatible to the
                space.
Marco Selig's avatar
Marco Selig committed
479

Ultimanet's avatar
Ultimanet committed
480
481
482
483
484
            Other parameters
            ----------------
            verbose : bool, *optional*
                Whether the method should raise a warning if information is 
                lost during casting (default: False).
Marco Selig's avatar
Marco Selig committed
485
        """
Ultimanet's avatar
Ultimanet committed
486
        return self.enforce_values(x, extend=True)
Marco Selig's avatar
Marco Selig committed
487

Ultimanet's avatar
Ultimanet committed
488
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
489

Ultimanet's avatar
Ultimanet committed
490
    def enforce_shape(self,x):
Marco Selig's avatar
Marco Selig committed
491
        """
Ultimanet's avatar
Ultimanet committed
492
493
            Shapes an array of valid field values correctly, according to the
            specifications of the space instance.
Marco Selig's avatar
Marco Selig committed
494

Ultimanet's avatar
Ultimanet committed
495
496
497
498
            Parameters
            ----------
            x : numpy.ndarray
                Array containing the field values to be put into shape.
Marco Selig's avatar
Marco Selig committed
499

Ultimanet's avatar
Ultimanet committed
500
501
502
503
504
505
            Returns
            -------
            y : numpy.ndarray
                Correctly shaped array.
        """
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'enforce_shape'."))
Marco Selig's avatar
Marco Selig committed
506
507
508

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
509
510
511
512
    def enforce_values(self,x,extend=True):
        """
            Computes valid field values from a given object, according to the
            constraints from the space instance.
Marco Selig's avatar
Marco Selig committed
513

Ultimanet's avatar
Ultimanet committed
514
515
516
517
            Parameters
            ----------
            x : {float, numpy.ndarray, nifty.field}
                Object to be transformed into an array of valid field values.
Marco Selig's avatar
Marco Selig committed
518

Ultimanet's avatar
Ultimanet committed
519
520
521
522
            Returns
            -------
            x : numpy.ndarray
                Array containing the valid field values.
Marco Selig's avatar
Marco Selig committed
523

Ultimanet's avatar
Ultimanet committed
524
525
526
527
528
529
530
            Other parameters
            ----------------
            extend : bool, *optional*
                Whether a scalar is extented to a constant array or not
                (default: True).
        """
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'enforce_values'."))
Marco Selig's avatar
Marco Selig committed
531
532
533
534


    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
535
    def get_random_values(self,**kwargs):
Marco Selig's avatar
Marco Selig committed
536
        """
Ultimanet's avatar
Ultimanet committed
537
538
            Generates random field values according to the specifications given
            by the parameters.
Marco Selig's avatar
Marco Selig committed
539

Ultimanet's avatar
Ultimanet committed
540
541
542
543
544
545
546
            Returns
            -------
            x : numpy.ndarray
                Valid field values.

            Other parameters
            ----------------
Marco Selig's avatar
Marco Selig committed
547
            random : string, *optional*
Ultimanet's avatar
Ultimanet committed
548
549
550
                Specifies the probability distribution from which the random
                numbers are to be drawn.
                Supported distributions are:
Marco Selig's avatar
Marco Selig committed
551
552

                - "pm1" (uniform distribution over {+1,-1} or {+1,+i,-1,-i}
Ultimanet's avatar
Ultimanet committed
553
554
                - "gau" (normal distribution with zero-mean and a given standard
                    deviation or variance)
Marco Selig's avatar
Marco Selig committed
555
556
557
558
                - "syn" (synthesizes from a given power spectrum)
                - "uni" (uniform distribution over [vmin,vmax[)

                (default: None).
Ultimanet's avatar
Ultimanet committed
559
560
561
562
563
564
565
            dev : float, *optional*
                Standard deviation (default: 1).
            var : float, *optional*
                Variance, overriding `dev` if both are specified
                (default: 1).
            spec : {scalar, list, numpy.ndarray, nifty.field, function}, *optional*
                Power spectrum (default: 1).
566
567
568
569
            pindex : numpy.ndarray, *optional*
                Indexing array giving the power spectrum index of each band
                (default: None).
            kindex : numpy.ndarray, *optional*
Ultimanet's avatar
Ultimanet committed
570
                Scale of each band (default: None).
571
            codomain : nifty.space, *optional*
Ultimanet's avatar
Ultimanet committed
572
                A compatible codomain with power indices (default: None).
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
            log : bool, *optional*
                Flag specifying if the spectral binning is performed on logarithmic
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
            nbin : integer, *optional*
                Number of used spectral bins; if given `log` is set to ``False``;
                integers below the minimum of 3 induce an automatic setting;
                by default no binning is done (default: None).
            binbounds : {list, array}, *optional*
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
                Lower limit of the uniform distribution if ``random == "uni"``
                (default: 0).
Ultimanet's avatar
Ultimanet committed
588
589
590
591
            vmin : float, *optional*
                Lower limit for a uniform distribution (default: 0).
            vmax : float, *optional*
                Upper limit for a uniform distribution (default: 1).
Marco Selig's avatar
Marco Selig committed
592
        """
Ultimanet's avatar
Ultimanet committed
593
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'get_random_values'."))
Marco Selig's avatar
Marco Selig committed
594
595
596

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
597
    def check_codomain(self,codomain):
Marco Selig's avatar
Marco Selig committed
598
        """
Ultimanet's avatar
Ultimanet committed
599
            Checks whether a given codomain is compatible to the space or not.
Marco Selig's avatar
Marco Selig committed
600
601
602

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
603
604
            codomain : nifty.space
                Space to be checked for compatibility.
Marco Selig's avatar
Marco Selig committed
605
606
607

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
608
609
            check : bool
                Whether or not the given codomain is compatible to the space.
Marco Selig's avatar
Marco Selig committed
610
        """
Ultimanet's avatar
Ultimanet committed
611
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'check_codomain'."))
Marco Selig's avatar
Marco Selig committed
612
613
614

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
615
    def get_codomain(self,**kwargs):
Marco Selig's avatar
Marco Selig committed
616
        """
Ultimanet's avatar
Ultimanet committed
617
618
619
            Generates a compatible codomain to which transformations are
            reasonable, usually either the position basis or the basis of
            harmonic eigenmodes.
Marco Selig's avatar
Marco Selig committed
620
621
622

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
623
624
625
626
627
628
629
630
631
            coname : string, *optional*
                String specifying a desired codomain (default: None).
            cozerocenter : {bool, numpy.ndarray}, *optional*
                Whether or not the grid is zerocentered for each axis or not
                (default: None).
            conest : list, *optional*
                List of nested spaces of the codomain (default: None).
            coorder : list, *optional*
                Permutation of the list of nested spaces (default: None).
Marco Selig's avatar
Marco Selig committed
632
633
634

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
635
636
637
638
            codomain : nifty.space
                A compatible codomain.
        """
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'get_codomain'."))
Marco Selig's avatar
Marco Selig committed
639

Ultimanet's avatar
Ultimanet committed
640
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
641

Ultimanet's avatar
Ultimanet committed
642
    def get_meta_volume(self,total=False):
Marco Selig's avatar
Marco Selig committed
643
        """
Ultimanet's avatar
Ultimanet committed
644
            Calculates the meta volumes.
Marco Selig's avatar
Marco Selig committed
645

Ultimanet's avatar
Ultimanet committed
646
647
648
649
            The meta volumes are the volumes associated with each component of
            a field, taking into account field components that are not
            explicitly included in the array of field values but are determined
            by symmetry conditions.
Marco Selig's avatar
Marco Selig committed
650

Ultimanet's avatar
Ultimanet committed
651
652
653
654
655
            Parameters
            ----------
            total : bool, *optional*
                Whether to return the total meta volume of the space or the
                individual ones of each field component (default: False).
Marco Selig's avatar
Marco Selig committed
656

Ultimanet's avatar
Ultimanet committed
657
658
659
660
661
662
            Returns
            -------
            mol : {numpy.ndarray, float}
                Meta volume of the field components or the complete space.
        """
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'get_meta_volume'."))
Marco Selig's avatar
Marco Selig committed
663
664
665

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
666
    def calc_weight(self,x,power=1):
Marco Selig's avatar
Marco Selig committed
667
        """
Ultimanet's avatar
Ultimanet committed
668
669
            Weights a given array of field values with the pixel volumes (not
            the meta volumes) to a given power.
Marco Selig's avatar
Marco Selig committed
670
671
672

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
673
674
675
676
            x : numpy.ndarray
                Array to be weighted.
            power : float, *optional*
                Power of the pixel volumes to be used (default: 1).
Marco Selig's avatar
Marco Selig committed
677
678
679

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
680
681
682
683
            y : numpy.ndarray
                Weighted array.
        """
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'calc_weight'."))
Marco Selig's avatar
Marco Selig committed
684
685
686

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
687
688
689
690
    def calc_dot(self,x,y):
        """
            Computes the discrete inner product of two given arrays of field
            values.
Marco Selig's avatar
Marco Selig committed
691

Ultimanet's avatar
Ultimanet committed
692
693
694
695
696
697
            Parameters
            ----------
            x : numpy.ndarray
                First array
            y : numpy.ndarray
                Second array
Marco Selig's avatar
Marco Selig committed
698

Ultimanet's avatar
Ultimanet committed
699
700
701
702
703
704
705
            Returns
            -------
            dot : scalar
                Inner product of the two arrays.
        """
        raise NotImplementedError(about._errors.cstring(\
            "ERROR: no generic instance method 'dot'."))
Marco Selig's avatar
Marco Selig committed
706
707
708



Ultimanet's avatar
Ultimanet committed
709
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
710

Ultimanet's avatar
Ultimanet committed
711
712
713
    def calc_transform(self,x,codomain=None,**kwargs):
        """
            Computes the transform of a given array of field values.
Marco Selig's avatar
Marco Selig committed
714
715
716

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
717
718
719
720
721
            x : numpy.ndarray
                Array to be transformed.
            codomain : nifty.space, *optional*
                Target space to which the transformation shall map
                (default: self).
Marco Selig's avatar
Marco Selig committed
722
723
724

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
725
726
            Tx : numpy.ndarray
                Transformed array
727

Ultimanet's avatar
Ultimanet committed
728
729
730
731
            Other parameters
            ----------------
            iter : int, *optional*
                Number of iterations performed in specific transformations.
732
        """
Ultimanet's avatar
Ultimanet committed
733
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'calc_transform'."))
Marco Selig's avatar
Marco Selig committed
734
735

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
736

Ultimanet's avatar
Ultimanet committed
737
    def calc_smooth(self,x,sigma=0,**kwargs):
Marco Selig's avatar
Marco Selig committed
738
        """
Ultimanet's avatar
Ultimanet committed
739
740
            Smoothes an array of field values by convolution with a Gaussian
            kernel.
Marco Selig's avatar
Marco Selig committed
741
742
743

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
744
745
746
747
748
            x : numpy.ndarray
                Array of field values to be smoothed.
            sigma : float, *optional*
                Standard deviation of the Gaussian kernel, specified in units
                of length in position space (default: 0).
Marco Selig's avatar
Marco Selig committed
749
750
751

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
752
753
            Gx : numpy.ndarray
                Smoothed array.
Marco Selig's avatar
Marco Selig committed
754

Ultimanet's avatar
Ultimanet committed
755
756
757
758
            Other parameters
            ----------------
            iter : int, *optional*
                Number of iterations (default: 0).
Marco Selig's avatar
Marco Selig committed
759
        """
Ultimanet's avatar
Ultimanet committed
760
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'calc_smooth'."))
Marco Selig's avatar
Marco Selig committed
761
762
763

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
764
    def calc_power(self,x,**kwargs):
Marco Selig's avatar
Marco Selig committed
765
        """
Ultimanet's avatar
Ultimanet committed
766
            Computes the power of an array of field values.
Marco Selig's avatar
Marco Selig committed
767
768
769

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
770
771
772
            x : numpy.ndarray
                Array containing the field values of which the power is to be
                calculated.
Marco Selig's avatar
Marco Selig committed
773
774
775
776

            Returns
            -------
            spec : numpy.ndarray
Ultimanet's avatar
Ultimanet committed
777
                Power contained in the input array.
Marco Selig's avatar
Marco Selig committed
778
779
780

            Other parameters
            ----------------
Ultimanet's avatar
Ultimanet committed
781
782
783
            pindex : numpy.ndarray, *optional*
                Indexing array assigning the input array components to
                components of the power spectrum (default: None).
784
            kindex : numpy.ndarray, *optional*
Ultimanet's avatar
Ultimanet committed
785
786
787
788
                Scale corresponding to each band in the power spectrum
                (default: None).
            rho : numpy.ndarray, *optional*
                Number of degrees of freedom per band (default: None).
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
            codomain : nifty.space, *optional*
                A compatible codomain for power indexing (default: None).
            log : bool, *optional*
                Flag specifying if the spectral binning is performed on logarithmic
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
            nbin : integer, *optional*
                Number of used spectral bins; if given `log` is set to ``False``;
                integers below the minimum of 3 induce an automatic setting;
                by default no binning is done (default: None).
            binbounds : {list, array}, *optional*
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
                Lower limit of the uniform distribution if ``random == "uni"``
                (default: 0).
806

Marco Selig's avatar
Marco Selig committed
807
        """
Ultimanet's avatar
Ultimanet committed
808
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'calc_power'."))
Marco Selig's avatar
Marco Selig committed
809
810
811

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
812
    def get_plot(self,x,**kwargs):
Marco Selig's avatar
Marco Selig committed
813
        """
Ultimanet's avatar
Ultimanet committed
814
815
            Creates a plot of field values according to the specifications
            given by the parameters.
816
817
818

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
            x : numpy.ndarray
                Array containing the field values.

            Returns
            -------
            None

            Other parameters
            ----------------
            title : string, *optional*
                Title of the plot (default: "").
            vmin : float, *optional*
                Minimum value to be displayed (default: ``min(x)``).
            vmax : float, *optional*
                Maximum value to be displayed (default: ``max(x)``).
            power : bool, *optional*
                Whether to plot the power contained in the field or the field
                values themselves (default: False).
            unit : string, *optional*
                Unit of the field values (default: "").
            norm : string, *optional*
                Scaling of the field values before plotting (default: None).
            cmap : matplotlib.colors.LinearSegmentedColormap, *optional*
                Color map to be used for two-dimensional plots (default: None).
            cbar : bool, *optional*
                Whether to show the color bar or not (default: True).
            other : {single object, tuple of objects}, *optional*
                Object or tuple of objects to be added, where objects can be
                scalars, arrays, or fields (default: None).
            legend : bool, *optional*
                Whether to show the legend or not (default: False).
            mono : bool, *optional*
                Whether to plot the monopole or not (default: True).
            save : string, *optional*
                Valid file name where the figure is to be stored, by default
                the figure is not saved (default: False).
            error : {float, numpy.ndarray, nifty.field}, *optional*
                Object indicating some confidence interval to be plotted
                (default: None).
            kindex : numpy.ndarray, *optional*
                Scale corresponding to each band in the power spectrum
                (default: None).
            codomain : nifty.space, *optional*
                A compatible codomain for power indexing (default: None).
            log : bool, *optional*
                Flag specifying if the spectral binning is performed on logarithmic
865
866
867
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
Ultimanet's avatar
Ultimanet committed
868
869
            nbin : integer, *optional*
                Number of used spectral bins; if given `log` is set to ``False``;
870
                integers below the minimum of 3 induce an automatic setting;
871
                by default no binning is done (default: None).
Ultimanet's avatar
Ultimanet committed
872
            binbounds : {list, array}, *optional*
873
874
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
Ultimanet's avatar
Ultimanet committed
875
876
877
878
879
                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
                Lower limit of the uniform distribution if ``random == "uni"``
                (default: 0).
            iter : int, *optional*
                Number of iterations (default: 0).
Marco Selig's avatar
Marco Selig committed
880
881

        """
Ultimanet's avatar
Ultimanet committed
882
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'get_plot'."))
Marco Selig's avatar
Marco Selig committed
883

Ultimanet's avatar
Ultimanet committed
884
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
885

Ultimanet's avatar
Ultimanet committed
886
887
    def __repr__(self):
        return "<nifty_core.space>"
Marco Selig's avatar
Marco Selig committed
888

Ultimanet's avatar
Ultimanet committed
889
890
    def __str__(self):
        return "nifty_core.space instance\n- para     = "+str(self.para)+"\n- datatype = numpy."+str(np.result_type(self.datatype))
Marco Selig's avatar
Marco Selig committed
891

Ultimanet's avatar
Ultimanet committed
892
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
893

Ultimanet's avatar
Ultimanet committed
894
895
    def __len__(self):
        return int(self.dim(split=False))
Marco Selig's avatar
Marco Selig committed
896

897
    ## _identiftier returns an object which contains all information needed 
Ultimanet's avatar
Ultimanet committed
898
899
    ## to uniquely idetnify a space. It returns a (immutable) tuple which therefore
    ## can be compored. 
900
    def _identifier(self):
Ultimanet's avatar
Ultimanet committed
901
        return tuple(sorted(vars(self).items()))
Marco Selig's avatar
Marco Selig committed
902

Ultimanet's avatar
Ultimanet committed
903
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
904

Ultimanet's avatar
Ultimanet committed
905
906
907
908
909
910
    def _meta_vars(self): ## > captures all nonstandard properties
        mars = np.array([ii[1] for ii in vars(self).iteritems() if ii[0] not in ["para","datatype","discrete","vol","power_indices"]],dtype=np.object)
        if(np.size(mars)==0):
            return None
        else:
            return mars
Marco Selig's avatar
Marco Selig committed
911

Ultimanet's avatar
Ultimanet committed
912
    def __eq__(self,x): ## __eq__ : self == x
913
914
915
916
        if isinstance(x, type(self)):
            return self._identifier() == x._identifier()
        else:
            return False
Marco Selig's avatar
Marco Selig committed
917

Ultimanet's avatar
Ultimanet committed
918
919
920
921
922
    def __ne__(self,x): ## __ne__ : self <> x
        if(isinstance(x,space)):
            if(not isinstance(x,type(self)))or(np.any(self.para!=x.para))or(self.discrete!=x.discrete)or(np.any(self.vol!=x.vol))or(np.any(self._meta_vars()!=x._meta_vars())): ## data types are ignored
                return True
        return False
Marco Selig's avatar
Marco Selig committed
923

Ultimanet's avatar
Ultimanet committed
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
    def __lt__(self,x): ## __lt__ : self < x
        if(isinstance(x,space)):
            if(not isinstance(x,type(self)))or(np.size(self.para)!=np.size(x.para))or(np.size(self.vol)!=np.size(x.vol)):
                raise ValueError(about._errors.cstring("ERROR: incomparable spaces."))
            elif(self.discrete==x.discrete): ## data types are ignored
                for ii in xrange(np.size(self.para)):
                    if(self.para[ii]<x.para[ii]):
                        return True
                    elif(self.para[ii]>x.para[ii]):
                        return False
                for ii in xrange(np.size(self.vol)):
                    if(self.vol[ii]<x.vol[ii]):
                        return True
                    elif(self.vol[ii]>x.vol[ii]):
                        return False
                s_mars = self._meta_vars()
                x_mars = x._meta_vars()
                for ii in xrange(np.size(s_mars)):
                    if(np.all(s_mars[ii]<x_mars[ii])):
                        return True
                    elif(np.any(s_mars[ii]>x_mars[ii])):
                        break
        return False
Marco Selig's avatar
Marco Selig committed
947

Ultimanet's avatar
Ultimanet committed
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
    def __le__(self,x): ## __le__ : self <= x
        if(isinstance(x,space)):
            if(not isinstance(x,type(self)))or(np.size(self.para)!=np.size(x.para))or(np.size(self.vol)!=np.size(x.vol)):
                raise ValueError(about._errors.cstring("ERROR: incomparable spaces."))
            elif(self.discrete==x.discrete): ## data types are ignored
                for ii in xrange(np.size(self.para)):
                    if(self.para[ii]<x.para[ii]):
                        return True
                    if(self.para[ii]>x.para[ii]):
                        return False
                for ii in xrange(np.size(self.vol)):
                    if(self.vol[ii]<x.vol[ii]):
                        return True
                    if(self.vol[ii]>x.vol[ii]):
                        return False
                s_mars = self._meta_vars()
                x_mars = x._meta_vars()
                for ii in xrange(np.size(s_mars)):
                    if(np.all(s_mars[ii]<x_mars[ii])):
                        return True
                    elif(np.any(s_mars[ii]>x_mars[ii])):
                        return False
                return True
        return False
Marco Selig's avatar
Marco Selig committed
972

Ultimanet's avatar
Ultimanet committed
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
    def __gt__(self,x): ## __gt__ : self > x
        if(isinstance(x,space)):
            if(not isinstance(x,type(self)))or(np.size(self.para)!=np.size(x.para))or(np.size(self.vol)!=np.size(x.vol)):
                raise ValueError(about._errors.cstring("ERROR: incomparable spaces."))
            elif(self.discrete==x.discrete): ## data types are ignored
                for ii in xrange(np.size(self.para)):
                    if(self.para[ii]>x.para[ii]):
                        return True
                    elif(self.para[ii]<x.para[ii]):
                        break
                for ii in xrange(np.size(self.vol)):
                    if(self.vol[ii]>x.vol[ii]):
                        return True
                    elif(self.vol[ii]<x.vol[ii]):
                        break
                s_mars = self._meta_vars()
                x_mars = x._meta_vars()
                for ii in xrange(np.size(s_mars)):
                    if(np.all(s_mars[ii]>x_mars[ii])):
                        return True
                    elif(np.any(s_mars[ii]<x_mars[ii])):
                        break
        return False
Marco Selig's avatar
Marco Selig committed
996

Ultimanet's avatar
Ultimanet committed
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
    def __ge__(self,x): ## __ge__ : self >= x
        if(isinstance(x,space)):
            if(not isinstance(x,type(self)))or(np.size(self.para)!=np.size(x.para))or(np.size(self.vol)!=np.size(x.vol)):
                raise ValueError(about._errors.cstring("ERROR: incomparable spaces."))
            elif(self.discrete==x.discrete): ## data types are ignored
                for ii in xrange(np.size(self.para)):
                    if(self.para[ii]>x.para[ii]):
                        return True
                    if(self.para[ii]<x.para[ii]):
                        return False
                for ii in xrange(np.size(self.vol)):
                    if(self.vol[ii]>x.vol[ii]):
                        return True
                    if(self.vol[ii]<x.vol[ii]):
                        return False
                s_mars = self._meta_vars()
                x_mars = x._meta_vars()
                for ii in xrange(np.size(s_mars)):
                    if(np.all(s_mars[ii]>x_mars[ii])):
                        return True
                    elif(np.any(s_mars[ii]<x_mars[ii])):
                        return False
                return True
        return False
Marco Selig's avatar
Marco Selig committed
1021

Ultimanet's avatar
Ultimanet committed
1022
##=============================================================================
Marco Selig's avatar
Marco Selig committed
1023
1024
1025



Ultimanet's avatar
Ultimanet committed
1026
##-----------------------------------------------------------------------------
Marco Selig's avatar
Marco Selig committed
1027

Ultimanet's avatar
Ultimanet committed
1028
class point_space(space):
Marco Selig's avatar
Marco Selig committed
1029
    """
Ultimanet's avatar
Ultimanet committed
1030
1031
1032
1033
1034
1035
1036
        ..                            __             __
        ..                          /__/           /  /_
        ..      ______    ______    __   __ ___   /   _/
        ..    /   _   | /   _   | /  / /   _   | /  /
        ..   /  /_/  / /  /_/  / /  / /  / /  / /  /_
        ..  /   ____/  \______/ /__/ /__/ /__/  \___/  space class
        .. /__/
Marco Selig's avatar
Marco Selig committed
1037

Ultimanet's avatar
Ultimanet committed
1038
        NIFTY subclass for unstructured spaces.
Marco Selig's avatar
Marco Selig committed
1039

Ultimanet's avatar
Ultimanet committed
1040
1041
        Unstructured spaces are lists of values without any geometrical
        information.
Marco Selig's avatar
Marco Selig committed
1042
1043
1044

        Parameters
        ----------
Ultimanet's avatar
Ultimanet committed
1045
1046
1047
1048
        num : int
            Number of points.
        datatype : numpy.dtype, *optional*
            Data type of the field values (default: None).
Marco Selig's avatar
Marco Selig committed
1049

Ultimanet's avatar
Ultimanet committed
1050
        Attributes
Marco Selig's avatar
Marco Selig committed
1051
        ----------
Ultimanet's avatar
Ultimanet committed
1052
1053
1054
1055
1056
1057
1058
1059
1060
        para : numpy.ndarray
            Array containing the number of points.
        datatype : numpy.dtype
            Data type of the field values.
        discrete : bool
            Parameter captioning the fact that a :py:class:`point_space` is
            always discrete.
        vol : numpy.ndarray
            Pixel volume of the :py:class:`point_space`, which is always 1.
Marco Selig's avatar
Marco Selig committed
1061
    """
Ultimanet's avatar
Ultimanet committed
1062
1063
1064
    def __init__(self,num,datatype=None):
        """
            Sets the attributes for a point_space class instance.
Marco Selig's avatar
Marco Selig committed
1065

Ultimanet's avatar
Ultimanet committed
1066
1067
1068
1069
1070
1071
            Parameters
            ----------
            num : int
                Number of points.
            datatype : numpy.dtype, *optional*
                Data type of the field values (default: numpy.float64).
Marco Selig's avatar
Marco Selig committed
1072

Ultimanet's avatar
Ultimanet committed
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
            Returns
            -------
            None.
        """
        self.paradict = point_space_paradict(num=num)       
        
        ## check datatype
        if(datatype is None):
            datatype = np.float64
        elif(datatype not in [np.int8,np.int16,np.int32,np.int64,np.float16,np.float32,np.float64,np.complex64,np.complex128]):
            about.warnings.cprint("WARNING: data type set to default.")
            datatype = np.float64
        self.datatype = datatype
Marco Selig's avatar
Marco Selig committed
1086

Ultimanet's avatar
Ultimanet committed
1087
1088
        self.discrete = True
        self.vol = np.real(np.array([1],dtype=self.datatype))
Marco Selig's avatar
Marco Selig committed
1089

1090

Ultimanet's avatar
Ultimanet committed
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
    @property
    def para(self):
        temp = np.array([self.paradict['num']], dtype=int)
        return temp
    
    @para.setter
    def para(self, x):
        self.paradict['num'] = x
        
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def getitem(self, data, key):
        return data[key]
        
Marco Selig's avatar
Marco Selig committed
1104

Ultimanet's avatar
Ultimanet committed
1105
1106
1107
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def setitem(self, data, update, key):
        data[key]=update
Marco Selig's avatar
Marco Selig committed
1108

Ultimanet's avatar
Ultimanet committed
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def apply_scalar_function(self, x, function, inplace=False):
        if inplace == False:        
            try: 
                return function(x)
            except:
                return np.vectorize(function)(x)
        else:
            try:
                x[:] = function(x)
            except:
                x[:] = np.vectorize(function)(x)
            return x
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++          
    
    
    def unary_operation(self, x, op='None', **kwargs):
        """
        x must be a numpy array which is compatible with the space!
        Valid operations are
        
        """
                                
        def _argmin(z, **kwargs):
            ind = np.argmin(z, **kwargs)
            if np.isscalar(ind):
                ind = np.unravel_index(ind, z.shape, order='C')
                if(len(ind)==1):
                    return ind[0]
            return ind         
Marco Selig's avatar
Marco Selig committed
1139

Ultimanet's avatar
Ultimanet committed
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
        def _argmax(z, **kwargs):
            ind = np.argmax(z, **kwargs)
            if np.isscalar(ind):
                ind = np.unravel_index(ind, z.shape, order='C')
                if(len(ind)==1):
                    return ind[0]
            return ind         
        
        
        translation = {"pos" : lambda y: getattr(y, '__pos__')(),
                        "neg" : lambda y: getattr(y, '__neg__')(),
                        "abs" : lambda y: getattr(y, '__abs__')(),
                        "nanmin" : np.nanmin,  
                        "min" : np.amin,
                        "nanmax" : np.nanmax,
                        "max" : np.amax,
                        "med" : np.median,
                        "mean" : np.mean,
                        "std" : np.std,
                        "var" : np.var,
                        "argmin" : _argmin,
                        "argmin_flat" : np.argmin,
                        "argmax" : _argmax, 
                        "argmax_flat" : np.argmax,
                        "conjugate" : np.conjugate,
                        "None" : lambda y: y}
Marco Selig's avatar
Marco Selig committed
1166

Ultimanet's avatar
Ultimanet committed
1167
1168
                
        return translation[op](x, **kwargs)      
Marco Selig's avatar
Marco Selig committed
1169

Ultimanet's avatar
Ultimanet committed
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    def binary_operation(self, x, y, op='None', cast=0):
        
        translation = {"add" : lambda z: getattr(z, '__add__'),
                        "radd" : lambda z: getattr(z, '__radd__'),
                        "iadd" : lambda z: getattr(z, '__iadd__'),
                        "sub" : lambda z: getattr(z, '__sub__'),
                        "rsub" : lambda z: getattr(z, '__rsub__'),
                        "isub" : lambda z: getattr(z, '__isub__'),
                        "mul" : lambda z: getattr(z, '__mul__'),
                        "rmul" : lambda z: getattr(z, '__rmul__'),
                        "imul" : lambda z: getattr(z, '__imul__'),
                        "div" : lambda z: getattr(z, '__div__'),
                        "rdiv" : lambda z: getattr(z, '__rdiv__'),
                        "idiv" : lambda z: getattr(z, '__idiv__'),
                        "pow" : lambda z: getattr(z, '__pow__'),
                        "rpow" : lambda z: getattr(z, '__rpow__'),
                        "ipow" : lambda z: getattr(z, '__ipow__'),
                        "None" : lambda z: lambda u: u}
        
        if (cast & 1) != 0:
            x = self.cast(x)
        if (cast & 2) != 0:
            y = self.cast(y)        
        
        return translation[op](x)(y)
Marco Selig's avatar
Marco Selig committed
1196

Ultimanet's avatar
Ultimanet committed
1197
1198
1199
1200
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    def norm(self, x, q=2):
        """
            Computes the Lq-norm of field values.
Marco Selig's avatar
Marco Selig committed
1201

Ultimanet's avatar
Ultimanet committed
1202
1203
1204
1205
1206
1207
            Parameters
            ----------
            x : np.ndarray 
                The data array 
            q : scalar
                Parameter q of the Lq-norm (default: 2).
Marco Selig's avatar
Marco Selig committed
1208

Ultimanet's avatar
Ultimanet committed
1209
1210
1211
1212
            Returns
            -------
            norm : scalar
                The Lq-norm of the field values.
Marco Selig's avatar
Marco Selig committed
1213

Ultimanet's avatar
Ultimanet committed
1214
        """
Marco Selig's avatar
Marco Selig committed
1215

Ultimanet's avatar
Ultimanet committed
1216
1217
1218
1219
1220
1221
1222
1223
1224
        
        if(q == 2):
            result = self.calc_dot(x,x)
        else:
            y = x**(q-1)        
            result = self.calc_dot(x,y)
        
        result = result**(1./q)
        return result 
Marco Selig's avatar
Marco Selig committed
1225
1226
1227



Ultimanet's avatar
Ultimanet committed
1228
1229
1230
1231
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def num(self):
        """
            Returns the number of points.
Marco Selig's avatar
Marco Selig committed
1232

Ultimanet's avatar
Ultimanet committed
1233
1234
1235
1236
1237
1238
            Returns
            -------
            num : int
                Number of points.
        """
        return self.para[0]
Marco Selig's avatar
Marco Selig committed
1239

Ultimanet's avatar
Ultimanet committed
1240
1241
    def shape(self):
        return np.array([self.paradict['num']])
Marco Selig's avatar
Marco Selig committed
1242

Ultimanet's avatar
Ultimanet committed
1243
1244
1245
1246
        
    def dim(self,split=False):
        """
            Computes the dimension of the space, i.e.\  the number of points.
Marco Selig's avatar
Marco Selig committed
1247

Ultimanet's avatar
Ultimanet committed
1248
1249
1250
1251
1252
            Parameters
            ----------
            split : bool, *optional*
                Whether to return the dimension as an array with one component
                or as a scalar (default: False).
Marco Selig's avatar
Marco Selig committed
1253

Ultimanet's avatar
Ultimanet committed
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
            Returns
            -------
            dim : {int, numpy.ndarray}
                Dimension(s) of the space.
        """
        ## dim = num
        if(split):
            return self.shape()
            #return np.array([self.para[0]],dtype=np.int)
        else:
            return np.prod(self.shape())
            #return self.para[0]
Marco Selig's avatar
Marco Selig committed
1266

Ultimanet's avatar
Ultimanet committed
1267
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
1268

Ultimanet's avatar
Ultimanet committed
1269
1270
1271
1272
1273
    def dof(self):
        """
            Computes the number of degrees of freedom of the space, i.e./  the
            number of points for real-valued fields and twice that number for
            complex-valued fields.
Marco Selig's avatar
Marco Selig committed
1274

Ultimanet's avatar
Ultimanet committed
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
            Returns
            -------
            dof : int
                Number of degrees of freedom of the space.
        """
        ## dof ~ dim
        if(issubclass(self.datatype,np.complexfloating)):
            return 2*self.para[0]
        else:
            return self.para[0]
Marco Selig's avatar
Marco Selig committed
1285

Ultimanet's avatar
Ultimanet committed
1286
1287
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def get_power_indices(self,**kwargs):
Marco Selig's avatar
Marco Selig committed
1288
        """
Ultimanet's avatar
Ultimanet committed
1289
1290
1291
1292
1293
1294
            Provides the (un)indexing objects for spectral indexing.

            Provides one-dimensional arrays containing the scales of the
            spectral bands and the numbers of modes per scale, and an array
            giving for each component of a field the corresponding index of a
            power spectrum as well as an Unindexing array.
Marco Selig's avatar
Marco Selig committed
1295
1296
1297

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
            log : bool
                Flag specifying if the binning is performed on logarithmic
                scale or not; if set, the number of used bins is set
                automatically (if not given otherwise); by default no binning
                is done (default: None).
            nbin : integer
                Number of used bins; if given `log` is set to ``False``;
                integers below the minimum of 3 induce an automatic setting;
                by default no binning is done (default: None).
            binbounds : {list, array}
                User specific inner boundaries of the bins, which are preferred
                over the above parameters; by default no binning is done
                (default: None).
Marco Selig's avatar
Marco Selig committed
1311
1312
1313

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
1314
1315
1316
1317
1318
1319
1320
1321
1322
            kindex : numpy.ndarray
                Scale of each spectral band.
            rho : numpy.ndarray
                Number of modes per scale represented in the discretization.
            pindex : numpy.ndarray
                Indexing array giving the power spectrum index for each
                represented mode.
            pundex : numpy.ndarray
                Unindexing array undoing power spectrum indexing.
Marco Selig's avatar
Marco Selig committed
1323

Ultimanet's avatar
Ultimanet committed
1324
1325
1326
1327
1328
1329
1330
            Notes
            -----
            The ``kindex`` and ``rho`` are each one-dimensional arrays.
            The indexing array is of the same shape as a field living in this
            space and contains the indices of the associated bands.
            Indexing with the unindexing array undoes the indexing with the
            indexing array; i.e., ``power == power[pindex].flatten()[pundex]``.
Marco Selig's avatar
Marco Selig committed
1331

Ultimanet's avatar
Ultimanet committed
1332
1333
1334
            See Also
            --------
            set_power_indices
Marco Selig's avatar
Marco Selig committed
1335

Ultimanet's avatar
Ultimanet committed
1336
1337
        """
        self.set_power_indices(**kwargs)
Ultimanet's avatar
Ultimanet committed
1338
1339
1340
1341
        return self.power_indices.get("kindex"),\
                self.power_indices.get("rho"),\
                self.power_indices.get("pindex"),\
                self.power_indices.get("pundex")
Marco Selig's avatar
Marco Selig committed
1342
1343
1344

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
1345
    def enforce_shape(self,x):
Marco Selig's avatar
Marco Selig committed
1346
        """
Ultimanet's avatar
Ultimanet committed
1347
1348
1349
1350
1351
1352
1353
            Shapes an array of valid field values correctly, according to the
            specifications of the space instance.

            Parameters
            ----------
            x : numpy.ndarray
                Array containing the field values to be put into shape.
Marco Selig's avatar
Marco Selig committed
1354
1355
1356

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
1357
1358
            y : numpy.ndarray
                Correctly shaped array.
Marco Selig's avatar
Marco Selig committed
1359
        """
Ultimanet's avatar
Ultimanet committed
1360
        x = np.array(x)
Marco Selig's avatar
Marco Selig committed
1361

Ultimanet's avatar
Ultimanet committed
1362
1363
1364
1365
        if(np.size(x)!=self.dim(split=False)):
            raise ValueError(about._errors.cstring("ERROR: dimension mismatch ( "+str(np.size(x))+" <> "+str(self.dim(split=False))+" )."))
#        elif(not np.all(np.array(np.shape(x))==self.dim(split=True))):
#            about.warnings.cprint("WARNING: reshaping forced.")
Marco Selig's avatar
Marco Selig committed
1366

Ultimanet's avatar
Ultimanet committed
1367
        return x.reshape(self.dim(split=True),order='C')
Marco Selig's avatar
Marco Selig committed
1368

Ultimanet's avatar
Ultimanet committed
1369
1370
1371
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def enforce_values(self,x,extend=True):
Marco Selig's avatar
Marco Selig committed
1372
        """
Ultimanet's avatar
Ultimanet committed
1373
1374
            Computes valid field values from a given object, according to the
            constraints from the space instance.
Marco Selig's avatar
Marco Selig committed
1375
1376
1377

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
1378
1379
            x : {float, numpy.ndarray, nifty.field}
                Object to be transformed into an array of valid field values.
Marco Selig's avatar
Marco Selig committed
1380
1381
1382

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
1383
1384
            x : numpy.ndarray
                Array containing the valid field values.
Marco Selig's avatar
Marco Selig committed
1385