예제 #1
0
    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)
예제 #3
0
    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)
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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