Skip to content

Commit 87fd1d0

Browse files
author
perdaug
committed
[MaxVar, Part 1] Added the general Gaussian noise model.
1 parent 54e62b2 commit 87fd1d0

File tree

7 files changed

+163
-14
lines changed

7 files changed

+163
-14
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
0.x
5+
---
6+
7+
- Added the general Gaussian noise example model (fixed covariance)
8+
49
0.6.2 (2017-09-06)
510
------------------
611

elfi/examples/bignk.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def BiGNK(a1, a2, b1, b2, g1, g2, k1, k2, rho, c=.8, n_obs=150, batch_size=1,
9898
term_product_misaligned = np.swapaxes(term_product, 1, 0)
9999
y_misaligned = np.add(a, term_product_misaligned)
100100
y = np.swapaxes(y_misaligned, 1, 0)
101-
# print(y.shape)
101+
102102
return y
103103

104104

elfi/examples/gauss_nd.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
"""The general, n-dimensional Gaussian noise model."""
2+
3+
from functools import partial
4+
5+
import numpy as np
6+
import scipy.stats as ss
7+
8+
import elfi
9+
from elfi.examples.gnk import euclidean_multidim
10+
11+
12+
def Gauss_nd(*params, cov_ii=None, cov_ij=None, n_obs=15, batch_size=1, random_state=None):
13+
"""Sample the Gaussian distribution.
14+
15+
Reference
16+
---------
17+
The default settings replicate the experiment settings used in [1].
18+
19+
[1] arXiv:1704.00520 (Järvenpää et al., 2017).
20+
21+
Parameters
22+
----------
23+
*params : array_like
24+
The array elements correspond to the mean parameters.
25+
cov_ii : float, optional
26+
The diagonal variance.
27+
cov_ij : float, optional
28+
The non-diagonal variance.
29+
n_obs : int, optional
30+
The number of observations.
31+
batch_size : int, optional
32+
The number of batches.
33+
random_state : np.random.RandomState, optional
34+
35+
Returns
36+
-------
37+
y : array_like
38+
39+
"""
40+
n_dim = len(params)
41+
# Formatting the mean.
42+
mu = np.zeros(shape=(batch_size, n_dim))
43+
for idx_dim, param_mu in enumerate(params):
44+
mu[:, idx_dim] = param_mu
45+
# Formatting the diagonal covariance.
46+
cov_ii = np.repeat(cov_ii, batch_size)
47+
if batch_size == 1:
48+
cov_ii = cov_ii[None]
49+
# Formatting the non-diagonal covariance.
50+
if n_dim != 1:
51+
cov_ij = np.repeat(cov_ij, batch_size)
52+
if batch_size == 1:
53+
cov_ij = cov_ij[None]
54+
# Creating the covariance matrix.
55+
cov = np.zeros(shape=(batch_size, n_dim, n_dim))
56+
for idx_batch in range(batch_size):
57+
if n_dim != 1:
58+
cov[idx_batch].fill(np.asscalar(cov_ij[idx_batch]))
59+
np.fill_diagonal(cov[idx_batch], cov_ii[idx_batch])
60+
# Sampling observations.
61+
y = np.zeros(shape=(batch_size, n_obs, n_dim))
62+
for idx_batch in range(batch_size):
63+
y_batch = ss.multivariate_normal.rvs(mean=mu[idx_batch],
64+
cov=cov[idx_batch],
65+
size=n_obs,
66+
random_state=random_state)
67+
if n_dim == 1:
68+
y_batch = y_batch[:, None]
69+
y[idx_batch, :, :] = y_batch
70+
return y
71+
72+
73+
def ss_mean(x):
74+
"""Return the summary statistic corresponding to the mean."""
75+
ss = np.mean(x, axis=1)
76+
return ss
77+
78+
79+
def ss_var(x):
80+
"""Return the summary statistic corresponding to the variance."""
81+
ss = np.var(x, axis=1)
82+
return ss
83+
84+
85+
def get_model(true_params=None, cov_ii=1, cov_ij=.5, n_obs=15, seed_obs=None):
86+
"""Return an initialised Gaussian noise model.
87+
88+
Parameters
89+
----------
90+
true_params : array_like
91+
The array elements correspond to the mean parameters.
92+
cov_ii : float, optional
93+
The diagonal variance.
94+
cov_ij : float, optional
95+
The non-diagonal variance.
96+
n_obs : int, optional
97+
The number of observations.
98+
random_state : np.random.RandomState, optional
99+
100+
Returns
101+
-------
102+
m : elfi.ElfiModel
103+
104+
"""
105+
# The default settings use the 2-D Gaussian model.
106+
if true_params is None:
107+
true_params = [4, 4]
108+
n_dim = len(true_params)
109+
# Obtaining the observations.
110+
y_obs = Gauss_nd(*true_params,
111+
cov_ii=cov_ii,
112+
cov_ij=cov_ij,
113+
n_obs=n_obs,
114+
random_state=np.random.RandomState(seed_obs))
115+
sim_fn = partial(
116+
Gauss_nd, cov_ii=cov_ii, cov_ij=cov_ij, n_obs=n_obs)
117+
m = elfi.ElfiModel()
118+
# Defining the priors.
119+
priors = []
120+
for i in range(n_dim):
121+
name_prior = 'mu_{}'.format(i)
122+
prior_mu = elfi.Prior('uniform', 0, 8, model=m, name=name_prior)
123+
priors.append(prior_mu)
124+
125+
elfi.Simulator(sim_fn, *priors, observed=y_obs, name='gm')
126+
elfi.Summary(ss_mean, m['gm'], name='ss_mean')
127+
elfi.Summary(ss_var, m['gm'], name='ss_var')
128+
elfi.Discrepancy(euclidean_multidim, m['ss_mean'], m['ss_var'], name='d')
129+
130+
return m

elfi/examples/gnk.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ def euclidean_multidim(*simulated, observed):
134134
array_like
135135
136136
"""
137-
pts_sim = np.column_stack(simulated)
138-
pts_obs = np.column_stack(observed)
139-
d_multidim = np.sum((pts_sim - pts_obs)**2., axis=1)
140-
d_squared = np.sum(d_multidim, axis=1)
141-
d = np.sqrt(d_squared)
137+
pts_sim = np.stack(simulated, axis=1)
138+
pts_obs = np.stack(observed, axis=1)
139+
d_ss_merged = np.sum((pts_sim - pts_obs)**2., axis=1)
140+
d_dim_merged = np.sum(d_ss_merged, axis=1)
141+
d = np.sqrt(d_dim_merged)
142142

143143
return d
144144

@@ -185,8 +185,8 @@ def ss_robust(y):
185185
ss_g = _get_ss_g(y)
186186
ss_k = _get_ss_k(y)
187187

188-
ss_robust = np.stack((ss_a, ss_b, ss_g, ss_k), axis=1)
189-
188+
# Combining the summary statistics by expanding the dimensionality.
189+
ss_robust = np.hstack((ss_a, ss_b, ss_g, ss_k))
190190
return ss_robust
191191

192192

@@ -209,7 +209,8 @@ def ss_octile(y):
209209
octiles = np.linspace(12.5, 87.5, 7)
210210
E1, E2, E3, E4, E5, E6, E7 = np.percentile(y, octiles, axis=1)
211211

212-
ss_octile = np.stack((E1, E2, E3, E4, E5, E6, E7), axis=1)
212+
# Combining the summary statistics by expanding the dimensionality.
213+
ss_octile = np.hstack((E1, E2, E3, E4, E5, E6, E7))
213214

214215
return ss_octile
215216

elfi/methods/post_processing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ def _adjust(self, i, theta_i, regression_model):
204204

205205
def _input_variables(self, model, sample, summary_names):
206206
"""Regress on the differences to the observed summaries."""
207-
observed_summaries = np.stack([model[s].observed for s in summary_names], axis=1)
208-
summaries = np.stack([sample.outputs[name] for name in summary_names], axis=1)
207+
observed_summaries = np.stack([model[s].observed.ravel() for s in summary_names], axis=1)
208+
summaries = np.stack([sample.outputs[name].ravel() for name in summary_names], axis=1)
209209
return summaries - observed_summaries
210210

211211

tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import elfi.clients.ipyparallel as eipp
1010
import elfi.clients.multiprocessing as mp
1111
import elfi.clients.native as native
12+
import elfi.examples.gauss_nd
1213
import elfi.examples.ma2
1314

1415
elfi.clients.native.set_as_default()

tests/unit/test_examples.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
import elfi
6-
from elfi.examples import bdm, gauss, ricker, gnk, bignk
6+
from elfi.examples import bdm, gauss, gauss_nd, ricker, gnk, bignk
77

88

99
def test_bdm():
@@ -41,12 +41,24 @@ def test_bdm():
4141
if do_cleanup:
4242
os.system('rm {}/bdm'.format(cpp_path))
4343

44-
45-
def test_Gauss():
44+
def test_gauss():
4645
m = gauss.get_model()
4746
rej = elfi.Rejection(m, m['d'], batch_size=10)
4847
rej.sample(20)
4948

49+
def test_gauss_1d():
50+
params_true = [4]
51+
m = gauss_nd.get_model(true_params=params_true, cov_ii=1)
52+
rej = elfi.Rejection(m, m['d'], batch_size=10)
53+
rej.sample(20)
54+
55+
56+
def test_gauss_2d():
57+
params_true = [4, 4]
58+
m = gauss_nd.get_model(true_params=params_true, cov_ii=1, cov_ij=.5)
59+
rej = elfi.Rejection(m, m['d'], batch_size=10)
60+
rej.sample(20)
61+
5062

5163
def test_Ricker():
5264
m = ricker.get_model()

0 commit comments

Comments
 (0)