Source code for qmla.exploration_strategies.nv_centre_spin_characterisation.nature_physics_2021.tiered_greedy
from __future__ import absolute_import
import sys
import os
import random
from qmla.exploration_strategies.nv_centre_spin_characterisation.nature_physics_2021 import (
FullAccessNVCentre,
)
from qmla.model_building_utilities import alph
__all__ = ["TieredGreedySearchNVCentre"]
[docs]class TieredGreedySearchNVCentre(FullAccessNVCentre):
r"""
Exploration strategy for NV system described in Nature Physics 2021 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.initial_models = None
self.term_tiers = {
1: ["xTi", "yTi", "zTi"],
2: ["xTx", "yTy", "zTz"],
3: ["xTy", "xTz", "yTz"],
}
self.tier = 1
self.max_tier = max(self.term_tiers)
self.tier_branch_champs = {k: [] for k in self.term_tiers}
self.tier_champs = {}
self.prune_completed_initially = True
self.check_champion_reducibility = True
[docs] def generate_models(self, model_list, **kwargs):
r"""
Overwrites :meth:`qmla.QuantumModelLearningAgent.generate_models`.
Constructs models in tiers, where each tier is explored greedily, and only the
strongest model from the tier is progressed as the seed model for the subsequent tier.
"""
self.log_print(
[
"Generating models in tiered greedy search at spawn {}. available kwargs:\n {}".format(
self.spawn_step, kwargs
)
]
)
# self.spawn_step = kwargs['spawn_step']
if self.spawn_stage[-1] is None:
try:
previous_branch_champ = model_list[0]
self.tier_branch_champs[self.tier].append(previous_branch_champ)
except:
previous_branch_champ = None
elif "getting_tier_champ" in self.spawn_stage[-1]:
previous_branch_champ = model_list[0]
self.log_print(["Tier champ for {} is {}".format(self.tier, model_list[0])])
self.tier_champs[self.tier] = model_list[0]
self.tier += 1
self.log_print(["Tier now = ", self.tier])
self.spawn_stage.append(None) # normal processing
if self.tier > self.max_tier:
self.log_print(["Completed tree for ES"])
self.spawn_stage.append("Complete")
return list(self.tier_champs.values())
else:
self.log_print(["Spawn stage:", self.spawn_stage])
new_models = greedy_add(
current_model=previous_branch_champ, terms=self.term_tiers[self.tier]
)
self.log_print(["tiered search new_models=", new_models])
if len(new_models) == 0:
# no models left to find - get champions of branches from this tier
new_models = self.tier_branch_champs[self.tier]
self.log_print(["tier champions: {}".format(new_models)])
self.spawn_stage.append("getting_tier_champ_{}".format(self.tier))
return new_models
[docs] def check_tree_completed(self, spawn_step, **kwargs):
r"""
QMLA asks the exploration tree whether it has finished growing;
the exploration tree queries the exploration strategy through this method
"""
if self.tree_completed_initially:
return True
elif self.spawn_stage[-1] == "Complete":
return True
else:
return False
def check_tree_pruned(self, prune_step, **kwargs):
return self.prune_completed_initially
def greedy_add(
current_model,
terms,
):
r"""
Generate a list of models by appending all individual terms to the current model.
"""
try:
present_terms = current_model.split("+")
except:
present_terms = []
nonpresent_terms = list(set(terms) - set(present_terms))
term_sets = [present_terms + [t] for t in nonpresent_terms]
new_models = ["+".join(term_set) for term_set in term_sets]
return new_models