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']:
gc['lm2gl'] = False
LM_DISTRIBUTION_STRATEGIES = []
GL_DISTRIBUTION_STRATEGIES = []
HP_DISTRIBUTION_STRATEGIES = []
class lm_space(point_space):
......@@ -195,6 +197,17 @@ class lm_space(point_space):
self.paradict['lmax'] = x[0]
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):
return lm_space(lmax=self.paradict['lmax'],
mmax=self.paradict['mmax'],
......@@ -891,7 +904,7 @@ class gl_space(point_space):
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']):
"""
Sets the attributes for a gl_space class instance.
......@@ -978,8 +991,10 @@ class gl_space(point_space):
Since the :py:class:`gl_space` class only supports real-valued
fields, the number of degrees of freedom is the number of pixels.
"""
# dof = dim
return self.get_dim(split=split)
if split:
return self.get_shape()
else:
return self.get_dim()
def get_meta_volume(self, split=False):
"""
......@@ -1100,7 +1115,8 @@ class gl_space(point_space):
Supported distributions are:
- "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)
- "syn" (synthesizes from a given power spectrum)
- "uni" (uniform distribution over [vmin,vmax[)
......@@ -1111,7 +1127,8 @@ class gl_space(point_space):
var : float, *optional*
Variance, overriding `dev` if both are specified
(default: 1).
spec : {scalar, list, numpy.array, nifty.field, function}, *optional*
spec : {scalar, list, numpy.array, nifty.field, function},
*optional*
Power spectrum (default: 1).
codomain : nifty.lm_space, *optional*
A compatible codomain for power indexing (default: None).
......@@ -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))
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
fields, the number of degrees of freedom is the number of pixels.
"""
# dof = dim
return self.get_dim(split=split)
if split:
return self.get_shape()
else:
return self.get_dim()
def get_meta_volume(self, split=False):
"""
......
......@@ -159,10 +159,6 @@ import nifty.nifty_utilities as utilities
POINT_DISTRIBUTION_STRATEGIES = DISTRIBUTION_STRATEGIES['global']
#pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
class space(object):
"""
......@@ -220,7 +216,7 @@ class space(object):
have the same volume.
"""
def __init__(self, dtype=np.dtype('float'), datamodel='np'):
def __init__(self):
"""
Sets the attributes for a space class instance.
......@@ -236,11 +232,6 @@ class space(object):
None
"""
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
def para(self):
......@@ -830,11 +821,9 @@ class point_space(space):
# parse dtype
dtype = np.dtype(dtype)
if dtype not in [np.dtype('bool'),
np.dtype('int8'),
np.dtype('int16'),
np.dtype('int32'),
np.dtype('int64'),
np.dtype('float16'),
np.dtype('float32'),
np.dtype('float64'),
np.dtype('complex64'),
......@@ -946,62 +935,68 @@ class point_space(space):
return ind[0]
return ind
translation = {"pos": lambda y: getattr(y, '__pos__')(),
"neg": lambda y: getattr(y, '__neg__')(),
"abs": lambda y: getattr(y, '__abs__')(),
"real": lambda y: getattr(y, 'real'),
"imag": lambda y: getattr(y, 'imag'),
"nanmin": np.nanmin,
"amin": np.amin,
"nanmax": np.nanmax,
"amax": 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,
"sum": np.sum,
"prod": np.prod,
"unique": np.unique,
"copy": np.copy,
"isnan": np.isnan,
"isinf": np.isinf,
"isfinite": np.isfinite,
"nan_to_num": np.nan_to_num,
"None": lambda y: y}
translation = {'pos': lambda y: getattr(y, '__pos__')(),
'neg': lambda y: getattr(y, '__neg__')(),
'abs': lambda y: getattr(y, '__abs__')(),
'real': lambda y: getattr(y, 'real'),
'imag': lambda y: getattr(y, 'imag'),
'nanmin': np.nanmin,
'amin': np.amin,
'nanmax': np.nanmax,
'amax': np.amax,
'median': 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,
'sum': np.sum,
'prod': np.prod,
'unique': np.unique,
'copy': np.copy,
'copy_empty': np.empty_like,
'isnan': np.isnan,
'isinf': np.isinf,
'isfinite': np.isfinite,
'nan_to_num': np.nan_to_num,
'all': np.all,
'any': np.any,
'None': lambda y: y}
elif self.datamodel in POINT_DISTRIBUTION_STRATEGIES:
translation = {"pos": lambda y: getattr(y, '__pos__')(),
"neg": lambda y: getattr(y, '__neg__')(),
"abs": lambda y: getattr(y, '__abs__')(),
"real": lambda y: getattr(y, 'real'),
"imag": lambda y: getattr(y, 'imag'),
"nanmin": lambda y: getattr(y, 'nanmin')(),
"amin": lambda y: getattr(y, 'amin')(),
"nanmax": lambda y: getattr(y, 'nanmax')(),
"amax": lambda y: getattr(y, 'amax')(),
"median": lambda y: getattr(y, 'median')(),
"mean": lambda y: getattr(y, 'mean')(),
"std": lambda y: getattr(y, 'std')(),
"var": lambda y: getattr(y, 'var')(),
"argmin": lambda y: getattr(y, 'argmin_nonflat')(),
"argmin_flat": lambda y: getattr(y, 'argmin')(),
"argmax": lambda y: getattr(y, 'argmax_nonflat')(),
"argmax_flat": lambda y: getattr(y, 'argmax')(),
"conjugate": lambda y: getattr(y, 'conjugate')(),
"sum": lambda y: getattr(y, 'sum')(),
"prod": lambda y: getattr(y, 'prod')(),
"unique": lambda y: getattr(y, 'unique')(),
"copy": lambda y: getattr(y, 'copy')(),
"isnan": lambda y: getattr(y, 'isnan')(),
"isinf": lambda y: getattr(y, 'isinf')(),
"isfinite": lambda y: getattr(y, 'isfinite')(),
"nan_to_num": lambda y: getattr(y, 'nan_to_num')(),
"None": lambda y: y}
translation = {'pos': lambda y: getattr(y, '__pos__')(),
'neg': lambda y: getattr(y, '__neg__')(),
'abs': lambda y: getattr(y, '__abs__')(),
'real': lambda y: getattr(y, 'real'),
'imag': lambda y: getattr(y, 'imag'),
'nanmin': lambda y: getattr(y, 'nanmin')(),
'amin': lambda y: getattr(y, 'amin')(),
'nanmax': lambda y: getattr(y, 'nanmax')(),
'amax': lambda y: getattr(y, 'amax')(),
'median': lambda y: getattr(y, 'median')(),
'mean': lambda y: getattr(y, 'mean')(),
'std': lambda y: getattr(y, 'std')(),
'var': lambda y: getattr(y, 'var')(),
'argmin': lambda y: getattr(y, 'argmin_nonflat')(),
'argmin_flat': lambda y: getattr(y, 'argmin')(),
'argmax': lambda y: getattr(y, 'argmax_nonflat')(),
'argmax_flat': lambda y: getattr(y, 'argmax')(),
'conjugate': lambda y: getattr(y, 'conjugate')(),
'sum': lambda y: getattr(y, 'sum')(),
'prod': lambda y: getattr(y, 'prod')(),
'unique': lambda y: getattr(y, 'unique')(),
'copy': lambda y: getattr(y, 'copy')(),
'copy_empty': lambda y: getattr(y, 'copy_empty')(),
'isnan': lambda y: getattr(y, 'isnan')(),
'isinf': lambda y: getattr(y, 'isinf')(),
'isfinite': lambda y: getattr(y, 'isfinite')(),
'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:
raise NotImplementedError(about._errors.cstring(
"ERROR: function is not implemented for given datamodel."))
......@@ -1010,28 +1005,28 @@ class point_space(space):
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__'),
"ne": lambda z: getattr(z, '__ne__'),
"lt": lambda z: getattr(z, '__lt__'),
"le": lambda z: getattr(z, '__le__'),
"eq": lambda z: getattr(z, '__eq__'),
"ge": lambda z: getattr(z, '__ge__'),
"gt": lambda z: getattr(z, '__gt__'),
"None": lambda z: lambda u: u}
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__'),
'ne': lambda z: getattr(z, '__ne__'),
'lt': lambda z: getattr(z, '__lt__'),
'le': lambda z: getattr(z, '__le__'),
'eq': lambda z: getattr(z, '__eq__'),
'ge': lambda z: getattr(z, '__ge__'),
'gt': lambda z: getattr(z, '__gt__'),
'None': lambda z: lambda u: u}
if (cast & 1) != 0:
x = self.cast(x)
......@@ -1069,7 +1064,7 @@ class point_space(space):
def get_shape(self):
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.
......@@ -1084,9 +1079,6 @@ class point_space(space):
dim : {int, numpy.ndarray}
Dimension(s) of the space.
"""
if split:
return self.get_shape()
else:
return np.prod(self.get_shape())
def get_dof(self, split=False):
......@@ -1100,11 +1092,15 @@ class point_space(space):
dof : int
Number of degrees of freedom of the space.
"""
pre_dof = self.get_dim(split=split)
if split:
dof = self.get_shape()
if issubclass(self.dtype.type, np.complexfloating):
return pre_dof * 2
dof = tuple(np.array(dof)*2)
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):
if split:
......@@ -1139,7 +1135,7 @@ class point_space(space):
mol = self.cast(1, dtype=np.dtype('float'))
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:
dtype = np.dtype(dtype)
......@@ -1231,7 +1227,7 @@ class point_space(space):
if to_copy:
temp = x.copy_empty(dtype=dtype,
distribution_strategy=self.datamodel)
temp.set_local_data(x.get_local_data())
temp.inject((slice(None),), x, (slice(None),))
temp.hermitian = x.hermitian
x = temp
......@@ -1518,23 +1514,23 @@ class point_space(space):
return self.cast(0)
if self.datamodel == 'np':
if arg[0] == "pm1":
if arg['random'] == "pm1":
x = random.pm1(dtype=self.dtype,
shape=self.get_shape())
elif arg[0] == "gau":
elif arg['random'] == "gau":
x = random.gau(dtype=self.dtype,
shape=self.get_shape(),
mean=None,
dev=arg[2],
var=arg[3])
elif arg[0] == "uni":
mean=arg['mean'],
std=arg['std'])
elif arg['random'] == "uni":
x = random.uni(dtype=self.dtype,
shape=self.get_shape(),
vmin=arg[1],
vmax=arg[2])
vmin=arg['vmin'],
vmax=arg['vmax'])
else:
raise KeyError(about._errors.cstring(
"ERROR: unsupported random key '" + str(arg[0]) + "'."))
"ERROR: unsupported random key '" +
str(arg['random']) + "'."))
return x
elif self.datamodel in POINT_DISTRIBUTION_STRATEGIES:
......@@ -1543,46 +1539,34 @@ class point_space(space):
dtype=self.dtype)
# 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,
shape=s))
# Case 2: normal distribution with zero-mean and a given standard
# deviation or variance
elif arg[0] == 'gau':
var = arg[3]
if np.isscalar(var) or var is None:
processed_var = var
elif arg['random'] == 'gau':
std = arg['std']
if np.isscalar(std) or std is None:
processed_std = std
else:
try:
processed_var = sample.distributor.\
extract_local_data(var)
processed_std = sample.distributor.\
extract_local_data(std)
except(AttributeError):
processed_var = var
processed_std = std
sample.apply_generator(lambda s: random.gau(dtype=self.dtype,
shape=s,
mean=arg[1],
dev=arg[2],
var=processed_var))
mean=arg['mean'],
std=processed_std))
# Case 3: uniform distribution
elif arg[0] == 'gau':
var = arg[3]
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,
elif arg['random'] == 'uni':
sample.apply_generator(lambda s: random.uni(dtype=self.dtype,
shape=s,
mean=arg[1],
dev=arg[2],
var=processed_var))
vmin=arg['vmin'],
vmax=arg['vmax']))
return sample
else:
......@@ -2966,7 +2950,7 @@ class field(object):
def nanmax(self, **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.
......
......@@ -122,13 +122,14 @@ class random(object):
return None
if key == "pm1":
return [key]
return {'random': key}
elif key == "gau":
mean = kwargs.get('mean', None)
dev = kwargs.get('dev', None)
var = kwargs.get('var', None)
return [key, mean, dev, var]
std = kwargs.get('std', None)
return {'random': key,
'mean': mean,
'std': std}
elif key == "syn":
pindex = kwargs.get('pindex', None)
......@@ -162,12 +163,20 @@ class random(object):
size=size,
kindex=kindex)
return [key, spec, kpack, harmonic_domain, log, nbin, binbounds]
return {'random': key,
'spec': spec,
'kpack': kpack,
'harmonic_domain': harmonic_domain,
'log': log,
'nbin': nbin,
'binbounds': binbounds}
elif key == "uni":
vmin = domain.dtype(kwargs.get('vmin', 0))
vmax = domain.dtype(kwargs.get('vmax', 1))
return [key, vmin, vmax]
vmin = domain.dtype.type(kwargs.get('vmin', 0))
vmax = domain.dtype.type(kwargs.get('vmax', 1))
return {'random': key,
'vmin': vmin,
'vmax': vmax}
else:
raise KeyError(about._errors.cstring(
......@@ -196,7 +205,7 @@ class random(object):
"""
size = np.prod(shape, axis=0, dtype=np.dtype('int'), out=None)
if(issubclass(dtype.type, np.complexfloating)):
if issubclass(dtype.type, np.complexfloating):
x = np.array([1 + 0j, 0 + 1j, -1 + 0j, 0 - 1j],
dtype=dtype)[np.random.randint(4,
high=None,
......@@ -204,12 +213,12 @@ class random(object):
else:
x = 2 * np.random.randint(2, high=None, size=size) - 1
return x.astype(dtype).reshape(shape, order='C')
return x.astype(dtype).reshape(shape)
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@staticmethod
def gau(dtype=np.dtype('float64'), shape=1, mean=None, dev=None, var=None):
def gau(dtype=np.dtype('float64'), shape=(1,), mean=None, std=None):
"""
Generates random field values according to a normal distribution.
......@@ -239,44 +248,36 @@ class random(object):
`shape`.
"""
size = np.prod(shape, axis=0, dtype=np.dtype('int'), out=None)
size = np.prod(shape)
if(issubclass(dtype.type, np.complexfloating)):
x = np.empty(size, dtype=dtype, order='C')
if issubclass(dtype.type, np.complexfloating):
x = np.empty(size, dtype=dtype)
x.real = np.random.normal(loc=0, scale=np.sqrt(0.5), size=size)
x.imag = np.random.normal(loc=0, scale=np.sqrt(0.5), size=size)
else:
x = np.random.normal(loc=0, scale=1, size=size)
if(var is not None):
if(np.size(var) == 1):
x *= np.sqrt(np.abs(var))
elif(np.size(var) == size):
x *= np.sqrt(np.absolute(var).flatten(order='C'))
else:
raise ValueError(about._errors.cstring(
"ERROR: dimension mismatch ( " + str(np.size(var)) +
" <> " + str(size) + " )."))
elif(dev is not None):
if(np.size(dev) == 1):
x *= np.abs(dev)
elif(np.size(dev) == size):
x *= np.absolute(dev).flatten(order='C')
if std is not None:
if np.size(std) == 1:
x *= np.abs(std)
elif np.size(std) == size:
x *= np.absolute(std).flatten()
else:
raise ValueError(about._errors.cstring(
"ERROR: dimension mismatch ( " + str(np.size(dev)) +
"ERROR: dimension mismatch ( " + str(np.size(std)) +
" <> " + str(size) + " )."))
if(mean is not None):
if(np.size(mean) == 1):
if mean is not None:
if np.size(mean) == 1:
x += mean
elif(np.size(mean) == size):
elif np.size(mean) == size:
x += np.array(mean).flatten(order='C')
else:
raise ValueError(about._errors.cstring(
"ERROR: dimension mismatch ( " + str(np.size(mean)) +
" <> " + str(size) + " )."))
return x.astype(dtype).reshape(shape, order='C')
return x.astype(dtype).reshape(shape)
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......
......@@ -255,8 +255,8 @@ class rg_space(point_space):
casted_x = super(rg_space, self)._cast_to_d2o(x=x,
dtype=dtype,
**kwargs)
if hermitianize and self.paradict['complexity'] == 1 and \
not casted_x.hermitian:
if x is not None and hermitianize and \
self.paradict['complexity'] == 1 and not casted_x.hermitian:
about.warnings.cflush(
"WARNING: Data gets hermitianized. This operation is " +
"extremely expensive\n")
......@@ -268,7 +268,7 @@ class rg_space(point_space):