Exemplo n.º 1
0
def operations_dict_from_name(mod_name):
    constituents = model_building_utilities.get_constituent_names_from_name(
        mod_name)
    num_qubits = model_building_utilities.get_num_qubits(mod_name)
    initial_t_str = ""
    all_terms = []
    for j in range(num_qubits - 1):
        initial_t_str += "T"

    for i in range(len(constituents)):
        t_str = initial_t_str
        single_term = constituents[i]
        all_tuples_this_term = []
        n_minus_1_qubit_operators = single_term
        for k in range(num_qubits):
            if len(t_str) > 0:
                split_by_nth_qubit = n_minus_1_qubit_operators.split(t_str)
                this_tuple = (num_qubits - k, split_by_nth_qubit[1])
                n_minus_1_qubit_operators = split_by_nth_qubit[0]
                t_str = t_str[:-1]
            else:
                this_tuple = (num_qubits - k, n_minus_1_qubit_operators)

            all_tuples_this_term.append(this_tuple)

        all_tuples_this_term = sorted(all_tuples_this_term)
        all_terms.append(all_tuples_this_term)

    operations = {"dim": num_qubits, "terms": all_terms}

    return operations
Exemplo n.º 2
0
def increase_dimension_pauli_set(initial_model, new_dimension=None):
    individual_terms = model_building_utilities.get_constituent_names_from_name(
        initial_model)
    separate_terms = []

    for model in individual_terms:
        components = model.split("_")

        for c in components:
            if c[0] == "d":
                current_dim = int(c.replace("d", ""))
                components.remove(c)

        if new_dimension is None:
            new_dimension = current_dim + 1
        new_component = "d{}".format(new_dimension)
        components.append(new_component)
        new_mod = "_".join(components)
        separate_terms.append(new_mod)

    p_str = "P" * (new_dimension)
    full_model = p_str.join(separate_terms)
    # full_model = '+'.join(separate_terms)

    return full_model
Exemplo n.º 3
0
    def check_model_validity(self, model, **kwargs):
        # possibility that some models not valid; not needed by default but
        # checked for general case
        terms = model_building_utilities.get_constituent_names_from_name(model)

        if np.all(["FHhop" in a for a in terms]):
            return True
        elif np.all(["FHonsite" in a for a in terms]):
            # onsite present in all terms: discard
            # self.log_print(
            #     ["Rejecting model", model, "b/c all onsite terms"]
            # )
            return False
        else:
            hopping_sites = []
            number_term_sites = []
            chemical_sites = []
            num_sites = model_building_utilities.get_num_qubits(model)
            for term in terms:
                constituents = term.split("_")
                constituents.remove("d{}".format(num_sites))
                if "FHhop" in term:
                    constituents.remove("FHhop")
                    for c in constituents:
                        if "h" in c:
                            hopping_sites.extend(c.split("h"))
                elif "FHonsite" in term:
                    constituents.remove("FHonsite")
                    number_term_sites.extend(constituents)
                elif "FHchemical" in term:
                    constituents.remove("FHchemical")
                    chemical_sites.extend(constituents)

            #         print("hopping_sites:", hopping_sites)
            #         print('number term sites:', number_term_sites)
            hopping_sites = set(hopping_sites)
            number_term_sites = set(number_term_sites)
            overlap = number_term_sites.intersection(hopping_sites)

            if number_term_sites.issubset(hopping_sites):
                return True
            else:
                # no overlap between hopping sites and number term sites
                # so number term will be constant
                self.log_print(
                    [
                        "Rejecting model",
                        model,
                        "bc number terms present"
                        "which aren't present in kinetic term",
                    ]
                )
                return False
Exemplo n.º 4
0
def uniform_prior(
        model_name,
        param_minimum=0,
        param_maximum=1,
        default_sigma=None,
        random_mean=False,  # if set to true, chooses a random mean between given uniform min/max
        prior_specific_terms={},
        log_file="qmd.log",
        log_identifier=None,
        **kwargs):

    individual_terms = model_building_utilities.get_constituent_names_from_name(
        model_name)
    num_terms = len(individual_terms)
    available_specific_terms = list(prior_specific_terms.keys())

    u = [[param_minimum, param_maximum]] * num_terms
    u = np.array(u)
    dist = qinfer.UniformDistribution(u)
    return dist
Exemplo n.º 5
0
    def add_terms_greedy(
            self,
            models_to_build_on,
            available_terms,
            model_names_ids,
            # model_points,
            **kwargs):
        # models_to_build_on = [
        #     kwargs['model_names_ids'][mod_id] for mod_id in models_to_build_on
        # ]
        self.log_print([
            "[Greedy add terms] models to build on {}".format(
                models_to_build_on)
        ])
        new_models = []
        models_by_parent = {}
        for mod_id in models_to_build_on:
            mod_name = model_names_ids[mod_id]
            models_by_parent[mod_id] = 0
            mod_name = self.match_dimension(mod_name,
                                            self.topology.num_sites())
            present_terms = model_building_utilities.get_constituent_names_from_name(
                mod_name)
            terms_to_add = list(set(available_terms) - set(present_terms))

            if len(terms_to_add) == 0:
                # this dimension exhausted
                # return branch champs for this generation so far
                # such that final branch computes this generation champion
                self.spawn_stage.append("finish_generation")
                new_models = [
                    self.generation_champs[self.generation_DAG][k] for k in
                    list(self.generation_champs[self.generation_DAG].keys())
                ]
                new_models = flatten(new_models)
                # new_models = [new_models[0]] # hack to force non-crash for
                # single generation
                self.log_print([
                    "No remaining available terms. Completing generation",
                    self.generation_DAG,
                    "\nSub generation champion models:",
                    new_models,
                ])
                if self.generation_DAG == self.max_num_generations:
                    # this was the final generation to learn.
                    # instead of building new generation, skip straight to
                    # Complete stage
                    self.log_print(["Completing exploration strategy"])
                    self.spawn_stage.append("Complete")
            else:
                for term in terms_to_add:
                    new_mod = self.combine_terms(terms=[mod_name, term])
                    if self.determine_whether_to_include_model(mod_id) == True:
                        new_models.append(new_mod)
                        self.models_accepted[self.generation_DAG].append(
                            new_mod)
                        models_by_parent[mod_id] += 1
                    else:
                        self.models_rejected[self.generation_DAG].append(
                            new_mod)
        self.log_print(
            ["# models added by parent: {}".format(models_by_parent)])
        return new_models
Exemplo n.º 6
0
    def generate_models(self, model_list, **kwargs):
        if self.spawn_stage[-1] == "Start":
            new_models = self.available_mods_by_generation[self.generation_DAG]
            # self.log_print(["Spawning initial models:", new_models])
            self.spawn_stage.append(None)

        else:
            # model_points = kwargs['branch_model_points']
            ranked_model_list = self.model_group_fitness_calculation(
                model_points=kwargs["branch_model_points"],
                generation=self.generation_DAG,
                subgeneration=self.sub_generation_idx,
            )

            if self.num_top_models_to_build_on == "all":
                models_to_build_on = ranked_model_list
            else:
                models_to_build_on = ranked_model_list[:self.
                                                       num_top_models_to_build_on]

            self.sub_generation_idx += 1
            self.generation_champs[self.generation_DAG][
                self.sub_generation_idx] = [
                    kwargs["model_names_ids"][models_to_build_on[0]]
                ]
            self.counter += 1
            new_models = []

            if self.spawn_stage[-1] == "finish_generation":
                # increase generation idx; add site; get newly available terms;
                # add greedily as above
                self.new_generation()

            if self.spawn_stage[-1] is None:
                # new models given by models_to_build_on plus terms in
                # available_terms (greedy)
                new_models = self.add_terms_greedy(
                    models_to_build_on=models_to_build_on,
                    available_terms=self.available_mods_by_generation[
                        self.generation_DAG],
                    model_names_ids=kwargs["model_names_ids"],
                    # model_points=model_points
                )

        new_models = [
            model_building_utilities.alph(mod) for mod in new_models
            # Final check whether this model is allowed
            if self.check_model_validity(mod)
        ]
        # store branch idx for new models

        registered_models = list(self.model_branches.keys())
        for model in new_models:
            if model not in registered_models:
                latex_model_name = self.latex_name(model)
                branch_id = self.generation_DAG + len(
                    model_building_utilities.get_constituent_names_from_name(
                        model))
                self.model_branches[latex_model_name] = branch_id

        return new_models
Exemplo n.º 7
0
    def terms_names(self):
        """
        List of constituent operators names.
        """

        return get_constituent_names_from_name(self.name)
Exemplo n.º 8
0
def plot_learned_models_dynamics(
    qmd,
    model_ids=None,
    include_expec_vals=True,
    include_bayes_factors=True,
    include_times_learned=True,
    include_param_estimates=False,
    save_to_file=None,
):

    model_ids = list(sorted(set(model_ids)))  # only uniques values
    true_expec_vals = pickle.load(
        open(qmd.qmla_controls.system_measurements_file, "rb")
    )
    times_to_plot = list(sorted(true_expec_vals.keys()))

    # TODO this is overwritten within for loop below so that large
    # Hamiltonians don't have to work out each time step
    true_exp = [true_expec_vals[t] for t in times_to_plot]
    qmd.log_print(
        [
            "[Dynamics plot] plot probe file:",
            qmd.qmla_controls.probes_plot_file,
            "\n true expectation value path:",
            qmd.qmla_controls.system_measurements_file,
        ]
    )
    plot_probes = pickle.load(open(qmd.qmla_controls.probes_plot_file, "rb"))
    num_models_to_plot = len(model_ids)
    all_bayes_factors = qmd.all_bayes_factors
    max_time = max(times_to_plot)
    individual_terms_already_in_legend = []

    #     ncols = int(np.ceil(np.sqrt(num_models_to_plot)))
    # nrows = 3*int(np.ceil(num_models_to_plot/ncols)) + 1 # 1 extra row for
    # "master"

    ncols = (
        include_expec_vals
        + include_bayes_factors
        + include_times_learned
        + include_param_estimates
    )
    #     ncols = 4
    nrows = num_models_to_plot

    fig = plt.figure(
        figsize=(18, 10),
        # constrained_layout=True,
        tight_layout=True,
    )
    gs = GridSpec(
        nrows,
        ncols,
        # figure=fig # not available on matplotlib 2.1.1 (on BC)
    )

    row = 0
    col = 0

    for mod_id in model_ids:
        qmd.log_print(["Plotting dynamics for model {}".format(mod_id)])
        reduced = qmd.get_model_storage_instance_by_id(mod_id)
        reduced.compute_expectation_values(times=qmd.times_to_plot)
        #         exploration_rule = reduced.exploration_strategy_of_true_model
        desc = str("ID:{}\n".format(mod_id) + reduced.model_name_latex)
        times_to_plot = list(sorted(true_expec_vals.keys()))
        plot_colour = "blue"
        name_colour = "black"
        dynamics_label = str(mod_id)
        try:
            true_model_id = qmd.true_model_id
        except BaseException:
            true_model_id = -1
        if mod_id == qmd.champion_model_id and mod_id == true_model_id:
            plot_colour = "green"
            name_colour = "green"
            dynamics_label += " [true + champ]"
            desc += str("\n[True + Champ]")
        elif mod_id == qmd.champion_model_id:
            plot_colour = "orange"
            name_colour = "orange"
            dynamics_label += " [champ]"
            desc += str("\n[Champ]")
        elif mod_id == true_model_id:
            plot_colour = "green"
            name_colour = "green"
            dynamics_label += " [true]"
            desc += str("\n[True]")

        ############ --------------- ############
        ############ Plot dynamics in left most column ############
        ############ --------------- ############
        if include_expec_vals is True:
            ham = reduced.learned_hamiltonian
            dim = np.log2(np.shape(ham)[0])
            probe = plot_probes[reduced.probe_num_qubits]
            qmd.log_print(
                [
                    "[plot_learned_models_dynamics]",
                    "\n\tModel ",
                    reduced.model_name_latex,
                    "\n\tnum qubits:",
                    dim,
                    "\n\tprobe:",
                    probe,
                ]
            )
            # expec_vals = {}
            if dim > 4:
                times_to_plot = times_to_plot[0::5]

            times_to_plot = sorted(list(true_expec_vals.keys()))
            true_exp = [true_expec_vals[t] for t in times_to_plot]

            # choose an axis to plot on
            ax = fig.add_subplot(gs[row, col])
            # first plot true dynamics
            ax.plot(times_to_plot, true_exp, c="r")

            # now plot learned dynamics
            expec_vals = reduced.expectation_values
            sim_times = sorted(list(expec_vals.keys()))
            sim_exp = [expec_vals[t] for t in sim_times]

            # print(
            #     "[plotDynamics]",
            #     "\nsim exp:", sim_exp,
            #     "\nsim_times:", sim_times
            # )
            ax.plot(
                sim_times,
                sim_exp,
                marker="o",
                markevery=10,
                c=plot_colour,
                # label = dynamics_label
                label=desc,
            )
            # qmd.log_print([
            #     "[Dynamics plot]",
            #     "sim_exp:", sim_exp[0:20],
            #     "true exp:", true_exp[0:20]
            # ])
            #         ax.legend()
            ax.set_ylim(-0.05, 1.05)

            if row == 0:
                ax.set_title("Expectation Values")
            if ncols == 1:
                ax.legend()

            col += 1
            if col == ncols:
                col = 0
                row += 1
        ############ --------------- ############
        ############ Plot Bayes factors ############
        ############ --------------- ############
        if include_bayes_factors == True:
            bayes_factors_this_mod = []
            bf_opponents = []
            for b in model_ids:
                if b != mod_id:
                    if b in list(all_bayes_factors[mod_id].keys()):
                        # bf_opponents.append(
                        #     qmd.get_model_storage_instance_by_id(b).model_name_latex
                        # )
                        bayes_factors_this_mod.append(
                            np.log10(all_bayes_factors[mod_id][b][-1])
                        )
                        bf_opponents.append(str(b))
            ax = fig.add_subplot(gs[row, col])
            ax.bar(bf_opponents, bayes_factors_this_mod, color=plot_colour)
            ax.axhline(0, color="black")
            if row == 0:
                ax.set_title("Bayes Factors [$log_{10}$]")

            col += 1
            if col == ncols:
                col = 0
                row += 1
        ############ --------------- ############
        ############ Plot times learned over ############
        ############ --------------- ############
        if include_times_learned == True:
            ax = fig.add_subplot(gs[row, col])
            if row == 0:
                ax.set_title("Times learned")
            ax.yaxis.set_label_position("right")

            times_learned_over = sorted(
                qmla.utilities.flatten(reduced.times_learned_over)
            )
            qmd.log_print(["[single instance plot] Times for bin:", times_learned_over])
            n, bins, patches = ax.hist(
                times_learned_over,
                # histtype='step',
                color=plot_colour,
                # fill=False,
                label=desc,
            )
            ax.legend()
            # ax.semilogy()
            for bin_value in bins:
                ax.axvline(bin_value, linestyle="--", alpha=0.3)
            plot_time_max = max(times_to_plot)
            max_time = max(times_learned_over)
            if max_time > plot_time_max:
                ax.axvline(
                    plot_time_max,
                    color="red",
                    linestyle="--",
                    label="Dynamics plot cutoff",
                )
                ax.legend()
            ax.set_xlim(0, max_time)

            col += 1
            if col == ncols:
                col = 0
                row += 1

        ############ --------------- ############
        ############ Plot parameters estimates ############
        ############ --------------- ############
        if include_param_estimates == True:
            ax = fig.add_subplot(gs[row, col])
            name = reduced.model_name
            terms = model_building_utilities.get_constituent_names_from_name(name)
            num_terms = len(terms)

            term_positions = {}
            param_estimate_by_term = {}
            std_devs = {}

            for t in range(num_terms):
                term_positions[terms[t]] = t
                term = terms[t]
                param_position = term_positions[term]
                param_estimates = reduced.track_param_means[:, param_position]
                # std_dev = mod.cov_matrix[param_position,param_position]
                # std_dev = reduced.track_covariance_matrices[
                #     :,param_position,param_position
                # ]
                std_dev = reduced.track_param_uncertainties[:, param_position]
                param_estimate_by_term[term] = param_estimates
                std_devs[term] = std_dev

            cm_subsection = np.linspace(0, 0.8, num_terms)
            colours = [cm.magma(x) for x in cm_subsection]
            # TODO use color map as list
            num_epochs = reduced.num_experiments

            i = 0
            #    for term in list(param_estimate_by_term.keys()):
            for term in terms:
                colour = colours[i % len(colours)]
                i += 1
                try:
                    y_true = qmd.true_param_dict[term]
                    true_term_latex = qmd.exploration_class.latex_name(name=term)

                    ax.axhline(
                        y_true,
                        ls="--",
                        label=str(true_term_latex + " True"),
                        color=colour,
                    )
                except BaseException:
                    pass
                y = np.array(param_estimate_by_term[term])
                s = np.array(std_devs[term])
                x = range(1, 1 + len(param_estimate_by_term[term]))
                latex_term = qmd.exploration_class.latex_name(name=term)
                if latex_term not in individual_terms_already_in_legend:
                    individual_terms_already_in_legend.append(latex_term)
                    plot_label = str(latex_term)
                else:
                    plot_label = ""
                # print("[pQMD] latex_term:", latex_term)
                ax.plot(
                    x,
                    y,
                    #                 s=max(1,50/num_epochs),
                    label=plot_label,
                    color=colour,
                )
                #        ax.set_yscale('symlog')
                # print("[pQMD] scatter done" )
                #             ax.fill_between(
                #                 x,
                #                 y+s,
                #                 y-s,
                #                 alpha=0.2,
                #                 facecolor=colour
                #             )

                ax.legend()
            if row == 0:
                ax.set_title("Parameter Estimates")

            col += 1
            if col == ncols:
                col = 0
                row += 1
    if save_to_file is not None:
        plt.savefig(save_to_file, bbox_inches="tight")
Exemplo n.º 9
0
def plot_parameter_estimates(qmd, model_id, save_to_file=None):
    from matplotlib import cm

    mod = qmd.get_model_storage_instance_by_id(model_id)
    name = mod.model_name

    if name not in list(qmd.model_name_id_map.values()):
        print(
            "True model ",
            name,
            "not in studied models",
            list(qmd.model_name_id_map.values()),
        )
        return False
    terms = model_building_utilities.get_constituent_names_from_name(name)
    num_terms = len(terms)

    term_positions = {}
    param_estimate_by_term = {}
    std_devs = {}

    for t in range(num_terms):
        term_positions[terms[t]] = t
        term = terms[t]
        param_position = term_positions[term]
        param_estimates = mod.track_param_means[:, param_position]
        # std_dev = mod.cov_matrix[param_position,param_position]
        std_dev = mod.track_covariance_matrices[:, param_position, param_position]
        param_estimate_by_term[term] = param_estimates
        std_devs[term] = std_dev

    cm_subsection = np.linspace(0, 0.8, num_terms)
    colours = [cm.magma(x) for x in cm_subsection]
    # TODO use color map as list
    num_epochs = mod.num_experiments
    ncols = int(np.ceil(np.sqrt(num_terms)))
    nrows = int(np.ceil(num_terms / ncols))
    fig, axes = plt.subplots(figsize=(10, 7), nrows=nrows, ncols=ncols, squeeze=False)
    row = 0
    col = 0
    axes_so_far = 0
    i = 0
    #    for term in list(param_estimate_by_term.keys()):
    for term in terms:
        ax = axes[row, col]
        colour = colours[i % len(colours)]
        i += 1
        try:
            y_true = qmd.true_param_dict[term]
            true_term_latex = qmd.exploration_class.latex_name(name=term)
            true_term_latex = true_term_latex[:-1] + "_{0}" + "$"

            ax.axhline(y_true, label=str(true_term_latex), color="red", linestyle="--")
        except BaseException:
            pass
        y = np.array(param_estimate_by_term[term])
        s = np.array(std_devs[term])
        x = range(1, 1 + len(param_estimate_by_term[term]))
        latex_term = mod.exploration_class.latex_name(term)
        latex_term = latex_term[:-1] + r"^{\prime}" + "$"
        # print("[pQMD] latex_term:", latex_term)
        ax.scatter(x, y, s=max(1, 50 / num_epochs), label=str(latex_term), color=colour)
        #        ax.set_yscale('symlog')
        # print("[pQMD] scatter done" )
        ax.fill_between(
            x,
            y + s,
            y - s,
            alpha=0.2,
            facecolor="green",
            # label='$\sigma$'
        )
        # print("[pQMD] fill between done")
        ax.legend(loc=1, fontsize=20)
        axes_so_far += 1
        col += 1
        if col == ncols:
            col = 0
            row += 1
        # ax.set_title(str(latex_term))
        # print("[pQMD] title set")

    #    ax = plt.subplot(111)
    plt.xlabel("Epoch", fontsize=20)
    plt.ylabel("Parameter Estimate", fontsize=15)

    if save_to_file is not None:
        print(
            "[plot_parameter_estimates] saving to file",
            save_to_file,
            "type:",
            type(save_to_file),
        )
        plt.savefig(save_to_file, bbox_inches="tight")
Exemplo n.º 10
0
def gaussian_prior(
        model_name,
        param_minimum=0,
        param_maximum=1,
        default_sigma=None,
        random_mean=False,  # if set to true, chooses a random mean between given uniform min/max
        prior_specific_terms={},
        log_file="qmd.log",
        log_identifier=None,
        **kwargs):
    """
    Genearates a QInfer Gaussian distribution .

    Given a model_name, deteremines the number of terms in the model, N.
    Generates a multivariate distribution with N dimensions.
    This is then used as the initial prior, which QHL uses to learn the
    model parameters.
    By default, each parameter's mean is the average of param_min and param_max,
    with sigma = mean/4. This can be changed by specifying prior_specific_terms:
        individual parameter's means/sigmas can be given.

    :param str model_name: Unique string representing a model.
    :param float param_minimum: Lower bound for distribution.
    :param float param_maximum: Upper bound for distribution.
    :param float default_sigma: Width of distribution desired. If None,
        defaults to 0.25 * (param_max - param_min).
    :param dict prior_specific_terms: Individual parameter mean and sigma
        to enforce in the distribution.
    :param str log_file: Path of the log file for logging errors.
    :param str log_identifier: Unique identifying sting for logging.
    :return QInfer.Distribution dist: distribution to be used as prior for parameter learning
        of the named model.
    """

    log_print(
        [
            "Getting prior for model:",
            model_name,
            "Specific terms:",
            prior_specific_terms,
        ],
        log_file,
        log_identifier,
    )
    individual_terms = model_building_utilities.get_constituent_names_from_name(
        model_name)
    num_terms = len(individual_terms)
    available_specific_terms = list(prior_specific_terms.keys())
    means = []
    sigmas = []
    default_mean = np.mean([param_minimum, param_maximum])
    # TODO reconsider how default sigma is generated
    # default_sigma = default_mean/2 # TODO is this safe?
    if default_sigma is None:
        default_sigma = (param_maximum - param_minimum) / 4
    for term in individual_terms:
        if term in available_specific_terms:
            means.append(prior_specific_terms[term][0])
            sigmas.append(prior_specific_terms[term][1])
        else:
            if random_mean:
                rand_mean = random.uniform(param_minimum, param_maximum)
                means.append(rand_mean)
            else:
                means.append(default_mean)
            sigmas.append(default_sigma)

    means = np.array(means)
    sigmas = np.array(sigmas)
    cov_mtx = np.diag(sigmas**2)
    dist = qinfer.MultivariateNormalDistribution(means, cov_mtx)

    return dist