def get_domain(self, objective: Objective, passive_angles: dict = None) -> typing.List[typing.Dict]: """ return a 'domain' object, for use by GPyOpt. This function constructs a list of dictionaries about each variable in objective to optimize over: we enforce the domain of 0 to 2 pi, the period of a rotation, since some domain MUST be specified. Parameters ---------- objective: Objective: the Objective to extract variables from to build the domain. passive_angles: dict, optional: a dictionary of which angles are passive, in Objective. Default: there are none; optimize all angles. Returns ------- list of dicts the domain object for use by gpyopt. """ op = objective.extract_variables() if passive_angles is not None: for i, thing in enumerate(op): if thing in passive_angles.keys(): op.remove(thing) return [{ 'name': v, 'type': 'continuous', 'domain': (0, 2 * np.pi) } for v in op]
def __call__(self, objective: Objective, maxiter: int, passives: typing.Dict[Variable, numbers.Real] = None, samples: int = None, backend: str = None, noise=None, method: str = 'lbfgs') -> GPyOptReturnType: if self.samples is not None: if samples is None: samples = self.samples else: pass else: pass dom = self.get_domain(objective, passives) init = {v: np.random.uniform(0, 2 * np.pi) for v in objective.extract_variables()} ### O is broken, not using it right now O = compile(objective=objective, variables=init, backend=backend, noise=noise, samples=samples) f = self.construct_function(O, backend, passives, samples, noise_model=noise) opt = self.get_object(f, dom, method) opt.run_optimization(maxiter) if self.save_history: self.history.energies = opt.get_evaluations()[1].flatten() self.history.angles = [self.redictify(v, objective, passives) for v in opt.get_evaluations()[0]] return GPyOptReturnType(energy=opt.fx_opt, angles=self.redictify(opt.x_opt, objective, passives), history=self.history, opt=opt)
def minimize(objective: Objective, maxiter: int, samples: int = None, variables: typing.List = None, initial_values: typing.Dict = None, backend: str = None, noise=None, method: str = 'lbfgs') -> GPyOptReturnType: """ Parameters ---------- objective: Objective : The tequila objective to optimize initial_values: typing.Dict[typing.Hashable, numbers.Real]: (Default value = None): Initial values as dictionary of Hashable types (variable keys) and floating point numbers. generates FIXED variables! if not provided, all variables will be optimized. variables: typing.List[typing.Hashable] : (Default value = None) List of Variables to optimize. If None, all variables optimized, and the passives command is over-ruled. samples: int : (Default value = None) samples/shots to take in every run of the quantum circuits (None activates full wavefunction simulation) maxiter: int : how many iterations of GPyOpt to run. Note: GPyOpt will override this as it sees fit. backend: str : (Default value = None) Simulator backend, will be automatically chosen if set to None noise: NoiseModel : (Default value = None) a noise model to apply to the circuits of Objective. method: str: (Default value = 'lbfgs') method of acquisition. Allowed arguments are 'lbfgs', 'DIRECT', and 'CMA' Returns ------- """ if variables is None: passives = None else: all_vars = Objective.extract_variables() passives = {} for k, v in initial_values.items(): if k not in variables and k in all_vars: passives[k] = v optimizer = OptimizerGpyOpt() return optimizer(objective=objective, samples=samples, backend=backend, passives=passives, maxiter=maxiter, noise=noise, method=method)
def preamble(objective: Objective, compile_args: dict = None, input_vars: list = None): """ Helper function for interfaces to ml backends. Parameters ---------- objective: Objective: the objective to manipulate and compile. compile_args: dict, optional: a dictionary of args that can be passed as kwargs to tq.compile input_vars: list, optional: a list of variables of the objective to specify as input, rather than itnernal weights. Returns ------- tuple the compiled objective, it's compile arguments, its weight variables, dicts for the weight and input gradients, and a dictionary that links positions in an array to each variable (parses parameters). """ def var_sorter(e): return hash(e.name) all_vars = objective.extract_variables() all_vars.sort(key=var_sorter) compile_args = check_compiler_args(compile_args) weight_vars = [] if input_vars is None: input_vars = [] weight_vars = all_vars else: input_vars = [assign_variable(v) for v in input_vars] for var in all_vars: if var not in input_vars: weight_vars.append(assign_variable(var)) init_vals = compile_args['initial_values'] if init_vals is not None: for k in init_vals.keys(): if assign_variable(k) in input_vars: raise TequilaMLException( 'initial_values contained key {},' 'which is meant to be an input variable.'.format(k)) compile_args['initial_values'] = format_variable_dictionary(init_vals) comped = compile(objective, **compile_args) gradients = get_gradients(objective, compile_args) w_grad, i_grad = separate_gradients(gradients, weight_vars=weight_vars, input_vars=input_vars) first, second = get_variable_orders(weight_vars, input_vars) return comped, compile_args, input_vars, weight_vars, i_grad, w_grad, first, second
def grad(objective: Objective, variable: Variable = None, no_compile=False): ''' wrapper function for getting the gradients of Objectives,ExpectationValues, Unitaries (including single gates), and Transforms. :param obj (QCircuit,ParametrizedGateImpl,Objective,ExpectationValue,Transform,Variable): structure to be differentiated :param variables (list of Variable): parameter with respect to which obj should be differentiated. default None: total gradient. return: dictionary of Objectives, if called on gate, circuit, exp.value, or objective; if Variable or Transform, returns number. ''' if variable is None: # None means that all components are created variables = objective.extract_variables() result = {} if len(variables) == 0: raise TequilaException( "Error in gradient: Objective has no variables") for k in variables: assert (k is not None) result[k] = grad(objective, k, no_compile=no_compile) return result else: variable = assign_variable(variable) if no_compile: compiled = objective else: compiler = Compiler(multitarget=True, trotterized=True, hadamard_power=True, power=True, controlled_phase=True, controlled_rotation=True) compiled = compiler(objective, variables=[variable]) if variable not in compiled.extract_variables(): raise TequilaException( "Error in taking gradient. Objective does not depend on variable {} " .format(variable)) if isinstance(objective, ExpectationValueImpl): return __grad_expectationvalue(E=objective, variable=variable) elif objective.is_expectationvalue(): return __grad_expectationvalue(E=compiled.args[-1], variable=variable) elif isinstance(compiled, Objective): return __grad_objective(objective=compiled, variable=variable) else: raise TequilaException( "Gradient not implemented for other types than ExpectationValue and Objective." )
def __call__(self, objective: Objective, maxiter=None, variables: typing.List[Variable] = None, initial_values: typing.Dict[Variable, numbers.Real] = None, previous=None, phoenics_config=None, save_to_file=False, file_name=None, *args, **kwargs): active_angles, passive_angles, variables = self.initialize_variables(objective, initial_values=initial_values, variables=variables) if maxiter is None: maxiter = 10 obs = [] bird = self._make_phoenics_object(objective, passive_angles, phoenics_config, *args, **kwargs) if previous is not None: if type(previous) is str: try: obs = pickle.load(open(previous, 'rb')) except: print( 'failed to load previous observations, which are meant to be a pickle file. Starting fresh.') elif type(previous) is list: if all([type(k) == dict for k in previous]): obs = previous else: print('previous observations were not in the correct format (list of dicts). Starting fresh.') if not (type(file_name) == str or file_name == None): raise TequilaException('file_name must be a string, or None!') best = None best_angles = None # avoid multiple compilations compiled_objective = compile_objective(objective=objective, backend=self.backend, backend_options=self.backend_options, samples=self.samples, noise=self.noise) if not self.silent: print('phoenics has recieved') print("objective: \n") print(objective) print("noise model : {}".format(self.noise)) print("samples : {}".format(self.samples)) print("maxiter : {}".format(maxiter)) print("variables : {}".format(objective.extract_variables())) print("passive var : {}".format(passive_angles)) print("backend options {} ".format(self.backend), self.backend_options) print('now lets begin') for i in range(0, maxiter): with warnings.catch_warnings(): np.testing.suppress_warnings() warnings.simplefilter("ignore") warnings.filterwarnings("ignore", category=FutureWarning) if len(obs) >= 1: precs = bird.recommend(observations=obs) else: precs = bird.recommend() runs = [] recs = self._process_for_sim(precs, passive_angles=passive_angles) start = time.time() for j, rec in enumerate(recs): En = compiled_objective(variables=rec, samples=self.samples, noise=self.noise, backend_options=self.backend_options) runs.append((rec, En)) if not self.silent: if self.print_level > 2: print("energy = {:+2.8f} , angles=".format(En), rec) else: print("energy = {:+2.8f}".format(En)) stop = time.time() if not self.silent: print("Quantum Objective evaluations: {}s Wall-Time".format(stop-start)) for run in runs: angles = run[0] E = run[1] if best is None: best = E best_angles = angles else: if self._minimize: if E < best: best = E best_angles = angles else: if E > best: best = E best_angles = angles if self.save_history: self.history.energies.append(E) self.history.angles.append(angles) obs.append(self._process_for_phoenics(angles, E, passive_angles=passive_angles)) if file_name is not None: with open(file_name, 'wb') as file: pickle.dump(obs, file) if not self.silent: print("best energy after {} iterations : {:+2.8f}".format(self.maxiter, best)) return PhoenicsReturnType(energy=best, angles=best_angles, history=self.history, observations=obs,object=bird)
def minimize(objective: Objective, maxiter: int = None, samples: int = None, variables: typing.List = None, initial_values: typing.Dict = None, backend: str = None, noise=None, previous: typing.Union[str, list] = None, phoenics_config: typing.Union[str, typing.Dict] = None, save_to_file: bool = False, file_name: str = None, silent: bool = False, *args, **kwargs): """ Parameters ---------- objective: Objective : The tequila objective to optimize initial_values: typing.Dict[typing.Hashable, numbers.Real]: (Default value = None): Initial values as dictionary of Hashable types (variable keys) and floating point numbers. If given None they will all be set to zero variables: typing.List[typing.Hashable] : (Default value = None) List of Variables to optimize samples: int : (Default value = None) samples/shots to take in every run of the quantum circuits (None activates full wavefunction simulation) maxiter: int : how many iterations of phoenics to run. Note that this is NOT identical to the number of times the circuit will run. backend: str : (Default value = None) Simulator backend, will be automatically chosen if set to None noise: NoiseModel : (Default value = None) a noise model to apply to the circuits of Objective. previous: (Default value = None) Previous phoenics observations. If string, the name of a file from which to load them. Else, a list. phoenics_config: (Default value = None) a pre-made phoenics configuration. if str, the name of a file from which to load it; Else, a dictionary. Individual keywords of the 'general' sections can also be passed down as kwargs save_to_file: bool: (Default value = False) whether or not to save the output of the optimization to an external file file_name: str: (Default value = None) where to save output to, if save_to_file is True. kwargs: dict: Send down more keywords for single replacements in the phoenics config 'general' section, like e.g. batches=5, boosted=True etc Returns ------- """ if variables is None: passives = None else: all_vars = Objective.extract_variables() passives = {} for k, v in initial_values.items(): if k not in variables and k in all_vars: passives[k] = v optimizer = OptimizerPhoenics(samples=samples, backend=backend, maxiter=maxiter, silent=silent) return optimizer(objective=objective, backend=backend, passives=passives, previous=previous, maxiter=maxiter, noise=noise, samples=samples, phoenics_config=phoenics_config, save_to_file=save_to_file, file_name=file_name, *args, **kwargs)
def __call__(self, objective: Objective, maxiter: int = None, passives: typing.Dict[Variable, numbers.Real] = None, samples: int = None, backend: str = None, noise=None, previous=None, phoenics_config=None, save_to_file=False, file_name=None, *args, **kwargs): backend_options = {} if 'backend_options' in kwargs: backend_options = kwargs['backend_options'] if maxiter is None: maxiter = 10 bird = self._make_phoenics_object(objective, passives, phoenics_config, *args, **kwargs) if previous is not None: if type(previous) is str: try: obs = pickle.load(open(previous, 'rb')) except: print( 'failed to load previous observations, which are meant to be a pickle file. Please try again or seek assistance. Starting fresh.') obs = [] elif type(previous) is list: if all([type(k) == dict for k in previous]): obs = previous else: print( 'previous observations were not in the correct format (list of dicts). Are you sure you gave me the right info? Starting fresh.') obs = [] else: obs = [] if save_to_file is True: if type(file_name) is str: pass elif file_name is None: raise TequilaException( 'You have asked me to save phoenics observations without telling me where to do so! please provide a file_name') else: raise TequilaException('file_name must be a string!') ### this line below just gets the damn compiler to run, since that argument is necessary init = {key: np.pi for key in objective.extract_variables()} best = None best_angles = None # avoid multiple compilations compiled_objective = compile_objective(objective=objective, backend=backend, samples=samples, noise=noise) if not self.silent: print('phoenics has recieved') print("objective: \n") print(objective) print("noise model : {}".format(noise)) print("samples : {}".format(samples)) print("maxiter : {}".format(maxiter)) print("variables : {}".format(objective.extract_variables())) print("passive var : {}".format(passives)) print("backend options {} ".format(backend), backend_options) print('now lets begin') for i in range(0, maxiter): with warnings.catch_warnings(): np.testing.suppress_warnings() warnings.simplefilter("ignore") warnings.filterwarnings("ignore", category=FutureWarning) if len(obs) >= 1: precs = bird.recommend(observations=obs) else: precs = bird.recommend() runs = [] recs = self._process_for_sim(precs, passives=passives) start = time.time() for i, rec in enumerate(recs): En = compiled_objective(variables=rec, samples=samples, noise=noise, **backend_options) runs.append((rec, En)) if not self.silent: print("energy = {:+2.8f} , angles=".format(En), rec) stop = time.time() if not self.silent: print("Quantum Objective evaluations: {}s Wall-Time".format(stop-start)) for run in runs: angles = run[0] E = run[1] if best is None: best = E best_angles = angles else: if self._minimize: if E < best: best = E best_angles = angles else: if E > best: best = E best_angles = angles if self.save_history: self.history.energies.append(E) self.history.angles.append(angles) obs.append(self._process_for_phoenics(angles, E, passives=passives)) if save_to_file is True: with open(file_name, 'wb') as file: pickle.dump(obs, file) if not self.silent: print("best energy after {} iterations : {:+2.8f}".format(self.maxiter, best)) return PhoenicsReturnType(energy=best, angles=best_angles, history=self.history, observations=obs)
def __call__(self, objective: Objective, maxiter=None, variables: typing.List[Variable] = None, initial_values: typing.Dict[Variable, numbers.Real] = None, previous=None, phoenics_config=None, file_name=None, *args, **kwargs): """ Perform optimization with phoenics. Parameters ---------- objective: Objective the objective to optimize. maxiter: int: (Default value = None) if not None, overwrite the init maxiter with new number. variables: list: (Default value = None) which variables to optimize over. If None: all of the variables in objective are used. initial_values: dict: (Default value = None) an initial point to begin optimization from. Random, if None. previous: previous observations, formatted for phoenics, to use in optimization. For use by advanced users. phoenics_config: a config for a phoenics object. file_name: a file args kwargs Returns ------- PhoenicsResults: the results of optimization by phoenics. """ objective = objective.contract() active_angles, passive_angles, variables = self.initialize_variables( objective, initial_values=initial_values, variables=variables) if maxiter is None: maxiter = 10 obs = [] bird = self._make_phoenics_object(objective, passive_angles, phoenics_config, *args, **kwargs) if previous is not None: if type(previous) is str: try: obs = pickle.load(open(previous, 'rb')) except: print( 'failed to load previous observations, which are meant to be a pickle file. Starting fresh.' ) elif type(previous) is list: if all([type(k) == dict for k in previous]): obs = previous else: print( 'previous observations were not in the correct format (list of dicts). Starting fresh.' ) if not (type(file_name) == str or file_name == None): raise TequilaException( 'file_name must be a string, or None. Recieved {}'.format( type(file_name))) best = None best_angles = None # avoid multiple compilations compiled_objective = compile_objective(objective=objective, backend=self.backend, device=self.device, samples=self.samples, noise=self.noise) if not self.silent: print('phoenics has recieved') print("objective: \n") print(objective) print("noise model : {}".format(self.noise)) print("samples : {}".format(self.samples)) print("maxiter : {}".format(maxiter)) print("variables : {}".format(objective.extract_variables())) print("passive var : {}".format(passive_angles)) print('now lets begin') for i in range(0, maxiter): with warnings.catch_warnings(): np.testing.suppress_warnings() warnings.simplefilter("ignore") warnings.filterwarnings("ignore", category=FutureWarning) precs = bird.recommend(observations=obs) runs = [] recs = self._process_for_sim(precs, passive_angles=passive_angles) start = time.time() for j, rec in enumerate(recs): En = compiled_objective(variables=rec, samples=self.samples, noise=self.noise) runs.append((rec, En)) if not self.silent: if self.print_level > 2: print("energy = {:+2.8f} , angles=".format(En), rec) else: print("energy = {:+2.8f}".format(En)) stop = time.time() if not self.silent: print("Quantum Objective evaluations: {}s Wall-Time".format( stop - start)) for run in runs: angles = run[0] E = run[1] if best is None: best = E best_angles = angles else: if self._minimize: if E < best: best = E best_angles = angles else: if E > best: best = E best_angles = angles if self.save_history: self.history.energies.append(E) self.history.angles.append(angles) obs.append( self._process_for_phoenics(angles, E, passive_angles=passive_angles)) if file_name is not None: with open(file_name, 'wb') as file: pickle.dump(obs, file) if not self.silent: print("best energy after {} iterations : {:+2.8f}".format( self.maxiter, best)) return PhoenicsResults(energy=best, variables=best_angles, history=self.history, observations=obs, phoenics_instance=bird)