Commit 6c84c41b authored by Ultima's avatar Ultima
Browse files

Improved some of the d2o tests

Added more space tests.
Fixed and improved the random number generator machinery.
parent bf22cbea
...@@ -60,6 +60,8 @@ if gl is None and gc['lm2gl']: ...@@ -60,6 +60,8 @@ if gl is None and gc['lm2gl']:
gc['lm2gl'] = False gc['lm2gl'] = False
LM_DISTRIBUTION_STRATEGIES = [] LM_DISTRIBUTION_STRATEGIES = []
GL_DISTRIBUTION_STRATEGIES = []
HP_DISTRIBUTION_STRATEGIES = []
class lm_space(point_space): class lm_space(point_space):
...@@ -195,6 +197,17 @@ class lm_space(point_space): ...@@ -195,6 +197,17 @@ class lm_space(point_space):
self.paradict['lmax'] = x[0] self.paradict['lmax'] = x[0]
self.paradict['mmax'] = x[1] self.paradict['mmax'] = x[1]
def _identifier(self):
# Extract the identifying parts from the vars(self) dict.
temp = [(ii[0],
((lambda x: tuple(x) if
isinstance(x, np.ndarray) else x)(ii[1])))
for ii in vars(self).iteritems()
if ii[0] not in ['power_indices', 'comm']]
temp.append(('comm', self.comm.__hash__()))
# Return the sorted identifiers as a tuple.
return tuple(sorted(temp))
def copy(self): def copy(self):
return lm_space(lmax=self.paradict['lmax'], return lm_space(lmax=self.paradict['lmax'],
mmax=self.paradict['mmax'], mmax=self.paradict['mmax'],
...@@ -891,7 +904,7 @@ class gl_space(point_space): ...@@ -891,7 +904,7 @@ class gl_space(point_space):
An array containing the pixel sizes. An array containing the pixel sizes.
""" """
def __init__(self, nlat, nlon=None, dtype=np.dtype('float'), def __init__(self, nlat, nlon=None, dtype=np.dtype('float64'),
datamodel='np', comm=gc['default_comm']): datamodel='np', comm=gc['default_comm']):
""" """
Sets the attributes for a gl_space class instance. Sets the attributes for a gl_space class instance.
...@@ -978,8 +991,10 @@ class gl_space(point_space): ...@@ -978,8 +991,10 @@ class gl_space(point_space):
Since the :py:class:`gl_space` class only supports real-valued Since the :py:class:`gl_space` class only supports real-valued
fields, the number of degrees of freedom is the number of pixels. fields, the number of degrees of freedom is the number of pixels.
""" """
# dof = dim if split:
return self.get_dim(split=split) return self.get_shape()
else:
return self.get_dim()
def get_meta_volume(self, split=False): def get_meta_volume(self, split=False):
""" """
...@@ -1100,7 +1115,8 @@ class gl_space(point_space): ...@@ -1100,7 +1115,8 @@ class gl_space(point_space):
Supported distributions are: Supported distributions are:
- "pm1" (uniform distribution over {+1,-1} or {+1,+i,-1,-i} - "pm1" (uniform distribution over {+1,-1} or {+1,+i,-1,-i}
- "gau" (normal distribution with zero-mean and a given standard - "gau" (normal distribution with zero-mean and a given
standard
deviation or variance) deviation or variance)
- "syn" (synthesizes from a given power spectrum) - "syn" (synthesizes from a given power spectrum)
- "uni" (uniform distribution over [vmin,vmax[) - "uni" (uniform distribution over [vmin,vmax[)
...@@ -1111,7 +1127,8 @@ class gl_space(point_space): ...@@ -1111,7 +1127,8 @@ class gl_space(point_space):
var : float, *optional* var : float, *optional*
Variance, overriding `dev` if both are specified Variance, overriding `dev` if both are specified
(default: 1). (default: 1).
spec : {scalar, list, numpy.array, nifty.field, function}, *optional* spec : {scalar, list, numpy.array, nifty.field, function},
*optional*
Power spectrum (default: 1). Power spectrum (default: 1).
codomain : nifty.lm_space, *optional* codomain : nifty.lm_space, *optional*
A compatible codomain for power indexing (default: None). A compatible codomain for power indexing (default: None).
...@@ -1477,10 +1494,6 @@ class gl_space(point_space): ...@@ -1477,10 +1494,6 @@ class gl_space(point_space):
return "nifty_lm.gl_space instance\n- nlat = " + str(self.para[0]) + "\n- nlon = " + str(self.para[1]) + "\n- dtype = numpy." + str(np.result_type(self.dtype)) return "nifty_lm.gl_space instance\n- nlat = " + str(self.para[0]) + "\n- nlon = " + str(self.para[1]) + "\n- dtype = numpy." + str(np.result_type(self.dtype))
class hp_space(point_space): class hp_space(point_space):
""" """
.. __ .. __
...@@ -1604,8 +1617,10 @@ class hp_space(point_space): ...@@ -1604,8 +1617,10 @@ class hp_space(point_space):
Since the :py:class:`hp_space` class only supports real-valued Since the :py:class:`hp_space` class only supports real-valued
fields, the number of degrees of freedom is the number of pixels. fields, the number of degrees of freedom is the number of pixels.
""" """
# dof = dim if split:
return self.get_dim(split=split) return self.get_shape()
else:
return self.get_dim()
def get_meta_volume(self, split=False): def get_meta_volume(self, split=False):
""" """
......
...@@ -159,10 +159,6 @@ import nifty.nifty_utilities as utilities ...@@ -159,10 +159,6 @@ import nifty.nifty_utilities as utilities
POINT_DISTRIBUTION_STRATEGIES = DISTRIBUTION_STRATEGIES['global'] POINT_DISTRIBUTION_STRATEGIES = DISTRIBUTION_STRATEGIES['global']
#pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
class space(object): class space(object):
""" """
...@@ -220,7 +216,7 @@ class space(object): ...@@ -220,7 +216,7 @@ class space(object):
have the same volume. have the same volume.
""" """
def __init__(self, dtype=np.dtype('float'), datamodel='np'): def __init__(self):
""" """
Sets the attributes for a space class instance. Sets the attributes for a space class instance.
...@@ -236,11 +232,6 @@ class space(object): ...@@ -236,11 +232,6 @@ class space(object):
None None
""" """
self.paradict = space_paradict() self.paradict = space_paradict()
# self.datamodel = str(datamodel)
# self.dtype = np.dtype(dtype)
# self.discrete = False
# self.harmonic = False
# self.distances = np.real(np.array([1], dtype=self.dtype))
@property @property
def para(self): def para(self):
...@@ -830,11 +821,9 @@ class point_space(space): ...@@ -830,11 +821,9 @@ class point_space(space):
# parse dtype # parse dtype
dtype = np.dtype(dtype) dtype = np.dtype(dtype)
if dtype not in [np.dtype('bool'), if dtype not in [np.dtype('bool'),
np.dtype('int8'),
np.dtype('int16'), np.dtype('int16'),
np.dtype('int32'), np.dtype('int32'),
np.dtype('int64'), np.dtype('int64'),
np.dtype('float16'),
np.dtype('float32'), np.dtype('float32'),
np.dtype('float64'), np.dtype('float64'),
np.dtype('complex64'), np.dtype('complex64'),
...@@ -946,62 +935,68 @@ class point_space(space): ...@@ -946,62 +935,68 @@ class point_space(space):
return ind[0] return ind[0]
return ind return ind
translation = {"pos": lambda y: getattr(y, '__pos__')(), translation = {'pos': lambda y: getattr(y, '__pos__')(),
"neg": lambda y: getattr(y, '__neg__')(), 'neg': lambda y: getattr(y, '__neg__')(),
"abs": lambda y: getattr(y, '__abs__')(), 'abs': lambda y: getattr(y, '__abs__')(),
"real": lambda y: getattr(y, 'real'), 'real': lambda y: getattr(y, 'real'),
"imag": lambda y: getattr(y, 'imag'), 'imag': lambda y: getattr(y, 'imag'),
"nanmin": np.nanmin, 'nanmin': np.nanmin,
"amin": np.amin, 'amin': np.amin,
"nanmax": np.nanmax, 'nanmax': np.nanmax,
"amax": np.amax, 'amax': np.amax,
"med": np.median, 'median': np.median,
"mean": np.mean, 'mean': np.mean,
"std": np.std, 'std': np.std,
"var": np.var, 'var': np.var,
"argmin": _argmin, 'argmin': _argmin,
"argmin_flat": np.argmin, 'argmin_flat': np.argmin,
"argmax": _argmax, 'argmax': _argmax,
"argmax_flat": np.argmax, 'argmax_flat': np.argmax,
"conjugate": np.conjugate, 'conjugate': np.conjugate,
"sum": np.sum, 'sum': np.sum,
"prod": np.prod, 'prod': np.prod,
"unique": np.unique, 'unique': np.unique,
"copy": np.copy, 'copy': np.copy,
"isnan": np.isnan, 'copy_empty': np.empty_like,
"isinf": np.isinf, 'isnan': np.isnan,
"isfinite": np.isfinite, 'isinf': np.isinf,
"nan_to_num": np.nan_to_num, 'isfinite': np.isfinite,
"None": lambda y: y} 'nan_to_num': np.nan_to_num,
'all': np.all,
'any': np.any,
'None': lambda y: y}
elif self.datamodel in POINT_DISTRIBUTION_STRATEGIES: elif self.datamodel in POINT_DISTRIBUTION_STRATEGIES:
translation = {"pos": lambda y: getattr(y, '__pos__')(), translation = {'pos': lambda y: getattr(y, '__pos__')(),
"neg": lambda y: getattr(y, '__neg__')(), 'neg': lambda y: getattr(y, '__neg__')(),
"abs": lambda y: getattr(y, '__abs__')(), 'abs': lambda y: getattr(y, '__abs__')(),
"real": lambda y: getattr(y, 'real'), 'real': lambda y: getattr(y, 'real'),
"imag": lambda y: getattr(y, 'imag'), 'imag': lambda y: getattr(y, 'imag'),
"nanmin": lambda y: getattr(y, 'nanmin')(), 'nanmin': lambda y: getattr(y, 'nanmin')(),
"amin": lambda y: getattr(y, 'amin')(), 'amin': lambda y: getattr(y, 'amin')(),
"nanmax": lambda y: getattr(y, 'nanmax')(), 'nanmax': lambda y: getattr(y, 'nanmax')(),
"amax": lambda y: getattr(y, 'amax')(), 'amax': lambda y: getattr(y, 'amax')(),
"median": lambda y: getattr(y, 'median')(), 'median': lambda y: getattr(y, 'median')(),
"mean": lambda y: getattr(y, 'mean')(), 'mean': lambda y: getattr(y, 'mean')(),
"std": lambda y: getattr(y, 'std')(), 'std': lambda y: getattr(y, 'std')(),
"var": lambda y: getattr(y, 'var')(), 'var': lambda y: getattr(y, 'var')(),
"argmin": lambda y: getattr(y, 'argmin_nonflat')(), 'argmin': lambda y: getattr(y, 'argmin_nonflat')(),
"argmin_flat": lambda y: getattr(y, 'argmin')(), 'argmin_flat': lambda y: getattr(y, 'argmin')(),
"argmax": lambda y: getattr(y, 'argmax_nonflat')(), 'argmax': lambda y: getattr(y, 'argmax_nonflat')(),
"argmax_flat": lambda y: getattr(y, 'argmax')(), 'argmax_flat': lambda y: getattr(y, 'argmax')(),
"conjugate": lambda y: getattr(y, 'conjugate')(), 'conjugate': lambda y: getattr(y, 'conjugate')(),
"sum": lambda y: getattr(y, 'sum')(), 'sum': lambda y: getattr(y, 'sum')(),
"prod": lambda y: getattr(y, 'prod')(), 'prod': lambda y: getattr(y, 'prod')(),
"unique": lambda y: getattr(y, 'unique')(), 'unique': lambda y: getattr(y, 'unique')(),
"copy": lambda y: getattr(y, 'copy')(), 'copy': lambda y: getattr(y, 'copy')(),
"isnan": lambda y: getattr(y, 'isnan')(), 'copy_empty': lambda y: getattr(y, 'copy_empty')(),
"isinf": lambda y: getattr(y, 'isinf')(), 'isnan': lambda y: getattr(y, 'isnan')(),
"isfinite": lambda y: getattr(y, 'isfinite')(), 'isinf': lambda y: getattr(y, 'isinf')(),
"nan_to_num": lambda y: getattr(y, 'nan_to_num')(), 'isfinite': lambda y: getattr(y, 'isfinite')(),
"None": lambda y: y} 'nan_to_num': lambda y: getattr(y, 'nan_to_num')(),
'all': lambda y: getattr(y, 'all')(),
'any': lambda y: getattr(y, 'any')(),
'None': lambda y: y}
else: else:
raise NotImplementedError(about._errors.cstring( raise NotImplementedError(about._errors.cstring(
"ERROR: function is not implemented for given datamodel.")) "ERROR: function is not implemented for given datamodel."))
...@@ -1010,28 +1005,28 @@ class point_space(space): ...@@ -1010,28 +1005,28 @@ class point_space(space):
def binary_operation(self, x, y, op='None', cast=0): def binary_operation(self, x, y, op='None', cast=0):
translation = {"add": lambda z: getattr(z, '__add__'), translation = {'add': lambda z: getattr(z, '__add__'),
"radd": lambda z: getattr(z, '__radd__'), 'radd': lambda z: getattr(z, '__radd__'),
"iadd": lambda z: getattr(z, '__iadd__'), 'iadd': lambda z: getattr(z, '__iadd__'),
"sub": lambda z: getattr(z, '__sub__'), 'sub': lambda z: getattr(z, '__sub__'),
"rsub": lambda z: getattr(z, '__rsub__'), 'rsub': lambda z: getattr(z, '__rsub__'),
"isub": lambda z: getattr(z, '__isub__'), 'isub': lambda z: getattr(z, '__isub__'),
"mul": lambda z: getattr(z, '__mul__'), 'mul': lambda z: getattr(z, '__mul__'),
"rmul": lambda z: getattr(z, '__rmul__'), 'rmul': lambda z: getattr(z, '__rmul__'),
"imul": lambda z: getattr(z, '__imul__'), 'imul': lambda z: getattr(z, '__imul__'),
"div": lambda z: getattr(z, '__div__'), 'div': lambda z: getattr(z, '__div__'),
"rdiv": lambda z: getattr(z, '__rdiv__'), 'rdiv': lambda z: getattr(z, '__rdiv__'),
"idiv": lambda z: getattr(z, '__idiv__'), 'idiv': lambda z: getattr(z, '__idiv__'),
"pow": lambda z: getattr(z, '__pow__'), 'pow': lambda z: getattr(z, '__pow__'),
"rpow": lambda z: getattr(z, '__rpow__'), 'rpow': lambda z: getattr(z, '__rpow__'),
"ipow": lambda z: getattr(z, '__ipow__'), 'ipow': lambda z: getattr(z, '__ipow__'),
"ne": lambda z: getattr(z, '__ne__'), 'ne': lambda z: getattr(z, '__ne__'),
"lt": lambda z: getattr(z, '__lt__'), 'lt': lambda z: getattr(z, '__lt__'),
"le": lambda z: getattr(z, '__le__'), 'le': lambda z: getattr(z, '__le__'),
"eq": lambda z: getattr(z, '__eq__'), 'eq': lambda z: getattr(z, '__eq__'),
"ge": lambda z: getattr(z, '__ge__'), 'ge': lambda z: getattr(z, '__ge__'),
"gt": lambda z: getattr(z, '__gt__'), 'gt': lambda z: getattr(z, '__gt__'),
"None": lambda z: lambda u: u} 'None': lambda z: lambda u: u}
if (cast & 1) != 0: if (cast & 1) != 0:
x = self.cast(x) x = self.cast(x)
...@@ -1069,7 +1064,7 @@ class point_space(space): ...@@ -1069,7 +1064,7 @@ class point_space(space):
def get_shape(self): def get_shape(self):
return (self.paradict['num'],) return (self.paradict['num'],)
def get_dim(self, split=False): def get_dim(self):
""" """
Computes the dimension of the space, i.e.\ the number of points. Computes the dimension of the space, i.e.\ the number of points.
...@@ -1084,10 +1079,7 @@ class point_space(space): ...@@ -1084,10 +1079,7 @@ class point_space(space):
dim : {int, numpy.ndarray} dim : {int, numpy.ndarray}
Dimension(s) of the space. Dimension(s) of the space.
""" """
if split: return np.prod(self.get_shape())
return self.get_shape()
else:
return np.prod(self.get_shape())
def get_dof(self, split=False): def get_dof(self, split=False):
""" """
...@@ -1100,11 +1092,15 @@ class point_space(space): ...@@ -1100,11 +1092,15 @@ class point_space(space):
dof : int dof : int
Number of degrees of freedom of the space. Number of degrees of freedom of the space.
""" """
pre_dof = self.get_dim(split=split) if split:
if issubclass(self.dtype.type, np.complexfloating): dof = self.get_shape()
return pre_dof * 2 if issubclass(self.dtype.type, np.complexfloating):
dof = tuple(np.array(dof)*2)
else: else:
return pre_dof dof = self.get_dim()
if issubclass(self.dtype.type, np.complexfloating):
dof = dof * 2
return dof
def get_vol(self, split=False): def get_vol(self, split=False):
if split: if split:
...@@ -1139,7 +1135,7 @@ class point_space(space): ...@@ -1139,7 +1135,7 @@ class point_space(space):
mol = self.cast(1, dtype=np.dtype('float')) mol = self.cast(1, dtype=np.dtype('float'))
return self.calc_weight(mol, power=1) return self.calc_weight(mol, power=1)
def cast(self, x, dtype=None, **kwargs): def cast(self, x=None, dtype=None, **kwargs):
if dtype is not None: if dtype is not None:
dtype = np.dtype(dtype) dtype = np.dtype(dtype)
...@@ -1231,7 +1227,7 @@ class point_space(space): ...@@ -1231,7 +1227,7 @@ class point_space(space):
if to_copy: if to_copy:
temp = x.copy_empty(dtype=dtype, temp = x.copy_empty(dtype=dtype,
distribution_strategy=self.datamodel) distribution_strategy=self.datamodel)
temp.set_local_data(x.get_local_data()) temp.inject((slice(None),), x, (slice(None),))
temp.hermitian = x.hermitian temp.hermitian = x.hermitian
x = temp x = temp
...@@ -1518,23 +1514,23 @@ class point_space(space): ...@@ -1518,23 +1514,23 @@ class point_space(space):
return self.cast(0) return self.cast(0)
if self.datamodel == 'np': if self.datamodel == 'np':
if arg[0] == "pm1": if arg['random'] == "pm1":
x = random.pm1(dtype=self.dtype, x = random.pm1(dtype=self.dtype,
shape=self.get_shape()) shape=self.get_shape())
elif arg[0] == "gau": elif arg['random'] == "gau":
x = random.gau(dtype=self.dtype, x = random.gau(dtype=self.dtype,
shape=self.get_shape(), shape=self.get_shape(),
mean=None, mean=arg['mean'],
dev=arg[2], std=arg['std'])
var=arg[3]) elif arg['random'] == "uni":
elif arg[0] == "uni":
x = random.uni(dtype=self.dtype, x = random.uni(dtype=self.dtype,
shape=self.get_shape(), shape=self.get_shape(),
vmin=arg[1], vmin=arg['vmin'],
vmax=arg[2]) vmax=arg['vmax'])
else: else:
raise KeyError(about._errors.cstring( raise KeyError(about._errors.cstring(
"ERROR: unsupported random key '" + str(arg[0]) + "'.")) "ERROR: unsupported random key '" +
str(arg['random']) + "'."))
return x return x
elif self.datamodel in POINT_DISTRIBUTION_STRATEGIES: elif self.datamodel in POINT_DISTRIBUTION_STRATEGIES:
...@@ -1543,46 +1539,34 @@ class point_space(space): ...@@ -1543,46 +1539,34 @@ class point_space(space):
dtype=self.dtype) dtype=self.dtype)
# Case 1: uniform distribution over {-1,+1}/{1,i,-1,-i} # Case 1: uniform distribution over {-1,+1}/{1,i,-1,-i}
if arg[0] == 'pm1': if arg['random'] == 'pm1':
sample.apply_generator(lambda s: random.pm1(dtype=self.dtype, sample.apply_generator(lambda s: random.pm1(dtype=self.dtype,
shape=s)) shape=s))
# Case 2: normal distribution with zero-mean and a given standard # Case 2: normal distribution with zero-mean and a given standard
# deviation or variance # deviation or variance
elif arg[0] == 'gau': elif arg['random'] == 'gau':
var = arg[3] std = arg['std']
if np.isscalar(var) or var is None: if np.isscalar(std) or std is None:
processed_var = var processed_std = std
else: else:
try: try:
processed_var = sample.distributor.\ processed_std = sample.distributor.\
extract_local_data(var) extract_local_data(std)
except(AttributeError): except(AttributeError):
processed_var = var processed_std = std
sample.apply_generator(lambda s: random.gau(dtype=self.dtype, sample.apply_generator(lambda s: random.gau(dtype=self.dtype,
shape=s, shape=s,
mean=arg[1], mean=arg['mean'],
dev=arg[2], std=processed_std))
var=processed_var))
# Case 3: uniform distribution # Case 3: uniform distribution
elif arg[0] == 'gau': elif arg['random'] == 'uni':
var = arg[3] sample.apply_generator(lambda s: random.uni(dtype=self.dtype,
if np.isscalar(var) == True or var is None:
processed_var = var
else:
try:
processed_var = sample.distributor.extract_local_data(
var)
except(AttributeError):
processed_var = var
sample.apply_generator(lambda s: random.gau(dtype=self.dtype,
shape=s, shape=s,
mean=arg[1], vmin=arg['vmin'],
dev=arg[2], vmax=arg['vmax']))
var=processed_var))
return sample return sample
else: else:
...@@ -2966,7 +2950,7 @@ class field(object): ...@@ -2966,7 +2950,7 @@ class field(object):
def nanmax(self, **kwargs): def nanmax(self, **kwargs):
return self._unary_helper(self.get_val(), op='nanmax', **kwargs) return self._unary_helper(self.get_val(), op='nanmax', **kwargs)
def med(self, **kwargs): def median(self, **kwargs):
""" """
Returns the median of the field values. Returns the median of the field values.
......
...@@ -122,13 +122,14 @@ class random(object): ...@@ -122,13 +122,14 @@ class random(object):
return None return None
if key == "pm1": if key == "pm1":
return [key] return {'random': key}
elif key == "gau": elif key == "gau":
mean = kwargs.get('mean', None) mean = kwargs.get('mean', None)
dev = kwargs.get('dev', None) std = kwargs.get('std', None)
var = kwargs.get('var', None) return {'random': key,
return [key, mean, dev, var] 'mean': mean,
'std': std}
elif key == "syn": elif key == "syn":
pindex = kwargs.get('pindex', None) pindex = kwargs.get('pindex', None)
...@@ -162,12 +163,20 @@ class random(object): ...@@ -162,12 +163,20 @@ class random(object):
size=size, size=size,
kindex=kindex) kindex=kindex)
return [key, spec, kpack, harmonic_domain, log, nbin, binbounds]