Commit 9c050381 authored by Martin Reinecke's avatar Martin Reinecke
Browse files

merge NIFTy_6

parents 73c8b1a9 a9fea605
Pipeline #75246 passed with stages
in 8 minutes and 26 seconds
...@@ -43,6 +43,13 @@ test_serial: ...@@ -43,6 +43,13 @@ test_serial:
- > - >
grep TOTAL coverage.txt | awk '{ print "TOTAL: "$4; }' grep TOTAL coverage.txt | awk '{ print "TOTAL: "$4; }'
test_mpi:
stage: test
variables:
OMPI_MCA_btl_vader_single_copy_mechanism: none
script:
- mpiexec -n 2 --bind-to none pytest-3 -q test/test_mpi
pages: pages:
stage: release stage: release
script: script:
...@@ -61,7 +68,7 @@ before_script: ...@@ -61,7 +68,7 @@ before_script:
run_ipynb: run_ipynb:
stage: demo_runs stage: demo_runs
script: script:
- jupyter nbconvert --execute --ExecutePreprocessor.timeout=None demos/Wiener_Filter.ipynb - jupyter nbconvert --execute --ExecutePreprocessor.timeout=None demos/getting_started_0.ipynb
run_getting_started_1: run_getting_started_1:
stage: demo_runs stage: demo_runs
......
Changes since NIFTy 5: Changes since NIFTy 5:
Minimum Python version increased to 3.6
=======================================
New operators
=============
In addition to the below changes, the following operators were introduced:
* UniformOperator: Transforms a Gaussian into a uniform distribution
* VariableCovarianceGaussianEnergy: Energy operator for inferring covariances
* MultiLinearEinsum: Multi-linear version of numpy's einsum with derivates
* LinearEinsum: Linear version of numpy's einsum with one free field
* PartialConjugate: Conjugates parts of a multi-field
* SliceOperator: Geometry preserving mask operator
* SplitOperator: Splits a single field into a multi-field
FFT convention adjusted
=======================
When going to harmonic space, NIFTy's FFT operator now uses a minus sign in the
exponent (and, consequently, a plus sign on the adjoint transform). This
convention is consistent with almost all other numerical FFT libraries.
Interface change in EndomorphicOperator.draw_sample()
=====================================================
Both complex-valued and real-valued Gaussian probability distributions have
Hermitian and positive endomorphisms as covariance. Just by looking at an
endomorphic operator itself it is not clear whether it is viewed as covariance
for real or complex Gaussians when a sample of the respective distribution shall
be drawn. Therefore, we introduce the method `draw_sample_with_dtype()` which
needs to be given the data type of the probability distribution. This function
is implemented for all operators which actually draw random numbers
(`DiagonalOperator` and `ScalingOperator`). The class `SamplingDtypeSetter` acts
as a wrapper for this kind of operators in order to fix the data type of the
distribution. Samples from these operators can be drawn with `.draw_sample()`.
In order to dive into those subtleties I suggest running the following code and
playing around with the dtypes.
```
import nifty6 as ift
import numpy as np
dom = ift.UnstructuredDomain(5)
dtype = [np.float64, np.complex128][1]
invcov = ift.ScalingOperator(dom, 3)
e = ift.GaussianEnergy(mean=ift.from_random(dom, 'normal', dtype=dtype),
inverse_covariance=invcov)
pos = ift.from_random(dom, 'normal', dtype=np.complex128)
lin = e(ift.Linearization.make_var(pos, want_metric=True))
met = lin.metric
print(met)
print(met.draw_sample())
```
MPI parallelisation over samples in MetricGaussianKL MPI parallelisation over samples in MetricGaussianKL
==================================================== ====================================================
...@@ -15,6 +71,13 @@ the generation of reproducible random numbers in the presence of MPI parallelism ...@@ -15,6 +71,13 @@ the generation of reproducible random numbers in the presence of MPI parallelism
and leads to cleaner code overall. Please see the documentation of and leads to cleaner code overall. Please see the documentation of
`nifty6.random` for details. `nifty6.random` for details.
Interface Change for from_random and OuterProduct
=================================================
The sugar.from_random, Field.from_random, MultiField.from_random now take domain
as the first argument and default to 'normal' for the second argument.
Likewise OuterProduct takes domain as the first argument and a field as the second.
Interface Change for non-linear Operators Interface Change for non-linear Operators
========================================= =========================================
......
...@@ -45,7 +45,7 @@ Installation ...@@ -45,7 +45,7 @@ Installation
### Requirements ### Requirements
- [Python 3](https://www.python.org/) (3.5.x or later) - [Python 3](https://www.python.org/) (3.6.x or later)
- [SciPy](https://www.scipy.org/) - [SciPy](https://www.scipy.org/)
Optional dependencies: Optional dependencies:
......
...@@ -43,7 +43,7 @@ if __name__ == '__main__': ...@@ -43,7 +43,7 @@ if __name__ == '__main__':
harmonic_space = position_space.get_default_codomain() harmonic_space = position_space.get_default_codomain()
HT = ift.HarmonicTransformOperator(harmonic_space, position_space) HT = ift.HarmonicTransformOperator(harmonic_space, position_space)
position = ift.from_random('normal', harmonic_space) position = ift.from_random(harmonic_space, 'normal')
# Define power spectrum and amplitudes # Define power spectrum and amplitudes
def sqrtpspec(k): def sqrtpspec(k):
...@@ -58,13 +58,13 @@ if __name__ == '__main__': ...@@ -58,13 +58,13 @@ if __name__ == '__main__':
# Generate mock data # Generate mock data
p = R(sky) p = R(sky)
mock_position = ift.from_random('normal', harmonic_space) mock_position = ift.from_random(harmonic_space, 'normal')
tmp = p(mock_position).val.astype(np.float64) tmp = p(mock_position).val.astype(np.float64)
data = ift.random.current_rng().binomial(1, tmp) data = ift.random.current_rng().binomial(1, tmp)
data = ift.Field.from_raw(R.target, data) data = ift.Field.from_raw(R.target, data)
# Compute likelihood and Hamiltonian # Compute likelihood and Hamiltonian
position = ift.from_random('normal', harmonic_space) position = ift.from_random(harmonic_space, 'normal')
likelihood = ift.BernoulliEnergy(data) @ p likelihood = ift.BernoulliEnergy(data) @ p
ic_newton = ift.DeltaEnergyController( ic_newton = ift.DeltaEnergyController(
name='Newton', iteration_limit=100, tol_rel_deltaE=1e-8) name='Newton', iteration_limit=100, tol_rel_deltaE=1e-8)
......
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
"R = HT #*ift.create_harmonic_smoothing_operator((h_space,), 0, 0.02)\n", "R = HT #*ift.create_harmonic_smoothing_operator((h_space,), 0, 0.02)\n",
"\n", "\n",
"# Fields and data\n", "# Fields and data\n",
"sh = Sh.draw_sample()\n", "sh = Sh.draw_sample_with_dtype(dtype=np.float64)\n",
"noiseless_data=R(sh)\n", "noiseless_data=R(sh)\n",
"noise_amplitude = np.sqrt(0.2)\n", "noise_amplitude = np.sqrt(0.2)\n",
"N = ift.ScalingOperator(s_space, noise_amplitude**2)\n", "N = ift.ScalingOperator(s_space, noise_amplitude**2)\n",
...@@ -394,7 +394,7 @@ ...@@ -394,7 +394,7 @@
"# R is defined below\n", "# R is defined below\n",
"\n", "\n",
"# Fields\n", "# Fields\n",
"sh = Sh.draw_sample()\n", "sh = Sh.draw_sample_with_dtype(dtype=np.float64)\n",
"s = HT(sh)\n", "s = HT(sh)\n",
"n = ift.Field.from_random(domain=s_space, random_type='normal',\n", "n = ift.Field.from_random(domain=s_space, random_type='normal',\n",
" std=noise_amplitude, mean=0)" " std=noise_amplitude, mean=0)"
...@@ -471,7 +471,7 @@ ...@@ -471,7 +471,7 @@
}, },
"outputs": [], "outputs": [],
"source": [ "source": [
"m_mean, m_var = ift.probe_with_posterior_samples(curv, HT, 200)" "m_mean, m_var = ift.probe_with_posterior_samples(curv, HT, 200, np.float64)"
] ]
}, },
{ {
...@@ -571,7 +571,7 @@ ...@@ -571,7 +571,7 @@
"N = ift.ScalingOperator(s_space, sigma2)\n", "N = ift.ScalingOperator(s_space, sigma2)\n",
"\n", "\n",
"# Fields and data\n", "# Fields and data\n",
"sh = Sh.draw_sample()\n", "sh = Sh.draw_sample_with_dtype(dtype=np.float64)\n",
"n = ift.Field.from_random(domain=s_space, random_type='normal',\n", "n = ift.Field.from_random(domain=s_space, random_type='normal',\n",
" std=np.sqrt(sigma2), mean=0)\n", " std=np.sqrt(sigma2), mean=0)\n",
"\n", "\n",
...@@ -598,7 +598,7 @@ ...@@ -598,7 +598,7 @@
"m = D(j)\n", "m = D(j)\n",
"\n", "\n",
"# Uncertainty\n", "# Uncertainty\n",
"m_mean, m_var = ift.probe_with_posterior_samples(curv, HT, 20)\n", "m_mean, m_var = ift.probe_with_posterior_samples(curv, HT, 20, np.float64)\n",
"\n", "\n",
"# Get data\n", "# Get data\n",
"s_data = HT(sh).val\n", "s_data = HT(sh).val\n",
...@@ -709,8 +709,15 @@ ...@@ -709,8 +709,15 @@
"\n", "\n",
"https://gitlab.mpcdf.mpg.de/ift/NIFTy\n", "https://gitlab.mpcdf.mpg.de/ift/NIFTy\n",
"\n", "\n",
"NIFTy v5 **more or less stable!**" "NIFTy v6 **more or less stable!**"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {
...@@ -730,7 +737,7 @@ ...@@ -730,7 +737,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.7.5" "version": "3.8.2"
} }
}, },
"nbformat": 4, "nbformat": 4,
......
...@@ -40,7 +40,7 @@ def make_checkerboard_mask(position_space): ...@@ -40,7 +40,7 @@ def make_checkerboard_mask(position_space):
def make_random_mask(): def make_random_mask():
# Random mask for spherical mode # Random mask for spherical mode
mask = ift.from_random('pm1', position_space) mask = ift.from_random(position_space, 'pm1')
mask = (mask + 1)/2 mask = (mask + 1)/2
return mask.val return mask.val
...@@ -114,8 +114,8 @@ if __name__ == '__main__': ...@@ -114,8 +114,8 @@ if __name__ == '__main__':
N = ift.ScalingOperator(data_space, noise) N = ift.ScalingOperator(data_space, noise)
# Create mock data # Create mock data
MOCK_SIGNAL = S.draw_sample() MOCK_SIGNAL = S.draw_sample_with_dtype(dtype=np.float64)
MOCK_NOISE = N.draw_sample() MOCK_NOISE = N.draw_sample_with_dtype(dtype=np.float64)
data = R(MOCK_SIGNAL) + MOCK_NOISE data = R(MOCK_SIGNAL) + MOCK_NOISE
# Build inverse propagator D and information source j # Build inverse propagator D and information source j
......
...@@ -90,7 +90,7 @@ if __name__ == '__main__': ...@@ -90,7 +90,7 @@ if __name__ == '__main__':
# Generate mock data and define likelihood operator # Generate mock data and define likelihood operator
d_space = R.target[0] d_space = R.target[0]
lamb = R(sky) lamb = R(sky)
mock_position = ift.from_random('normal', domain) mock_position = ift.from_random(domain, 'normal')
data = lamb(mock_position) data = lamb(mock_position)
data = ift.random.current_rng().poisson(data.val.astype(np.float64)) data = ift.random.current_rng().poisson(data.val.astype(np.float64))
data = ift.Field.from_raw(d_space, data) data = ift.Field.from_raw(d_space, data)
...@@ -103,7 +103,7 @@ if __name__ == '__main__': ...@@ -103,7 +103,7 @@ if __name__ == '__main__':
# Compute MAP solution by minimizing the information Hamiltonian # Compute MAP solution by minimizing the information Hamiltonian
H = ift.StandardHamiltonian(likelihood) H = ift.StandardHamiltonian(likelihood)
initial_position = ift.from_random('normal', domain) initial_position = ift.from_random(domain, 'normal')
H = ift.EnergyAdapter(initial_position, H, want_metric=True) H = ift.EnergyAdapter(initial_position, H, want_metric=True)
H, convergence = minimizer(H) H, convergence = minimizer(H)
......
...@@ -55,9 +55,32 @@ if __name__ == '__main__': ...@@ -55,9 +55,32 @@ if __name__ == '__main__':
position_space = ift.RGSpace([128, 128]) position_space = ift.RGSpace([128, 128])
cfmaker = ift.CorrelatedFieldMaker.make(1e-3, 1e-6, '') cfmaker = ift.CorrelatedFieldMaker.make(
cfmaker.add_fluctuations(position_space, offset_mean = 0.0, # 0.
1., 1e-2, 1, .5, .1, .5, -3, 0.5, '') offset_std_mean = 1e-3, # 1e-3
offset_std_std = 1e-6, # 1e-6
prefix = '')
fluctuations_dict = {
# Amplitude of the fluctuations
'fluctuations_mean': 2.0, # 1.0
'fluctuations_stddev': 1.0, # 1e-2
# Smooth variation speed
'flexibility_mean': 2.5, # 1.0
'flexibility_stddev': 1.0, # 0.5
# How strong the ragged component of the spectrum is
# (Ratio of Wiener process and integrated Wiener process ?)
'asperity_mean': 0.5, # 0.1
'asperity_stddev': 0.5, # 0.5
# Slope of linear spectrum component
'loglogavgslope_mean': -2.0, # -3.0
'loglogavgslope_stddev': 0.5 # 0.5
}
cfmaker.add_fluctuations(position_space, **fluctuations_dict)
correlated_field = cfmaker.finalize() correlated_field = cfmaker.finalize()
A = cfmaker.amplitude A = cfmaker.amplitude
...@@ -75,8 +98,8 @@ if __name__ == '__main__': ...@@ -75,8 +98,8 @@ if __name__ == '__main__':
N = ift.ScalingOperator(data_space, noise) N = ift.ScalingOperator(data_space, noise)
# Generate mock signal and data # Generate mock signal and data
mock_position = ift.from_random('normal', signal_response.domain) mock_position = ift.from_random(signal_response.domain, 'normal')
data = signal_response(mock_position) + N.draw_sample() data = signal_response(mock_position) + N.draw_sample_with_dtype(dtype=np.float64)
# Minimization parameters # Minimization parameters
ic_sampling = ift.AbsDeltaEnergyController( ic_sampling = ift.AbsDeltaEnergyController(
......
...@@ -73,7 +73,7 @@ if __name__ == '__main__': ...@@ -73,7 +73,7 @@ if __name__ == '__main__':
sp2 = ift.RGSpace(npix2) sp2 = ift.RGSpace(npix2)
# Set up signal model # Set up signal model
cfmaker = ift.CorrelatedFieldMaker.make(1e-2, 1e-6, '') cfmaker = ift.CorrelatedFieldMaker.make(0., 1e-2, 1e-6, '')
cfmaker.add_fluctuations(sp1, 0.1, 1e-2, 1, .1, .01, .5, -2, 1., 'amp1') cfmaker.add_fluctuations(sp1, 0.1, 1e-2, 1, .1, .01, .5, -2, 1., 'amp1')
cfmaker.add_fluctuations(sp2, 0.1, 1e-2, 1, .1, .01, .5, cfmaker.add_fluctuations(sp2, 0.1, 1e-2, 1, .1, .01, .5,
-1.5, .5, 'amp2') -1.5, .5, 'amp2')
...@@ -97,8 +97,8 @@ if __name__ == '__main__': ...@@ -97,8 +97,8 @@ if __name__ == '__main__':
N = ift.ScalingOperator(data_space, noise) N = ift.ScalingOperator(data_space, noise)
# Generate mock signal and data # Generate mock signal and data
mock_position = ift.from_random('normal', signal_response.domain) mock_position = ift.from_random(signal_response.domain, 'normal')
data = signal_response(mock_position) + N.draw_sample() data = signal_response(mock_position) + N.draw_sample_with_dtype(dtype=np.float64)
plot = ift.Plot() plot = ift.Plot()
plot.add(signal(mock_position), title='Ground Truth') plot.add(signal(mock_position), title='Ground Truth')
...@@ -114,7 +114,9 @@ if __name__ == '__main__': ...@@ -114,7 +114,9 @@ if __name__ == '__main__':
ic_newton = ift.AbsDeltaEnergyController(name='Newton', ic_newton = ift.AbsDeltaEnergyController(name='Newton',
deltaE=0.01, deltaE=0.01,
iteration_limit=35) iteration_limit=35)
minimizer = ift.NewtonCG(ic_newton) ic_sampling.enable_logging()
ic_newton.enable_logging()
minimizer = ift.NewtonCG(ic_newton, activate_logging=True)
## number of samples used to estimate the KL ## number of samples used to estimate the KL
N_samples = 20 N_samples = 20
...@@ -143,10 +145,15 @@ if __name__ == '__main__': ...@@ -143,10 +145,15 @@ if __name__ == '__main__':
plot.add([A2.force(KL.position), plot.add([A2.force(KL.position),
A2.force(mock_position)], A2.force(mock_position)],
title="power2") title="power2")
plot.output(nx=2, plot.add((ic_newton.history, ic_sampling.history,
minimizer.inversion_history),
label=['KL', 'Sampling', 'Newton inversion'],
title='Cumulative energies', s=[None, None, 1],
alpha=[None, 0.2, None])
plot.output(nx=3,
ny=2, ny=2,
ysize=10, ysize=10,
xsize=10, xsize=15,
name=filename.format("loop_{:02d}".format(i))) name=filename.format("loop_{:02d}".format(i)))
# Done, draw posterior samples # Done, draw posterior samples
......
...@@ -25,7 +25,8 @@ from .operators.adder import Adder ...@@ -25,7 +25,8 @@ from .operators.adder import Adder
from .operators.diagonal_operator import DiagonalOperator from .operators.diagonal_operator import DiagonalOperator
from .operators.distributors import DOFDistributor, PowerDistributor from .operators.distributors import DOFDistributor, PowerDistributor
from .operators.domain_tuple_field_inserter import DomainTupleFieldInserter from .operators.domain_tuple_field_inserter import DomainTupleFieldInserter
from .operators.contraction_operator import ContractionOperator from .operators.einsum import LinearEinsum, MultiLinearEinsum
from .operators.contraction_operator import ContractionOperator, IntegrationOperator
from .operators.linear_interpolation import LinearInterpolator from .operators.linear_interpolation import LinearInterpolator
from .operators.endomorphic_operator import EndomorphicOperator from .operators.endomorphic_operator import EndomorphicOperator
from .operators.harmonic_operators import ( from .operators.harmonic_operators import (
...@@ -35,15 +36,16 @@ from .operators.field_zero_padder import FieldZeroPadder ...@@ -35,15 +36,16 @@ from .operators.field_zero_padder import FieldZeroPadder
from .operators.inversion_enabler import InversionEnabler from .operators.inversion_enabler import InversionEnabler
from .operators.mask_operator import MaskOperator from .operators.mask_operator import MaskOperator
from .operators.regridding_operator import RegriddingOperator from .operators.regridding_operator import RegriddingOperator
from .operators.sampling_enabler import SamplingEnabler from .operators.sampling_enabler import SamplingEnabler, SamplingDtypeSetter
from .operators.sandwich_operator import SandwichOperator from .operators.sandwich_operator import SandwichOperator
from .operators.scaling_operator import ScalingOperator from .operators.scaling_operator import ScalingOperator
from .operators.selection_operators import SliceOperator, SplitOperator
from .operators.block_diagonal_operator import BlockDiagonalOperator from .operators.block_diagonal_operator import BlockDiagonalOperator
from .operators.outer_product_operator import OuterProduct from .operators.outer_product_operator import OuterProduct
from .operators.simple_linear_operators import ( from .operators.simple_linear_operators import (
VdotOperator, ConjugationOperator, Realizer, VdotOperator, ConjugationOperator, Realizer, FieldAdapter, ducktape,
FieldAdapter, ducktape, GeometryRemover, NullOperator, GeometryRemover, NullOperator, PartialExtractor)
MatrixProductOperator, PartialExtractor) from .operators.matrix_product_operator import MatrixProductOperator
from .operators.value_inserter import ValueInserter from .operators.value_inserter import ValueInserter
from .operators.energy_operators import ( from .operators.energy_operators import (
EnergyOperator, GaussianEnergy, PoissonianEnergy, InverseGammaLikelihood, EnergyOperator, GaussianEnergy, PoissonianEnergy, InverseGammaLikelihood,
......
...@@ -142,8 +142,7 @@ class RGSpace(StructuredDomain): ...@@ -142,8 +142,7 @@ class RGSpace(StructuredDomain):
@staticmethod @staticmethod
def _kernel(x, sigma): def _kernel(x, sigma):
from ..sugar import exp return (x*x * (-2.*np.pi*np.pi*sigma*sigma)).ptw("exp")
return exp(x*x * (-2.*np.pi*np.pi*sigma*sigma))
def get_fft_smoothing_kernel_function(self, sigma): def get_fft_smoothing_kernel_function(self, sigma):
if (not self.harmonic): if (not self.harmonic):
......
...@@ -42,8 +42,8 @@ def _adjoint_implementation(op, domain_dtype, target_dtype, atol, rtol, ...@@ -42,8 +42,8 @@ def _adjoint_implementation(op, domain_dtype, target_dtype, atol, rtol,
needed_cap = op.TIMES | op.ADJOINT_TIMES needed_cap = op.TIMES | op.ADJOINT_TIMES
if (op.capability & needed_cap) != needed_cap: if (op.capability & needed_cap) != needed_cap:
return return
f1 = from_random("normal", op.domain, dtype=domain_dtype) f1 = from_random(op.domain, "normal", dtype=domain_dtype)
f2 = from_random("normal", op.target, dtype=target_dtype) f2 = from_random(op.target, "normal", dtype=target_dtype)
res1 = f1.s_vdot(op.adjoint_times(f2)) res1 = f1.s_vdot(op.adjoint_times(f2))
res2 = op.times(f1).s_vdot(f2) res2 = op.times(f1).s_vdot(f2)
if only_r_linear: if only_r_linear:
...@@ -55,11 +55,11 @@ def _inverse_implementation(op, domain_dtype, target_dtype, atol, rtol): ...@@ -55,11 +55,11 @@ def _inverse_implementation(op, domain_dtype, target_dtype, atol, rtol):
needed_cap = op.TIMES | op.INVERSE_TIMES needed_cap = op.TIMES | op.INVERSE_TIMES
if (op.capability & needed_cap) != needed_cap: if (op.capability & needed_cap) != needed_cap:
return return
foo = from_random("normal", op.target, dtype=target_dtype) foo = from_random(op.target, "normal", dtype=target_dtype)
res = op(op.inverse_times(foo)) res = op(op.inverse_times(foo))
assert_allclose(res, foo, atol=atol, rtol=rtol) assert_allclose(res, foo, atol=atol, rtol=rtol)
foo = from_random("normal", op.domain, dtype=domain_dtype) foo = from_random(op.domain, "normal", dtype=domain_dtype)
res = op.inverse_times(op(foo)) res = op.inverse_times(op(foo))
assert_allclose(res, foo, atol=atol, rtol=rtol) assert_allclose(res, foo, atol=atol, rtol=rtol)
...@@ -75,8 +75,8 @@ def _check_linearity(op, domain_dtype, atol, rtol): ...@@ -75,8 +75,8 @@ def _check_linearity(op, domain_dtype, atol, rtol):
needed_cap = op.TIMES needed_cap = op.TIMES
if (op.capability & needed_cap) != needed_cap: if (op.capability & needed_cap) != needed_cap:
return return
fld1 = from_random("normal", op.domain, dtype=domain_dtype) fld1 = from_random(op.domain, "normal", dtype=domain_dtype)
fld2 = from_random("normal", op.domain, dtype=domain_dtype) fld2 = from_random(op.domain, "normal", dtype=domain_dtype)
alpha = np.random.random() # FIXME: this can break badly with MPI! alpha = np.random.random() # FIXME: this can break badly with MPI!
val1 = op(alpha*fld1+fld2) val1 = op(alpha*fld1+fld2)
val2 = alpha*op(fld1)+op(fld2) val2 = alpha*op(fld1)+op(fld2)
...@@ -88,7 +88,7 @@ def _actual_domain_check_linear(op, domain_dtype=None, inp=None): ...@@ -88,7 +88,7 @@ def _actual_domain_check_linear(op, domain_dtype=None, inp=None):
if (op.capability & needed_cap) != needed_cap: if (op.capability & needed_cap) != needed_cap:
return return
if domain_dtype is not None: if domain_dtype is not None:
inp = from_random("normal", op.domain, dtype=domain_dtype) inp = from_random(op.domain, "normal", dtype=domain_dtype)
elif inp is None: elif inp is None:
raise ValueError('Need to specify either dtype or inp') raise ValueError('Need to specify either dtype or inp')
assert_(inp.domain is op.domain) assert_(inp.domain is op.domain)
...@@ -219,7 +219,7 @@ def consistency_check(op, domain_dtype=np.float64, target_dtype=np.float64, ...@@ -219,7 +219,7 @@ def consistency_check(op, domain_dtype=np.float64, target_dtype=np.float64,
def _get_acceptable_location(op, loc, lin): def _get_acceptable_location(op, loc, lin):
if not np.isfinite(lin.val.s_sum()): if not np.isfinite(lin.val.s_sum()):
raise ValueError('Initial value must be finite') raise ValueError('Initial value must be finite')
dir = from_random("normal", loc.domain) dir = from_random(loc.domain, "normal")
dirder = lin.jac(dir) dirder = lin.jac(dir)
if dirder.norm() == 0: if dirder.norm() == 0:
dir = dir * (lin.val.norm()*1e-5) dir = dir * (lin.val.norm()*1e-5)
...@@ -296,3 +296,11 @@ def check_jacobian_consistency(op, loc, tol=1e-8, ntries=100, perf_check=True): ...@@ -296,3 +296,11 @@ def check_jacobian_consistency(op, loc, tol=1e-8, ntries=100, perf_check=True):
print(hist) print(hist)
raise ValueError("gradient and value seem inconsistent") raise ValueError("gradient and value seem inconsistent")
loc = locnext loc = locnext
# FIXME The following code shows that we need prober tests for complex
# derivatives
ddtype = loc.values()[0].dtype if isinstance(loc, MultiField) else loc.dtype
tdtype = dirder.values()[0].dtype if isinstance(dirder, MultiField) else dirder.dtype
only_r_linear = ddtype != tdtype
consistency_check(linmid.jac, domain_dtype=ddtype, target_dtype=tdtype,
only_r_linear=only_r_linear)
...@@ -20,9 +20,10 @@ import numpy as np ...@@ -20,9 +20,10 @@ import numpy as np
from . import utilities from . import utilities