Source code for qmla.exploration_strategies.nv_centre_spin_characterisation.nature_physics_2021.full_access_nv

from __future__ import absolute_import
import sys
import os
import random

from qmla.exploration_strategies.exploration_strategy import ExplorationStrategy
import qmla.shared_functionality.experiment_design_heuristics
from qmla.model_building_utilities import alph, get_num_qubits

__all__ = ["FullAccessNVCentre"]


[docs]class FullAccessNVCentre(ExplorationStrategy): r""" Exploration strategy for NV system described in experimental paper, assuming full access to the state so the likelihood is based on :math`\langle++ | e^{ -i\hat{H(\vec{x})} t } | ++ \rangle`. This is the base class for results presented in the experimental paper, namely Fig 2. The same model generation strategy is used in each case (i), (ii), (iii): this ES is for (i) pure simulation. """ def __init__(self, exploration_rules, **kwargs): super().__init__(exploration_rules=exploration_rules, **kwargs) # self.true_model = 'xTz' self.true_model = "xTi+yTi+zTi+zTz" self.initial_models = ["xTi", "yTi", "zTi"] self.model_heuristic_subroutine = ( qmla.shared_functionality.experiment_design_heuristics.MixedMultiParticleLinspaceHeuristic ) # self.latex_string_map_subroutine = qmla.shared_functionality.latex_model_names.nv_centre_SAT self.max_num_parameter_estimate = 9 self.max_spawn_depth = 8 self.prune_completed_initially = False self.max_num_probe_qubits = 2 self.tree_completed_initially = False self.fixed_axis_generator = False self.fixed_axis = "z" # e.g. transverse axis self.check_champion_reducibility = True self.learned_param_limit_for_negligibility = 0.05 self.reduce_champ_bayes_factor_threshold = 1e1 self.min_param = 0 self.max_param = 10 self.fraction_own_experiments_for_bf = 0.5 self.fraction_opponents_experiments_for_bf = 0 # the last half of models' training data are deterministally the same anyway self.fraction_particles_for_bf = ( 0.1 # testing whether reduced num particles for BF can work ) if self.true_model == "xTi+yTi+zTi+zTz": self.true_model_terms_params = { # from Jul_05/16_40 "xTi": 0.92450565, "yTi": 6.00664336, "zTi": 1.65998543, "zTz": 0.76546868, } else: self.true_model_terms_params = { # Decohering param set # From 3000exp/20000prt, BC SelectedRuns/Nov_28/15_14/results_049 "xTi": -0.98288958683093952, "xTx": 6.7232235286284681, "yTi": 6.4842202054983122, "yTy": 2.7377867056770397, "zTi": 0.96477790489201143, "zTz": 1.6034234519563935, "xTy": 1.5, "xTz": 7, "yTz": 2, } self.gaussian_prior_means_and_widths = { "xTi": [4.0, 1.5], "yTi": [4.0, 1.5], "zTi": [4.0, 1.5], "xTx": [4.0, 1.5], "yTy": [4.0, 1.5], "zTz": [4.0, 1.5], "xTy": [4.0, 1.5], "xTz": [4.0, 1.5], "yTz": [4.0, 1.5], } self.num_processes_to_parallelise_over = 4 self.timing_insurance_factor = 0.5 self.max_num_models_by_shape = {1: 0, 2: 18, "other": 0}
[docs] def generate_models(self, model_list, spawn_step, model_dict, **kwargs): # TODO replace with newer greedy add mechanism (as in TieredGreedySearchNVCentre) # TODO then remove model_dict from qmla's call to next_layer self.log_print(["Generating. input model list:", model_list]) single_qubit_terms = ["xTi", "yTi", "zTi"] nontransverse_terms = ["xTx", "yTy", "zTz"] transverse_terms = ["xTy", "xTz", "yTz"] all_two_qubit_terms = ( single_qubit_terms + nontransverse_terms + transverse_terms ) model = model_list[0] present_terms = model.split("+") p_str = "+" new_models = [] if spawn_step in [1, 2]: for term in single_qubit_terms: if term not in present_terms: new_model = model + p_str + term new_models.append(new_model) elif spawn_step in [3, 4, 5]: for term in nontransverse_terms: if term not in present_terms: new_model = model + p_str + term new_models.append(new_model) elif spawn_step == 6: i = 0 while i < 3: term = random.choice(transverse_terms) if term not in present_terms: new_model = model + p_str + term if ( check_model_in_dict(new_model, model_dict) == False and new_model not in new_models ): new_models.append(new_model) i += 1 elif spawn_step == 7: i = 0 while i < 2: term = random.choice(transverse_terms) if term not in present_terms: new_model = model + p_str + term if ( check_model_in_dict(new_model, model_dict) == False and new_model not in new_models ): new_models.append(new_model) i += 1 elif spawn_step == 8: i = 0 while i < 1: term = random.choice(transverse_terms) if term not in present_terms: new_model = model + p_str + term if ( check_model_in_dict(new_model, model_dict) == False and new_model not in new_models ): new_models.append(new_model) i += 1 return new_models
def check_model_in_dict(name, model_dict): """ Check whether the new model, name, exists in all previously considered models, held in model_lists. [previously in construct_models] If name has not been previously considered, False is returned. """ # Return true indicates it has not been considered and so can be added al_name = alph(name) n_qub = get_num_qubits(name) if al_name in model_dict[n_qub]: return True # todo -- make clear if in legacy or running db else: return False