def _simulate(algorithm, ij_tuple, seeds, path): """ Run a number of monte carlo simulations in a single delta-rho point. The result of a simulation is the simulation error distance, i.e., the ratio between the energy of the coefficient residual and the energy of the coefficient vector. The time of the simulation is the execution time of the reconstruction attempt. Parameters ---------- algorithm : function A function handle to the reconstruction algorithm. ij_tuple : tuple A tuple (i, j) containing the parameters i, j as listed below. i : int The delta-index of the point in the delta-rho grid. j : int The rho-index of the point in the delta-rho grid. seeds : ndarray The seeds to pass to numpy.random when generating the problem suite instances. path : str The path of the HDF5 backup database. See Also -------- magni.cs.phase_transition._data.generate_matrix : Matrix generation. magni.cs.phase_transition._data.generate_vector : Coefficient vector generation. """ i, j = ij_tuple n = _config.get('n') m = int(np.round(n * _config.get('delta')[i])) k = int(np.round(m * _config.get('rho')[j])) stat_time = np.zeros(_config.get('monte_carlo'), dtype=np.float64) stat_dist = stat_time.copy() if k > 0: for l in range(_config.get('monte_carlo')): np.random.seed(seeds[l]) A = _data.generate_matrix(m, n) x = _data.generate_vector(n, k) y = A.dot(x) start = time.time() x_hat = algorithm(y, A) end = time.time() x_res = x_hat - x stat_time[l] = end - start stat_dist[l] = (np.linalg.norm(x_res) / np.linalg.norm(x))**2 _backup.set(path, (i, j), stat_time, stat_dist)
def run(algorithm, path, label): """ Simulate a reconstruction algorithm. The simulation results are stored in a HDF5 database rather than returned by the function. Parameters ---------- algorithm : function A function handle to the reconstruction algorithm. path : str The path of the HDF5 database where the results should be stored. label : str The label assigned to the simulation results. """ tmp_dir = _split_path(path)[0] + '.tmp' + os.sep tmp_file = tmp_dir + label.replace('/', '#') + '.hdf5' if not os.path.isdir(tmp_dir): os.mkdir(tmp_dir) if not os.path.isfile(tmp_file): _backup.create(tmp_file) done = _backup.get(tmp_file) shape = _config.get() shape = [len(shape['delta']), len(shape['rho']), shape['monte_carlo']] np.random.seed(_config.get('seed')) seeds = np.random.randint(0, 2**30, shape) tasks = [(algorithm, (i, j), seeds[i, j], tmp_file) for i in range(shape[0]) for j in range(shape[1]) if not done[i, j]] _process(_simulate, args_list=tasks) with _File(tmp_file, 'r') as f: stat_time = f.root.time[:] stat_dist = f.root.dist[:] with _File(path, 'a') as f: f.create_array('/' + label, 'time', stat_time, createparents=True) f.create_array('/' + label, 'dist', stat_dist, createparents=True) os.remove(tmp_file) if len(os.listdir(tmp_dir)) == 0: os.removedirs(tmp_dir)
def create(path): """ Create the HDF5 backup database with the required arrays. The required arrays are an array for the simulation results, an array for the simulation timings, and an array for tracking the status. Parameters ---------- path : str The path of the HDF5 backup database. See Also -------- magni.cs.phase_transition.config : Configuration options. """ shape = [_config.get(key) for key in ["delta", "rho", "monte_carlo"]] shape = [len(shape[0]), len(shape[1]), shape[2]] time = dist = np.zeros(shape) status = np.zeros(shape[:2], np.bool8) try: with _File(path, "w") as f: f.create_array("/", "time", time) f.create_array("/", "dist", dist) f.create_array("/", "status", status) except BaseException as e: if os.path.exists(path): os.remove(path) raise e
def run(path, label): """ Determine the phase transition from the simulation results. The simulation results should be present in the HDF5 database specified by `path` in the pytables group specified by `label` in an array named 'dist'. The determined phase transition is stored in the same HDF5 database, in the same pytables group in an array named 'phase_transition'. Parameters ---------- path : str The path of the HDF5 database. label : str The path of the pytables group in the HDF5 database. See Also -------- _estimate_PT : The actual phase transition estimation. Notes ----- A simulation is considered successful if the simulation result is less than 10 to the power of -4. """ _conf = _config.get() with _File(path, 'a') as f: if not '/' + label + '/phase_transition' in f: points = len(_conf['rho']) * _conf['monte_carlo'] z = np.zeros(points) y = np.zeros(points) rho = np.zeros(len(_conf['delta'])) dist = f.get_node('/' + label + '/dist')[:] for i in range(len(_conf['delta'])): n = np.round(_conf['delta'][i] * _conf['n']) for j in range(len(_conf['rho'])): if n > 0: var = _conf['rho'][j] var = np.round(var * n) / n else: var = 0. for m in range(_conf['monte_carlo']): z[j * _conf['monte_carlo'] + m] = var y[j * _conf['monte_carlo'] + m] = dist[i, j, m] < 1e-4 rho[i] = _estimate_PT(z, y) f.create_array('/' + label, 'phase_transition', rho)
def generate_vector(n, k): """ Generate a vector belonging to a specific problem suite. The available ensembles are the Gaussian ensemble and the Rademacher ensemble. See Notes for a description of the ensembles. Which of the available ensembles is used, is specified as a configuration option. Note, that the non-zero `k` non-zero coefficients are the `k` first entries. Parameters ---------- n : int The length of the vector. k : int The number of non-zero coefficients. Returns ------- alpha : ndarray The generated vector. See Also -------- magni.cs.phase_transition.config : Configuration options. Notes ----- The Gaussian ensemble : The non-zero coefficients are drawn from the normal Gaussian distribution. The Rademacher ensemble: The non-zero coefficients are drawn from the constant amplitude with random signs ensemble. """ x = np.zeros((n, 1)) coefficients = _config.get('coefficients') if coefficients == 'rademacher': x[:k, 0] = np.random.randint(0, 2, k) * 2 - 1 elif coefficients == 'gaussian': x[:k, 0] = np.random.randn(k) return x