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
687
    def get_weight(self, power=1):
        raise NotImplementedError(about._errors.cstring("ERROR: no generic instance method 'get_weight'."))
        
Marco Selig's avatar
Marco Selig committed
688
689
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ultimanet's avatar
Ultimanet committed
690
691
692
693
    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
694

Ultimanet's avatar
Ultimanet committed
695
696
697
698
699
700
            Parameters
            ----------
            x : numpy.ndarray
                First array
            y : numpy.ndarray
                Second array
Marco Selig's avatar
Marco Selig committed
701

Ultimanet's avatar
Ultimanet committed
702
703
704
705
706
707
708
            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
709
710
711



Ultimanet's avatar
Ultimanet committed
712
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
713

Ultimanet's avatar
Ultimanet committed
714
715
716
    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
717
718
719

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
720
721
722
723
724
            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
725
726
727

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
728
729
            Tx : numpy.ndarray
                Transformed array
730

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

    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
739

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

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
747
748
749
750
751
            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
752
753
754

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
755
756
            Gx : numpy.ndarray
                Smoothed array.
Marco Selig's avatar
Marco Selig committed
757

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

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

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

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

            Returns
            -------
            spec : numpy.ndarray
Ultimanet's avatar
Ultimanet committed
780
                Power contained in the input array.
Marco Selig's avatar
Marco Selig committed
781
782
783

            Other parameters
            ----------------
Ultimanet's avatar
Ultimanet committed
784
785
786
            pindex : numpy.ndarray, *optional*
                Indexing array assigning the input array components to
                components of the power spectrum (default: None).
787
            kindex : numpy.ndarray, *optional*
Ultimanet's avatar
Ultimanet committed
788
789
790
791
                Scale corresponding to each band in the power spectrum
                (default: None).
            rho : numpy.ndarray, *optional*
                Number of degrees of freedom per band (default: None).
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
            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).
809

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

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

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

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
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
865
866
867
            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
868
869
870
                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
871
872
            nbin : integer, *optional*
                Number of used spectral bins; if given `log` is set to ``False``;
873
                integers below the minimum of 3 induce an automatic setting;
874
                by default no binning is done (default: None).
Ultimanet's avatar
Ultimanet committed
875
            binbounds : {list, array}, *optional*
876
877
                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
878
879
880
881
882
                (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
883
884

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

Ultimanet's avatar
Ultimanet committed
887
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
888

Ultimanet's avatar
Ultimanet committed
889
890
    def __repr__(self):
        return "<nifty_core.space>"
Marco Selig's avatar
Marco Selig committed
891

Ultimanet's avatar
Ultimanet committed
892
893
    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
894

Ultimanet's avatar
Ultimanet committed
895
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
896

Ultimanet's avatar
Ultimanet committed
897
898
    def __len__(self):
        return int(self.dim(split=False))
Marco Selig's avatar
Marco Selig committed
899

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

Ultimanet's avatar
Ultimanet committed
906
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
907

Ultimanet's avatar
Ultimanet committed
908
909
910
911
912
913
    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
914

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

Ultimanet's avatar
Ultimanet committed
921
922
923
924
925
    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
926

Ultimanet's avatar
Ultimanet committed
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
    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
950

Ultimanet's avatar
Ultimanet committed
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
    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
975

Ultimanet's avatar
Ultimanet committed
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
    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
999

Ultimanet's avatar
Ultimanet committed
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
    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
1024

Ultimanet's avatar
Ultimanet committed
1025
##=============================================================================
Marco Selig's avatar
Marco Selig committed
1026
1027
1028



Ultimanet's avatar
Ultimanet committed
1029
##-----------------------------------------------------------------------------
Marco Selig's avatar
Marco Selig committed
1030

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

Ultimanet's avatar
Ultimanet committed
1041
        NIFTY subclass for unstructured spaces.
Marco Selig's avatar
Marco Selig committed
1042

Ultimanet's avatar
Ultimanet committed
1043
1044
        Unstructured spaces are lists of values without any geometrical
        information.
Marco Selig's avatar
Marco Selig committed
1045
1046
1047

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

Ultimanet's avatar
Ultimanet committed
1053
        Attributes
Marco Selig's avatar
Marco Selig committed
1054
        ----------
Ultimanet's avatar
Ultimanet committed
1055
1056
1057
1058
1059
1060
1061
1062
1063
        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
1064
    """
Ultimanet's avatar
Ultimanet committed
1065
1066
1067
    def __init__(self,num,datatype=None):
        """
            Sets the attributes for a point_space class instance.
Marco Selig's avatar
Marco Selig committed
1068

Ultimanet's avatar
Ultimanet committed
1069
1070
1071
1072
1073
1074
            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
1075

Ultimanet's avatar
Ultimanet committed
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
            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
1089

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

1093

Ultimanet's avatar
Ultimanet committed
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
    @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
1107

Ultimanet's avatar
Ultimanet committed
1108
1109
1110
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def setitem(self, data, update, key):
        data[key]=update
Marco Selig's avatar
Marco Selig committed
1111

Ultimanet's avatar
Ultimanet committed
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
1139
1140
1141
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    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
1142

Ultimanet's avatar
Ultimanet committed
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
        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
1169

Ultimanet's avatar
Ultimanet committed
1170
1171
                
        return translation[op](x, **kwargs)      
Marco Selig's avatar
Marco Selig committed
1172

Ultimanet's avatar
Ultimanet committed
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    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
1199

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

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

Ultimanet's avatar
Ultimanet committed
1212
1213
1214
1215
            Returns
            -------
            norm : scalar
                The Lq-norm of the field values.
Marco Selig's avatar
Marco Selig committed
1216

Ultimanet's avatar
Ultimanet committed
1217
        """
Marco Selig's avatar
Marco Selig committed
1218

Ultimanet's avatar
Ultimanet committed
1219
1220
1221
1222
1223
1224
1225
1226
1227
        
        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
1228
1229
1230



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

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

Ultimanet's avatar
Ultimanet committed
1243
1244
    def shape(self):
        return np.array([self.paradict['num']])
Marco Selig's avatar
Marco Selig committed
1245

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

Ultimanet's avatar
Ultimanet committed
1251
1252
1253
1254
1255
            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
1256

Ultimanet's avatar
Ultimanet committed
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
            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
1269

Ultimanet's avatar
Ultimanet committed
1270
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Marco Selig's avatar
Marco Selig committed
1271

Ultimanet's avatar
Ultimanet committed
1272
1273
1274
1275
1276
    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
1277

Ultimanet's avatar
Ultimanet committed
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
            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
1288

Ultimanet's avatar
Ultimanet committed
1289
1290
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def get_power_indices(self,**kwargs):
Marco Selig's avatar
Marco Selig committed
1291
        """
Ultimanet's avatar
Ultimanet committed
1292
1293
1294
1295
1296
1297
            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
1298
1299
1300

            Parameters
            ----------
Ultimanet's avatar
Ultimanet committed
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
            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
1314
1315
1316

            Returns
            -------
Ultimanet's avatar
Ultimanet committed
1317
1318
1319
1320
1321
1322
1323
1324
1325
            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
1326

Ultimanet's avatar
Ultimanet committed
1327
1328
1329
1330
1331
1332
1333
            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
1334

Ultimanet's avatar
Ultimanet committed
1335
1336
1337
            See Also
            --------
            set_power_indices
Marco Selig's avatar
Marco Selig committed
1338

Ultimanet's avatar
Ultimanet committed
1339
1340
        """
        self.set_power_indices(**kwargs)
Ultimanet's avatar
Ultimanet committed
1341
1342
1343
1344
        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
1345
1346
1347

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

Ultimanet's avatar
Ultimanet committed
1348
    def enforce_shape(self,x):
Marco Selig's avatar
Marco Selig committed
1349
        """
Ultimanet's avatar
Ultimanet committed
1350
1351
1352
1353
1354
1355
1356
            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
1357
1358
1359

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

Ultimanet's avatar
Ultimanet committed
1365
1366
1367
1368
        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
1369

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

Ultimanet's avatar
Ultimanet committed
1372
1373
1374
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

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

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