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

Ultima's avatar
Ultima 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
Ultima's avatar
Ultima committed
920
921
922
    
    def __ne__(self, x):
        return not self.__eq__(x)
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
        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,
Ultima's avatar
Ultima committed
1165
1166
                        "sum" : np.sum,
                        "prod" : np.prod,
Ultimanet's avatar
Ultimanet committed
1167
                        "None" : lambda y: y}
Marco Selig's avatar
Marco Selig committed
1168

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

Ultimanet's avatar
Ultimanet committed
1172
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
    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            
    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
1198

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

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

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

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ultimanet's avatar
Ultimanet committed
1388