field.py 16.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
# 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/>.
Theo Steininger's avatar
Theo Steininger committed
13
14
15
16
17
#
# Copyright(C) 2013-2017 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
18

Martin Reinecke's avatar
Martin Reinecke committed
19
from __future__ import division
Martin Reinecke's avatar
Martin Reinecke committed
20
from builtins import range
csongor's avatar
csongor committed
21
import numpy as np
Martin Reinecke's avatar
Martin Reinecke committed
22
from . import utilities
Martin Reinecke's avatar
Martin Reinecke committed
23
from .domain_tuple import DomainTuple
Martin Reinecke's avatar
Martin Reinecke committed
24
from functools import reduce
25
from . import dobj
26

27

Martin Reinecke's avatar
Martin Reinecke committed
28
class Field(object):
Theo Steininger's avatar
Theo Steininger committed
29
30
31
    """ The discrete representation of a continuous field over multiple spaces.

    In NIFTY, Fields are used to store data arrays and carry all the needed
32
    metainformation (i.e. the domain) for operators to be able to work on them.
Martin Reinecke's avatar
updates  
Martin Reinecke committed
33
    In addition, Field has methods to work with power spectra.
Theo Steininger's avatar
Theo Steininger committed
34

35
36
37
38
    Parameters
    ----------
    domain : DomainObject
        One of the space types NIFTY supports. RGSpace, GLSpace, HPSpace,
Theo Steininger's avatar
Theo Steininger committed
39
        LMSpace or PowerSpace. It might also be a FieldArray, which is
40
        an unstructured domain.
Theo Steininger's avatar
Theo Steininger committed
41

Martin Reinecke's avatar
stage1  
Martin Reinecke committed
42
    val : scalar, numpy.ndarray, Field
43
44
45
        The values the array should contain after init. A scalar input will
        fill the whole array with this scalar. If an array is provided the
        array's dimensions must match the domain's.
Theo Steininger's avatar
Theo Steininger committed
46

47
    dtype : type
Martin Reinecke's avatar
updates  
Martin Reinecke committed
48
        A numpy.type. Most common are float and complex.
Theo Steininger's avatar
Theo Steininger committed
49

50
51
52
53
    copy: boolean

    Attributes
    ----------
Martin Reinecke's avatar
stage1  
Martin Reinecke committed
54
    val : numpy.ndarray
Theo Steininger's avatar
Theo Steininger committed
55

Martin Reinecke's avatar
Martin Reinecke committed
56
    domain : DomainTuple
57
58
59
        See Parameters.
    dtype : type
        Contains the datatype stored in the Field.
Theo Steininger's avatar
Theo Steininger committed
60

61
62
63
64
65
66
67
68
    Raise
    -----
    TypeError
        Raised if
            *the given domain contains something that is not a DomainObject
             instance
            *val is an array that has a different dimension than the domain
    """
69

Theo Steininger's avatar
Theo Steininger committed
70
    # ---Initialization methods---
71

Martin Reinecke's avatar
stage1  
Martin Reinecke committed
72
    def __init__(self, domain=None, val=None, dtype=None, copy=False):
73
        self.domain = self._parse_domain(domain=domain, val=val)
74

Martin Reinecke's avatar
Martin Reinecke committed
75
        dtype = self._infer_dtype(dtype=dtype, val=val)
Martin Reinecke's avatar
cleanup  
Martin Reinecke committed
76
        if isinstance(val, Field):
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
77
            if self.domain != val.domain:
Martin Reinecke's avatar
cleanup  
Martin Reinecke committed
78
                raise ValueError("Domain mismatch")
79
            self._val = dobj.from_object(val.val, dtype=dtype, copy=copy)
Martin Reinecke's avatar
cleanup  
Martin Reinecke committed
80
        elif (np.isscalar(val)):
81
82
            self._val = dobj.full(self.domain.shape, dtype=dtype,
                                  fill_value=val)
83
        elif isinstance(val, dobj.data_object):
Martin Reinecke's avatar
Martin Reinecke committed
84
            if self.domain.shape == val.shape:
85
                self._val = dobj.from_object(val, dtype=dtype, copy=copy)
Martin Reinecke's avatar
cleanup  
Martin Reinecke committed
86
87
88
            else:
                raise ValueError("Shape mismatch")
        elif val is None:
89
            self._val = dobj.empty(self.domain.shape, dtype=dtype)
Martin Reinecke's avatar
cleanup  
Martin Reinecke committed
90
91
        else:
            raise TypeError("unknown source type")
csongor's avatar
csongor committed
92

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    @staticmethod
    def full(domain, val, dtype=None):
        if not np.isscalar(val):
            raise TypeError("val must be a scalar")
        return Field(DomainTuple.make(domain), val, dtype)

    @staticmethod
    def ones(domain, dtype=None):
        return Field(DomainTuple.make(domain), 1., dtype)

    @staticmethod
    def zeros(domain, dtype=None):
        return Field(DomainTuple.make(domain), 0., dtype)

    @staticmethod
    def empty(domain, dtype=None):
        return Field(DomainTuple.make(domain), None, dtype)

    @staticmethod
    def full_like(field, val, dtype=None):
        if not isinstance(field, Field):
            raise TypeError("field must be of Field type")
        return Field.full(field.domain, val, dtype)

    @staticmethod
    def zeros_like(field, dtype=None):
        if not isinstance(field, Field):
            raise TypeError("field must be of Field type")
        if dtype is None:
            dtype = field.dtype
        return Field.zeros(field.domain, dtype)

    @staticmethod
    def ones_like(field, dtype=None):
        if not isinstance(field, Field):
            raise TypeError("field must be of Field type")
        if dtype is None:
            dtype = field.dtype
        return Field.ones(field.domain, dtype)

    @staticmethod
    def empty_like(field, dtype=None):
        if not isinstance(field, Field):
            raise TypeError("field must be of Field type")
        if dtype is None:
            dtype = field.dtype
        return Field.empty(field.domain, dtype)

Martin Reinecke's avatar
Martin Reinecke committed
141
142
    @staticmethod
    def _parse_domain(domain, val=None):
143
        if domain is None:
144
            if isinstance(val, Field):
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
145
146
                return val.domain
            if np.isscalar(val):
147
                return DomainTuple.make(())  # empty domain tuple
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
148
            raise TypeError("could not infer domain from value")
Martin Reinecke's avatar
Martin Reinecke committed
149
        return DomainTuple.make(domain)
150

Martin Reinecke's avatar
Martin Reinecke committed
151
    # MR: this needs some rethinking ... do we need to have at least float64?
Martin Reinecke's avatar
Martin Reinecke committed
152
153
    @staticmethod
    def _infer_dtype(dtype, val):
Martin Reinecke's avatar
Martin Reinecke committed
154
155
156
157
158
        if val is None or dtype is not None:
            return np.result_type(dtype, np.float64)
        if isinstance(val, Field):
            return val.dtype
        return np.result_type(val, np.float64)
159

Martin Reinecke's avatar
Martin Reinecke committed
160
161
    @staticmethod
    def from_random(random_type, domain, dtype=np.float64, **kwargs):
162
163
164
165
166
167
168
        """ Draws a random field with the given parameters.

        Parameters
        ----------
        random_type : String
            'pm1', 'normal', 'uniform' are the supported arguments for this
            method.
Theo Steininger's avatar
Theo Steininger committed
169

170
171
        domain : DomainObject
            The domain of the output random field
Theo Steininger's avatar
Theo Steininger committed
172

173
174
        dtype : type
            The datatype of the output random field
Theo Steininger's avatar
Theo Steininger committed
175

176
177
178
179
180
        Returns
        -------
        out : Field
            The output object.
        """
Martin Reinecke's avatar
Martin Reinecke committed
181
        domain = DomainTuple.make(domain)
Martin Reinecke's avatar
Martin Reinecke committed
182
183
184
        return Field(domain=domain,
                     val=dobj.from_random(random_type, dtype=dtype,
                                          shape=domain.shape, **kwargs))
185

Martin Reinecke's avatar
Martin Reinecke committed
186
187
188
    def fill(self, fill_value):
        self._val.fill(fill_value)

Theo Steininger's avatar
Theo Steininger committed
189
    # ---Properties---
190

Theo Steininger's avatar
Theo Steininger committed
191
192
    @property
    def val(self):
Martin Reinecke's avatar
stage1  
Martin Reinecke committed
193
        """ Returns the data object associated with this Field.
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
194
        No copy is made.
195
        """
Martin Reinecke's avatar
Martin Reinecke committed
196
        return self._val
csongor's avatar
csongor committed
197

Martin Reinecke's avatar
Martin Reinecke committed
198
199
200
201
    @property
    def dtype(self):
        return self._val.dtype

202
203
    @property
    def shape(self):
Theo Steininger's avatar
Theo Steininger committed
204
        """ Returns the total shape of the Field's data array.
Theo Steininger's avatar
Theo Steininger committed
205

206
207
        Returns
        -------
Martin Reinecke's avatar
Martin Reinecke committed
208
209
        Integer tuple containing the dimensions of the spaces in domain.
        """
Martin Reinecke's avatar
Martin Reinecke committed
210
        return self.domain.shape
csongor's avatar
csongor committed
211

212
213
    @property
    def dim(self):
Theo Steininger's avatar
Theo Steininger committed
214
        """ Returns the total number of pixel-dimensions the field has.
Theo Steininger's avatar
Theo Steininger committed
215

Theo Steininger's avatar
Theo Steininger committed
216
        Effectively, all values from shape are multiplied.
Theo Steininger's avatar
Theo Steininger committed
217

218
219
220
221
222
        Returns
        -------
        out : int
            The dimension of the Field.
        """
Martin Reinecke's avatar
Martin Reinecke committed
223
        return self.domain.dim
csongor's avatar
csongor committed
224

Theo Steininger's avatar
Theo Steininger committed
225
226
    @property
    def real(self):
Martin Reinecke's avatar
Martin Reinecke committed
227
        """ The real part of the field (data is not copied)."""
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
228
        return Field(self.domain, self.val.real)
Theo Steininger's avatar
Theo Steininger committed
229
230
231

    @property
    def imag(self):
Martin Reinecke's avatar
Martin Reinecke committed
232
        """ The imaginary part of the field (data is not copied)."""
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
233
        return Field(self.domain, self.val.imag)
Theo Steininger's avatar
Theo Steininger committed
234

Theo Steininger's avatar
Theo Steininger committed
235
    # ---Special unary/binary operations---
236

Martin Reinecke's avatar
Martin Reinecke committed
237
    def copy(self):
238
        """ Returns a full copy of the Field.
Theo Steininger's avatar
Theo Steininger committed
239

Martin Reinecke's avatar
Martin Reinecke committed
240
        The returned object will be an identical copy of the original Field.
Theo Steininger's avatar
Theo Steininger committed
241

242
243
244
245
246
        Returns
        -------
        out : Field
            The output object. An identical copy of 'self'.
        """
Martin Reinecke's avatar
Martin Reinecke committed
247
        return Field(val=self, copy=True)
csongor's avatar
csongor committed
248

249
250
    def scalar_weight(self, spaces=None):
        if np.isscalar(spaces):
251
            return self.domain[spaces].scalar_dvol()
252
253
254

        if spaces is None:
            spaces = range(len(self.domain))
Martin Reinecke's avatar
Martin Reinecke committed
255
        res = 1.
256
        for i in spaces:
257
            tmp = self.domain[i].scalar_dvol()
258
259
260
261
262
            if tmp is None:
                return None
            res *= tmp
        return res

263
    def weight(self, power=1, spaces=None, out=None):
Theo Steininger's avatar
Theo Steininger committed
264
        """ Weights the pixels of `self` with their invidual pixel-volume.
265
266
267
268

        Parameters
        ----------
        power : number
Theo Steininger's avatar
Theo Steininger committed
269
            The pixels get weighted with the volume-factor**power.
Theo Steininger's avatar
Theo Steininger committed
270

Theo Steininger's avatar
Theo Steininger committed
271
272
        spaces : tuple of ints
            Determines on which subspace the operation takes place.
Theo Steininger's avatar
Theo Steininger committed
273

274
275
276
277
278
        out : Field or None
            if not None, the result is returned in a new Field
            otherwise the contents of "out" are overwritten with the result.
            "out" may be identical to "self"!

279
280
281
        Returns
        -------
        out : Field
Theo Steininger's avatar
Theo Steininger committed
282
            The weighted field.
283
        """
284
285
286
287
288
        if out is None:
            out = self.copy()
        else:
            if out is not self:
                out.copy_content_from(self)
csongor's avatar
csongor committed
289

csongor's avatar
csongor committed
290
        if spaces is None:
Martin Reinecke's avatar
Martin Reinecke committed
291
            spaces = range(len(self.domain))
Martin Reinecke's avatar
Martin Reinecke committed
292
293
        else:
            spaces = utilities.cast_iseq_to_tuple(spaces)
csongor's avatar
csongor committed
294

295
296
        fct = 1.
        for ind in spaces:
297
            wgt = self.domain[ind].dvol()
298
299
300
            if np.isscalar(wgt):
                fct *= wgt
            else:
Martin Reinecke's avatar
Martin Reinecke committed
301
                new_shape = np.ones(len(self.shape), dtype=np.int)
Martin Reinecke's avatar
Martin Reinecke committed
302
303
                new_shape[self.domain.axes[ind][0]:
                          self.domain.axes[ind][-1]+1] = wgt.shape
304
                wgt = wgt.reshape(new_shape)
Martin Reinecke's avatar
Martin Reinecke committed
305
306
                if dobj.distaxis(self._val) >= 0 and ind == 0:
                    # we need to distribute the weights along axis 0
Martin Reinecke's avatar
fixes  
Martin Reinecke committed
307
                    wgt = dobj.local_data(dobj.from_global_data(wgt))
308
                out *= wgt**power
309
        fct = fct**power
Martin Reinecke's avatar
Martin Reinecke committed
310
        if fct != 1.:
311
            out *= fct
312

313
        return out
csongor's avatar
csongor committed
314

Martin Reinecke's avatar
Martin Reinecke committed
315
    def vdot(self, x=None, spaces=None):
Theo Steininger's avatar
Theo Steininger committed
316
        """ Computes the volume-factor-aware dot product of 'self' with x.
Theo Steininger's avatar
Theo Steininger committed
317

318
319
320
        Parameters
        ----------
        x : Field
Theo Steininger's avatar
Theo Steininger committed
321
            The domain of x must contain `self.domain`
Theo Steininger's avatar
Theo Steininger committed
322

Theo Steininger's avatar
Theo Steininger committed
323
        spaces : tuple of ints
324
325
            If the domain of `self` and `x` are not the same, `spaces` defines
            which domains of `x` are mapped to those of `self`.
Theo Steininger's avatar
Theo Steininger committed
326

327
328
        Returns
        -------
Martin Reinecke's avatar
Martin Reinecke committed
329
        out : float, complex, either scalar or Field
330
        """
331
332
333
        if not isinstance(x, Field):
            raise ValueError("The dot-partner must be an instance of " +
                             "the NIFTy field class")
Theo Steininger's avatar
Theo Steininger committed
334

Martin Reinecke's avatar
Martin Reinecke committed
335
        # Compute the dot respecting the fact of discrete/continuous spaces
Martin Reinecke's avatar
Martin Reinecke committed
336
337
        tmp = self.scalar_weight(spaces)
        if tmp is None:
338
            fct = 1.
Martin Reinecke's avatar
Martin Reinecke committed
339
            y = self.weight(power=1)
340
        else:
Martin Reinecke's avatar
Martin Reinecke committed
341
342
            y = self
            fct = tmp
Theo Steininger's avatar
Theo Steininger committed
343

344
        if spaces is None:
Martin Reinecke's avatar
fixes  
Martin Reinecke committed
345
            return fct*dobj.vdot(y.val, x.val)
Martin Reinecke's avatar
Martin Reinecke committed
346
347
348
349
350
351
352
353
354
355
356
357
358

        spaces = utilities.cast_iseq_to_tuple(spaces)
        if spaces == tuple(range(len(self.domain))):  # full contraction
            return fct*dobj.vdot(y.val, x.val)

        raise NotImplementedError("special case for vdot not yet implemented")
        active_axes = []
        for i in spaces:
            active_axes += self.domain.axes[i]
        res = 0.
        for sl in utilities.get_slice_list(self.shape, active_axes):
            res += dobj.vdot(y.val, x.val[sl])
        return res*fct
Theo Steininger's avatar
Theo Steininger committed
359

Theo Steininger's avatar
Theo Steininger committed
360
    def norm(self):
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
361
        """ Computes the L2-norm of the field values.
csongor's avatar
csongor committed
362

Theo Steininger's avatar
Theo Steininger committed
363
364
        Returns
        -------
Martin Reinecke's avatar
Martin Reinecke committed
365
        norm : float
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
366
            The L2-norm of the field values.
csongor's avatar
csongor committed
367
        """
368
        return np.sqrt(np.abs(self.vdot(x=self)))
csongor's avatar
csongor committed
369

Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
370
    def conjugate(self):
Martin Reinecke's avatar
cleanup  
Martin Reinecke committed
371
        """ Returns the complex conjugate of the field.
Theo Steininger's avatar
Theo Steininger committed
372

373
374
        Returns
        -------
Martin Reinecke's avatar
Martin Reinecke committed
375
        The complex conjugated field.
csongor's avatar
csongor committed
376
        """
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
377
        return Field(self.domain, self.val.conjugate(), self.dtype)
csongor's avatar
csongor committed
378

Theo Steininger's avatar
Theo Steininger committed
379
    # ---General unary/contraction methods---
380

Theo Steininger's avatar
Theo Steininger committed
381
382
    def __pos__(self):
        return self.copy()
383

Theo Steininger's avatar
Theo Steininger committed
384
    def __neg__(self):
Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
385
        return Field(self.domain, -self.val, self.dtype)
csongor's avatar
csongor committed
386

Theo Steininger's avatar
Theo Steininger committed
387
    def __abs__(self):
388
        return Field(self.domain, dobj.abs(self.val), self.dtype)
csongor's avatar
csongor committed
389

390
    def _contraction_helper(self, op, spaces):
Theo Steininger's avatar
Theo Steininger committed
391
        if spaces is None:
392
            return getattr(self.val, op)()
Martin Reinecke's avatar
Martin Reinecke committed
393
394
        else:
            spaces = utilities.cast_iseq_to_tuple(spaces)
csongor's avatar
csongor committed
395

Martin Reinecke's avatar
Martin Reinecke committed
396
        axes_list = tuple(self.domain.axes[sp_index] for sp_index in spaces)
397

Martin Reinecke's avatar
Martin Reinecke committed
398
        if len(axes_list) > 0:
Theo Steininger's avatar
Theo Steininger committed
399
            axes_list = reduce(lambda x, y: x+y, axes_list)
csongor's avatar
csongor committed
400

Martin Reinecke's avatar
stage1  
Martin Reinecke committed
401
        # perform the contraction on the data
402
        data = getattr(self.val, op)(axis=axes_list)
csongor's avatar
csongor committed
403

Theo Steininger's avatar
Theo Steininger committed
404
405
406
        # check if the result is scalar or if a result_field must be constr.
        if np.isscalar(data):
            return data
csongor's avatar
csongor committed
407
        else:
Martin Reinecke's avatar
Martin Reinecke committed
408
409
            return_domain = tuple(dom
                                  for i, dom in enumerate(self.domain)
Theo Steininger's avatar
Theo Steininger committed
410
                                  if i not in spaces)
411

Martin Reinecke's avatar
updates  
Martin Reinecke committed
412
            return Field(domain=return_domain, val=data, copy=False)
csongor's avatar
csongor committed
413

414
415
    def sum(self, spaces=None):
        return self._contraction_helper('sum', spaces)
csongor's avatar
csongor committed
416

417
418
419
420
    def integrate(self, spaces=None):
        tmp = self.weight(1, spaces=spaces)
        return tmp.sum(spaces)

421
422
    def prod(self, spaces=None):
        return self._contraction_helper('prod', spaces)
csongor's avatar
csongor committed
423

424
425
    def all(self, spaces=None):
        return self._contraction_helper('all', spaces)
csongor's avatar
csongor committed
426

427
428
    def any(self, spaces=None):
        return self._contraction_helper('any', spaces)
csongor's avatar
csongor committed
429

430
431
    def min(self, spaces=None):
        return self._contraction_helper('min', spaces)
csongor's avatar
csongor committed
432

433
434
    def max(self, spaces=None):
        return self._contraction_helper('max', spaces)
csongor's avatar
csongor committed
435

436
437
    def mean(self, spaces=None):
        return self._contraction_helper('mean', spaces)
csongor's avatar
csongor committed
438

439
440
    def var(self, spaces=None):
        return self._contraction_helper('var', spaces)
csongor's avatar
csongor committed
441

442
443
    def std(self, spaces=None):
        return self._contraction_helper('std', spaces)
csongor's avatar
csongor committed
444

445
446
447
448
449
    def copy_content_from(self, other):
        if not isinstance(other, Field):
            raise TypeError("argument must be a Field")
        if other.domain != self.domain:
            raise ValueError("domains are incompatible.")
Martin Reinecke's avatar
tweaks  
Martin Reinecke committed
450
        dobj.local_data(self.val)[()] = dobj.local_data(other.val)[()]
451

Theo Steininger's avatar
Theo Steininger committed
452
    # ---General binary methods---
csongor's avatar
csongor committed
453

454
    def _binary_helper(self, other, op):
csongor's avatar
csongor committed
455
        # if other is a field, make sure that the domains match
456
        if isinstance(other, Field):
457
458
            if other.domain != self.domain:
                raise ValueError("domains are incompatible.")
Martin Reinecke's avatar
Martin Reinecke committed
459
460
            tval = getattr(self.val, op)(other.val)
            return self if tval is self.val else Field(self.domain, tval)
csongor's avatar
csongor committed
461

Martin Reinecke's avatar
Martin Reinecke committed
462
463
        tval = getattr(self.val, op)(other)
        return self if tval is self.val else Field(self.domain, tval)
csongor's avatar
csongor committed
464
465

    def __add__(self, other):
Theo Steininger's avatar
Theo Steininger committed
466
        return self._binary_helper(other, op='__add__')
467

468
    def __radd__(self, other):
Theo Steininger's avatar
Theo Steininger committed
469
        return self._binary_helper(other, op='__radd__')
csongor's avatar
csongor committed
470
471

    def __iadd__(self, other):
472
        return self._binary_helper(other, op='__iadd__')
csongor's avatar
csongor committed
473
474

    def __sub__(self, other):
Theo Steininger's avatar
Theo Steininger committed
475
        return self._binary_helper(other, op='__sub__')
csongor's avatar
csongor committed
476
477

    def __rsub__(self, other):
Theo Steininger's avatar
Theo Steininger committed
478
        return self._binary_helper(other, op='__rsub__')
csongor's avatar
csongor committed
479
480

    def __isub__(self, other):
481
        return self._binary_helper(other, op='__isub__')
csongor's avatar
csongor committed
482
483

    def __mul__(self, other):
Theo Steininger's avatar
Theo Steininger committed
484
        return self._binary_helper(other, op='__mul__')
485

486
    def __rmul__(self, other):
Theo Steininger's avatar
Theo Steininger committed
487
        return self._binary_helper(other, op='__rmul__')
csongor's avatar
csongor committed
488
489

    def __imul__(self, other):
490
        return self._binary_helper(other, op='__imul__')
csongor's avatar
csongor committed
491
492

    def __div__(self, other):
Theo Steininger's avatar
Theo Steininger committed
493
        return self._binary_helper(other, op='__div__')
csongor's avatar
csongor committed
494

Martin Reinecke's avatar
Martin Reinecke committed
495
496
497
    def __truediv__(self, other):
        return self._binary_helper(other, op='__truediv__')

csongor's avatar
csongor committed
498
    def __rdiv__(self, other):
Theo Steininger's avatar
Theo Steininger committed
499
        return self._binary_helper(other, op='__rdiv__')
csongor's avatar
csongor committed
500

Martin Reinecke's avatar
Martin Reinecke committed
501
502
503
    def __rtruediv__(self, other):
        return self._binary_helper(other, op='__rtruediv__')

csongor's avatar
csongor committed
504
    def __idiv__(self, other):
505
        return self._binary_helper(other, op='__idiv__')
506

csongor's avatar
csongor committed
507
    def __pow__(self, other):
Theo Steininger's avatar
Theo Steininger committed
508
        return self._binary_helper(other, op='__pow__')
csongor's avatar
csongor committed
509
510

    def __rpow__(self, other):
Theo Steininger's avatar
Theo Steininger committed
511
        return self._binary_helper(other, op='__rpow__')
csongor's avatar
csongor committed
512
513

    def __ipow__(self, other):
514
        return self._binary_helper(other, op='__ipow__')
csongor's avatar
csongor committed
515

Theo Steininger's avatar
Theo Steininger committed
516
    def __repr__(self):
Martin Reinecke's avatar
Martin Reinecke committed
517
        return "<nifty2go.Field>"
Theo Steininger's avatar
Theo Steininger committed
518
519
520
521

    def __str__(self):
        minmax = [self.min(), self.max()]
        mean = self.mean()
Martin Reinecke's avatar
Martin Reinecke committed
522
        return "nifty2go.Field instance\n- domain      = " + \
Theo Steininger's avatar
Theo Steininger committed
523
               repr(self.domain) + \
524
               "\n- val         = " + repr(self.val) + \
Theo Steininger's avatar
Theo Steininger committed
525
526
               "\n  - min.,max. = " + str(minmax) + \
               "\n  - mean = " + str(mean)