From 24bbbe18bec85b7157fe232bdc9091b0c4529de3 Mon Sep 17 00:00:00 2001 From: Henri Vuollekoski Date: Thu, 7 Sep 2017 15:35:50 +0300 Subject: [PATCH 1/6] Add the Zenodo badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b1f82820..1a990bba 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ ELFI - Engine for Likelihood-Free Inference [![Code Health](https://landscape.io/github/elfi-dev/elfi/dev/landscape.svg?style=flat)](https://landscape.io/github/elfi-dev/elfi/dev) [![Documentation Status](https://readthedocs.org/projects/elfi/badge/?version=latest)](http://elfi.readthedocs.io/en/latest/?badge=latest) [![Gitter](https://badges.gitter.im/elfi-dev/elfi.svg)](https://gitter.im/elfi-dev/elfi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![DOI](https://zenodo.org/badge/69855441.svg)](https://zenodo.org/badge/latestdoi/69855441) From 832046a9cf6b58366721efc8c8e91646e141c4d7 Mon Sep 17 00:00:00 2001 From: Jarno Lintusaari Date: Fri, 8 Sep 2017 08:11:52 +0300 Subject: [PATCH 2/6] Cache memmap in npyarray (#237) --- elfi/store.py | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/elfi/store.py b/elfi/store.py index a1a21302..4ab5b0e3 100644 --- a/elfi/store.py +++ b/elfi/store.py @@ -641,28 +641,20 @@ def __init__(self, filename, array=None, truncate=False): else: self.fs = open(self.filename, 'w+b') + # Numpy memmap for the file array data + self._memmap = None + if array is not None: self.append(array) self.flush() def __getitem__(self, sl): """Return a slice `sl` of data.""" - if not self.initialized: - raise IndexError("NpyArray is not initialized") - order = 'F' if self.fortran_order else 'C' - # TODO: do not recreate if nothing has changed - mmap = np.memmap( - self.fs, dtype=self.dtype, shape=self.shape, offset=self.header_length, order=order) - return mmap[sl] + return self.memmap[sl] def __setitem__(self, sl, value): """Set data at slice `sl` to `value`.""" - if not self.initialized: - raise IndexError("NpyArray is not initialized") - order = 'F' if self.fortran_order else 'C' - mmap = np.memmap( - self.fs, dtype=self.dtype, shape=self.shape, offset=self.header_length, order=order) - mmap[sl] = value + self.memmap[sl] = value def __len__(self): """Return the length of array.""" @@ -695,6 +687,20 @@ def append(self, array): # Only prepare the header bytes, need to be flushed to take effect self._prepare_header_data() + # Invalidate the memmap + self._memmap = None + + @property + def memmap(self): + if not self.initialized: + raise IndexError("NpyArray is not initialized") + + if self._memmap is None: + order = 'F' if self.fortran_order else 'C' + self._memmap = np.memmap(self.fs, dtype=self.dtype, shape=self.shape, + offset=self.header_length, order=order) + return self._memmap + def _init_from_file_header(self): """Initialize the object from an existing file.""" self.fs.seek(self.HEADER_DATA_SIZE_OFFSET) @@ -777,11 +783,16 @@ def truncate(self, length=0): self.fs.seek(self.header_length + self.size * self.itemsize) self.fs.truncate() + # Invalidate the memmap + self._memmap = None + def close(self): """Close the file.""" if self.initialized: self._write_header_data() self.fs.close() + # Invalidate the memmap + self._memmap = None def clear(self): """Truncate the array to 0.""" @@ -796,6 +807,8 @@ def delete(self): os.remove(name) self.fs = None self.header_length = None + # Invalidate the memmap + self._memmap = None def flush(self): """Flush any changes in memory to array.""" From 23f7a6de9a581d18a1fb87582f50b6efb72e7683 Mon Sep 17 00:00:00 2001 From: Jarno Lintusaari Date: Fri, 8 Sep 2017 12:46:22 +0300 Subject: [PATCH 3/6] Optimize node execution order (#238) * Further optimizations of going through a large pool of simulations * Linting and CHANGELOG --- CHANGELOG.rst | 5 +++ elfi/client.py | 3 ++ elfi/executor.py | 57 ++++++++++++++++++----------- elfi/loader.py | 5 +-- elfi/model/elfi_model.py | 6 ++- elfi/store.py | 3 +- elfi/utils.py | 16 ++++---- tests/functional/test_randomness.py | 2 +- 8 files changed, 60 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 17660926..976827a5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,11 @@ Changelog ========= +dev +--- + +- Furhther performance improvements for rerunning inference using stored data via caches + 0.6.2 (2017-09-06) ------------------ diff --git a/elfi/client.py b/elfi/client.py index 59ef04df..3b589cf7 100644 --- a/elfi/client.py +++ b/elfi/client.py @@ -326,4 +326,7 @@ def load_data(cls, compiled_net, context, batch_index): loaded_net = RandomStateLoader.load(context, loaded_net, batch_index) loaded_net = PoolLoader.load(context, loaded_net, batch_index) + # Add cache from the contect + loaded_net.graph['_executor_cache'] = context.caches['executor'] + return loaded_net diff --git a/elfi/executor.py b/elfi/executor.py index 52716c0b..f8aca08f 100644 --- a/elfi/executor.py +++ b/elfi/executor.py @@ -99,27 +99,42 @@ def get_execution_order(cls, G): nodes that require execution """ - nodes = set() - order = nx_constant_topological_sort(G) - dep_graph = nx.DiGraph(G.edges()) - - for node in order: - attr = G.node[node] - if attr.keys() >= {'operation', 'output'}: - raise ValueError('Generative graph has both op and output present') - - # Remove nodes from dependency graph whose outputs are present - if 'output' in attr: - dep_graph.remove_node(node) - elif 'operation' not in attr: - raise ValueError('Generative graph has no op or output present') - - for output_node in G.graph['outputs']: - if dep_graph.has_node(output_node): - nodes.update([output_node]) - nodes.update(nx.ancestors(dep_graph, output_node)) - - return [n for n in order if n in nodes] + # Get the cache dict if it exists + cache = G.graph.get('_executor_cache', {}) + + output_nodes = G.graph['outputs'] + # Filter those output nodes who have an operation to run + needed = tuple(sorted(node for node in output_nodes if 'operation' in G.node[node])) + + if needed not in cache: + # Resolve the nodes that need to be executed in the graph + nodes_to_execute = set(needed) + + if 'sort_order' not in cache: + cache['sort_order'] = nx_constant_topological_sort(G) + sort_order = cache['sort_order'] + + # Resolve the dependencies of needed + dep_graph = nx.DiGraph(G.edges()) + for node in sort_order: + attr = G.node[node] + if attr.keys() >= {'operation', 'output'}: + raise ValueError('Generative graph has both op and output present') + + # Remove those nodes from the dependency graph whose outputs are present + if 'output' in attr: + dep_graph.remove_node(node) + elif 'operation' not in attr: + raise ValueError('Generative graph has no op or output present') + + # Add the dependencies of the needed nodes + for needed_node in needed: + nodes_to_execute.update(nx.ancestors(dep_graph, needed_node)) + + # Turn in to a sorted list and cache + cache[needed] = [n for n in sort_order if n in nodes_to_execute] + + return cache[needed] @staticmethod def _run(fn, node, G): diff --git a/elfi/loader.py b/elfi/loader.py index 364cd0ae..738c7b49 100644 --- a/elfi/loader.py +++ b/elfi/loader.py @@ -164,9 +164,8 @@ def load(cls, context, compiled_net, batch_index): elif isinstance(seed, (int, np.int32, np.uint32)): # TODO: In the future, we could use https://pypi.python.org/pypi/randomstate to enable # jumps? - sub_seed, context.sub_seed_cache = get_sub_seed(seed, - batch_index, - cache=context.sub_seed_cache) + cache = context.caches.get('sub_seed', None) + sub_seed = get_sub_seed(seed, batch_index, cache=cache) random_state = np.random.RandomState(sub_seed) else: raise ValueError("Seed of type {} is not supported".format(seed)) diff --git a/elfi/model/elfi_model.py b/elfi/model/elfi_model.py index c08f804d..91c8a839 100644 --- a/elfi/model/elfi_model.py +++ b/elfi/model/elfi_model.py @@ -120,7 +120,7 @@ def random_name(length=4, prefix=''): return prefix + str(uuid.uuid4().hex[0:length]) -# TODO: move to another file +# TODO: move to another file? class ComputationContext: """Container object for key components for consistent computation results. @@ -167,9 +167,11 @@ def __init__(self, batch_size=None, seed=None, pool=None): self._batch_size = batch_size or 1 self._seed = random_seed() if seed is None else seed - self.sub_seed_cache = {} self._pool = pool + # Caches will not be used if they are not found from the caches dict + self.caches = {'executor': {}, 'sub_seed': {}} + # Count the number of submissions from this context self.num_submissions = 0 diff --git a/elfi/store.py b/elfi/store.py index 4ab5b0e3..02a3749d 100644 --- a/elfi/store.py +++ b/elfi/store.py @@ -692,13 +692,14 @@ def append(self, array): @property def memmap(self): + """Return a NumPy memory map to the array data.""" if not self.initialized: raise IndexError("NpyArray is not initialized") if self._memmap is None: order = 'F' if self.fortran_order else 'C' self._memmap = np.memmap(self.fs, dtype=self.dtype, shape=self.shape, - offset=self.header_length, order=order) + offset=self.header_length, order=order) return self._memmap def _init_from_file_header(self): diff --git a/elfi/utils.py b/elfi/utils.py index 30fd4767..5314c745 100644 --- a/elfi/utils.py +++ b/elfi/utils.py @@ -81,13 +81,12 @@ def get_sub_seed(seed, sub_seed_index, high=2**31, cache=None): high : int upper limit for the range of sub seeds (exclusive) cache : dict or None, optional - If provided, cached state will be used to compute the next sub_seed. + If provided, cached state will be used to compute the next sub_seed and then updated. Returns ------- - int or tuple - The seed will be from the interval [0, high - 1]. If cache is provided, will also return - the updated cache. + int + The seed will be from the interval [0, high - 1]. Notes ----- @@ -121,9 +120,8 @@ def get_sub_seed(seed, sub_seed_index, high=2**31, cache=None): seen.update(sub_seeds) n_unique = len(seen) - sub_seed = sub_seeds[-1] if cache is not None: - cache = {'random_state': random_state, 'seen': seen} - return sub_seed, cache - else: - return sub_seed + cache['random_state'] = random_state + cache['seen'] = seen + + return sub_seeds[-1] diff --git a/tests/functional/test_randomness.py b/tests/functional/test_randomness.py index 64559b3e..251c4f60 100644 --- a/tests/functional/test_randomness.py +++ b/tests/functional/test_randomness.py @@ -57,7 +57,7 @@ def test_get_sub_seed(): cache = {} sub_seeds_cached = [] for i in range(n): - sub_seed, cache = get_sub_seed(seed, i, n, cache=cache) + sub_seed = get_sub_seed(seed, i, n, cache=cache) sub_seeds_cached.append(sub_seed) assert np.array_equal(sub_seeds, sub_seeds_cached) From a6f641aa214b33f860f396eaedd166d831f65a9e Mon Sep 17 00:00:00 2001 From: Arijus Pleska Date: Thu, 28 Sep 2017 13:04:01 +0300 Subject: [PATCH 4/6] [MaxVar split, Part 1] Added the general Gaussian noise model. (#233) * [MaxVar, Part 1] Added the general Gaussian noise model. * Removed the covariance matrix duplicates. * Set the priors to be always accustomed to the true parameters' values. --- CHANGELOG.rst | 1 + elfi/examples/bignk.py | 2 +- elfi/examples/gauss.py | 131 ++++++++++++++++++----- elfi/examples/gnk.py | 17 +-- elfi/methods/post_processing.py | 4 +- tests/conftest.py | 1 + tests/functional/test_post_processing.py | 30 +++--- tests/unit/test_examples.py | 20 +++- 8 files changed, 154 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 976827a5..3ac6b4e3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,7 @@ dev --- - Furhther performance improvements for rerunning inference using stored data via caches +- Added the general Gaussian noise example model (fixed covariance) 0.6.2 (2017-09-06) ------------------ diff --git a/elfi/examples/bignk.py b/elfi/examples/bignk.py index 7c1db509..d7feeca7 100644 --- a/elfi/examples/bignk.py +++ b/elfi/examples/bignk.py @@ -98,7 +98,7 @@ def BiGNK(a1, a2, b1, b2, g1, g2, k1, k2, rho, c=.8, n_obs=150, batch_size=1, term_product_misaligned = np.swapaxes(term_product, 1, 0) y_misaligned = np.add(a, term_product_misaligned) y = np.swapaxes(y_misaligned, 1, 0) - # print(y.shape) + return y diff --git a/elfi/examples/gauss.py b/elfi/examples/gauss.py index 2e2b8091..89557cc8 100644 --- a/elfi/examples/gauss.py +++ b/elfi/examples/gauss.py @@ -1,4 +1,4 @@ -"""An example implementation of a Gaussian noise model.""" +"""Example implementations of Gaussian noise models.""" from functools import partial @@ -6,10 +6,11 @@ import scipy.stats as ss import elfi +from elfi.examples.gnk import euclidean_multidim -def Gauss(mu, sigma, n_obs=50, batch_size=1, random_state=None): - """Sample the Gaussian distribution. +def gauss(mu, sigma, n_obs=50, batch_size=1, random_state=None): + """Sample the 1-D Gaussian distribution. Parameters ---------- @@ -17,14 +18,61 @@ def Gauss(mu, sigma, n_obs=50, batch_size=1, random_state=None): sigma : float, array_like n_obs : int, optional batch_size : int, optional - random_state : RandomState, optional + random_state : np.random.RandomState, optional + + Returns + ------- + y_obs : array_like + 1-D observation. + + """ + # Handling batching. + batches_mu = np.asanyarray(mu).reshape((-1, 1)) + batches_sigma = np.asanyarray(sigma).reshape((-1, 1)) + + # Sampling observations. + y_obs = ss.norm.rvs(loc=batches_mu, scale=batches_sigma, + size=(batch_size, n_obs), random_state=random_state) + return y_obs + + +def gauss_nd_mean(*mu, cov_matrix, n_obs=15, batch_size=1, random_state=None): + """Sample an n-D Gaussian distribution. + + Parameters + ---------- + *mu : array_like + Mean parameters. + cov_matrix : array_like + Covariance matrix. + n_obs : int, optional + batch_size : int, optional + random_state : np.random.RandomState, optional + + Returns + ------- + y_obs : array_like + n-D observation. """ - # Standardising the parameter's format. - mu = np.asanyarray(mu).reshape((-1, 1)) - sigma = np.asanyarray(sigma).reshape((-1, 1)) - y = ss.norm.rvs(loc=mu, scale=sigma, size=(batch_size, n_obs), random_state=random_state) - return y + n_dim = len(mu) + + # Handling batching. + batches_mu = np.zeros(shape=(batch_size, n_dim)) + for idx_dim, param_mu in enumerate(mu): + batches_mu[:, idx_dim] = param_mu + + # Sampling the observations. + y_obs = np.zeros(shape=(batch_size, n_obs, n_dim)) + for idx_batch in range(batch_size): + y_batch = ss.multivariate_normal.rvs(mean=batches_mu[idx_batch], + cov=cov_matrix, + size=n_obs, + random_state=random_state) + if n_dim == 1: + y_batch = y_batch[:, np.newaxis] + y_obs[idx_batch, :, :] = y_batch + return y_obs def ss_mean(x): @@ -39,36 +87,71 @@ def ss_var(x): return ss -def get_model(n_obs=50, true_params=None, seed_obs=None): - """Return a complete Gaussian noise model. +def get_model(n_obs=50, true_params=None, seed_obs=None, nd_mean=False, cov_matrix=None): + """Return a Gaussian noise model. Parameters ---------- n_obs : int, optional - the number of observations true_params : list, optional - true_params[0] corresponds to the mean, - true_params[1] corresponds to the standard deviation + Default parameter settings. seed_obs : int, optional - seed for the observed data generation + Seed for the observed data generation. + nd_mean : bool, optional + Option to use an n-D mean Gaussian noise model. + cov_matrix : None, optional + Covariance matrix, a requirement for the nd_mean model. Returns ------- m : elfi.ElfiModel """ + # Defining the default settings. if true_params is None: - true_params = [10, 2] + if nd_mean: + true_params = [4, 4] # 2-D mean. + else: + true_params = [4, .4] # mean and standard deviation. - y_obs = Gauss(*true_params, n_obs=n_obs, random_state=np.random.RandomState(seed_obs)) - sim_fn = partial(Gauss, n_obs=n_obs) + # Choosing the simulator for both observations and simulations. + if nd_mean: + sim_fn = partial(gauss_nd_mean, cov_matrix=cov_matrix, n_obs=n_obs) + else: + sim_fn = partial(gauss, n_obs=n_obs) + + # Obtaining the observations. + y_obs = sim_fn(*true_params, n_obs=n_obs, random_state=np.random.RandomState(seed_obs)) m = elfi.ElfiModel() - elfi.Prior('uniform', -10, 50, model=m, name='mu') - elfi.Prior('truncnorm', 0.01, 5, model=m, name='sigma') - elfi.Simulator(sim_fn, m['mu'], m['sigma'], observed=y_obs, name='Gauss') - elfi.Summary(ss_mean, m['Gauss'], name='S1') - elfi.Summary(ss_var, m['Gauss'], name='S2') - elfi.Distance('euclidean', m['S1'], m['S2'], name='d') + + # Initialising the priors. + eps_prior = 5 # The longest distance from the median of an initialised prior's distribution. + priors = [] + if nd_mean: + n_dim = len(true_params) + for i in range(n_dim): + name_prior = 'mu_{}'.format(i) + prior_mu = elfi.Prior('uniform', true_params[i] - eps_prior, + 2 * eps_prior, model=m, name=name_prior) + priors.append(prior_mu) + else: + priors.append(elfi.Prior('uniform', true_params[0] - eps_prior, + 2 * eps_prior, model=m, name='mu')) + priors.append(elfi.Prior('truncnorm', + np.amax([.01, true_params[1] - eps_prior]), + 2 * eps_prior, model=m, name='sigma')) + elfi.Simulator(sim_fn, *priors, observed=y_obs, name='gauss') + + # Initialising the summary statistics. + sumstats = [] + sumstats.append(elfi.Summary(ss_mean, m['gauss'], name='ss_mean')) + sumstats.append(elfi.Summary(ss_var, m['gauss'], name='ss_var')) + + # Choosing the discrepancy metric. + if nd_mean: + elfi.Discrepancy(euclidean_multidim, *sumstats, name='d') + else: + elfi.Distance('euclidean', *sumstats, name='d') return m diff --git a/elfi/examples/gnk.py b/elfi/examples/gnk.py index eeabb4df..80337c0c 100644 --- a/elfi/examples/gnk.py +++ b/elfi/examples/gnk.py @@ -134,11 +134,11 @@ def euclidean_multidim(*simulated, observed): array_like """ - pts_sim = np.column_stack(simulated) - pts_obs = np.column_stack(observed) - d_multidim = np.sum((pts_sim - pts_obs)**2., axis=1) - d_squared = np.sum(d_multidim, axis=1) - d = np.sqrt(d_squared) + pts_sim = np.stack(simulated, axis=1) + pts_obs = np.stack(observed, axis=1) + d_ss_merged = np.sum((pts_sim - pts_obs)**2., axis=1) + d_dim_merged = np.sum(d_ss_merged, axis=1) + d = np.sqrt(d_dim_merged) return d @@ -185,8 +185,8 @@ def ss_robust(y): ss_g = _get_ss_g(y) ss_k = _get_ss_k(y) - ss_robust = np.stack((ss_a, ss_b, ss_g, ss_k), axis=1) - + # Combining the summary statistics by expanding the dimensionality. + ss_robust = np.hstack((ss_a, ss_b, ss_g, ss_k)) return ss_robust @@ -209,7 +209,8 @@ def ss_octile(y): octiles = np.linspace(12.5, 87.5, 7) E1, E2, E3, E4, E5, E6, E7 = np.percentile(y, octiles, axis=1) - ss_octile = np.stack((E1, E2, E3, E4, E5, E6, E7), axis=1) + # Combining the summary statistics by expanding the dimensionality. + ss_octile = np.hstack((E1, E2, E3, E4, E5, E6, E7)) return ss_octile diff --git a/elfi/methods/post_processing.py b/elfi/methods/post_processing.py index 384c7abc..cc3ba785 100644 --- a/elfi/methods/post_processing.py +++ b/elfi/methods/post_processing.py @@ -242,8 +242,8 @@ def adjust_posterior(sample, model, summary_names, parameter_names=None, adjustm >>> import elfi >>> from elfi.examples import gauss >>> m = gauss.get_model() - >>> res = elfi.Rejection(m['d'], output_names=['S1', 'S2']).sample(1000) - >>> adj = adjust_posterior(res, m, ['S1', 'S2'], ['mu'], LinearAdjustment()) + >>> res = elfi.Rejection(m['d'], output_names=['ss_mean', 'ss_var']).sample(1000) + >>> adj = adjust_posterior(res, m, ['ss_mean', 'ss_var'], ['mu'], LinearAdjustment()) """ adjustment = _get_adjustment(adjustment) diff --git a/tests/conftest.py b/tests/conftest.py index 2f749a3c..7213e864 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,6 +9,7 @@ import elfi.clients.ipyparallel as eipp import elfi.clients.multiprocessing as mp import elfi.clients.native as native +import elfi.examples.gauss import elfi.examples.ma2 elfi.clients.native.set_as_default() diff --git a/tests/functional/test_post_processing.py b/tests/functional/test_post_processing.py index bcce3e95..a7e2e0da 100644 --- a/tests/functional/test_post_processing.py +++ b/tests/functional/test_post_processing.py @@ -28,9 +28,9 @@ def test_single_parameter_linear_adjustment(): # Hyperparameters mu0, sigma0 = (10, 100) - y_obs = gauss.Gauss( + y_obs = gauss.gauss( mu, sigma, n_obs=n_obs, batch_size=1, random_state=np.random.RandomState(seed)) - sim_fn = partial(gauss.Gauss, sigma=sigma, n_obs=n_obs) + sim_fn = partial(gauss.gauss, sigma=sigma, n_obs=n_obs) # Posterior n = y_obs.shape[1] @@ -40,12 +40,12 @@ def test_single_parameter_linear_adjustment(): # Model m = elfi.ElfiModel() elfi.Prior('norm', mu0, sigma0, model=m, name='mu') - elfi.Simulator(sim_fn, m['mu'], observed=y_obs, name='Gauss') - elfi.Summary(lambda x: x.mean(axis=1), m['Gauss'], name='S1') - elfi.Distance('euclidean', m['S1'], name='d') + elfi.Simulator(sim_fn, m['mu'], observed=y_obs, name='gauss') + elfi.Summary(lambda x: x.mean(axis=1), m['gauss'], name='ss_mean') + elfi.Distance('euclidean', m['ss_mean'], name='d') - res = elfi.Rejection(m['d'], output_names=['S1'], seed=seed).sample(1000, threshold=1) - adj = elfi.adjust_posterior(model=m, sample=res, parameter_names=['mu'], summary_names=['S1']) + res = elfi.Rejection(m['d'], output_names=['ss_mean'], seed=seed).sample(1000, threshold=1) + adj = elfi.adjust_posterior(model=m, sample=res, parameter_names=['mu'], summary_names=['ss_mean']) assert np.allclose(_statistics(adj.outputs['mu']), (4.9772879640569778, 0.02058680115402544)) @@ -61,9 +61,9 @@ def test_nonfinite_values(): # Hyperparameters mu0, sigma0 = (10, 100) - y_obs = gauss.Gauss( + y_obs = gauss.gauss( mu, sigma, n_obs=n_obs, batch_size=1, random_state=np.random.RandomState(seed)) - sim_fn = partial(gauss.Gauss, sigma=sigma, n_obs=n_obs) + sim_fn = partial(gauss.gauss, sigma=sigma, n_obs=n_obs) # Posterior n = y_obs.shape[1] @@ -73,19 +73,19 @@ def test_nonfinite_values(): # Model m = elfi.ElfiModel() elfi.Prior('norm', mu0, sigma0, model=m, name='mu') - elfi.Simulator(sim_fn, m['mu'], observed=y_obs, name='Gauss') - elfi.Summary(lambda x: x.mean(axis=1), m['Gauss'], name='S1') - elfi.Distance('euclidean', m['S1'], name='d') + elfi.Simulator(sim_fn, m['mu'], observed=y_obs, name='gauss') + elfi.Summary(lambda x: x.mean(axis=1), m['gauss'], name='ss_mean') + elfi.Distance('euclidean', m['ss_mean'], name='d') - res = elfi.Rejection(m['d'], output_names=['S1'], seed=seed).sample(1000, threshold=1) + res = elfi.Rejection(m['d'], output_names=['ss_mean'], seed=seed).sample(1000, threshold=1) # Add some invalid values res.outputs['mu'] = np.append(res.outputs['mu'], np.array([np.inf])) - res.outputs['S1'] = np.append(res.outputs['S1'], np.array([np.inf])) + res.outputs['ss_mean'] = np.append(res.outputs['ss_mean'], np.array([np.inf])) with pytest.warns(UserWarning): adj = elfi.adjust_posterior( - model=m, sample=res, parameter_names=['mu'], summary_names=['S1']) + model=m, sample=res, parameter_names=['mu'], summary_names=['ss_mean']) assert np.allclose(_statistics(adj.outputs['mu']), (4.9772879640569778, 0.02058680115402544)) diff --git a/tests/unit/test_examples.py b/tests/unit/test_examples.py index 92c6feff..6e0f09bb 100644 --- a/tests/unit/test_examples.py +++ b/tests/unit/test_examples.py @@ -41,12 +41,28 @@ def test_bdm(): if do_cleanup: os.system('rm {}/bdm'.format(cpp_path)) - -def test_Gauss(): +def test_gauss(): m = gauss.get_model() rej = elfi.Rejection(m, m['d'], batch_size=10) rej.sample(20) +def test_gauss_1d_mean(): + params_true = [4] + cov_matrix = [1] + + m = gauss.get_model(true_params=params_true, nd_mean=True, cov_matrix=cov_matrix) + rej = elfi.Rejection(m, m['d'], batch_size=10) + rej.sample(20) + + +def test_gauss_2d_mean(): + params_true = [4, 4] + cov_matrix = [[1, .5], [.5, 1]] + + m = gauss.get_model(true_params=params_true, nd_mean=True, cov_matrix=cov_matrix) + rej = elfi.Rejection(m, m['d'], batch_size=10) + rej.sample(20) + def test_Ricker(): m = ricker.get_model() From c804b94adc3cec3f11d273f5cf39709038cc8bc8 Mon Sep 17 00:00:00 2001 From: Henri Vuollekoski Date: Thu, 28 Sep 2017 13:31:47 +0300 Subject: [PATCH 5/6] Restrict networkX to <2.0 for now (#241) --- CHANGELOG.rst | 3 ++- README.md | 3 +++ docs/installation.rst | 3 +++ requirements.txt | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3ac6b4e3..24a3face 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,8 +4,9 @@ Changelog dev --- -- Furhther performance improvements for rerunning inference using stored data via caches +- Further performance improvements for rerunning inference using stored data via caches - Added the general Gaussian noise example model (fixed covariance) +- restrict NetworkX to versions < 2.0 0.6.2 (2017-09-06) ------------------ diff --git a/README.md b/README.md index 1a990bba..b4e13611 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ **Version 0.6.2 released!** See the CHANGELOG and [notebooks](https://github.com/elfi-dev/notebooks). +**NOTE:** For the time being NetworkX 2 is incompatible with ELFI. + ELFI - Engine for Likelihood-Free Inference =========================================== @@ -80,6 +82,7 @@ Resolving these may sometimes go wrong: - On OS X with Anaconda virtual environment say `conda install python.app` and then use `pythonw` instead of `python`. - Note that ELFI requires Python 3.5 or greater so try `pip3 install elfi`. +- Make sure your Python installation meets the versions listed in `requirements.txt`. Citation diff --git a/docs/installation.rst b/docs/installation.rst index a4ae1ec7..bd5e6b73 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -53,6 +53,9 @@ Resolving these may sometimes go wrong: * On OS X with Anaconda virtual environment say `conda install python.app` and then use `pythonw` instead of `python`. * Note that ELFI requires Python 3.5 or greater * In some environments ``pip`` refers to Python 2.x, and you have to use ``pip3`` to use the Python 3.x version +* Make sure your Python installation meets the versions listed in requirements_. + +.. _requirements: https://github.com/elfi-dev/elfi/blob/dev/requirements.txt Developer installation from sources ----------------------------------- diff --git a/requirements.txt b/requirements.txt index e1fe765a..113bf97c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy>=1.12.1 scipy>=0.19 matplotlib>=1.1 GPy>=1.0.9 -networkX>=1.11 +networkX>=1.11,<2.0 ipyparallel>=6 toolz>=0.8 scikit-learn>=0.18.1 From 077308b9a7413457c5460bd7b944504d0d1ad95a Mon Sep 17 00:00:00 2001 From: Henri Vuollekoski Date: Thu, 28 Sep 2017 15:33:31 +0300 Subject: [PATCH 6/6] Release 0.6.3 (#242) * Release 0.6.3 * Bump version in CHANGELOG --- CHANGELOG.rst | 4 ++-- README.md | 2 +- elfi/__init__.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 24a3face..e3fc4d70 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,8 @@ Changelog ========= -dev ---- +0.6.3 (2017-09-28) +------------------ - Further performance improvements for rerunning inference using stored data via caches - Added the general Gaussian noise example model (fixed covariance) diff --git a/README.md b/README.md index b4e13611..cf23be66 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -**Version 0.6.2 released!** See the CHANGELOG and [notebooks](https://github.com/elfi-dev/notebooks). +**Version 0.6.3 released!** See the CHANGELOG and [notebooks](https://github.com/elfi-dev/notebooks). **NOTE:** For the time being NetworkX 2 is incompatible with ELFI. diff --git a/elfi/__init__.py b/elfi/__init__.py index ef2fa9f9..c1b61669 100644 --- a/elfi/__init__.py +++ b/elfi/__init__.py @@ -23,4 +23,4 @@ __email__ = 'elfi-support@hiit.fi' # make sure __version_ is on the last non-empty line (read by setup.py) -__version__ = '0.6.2' +__version__ = '0.6.3'