def set_measurements(self, seed=None): # random trajectory and anchors self.traj.set_coeffs(seed=seed) if seed is not None: np.random.seed(seed) self.anchors = create_anchors(self.traj.dim, self.n_anchors) # get measurements self.basis, self.D_topright = get_measurements(self.traj, self.anchors, seed=seed, n_samples=20)
def test_dimensions(self): n_anchors = 3 n_constrains = 5 n_positions = 13 ind_a = [0] * 8 ind_b = ind_a anchors = m.create_anchors(2, n_anchors, check=True) frame = get_frame(n_constrains, n_positions) self.assertEqual((len(ind_a), (anchors.shape[0] + 1) * n_constrains), get_left_submatrix(ind_a, ind_b, anchors, frame).shape)
def test_f_multidim(self): from trajectory import Trajectory from measurements import get_measurements, create_anchors anchors = create_anchors(dim=2, n_anchors=5) trajectory = Trajectory(n_complexity=4, dim=2) basis, D_topright = get_measurements(trajectory, anchors, n_samples=10) eps = 1e-10 self.assertTrue(np.all(abs(f_multidim(anchors, basis, D_topright, trajectory.coeffs)) < eps)) self.assertTrue(abs(f_onedim(anchors, basis, D_topright, trajectory.coeffs)) < eps) coeffs_hat = np.squeeze(compute_exact(D_topright, anchors, basis)) np.testing.assert_allclose(coeffs_hat, trajectory.coeffs)
def matrix_rank_experiment(n_dimensions, n_constraints, n_times, n_repetitions, full_matrix, n_anchors_list, one_per_time=False): """Run simulations to estimate probability of matrix being full rank for different number of measurements :param n_dimensions: number of dimensions :param n_constraints: number of constrains / degrees of freedom of the trajectory :param n_times: number of positions at which measurements are taken :param n_repetitions: number of runs with the same parameters :param full_matrix: if True simulate the whole matrix, otherwise only the left part :param n_anchors_list: list of numbers of anchors to iterate over :param one_per_time: if True, number of measurements per time/position is limited to 1 """ params = locals() n_anchors_list = np.array(n_anchors_list) n_anchors_list = n_anchors_list[n_anchors_list > n_dimensions] if len(n_anchors_list) == 0: raise ValueError( 'Number of anchors must be bigger than number of dimensions') if len(n_anchors_list) < len(params["n_anchors_list"]): print( "Some numbers of anchors are smaller than number of dimensions +1: cropping anchor list" ) params["n_anchors_list"] = n_anchors_list max_measurements = (1 if one_per_time else (np.min(n_anchors_list))) * n_times + 1 params["n_measurements_list"] = list( range(n_dimensions * n_constraints, max_measurements)) ranks = np.zeros((len(params["n_measurements_list"]), len(n_anchors_list), n_repetitions)) for a_idx, n_anchors in enumerate(n_anchors_list): anchors = m.create_anchors(n_anchors=n_anchors, dim=n_dimensions, check=True) for m_idx, n_measurements in enumerate(params["n_measurements_list"]): for r in range(n_repetitions): frame = c.get_frame(n_constraints, n_times) try: idx_a, idx_f = random_indexes(n_anchors, n_times, n_measurements, one_per_time=one_per_time) if full_matrix: constraints = c.get_reduced_constraints( idx_a, idx_f, anchors, frame) else: constraints = c.get_left_submatrix(idx_a, idx_f, anchors, frame, extended=True) ranks[m_idx, a_idx, r] = np.linalg.matrix_rank(constraints) except ValueError as e: ranks[m_idx, a_idx, r] = np.NaN print(e) break params["max_rank"] = (n_dimensions + 1) * n_constraints if full_matrix: params["max_rank"] += n_constraints - 1 return ranks, params
def matrix_rank_experiment(params): """Run simulations to estimate probability of matrix being full rank for different number of measurements :param params: all parameters of the simulation, might contain: n_dimensions: number of dimensions n_constraints: number of constrains / degrees of freedom of the trajectory n_positions: number of positions at which measurements are taken n_repetitions: number of runs with the same parameters full_matrix: if True simulate the whole matrix, otherwise only the left part n_anchors_list: list of number number of anchors f one_per_time: if True, number of measurements per time/position is limited to 1 fixed_n_measurements: if present, the number of measurements is fixed, and the number of positions/times very incompatible with `one_per_time` """ n_measurements = 0 n_positions = 0 n_anchors_list = [ max(params["n_dimensions"] * n, params["n_dimensions"] + 1) for n in params["n_anchors_list"] ] params["n_anchors_list"] = n_anchors_list if 'one_per_time' not in params: params['one_per_time'] = False # prepare parameters for when the number of measurements is fixed if "fixed_n_measurements" in params: if params["one_per_time"]: warnings.warn( "It does not make sense to fix number of measurements and have only one measurement per " "time. All iterations will give the same result.") if params["fixed_n_measurements"] == 0: n_measurements = (params["n_dimensions"] + 1) * params["n_constraints"] if params["full_matrix"]: n_measurements += params["n_constraints"] - 1 params["fixed_n_measurements"] = n_measurements else: n_measurements = params["fixed_n_measurements"] params["min_positions"] = n_measurements if params[ 'one_per_time'] else int( np.ceil(n_measurements / np.min(n_anchors_list))) params["second_key"] = "m{}".format(n_measurements) second_list = list( range(params["min_positions"], params["max_positions"])) # prepare parameters for when the number of positions is fixed else: n_positions = params["n_positions"] max_measurements = (1 if params["one_per_time"] else (np.min(params["n_anchors_list"]))) * n_positions second_list = list( range(params["n_dimensions"] * params["n_constraints"], max_measurements)) params["second_key"] = "p{}".format(n_positions) params["second_list"] = second_list ranks = np.zeros( (len(second_list), len(n_anchors_list), params["n_repetitions"])) anchor_condition = np.zeros_like(ranks) frame_condition = np.zeros_like(ranks) wrong_matrices = [] for a_idx, n_anchors in enumerate(n_anchors_list): anchors = m.create_anchors(n_anchors=n_anchors, dim=params["n_dimensions"], check=True) # iterate over whatever the second parameter is (number of positions or number of measurements) for second_idx, second_param in enumerate(second_list): if "fixed_n_measurements" in params: n_positions = second_param else: n_measurements = second_param for r in range(params["n_repetitions"]): frame = get_frame(params["n_constraints"], n_positions) try: idx_a, idx_f = random_indexes( n_anchors, n_positions, n_measurements, one_per_time=params["one_per_time"]) if params["full_matrix"]: constraints = get_full_matrix(idx_a, idx_f, anchors, frame) else: constraints = get_left_submatrix( idx_a, idx_f, anchors, frame) ranks[second_idx, a_idx, r] = np.linalg.matrix_rank(constraints) measurement_matrix = indexes_to_matrix( idx_a, idx_f, n_anchors, n_positions) if limit_condition( -np.sort(-np.sum(measurement_matrix, axis=0)), params["n_constraints"], params["n_dimensions"] + 1): anchor_condition[second_idx, a_idx, r] = 1 if limit_condition( -np.sort(-np.sum(measurement_matrix, axis=1)), params["n_dimensions"] + 1, params["n_constraints"]): frame_condition[second_idx, a_idx, r] = 1 if ranks[second_idx, a_idx, r] < params["n_constraints"] * ( params["n_dimensions"] + 1): if frame_condition[second_idx, a_idx, r] * anchor_condition[second_idx, a_idx, r] == 1: wrong_matrices.append({ "constraints": constraints, "measurements": measurement_matrix, "second_idx": second_idx, "a_idx": a_idx }) except ValueError as e: ranks[second_idx, a_idx, r] = np.NaN print(e) break params["anchor_condition"] = anchor_condition params["frame_condition"] = frame_condition params["wrong_matrices"] = wrong_matrices params["max_rank"] = (params["n_dimensions"] + 1) * params["n_constraints"] if params["full_matrix"]: params["max_rank"] += params["n_constraints"] - 1 return ranks, params
def run_simulation(parameters, outfolder=None, solver=None, verbose=False): """ Run simulation. :param parameters: Can be either the name of the folder where parameters.json is stored, or a new dict of parameters. """ if type(parameters) == str: fname = parameters + 'parameters.json' parameters = read_params(fname) print('read parameters from file {}.'.format(fname)) elif type(parameters) == dict: parameters = parameters # if we are trying new parameters and saving in a directory that already exists, # we need to make sure that the saved parameters are actually the same. if outfolder is not None: try: parameters_old = read_params(outfolder + 'parameters.json') parameters['time'] = parameters_old['time'] assert parameters == parameters_old, 'found conflicting parameters file: {}'.format(outfolder + 'parameters.json') except FileNotFoundError: print('no conflicting parameters file found.') except AssertionError as error: raise (error) else: raise TypeError('parameters needs to be folder name or dictionary.') if 'noise_to_square' not in parameters: parameters['noise_to_square'] = False if 'measure_distances' not in parameters: parameters['measure_distances'] = False if 'sampling_strategy' not in parameters: parameters['sampling_strategy'] = 'uniform' complexities = parameters['complexities'] anchors = parameters['anchors'] positions = parameters['positions'] n_its = parameters['n_its'] noise_sigmas = parameters['noise_sigmas'] success_thresholds = parameters['success_thresholds'] assert len(success_thresholds) == len(noise_sigmas) if parameters['sampling_strategy'] == 'single_time': max_measurements = max(positions) else: max_measurements = max(positions) * max(anchors) successes = np.full((len(complexities), len(anchors), len(positions), len(noise_sigmas), max_measurements), np.nan) errors = np.full(successes.shape, np.nan) relative_errors = np.full(successes.shape, np.nan) absolute_errors = np.full(successes.shape, np.nan) num_not_solved = np.full(successes.shape, np.nan) num_not_accurate = np.full(successes.shape, np.nan) squared_distances = [] for c_idx, n_complexity in enumerate(complexities): print('n_complexity', n_complexity) for a_idx, n_anchors in enumerate(anchors): print('n_anchors', n_anchors) for p_idx, n_positions in enumerate(positions): print('n_positions', n_positions) if parameters['sampling_strategy'] == 'single_time': n_measurements = n_positions else: n_measurements = n_positions * n_anchors for m_idx, n_missing in enumerate(range(n_measurements)): if verbose: print('measurements idx', m_idx) for noise_idx, noise_sigma in enumerate(noise_sigmas): indexes = np.s_[c_idx, a_idx, p_idx, noise_idx, m_idx] if verbose: print("noise", noise_sigma) # set all values to 0 since we have visited them. if np.isnan(successes[indexes]): successes[indexes] = 0.0 if np.isnan(num_not_solved[indexes]): num_not_solved[indexes] = 0.0 if np.isnan(num_not_accurate[indexes]): num_not_accurate[indexes] = 0.0 for _ in range(n_its): trajectory = Trajectory(n_complexity, dim=DIM) anchors_coord = create_anchors(DIM, n_anchors) trajectory.set_coeffs(seed=None) basis, D_topright = get_measurements(trajectory, anchors_coord, n_samples=n_positions) distances = np.sqrt(D_topright) D_topright = add_noise(D_topright, noise_sigma, parameters["noise_to_square"]) mask = create_mask(n_positions, n_anchors, strategy=parameters['sampling_strategy'], n_missing=n_missing) if parameters['measure_distances']: squared_distances.extend(D_topright.flatten().tolist()) D_topright = np.multiply(D_topright, mask) try: assert p.full_rank_condition( np.sort(np.sum(mask, axis=0))[::-1], DIM + 1, n_complexity), "insufficient rank" if (solver is None) or (solver == "semidef_relaxation_noiseless"): X = semidef_relaxation_noiseless(D_topright, anchors_coord, basis, chosen_solver=cvxpy.CVXOPT) P_hat = X[:DIM, DIM:] elif solver == 'trajectory_recovery': P_hat = trajectory_recovery(D_topright, anchors_coord, basis) elif solver == 'weighted_trajectory_recovery': P_hat = trajectory_recovery(D_topright, anchors_coord, basis, weighted=True) else: raise ValueError(solver) # calculate reconstruction error with respect to distances trajectory_estimated = Trajectory(coeffs=P_hat) _, D_estimated = get_measurements(trajectory_estimated, anchors_coord, n_samples=n_positions) estimated_distances = np.sqrt(D_estimated) robust_add(errors, indexes, np.linalg.norm(P_hat - trajectory.coeffs)) robust_add(relative_errors, indexes, np.linalg.norm((distances - estimated_distances) / (distances + 1e-10))) robust_add(absolute_errors, indexes, np.linalg.norm(distances - estimated_distances)) assert not np.linalg.norm(P_hat - trajectory.coeffs) > success_thresholds[noise_idx] robust_increment(successes, indexes) except cvxpy.SolverError: logging.info("could not solve n_positions={}, n_missing={}".format( n_positions, n_missing)) robust_increment(num_not_solved, indexes) except ZeroDivisionError: logging.info("could not solve n_positions={}, n_missing={}".format( n_positions, n_missing)) robust_increment(num_not_solved, indexes) except np.linalg.LinAlgError: robust_increment(num_not_solved, indexes) except AssertionError as e: if str(e) == "insufficient rank": robust_increment(num_not_solved, indexes) else: logging.info("result not accurate n_positions={}, n_missing={}".format( n_positions, n_missing)) robust_increment(num_not_accurate, indexes) errors[indexes] = errors[indexes] / (n_its - num_not_solved[indexes]) relative_errors[indexes] = relative_errors[indexes] / (n_its - num_not_solved[indexes]) results = { 'successes': successes, 'num-not-solved': num_not_solved, 'num-not-accurate': num_not_accurate, 'errors': errors, 'relative-errors': relative_errors, 'absolute-errors': absolute_errors, 'distances': squared_distances } if outfolder is not None: print('Done with simulation. Saving results...') parameters['time'] = time.time() if not os.path.exists(outfolder): os.makedirs(outfolder) save_params(outfolder + 'parameters.json', **parameters) save_results(outfolder + 'result_{}_{}', results) else: return results