From ac8f1fe281df90a13b1893df4d5472da75de1b9c Mon Sep 17 00:00:00 2001
From: Theo Steininger <theo.steininger@ultimanet.de>
Date: Wed, 12 Jul 2017 00:11:41 +0200
Subject: [PATCH] Refactored critical power files.
---
demos/critical_filtering.py | 9 +-
.../critical_filter/critical_power_energy.py | 103 +++++++++---------
.../wiener_filter/wiener_filter_energy.py | 5 +-
.../invertible_operator_mixin.py | 3 +-
.../smoothness_operator.py | 38 ++++---
nifty/sugar.py | 15 +--
6 files changed, 88 insertions(+), 85 deletions(-)
diff --git a/demos/critical_filtering.py b/demos/critical_filtering.py
index 8ca2cf927..9a9e2103f 100644
--- a/demos/critical_filtering.py
+++ b/demos/critical_filtering.py
@@ -123,9 +123,6 @@ if __name__ == "__main__":
callback=convergence_measure,
max_history_length=3)
- inverter = ConjugateGradient(convergence_level=1,
- convergence_tolerance=10e-4,
- preconditioner=None)
# Setting starting position
flat_power = Field(p_space,val=10e-8)
m0 = flat_power.power_synthesize(real_signal=True)
@@ -144,7 +141,7 @@ if __name__ == "__main__":
D0 = map_energy.curvature
m0 = D0.inverse_times(j)
# Initializing the power energy with updated parameters
- power_energy = CriticalPowerEnergy(position=t0, m=m0, D=D0, sigma=10., samples=3, inverter=inverter)
+ power_energy = CriticalPowerEnergy(position=t0, m=m0, D=D0, smoothness_prior=10., samples=3)
(power_energy, convergence) = minimizer1(power_energy)
@@ -153,6 +150,8 @@ if __name__ == "__main__":
t0.val = power_energy.position.val.real
# Plotting current estimate
- plot_parameters(m0,t0,log(sp), data_power)
+ print i
+ if i%50 == 0:
+ plot_parameters(m0,t0,log(sp), data_power)
diff --git a/nifty/library/critical_filter/critical_power_energy.py b/nifty/library/critical_filter/critical_power_energy.py
index bddac6bb9..7848aee59 100644
--- a/nifty/library/critical_filter/critical_power_energy.py
+++ b/nifty/library/critical_filter/critical_power_energy.py
@@ -1,3 +1,5 @@
+import numpy as np
+
from nifty.energies.energy import Energy
from nifty.operators.smoothness_operator import SmoothnessOperator
from nifty.library.critical_filter import CriticalPowerCurvature
@@ -10,9 +12,10 @@ from nifty import Field, exp
class CriticalPowerEnergy(Energy):
"""The Energy of the power spectrum according to the critical filter.
- It describes the energy of the logarithmic amplitudes of the power spectrum of
- a Gaussian random field under reconstruction uncertainty with smoothness and
- inverse gamma prior. It is used to infer the correlation structure of a correlated signal.
+ It describes the energy of the logarithmic amplitudes of the power spectrum
+ of a Gaussian random field under reconstruction uncertainty with smoothness
+ and inverse gamma prior. It is used to infer the correlation structure of a
+ correlated signal.
Parameters
----------
@@ -25,20 +28,21 @@ class CriticalPowerEnergy(Energy):
If not specified, the map is assumed to be no reconstruction.
default : None
alpha : float
- The spectral prior of the inverse gamma distribution. 1.0 corresponds to
- non-informative.
+ The spectral prior of the inverse gamma distribution. 1.0 corresponds
+ to non-informative.
default : 1.0
q : float
- The cutoff parameter of the inverse gamma distribution. 0.0 corresponds to
- non-informative.
+ The cutoff parameter of the inverse gamma distribution. 0.0 corresponds
+ to non-informative.
+ default : 0.0
+ smoothness_prior : float
+ Controls the strength of the smoothness prior
default : 0.0
- sigma : float
- The parameter of the smoothness prior.
- default : ??? None? ???????
logarithmic : boolean
Whether smoothness acts on linear or logarithmic scale.
samples : integer
- Number of samples used for the estimation of the uncertainty corrections.
+ Number of samples used for the estimation of the uncertainty
+ corrections.
default : 3
w : Field
The contribution from the map with or without uncertainty. It is used
@@ -49,76 +53,72 @@ class CriticalPowerEnergy(Energy):
default : None
"""
- def __init__(self, position, m, D=None, alpha =1.0, q=0., sigma=0.,
- logarithmic = True, samples=3, w=None, inverter=None):
- super(CriticalPowerEnergy, self).__init__(position = position)
+ def __init__(self, position, m, D=None, alpha=1.0, q=0.,
+ smoothness_prior=0., logarithmic=True, samples=3, w=None):
+ super(CriticalPowerEnergy, self).__init__(position=position)
self.m = m
self.D = D
self.samples = samples
- self.sigma = sigma
+ self.smoothness_prior = np.float(smoothness_prior)
self.alpha = Field(self.position.domain, val=alpha)
self.q = Field(self.position.domain, val=q)
- self.T = SmoothnessOperator(domain=self.position.domain[0], sigma=self.sigma,
+ self.T = SmoothnessOperator(domain=self.position.domain[0],
+ strength=self.smoothness_prior,
logarithmic=logarithmic)
self.rho = self.position.domain[0].rho
- self.inverter = inverter
- self.w = w
- if self.w is None:
- self.w = self._calculate_w(self.m, self.D, self.samples)
- self.theta = (exp(-self.position) * (self.q + self.w / 2.))
-
+ self._w = w if w is not None else None
def at(self, position):
- return self.__class__(position, self.m, D=self.D,
- alpha =self.alpha,
- q=self.q,
- sigma=self.sigma, w=self.w,
- samples=self.samples)
+ return self.__class__(position, self.m, D=self.D, alpha=self.alpha,
+ q=self.q, smoothness_prior=self.smoothness_prior,
+ w=self.w, samples=self.samples)
@property
def value(self):
- energy = self._theta.vdot(Field(self.position.domain,val=1.), bare= True)
+ energy = self._theta.sum()
energy += self.position.vdot(self._rho_prime, bare=True)
energy += 0.5 * self.position.vdot(self._Tt)
return energy.real
@property
def gradient(self):
- gradient = - self._theta.weight(-1)
+ gradient = -self._theta.weight(-1)
gradient += (self._rho_prime).weight(-1)
- gradient += self._Tt
+ gradient += self._Tt
gradient.val = gradient.val.real
return gradient
@property
def curvature(self):
- curvature = CriticalPowerCurvature(theta=self._theta.weight(-1), T=self.T,
- inverter=self.inverter)
+ curvature = CriticalPowerCurvature(theta=self._theta.weight(-1),
+ T=self.T)
return curvature
- def _calculate_w(self, m, D, samples):
- w = Field(domain=self.position.domain, val=0. , dtype=m.dtype)
- if D is not None:
- for i in range(samples):
- posterior_sample = generate_posterior_sample(m, D, inverter = self.inverter)
- projected_sample = posterior_sample.power_analyze(
- logarithmic=self.position.domain[0].config["logarithmic"],
- nbin= self.position.domain[0].config["nbin"])
- w += (projected_sample) * self.rho
- w /= float(samples)
- else:
- w = m.power_analyze(
- logarithmic=self.position.domain[0].config["logarithmic"],
- nbin=self.position.domain[0].config["nbin"])
- w *= self.rho
-
- return w
-
+ @property
+ def w(self):
+ if self._w is None:
+ w = Field(domain=self.position.domain, val=0., dtype=self.m.dtype)
+ if self.D is not None:
+ for i in range(self.samples):
+ posterior_sample = generate_posterior_sample(
+ self.m, self.D)
+ projected_sample = posterior_sample.power_analyze(
+ logarithmic=self.position.domain[0].config["logarithmic"],
+ nbin=self.position.domain[0].config["nbin"])
+ w += (projected_sample) * self.rho
+ w /= float(self.samples)
+ else:
+ w = self.m.power_analyze(
+ logarithmic=self.position.domain[0].config["logarithmic"],
+ nbin=self.position.domain[0].config["nbin"])
+ w *= self.rho
+ self._w = w
+ return self._w
@property
@memo
def _theta(self):
- return (exp(-self.position) * (self.q + self.w / 2.))
+ return exp(-self.position) * (self.q + self.w / 2.)
@property
@memo
@@ -129,4 +129,3 @@ class CriticalPowerEnergy(Energy):
@memo
def _Tt(self):
return self.T(self.position)
-
diff --git a/nifty/library/wiener_filter/wiener_filter_energy.py b/nifty/library/wiener_filter/wiener_filter_energy.py
index 798319e59..8eec64c51 100644
--- a/nifty/library/wiener_filter/wiener_filter_energy.py
+++ b/nifty/library/wiener_filter/wiener_filter_energy.py
@@ -29,7 +29,6 @@ class WienerFilterEnergy(Energy):
self.R = R
self.N = N
self.S = S
- self.inverter = inverter
def at(self, position):
return self.__class__(position=position, d=self.d, R=self.R, N=self.N,
@@ -48,10 +47,8 @@ class WienerFilterEnergy(Energy):
@property
@memo
def curvature(self):
- return WienerFilterCurvature(R=self.R, N=self.N, S=self.S,
- inverter=self.inverter)
+ return WienerFilterCurvature(R=self.R, N=self.N, S=self.S)
- @property
@memo
def _Dx(self):
return self.curvature(self.position)
diff --git a/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py b/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py
index e134656b4..ad41ba0b7 100644
--- a/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py
+++ b/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py
@@ -38,7 +38,8 @@ class InvertibleOperatorMixin(object):
(default: ConjugateGradient)
preconditioner : LinearOperator
- Preconditions the minimizaion problem
+ Preconditioner that is used by ConjugateGraduent if no minimizer was
+ given.
Attributes
----------
diff --git a/nifty/operators/smoothness_operator/smoothness_operator.py b/nifty/operators/smoothness_operator/smoothness_operator.py
index ae7efd294..e9e354536 100644
--- a/nifty/operators/smoothness_operator/smoothness_operator.py
+++ b/nifty/operators/smoothness_operator/smoothness_operator.py
@@ -5,14 +5,17 @@ from nifty.operators.laplace_operator import LaplaceOperator
class SmoothnessOperator(EndomorphicOperator):
- """An operator measuring the smoothness on an irregular grid with respect to some scale.
+ """An operator measuring the smoothness on an irregular grid with respect
+ to some scale.
- This operator applies the irregular LaplaceOperator and its adjoint to some Field over a
- PowerSpace which corresponds to its smoothness and weights the result with a scale parameter sigma.
- It is used in the smoothness prior terms of the CriticalPowerEnergy. For this purpose we
- use free boundary conditions in the LaplaceOperator, having no curvature at both ends.
- In addition the first entry is ignored as well, corresponding to the overall mean of the map.
- The mean is therefore not considered in the smoothness prior.
+ This operator applies the irregular LaplaceOperator and its adjoint to some
+ Field over a PowerSpace which corresponds to its smoothness and weights the
+ result with a scale parameter sigma. It is used in the smoothness prior
+ terms of the CriticalPowerEnergy. For this purpose we use free boundary
+ conditions in the LaplaceOperator, having no curvature at both ends. In
+ addition the first entry is ignored as well, corresponding to the overall
+ mean of the map. The mean is therefore not considered in the smoothness
+ prior.
Parameters
@@ -26,7 +29,8 @@ class SmoothnessOperator(EndomorphicOperator):
# ---Overwritten properties and methods---
- def __init__(self, domain, sigma, logarithmic=True, default_spaces=None):
+ def __init__(self, domain, strength=1., logarithmic=True,
+ default_spaces=None):
super(SmoothnessOperator, self).__init__(default_spaces=default_spaces)
@@ -37,10 +41,10 @@ class SmoothnessOperator(EndomorphicOperator):
if not isinstance(self.domain[0], PowerSpace):
raise TypeError("The domain must contain exactly one PowerSpace.")
- if sigma <= 0:
+ if strength <= 0:
raise ValueError("ERROR: invalid sigma.")
- self._sigma = sigma
+ self._strength = strength
self._laplace = LaplaceOperator(domain=self.domain,
logarithmic=logarithmic)
@@ -68,11 +72,17 @@ class SmoothnessOperator(EndomorphicOperator):
return False
def _times(self, x, spaces):
- res = self._laplace.adjoint_times(self._laplace(x, spaces), spaces)
- return (1./self.sigma)**2*res
+ if self._strength != 0:
+ result = self._laplace.adjoint_times(self._laplace(x, spaces),
+ spaces)
+ result *= self._strength**2
+ else:
+ result = x.copy_empty()
+ result.val[:] = 0
+ return result
# ---Added properties and methods---
@property
- def sigma(self):
- return self._sigma
+ def strength(self):
+ return self._strength
diff --git a/nifty/sugar.py b/nifty/sugar.py
index 5114a949f..b1835af91 100644
--- a/nifty/sugar.py
+++ b/nifty/sugar.py
@@ -64,11 +64,13 @@ def create_power_operator(domain, power_spectrum, dtype=None,
return DiagonalOperator(domain, diagonal=f, bare=True)
-def generate_posterior_sample(mean, covariance, inverter=None):
- """ Generates a posterior sample from a Gaussian distribution with given mean and covariance
+def generate_posterior_sample(mean, covariance):
+ """ Generates a posterior sample from a Gaussian distribution with given
+ mean and covariance
- This method generates samples by setting up the observation and reconstruction of a mock signal
- in order to obtain residuals of the right correlation which are added to the given mean.
+ This method generates samples by setting up the observation and
+ reconstruction of a mock signal in order to obtain residuals of the right
+ correlation which are added to the given mean.
Parameters
----------
@@ -77,9 +79,6 @@ def generate_posterior_sample(mean, covariance, inverter=None):
covariance : WienerFilterCurvature
The posterior correlation structure consisting of a
response operator, noise covariance and prior signal covariance
- inverter : ConjugateGradient *optional*
- the conjugate gradient used to invert the curvature for the Wiener filter.
- default : None
Returns
-------
@@ -91,8 +90,6 @@ def generate_posterior_sample(mean, covariance, inverter=None):
S = covariance.S
R = covariance.R
N = covariance.N
- if inverter is None:
- inverter = ConjugateGradient(preconditioner=S)
power = S.diagonal().power_analyze()**.5
mock_signal = power.power_synthesize(real_signal=True)
--
GitLab