def test_value_estimate_to_string(self): value = -1.0 precision = 0.1 value_estimate = ValueEstimate(value, precision) assert str(value_estimate) == f"{value} ± {precision}" value_estimate_no_precision = ValueEstimate(value) assert str(value_estimate_no_precision) == f"{value}"
def __call__(self, parameters: np.ndarray) -> ValueEstimate: """Evaluates the value of the cost function for given parameters. Args: parameters: parameters for which the evaluation should occur. Returns: value: cost function value for given parameters. """ full_parameters = parameters.copy() if self.fixed_parameters is not None: full_parameters = combine_ansatz_params(self.fixed_parameters, parameters) if self.parameter_precision is not None: rng = np.random.default_rng(self.parameter_precision_seed) noise_array = rng.normal(0.0, self.parameter_precision, len(full_parameters)) full_parameters += noise_array circuit = self.ansatz.get_executable_circuit(full_parameters) expectation_values = self.estimator.get_estimated_expectation_values( self.backend, circuit, self.target_operator, n_samples=self.n_samples, epsilon=self.epsilon, delta=self.delta, ) return ValueEstimate(np.sum(expectation_values.values))
def evaluate_qubit_operator( qubit_operator: QubitOperator, expectation_values: ExpectationValues) -> ValueEstimate: """Evaluate the expectation value of a qubit operator using expectation values for the terms. Args: qubit_operator (openfermion.QubitOperator): the operator expectation_values (core.measurement.ExpectationValues): the expectation values Returns: value_estimate (zquantum.core.utils.ValueEstimate): stores the value of the expectation and its precision """ # Sum the contributions from all terms total = 0 # Add all non-trivial terms term_index = 0 for term in qubit_operator.terms: total += np.real(qubit_operator.terms[term] * expectation_values.values[term_index]) term_index += 1 value_estimate = ValueEstimate(total) return value_estimate
def cost_function(parameters: np.ndarray, store_artifact: StoreArtifact = None) -> ValueEstimate: """ Evaluates the value of the cost function for given parameters. Args: parameters: parameters for which the evaluation should occur. store_artifact: callable defining how the bitstring distributions should be stored. """ # TODO: we use private method here due to performance reasons. # This should be fixed once better mechanism for handling it will be implemented. # In case of questions ask mstechly. # circuit = ansatz.get_executable_circuit(parameters) circuit = ansatz._generate_circuit(parameters) distribution = backend.get_bitstring_distribution(circuit, n_samples) value = evaluate_distribution_distance( target_bitstring_distribution, distribution, distance_measure, distance_measure_parameters=distance_measure_parameters, ) if store_artifact: store_artifact("bitstring_distribution", distribution) return ValueEstimate(value)
def cost_function(parameters: np.ndarray, store_artifact: StoreArtifact = None) -> ValueEstimate: """ Evaluates the value of the cost function for given parameters. Args: parameters: parameters for which the evaluation should occur. Returns: (float): cost function value for given parameters zquantum.core.bitstring_distribution.BitstringDistribution: distribution obtained """ circuit = ansatz.get_executable_circuit(parameters) distribution = backend.get_bitstring_distribution(circuit) value = evaluate_distribution_distance( target_bitstring_distribution, distribution, distance_measure, distance_measure_parameters=distance_measure_parameters, ) if store_artifact: store_artifact("bitstring_distribution", distribution) return ValueEstimate(value)
def test_value_estimate_with_specified_precision_is_not_equal_to_its_raw_value( ): value = 6.193 estimate = ValueEstimate(value, precision=4) assert value != estimate assert estimate != value
def solve_relaxed_qubo( qubo, optimizer_specs=None, number_of_trials=10, symmetrize_matrix=True, ): qubo = load_qubo(qubo) qubo_matrix = qubo.to_numpy_matrix().astype(float) if symmetrize_matrix: qubo_matrix = (qubo_matrix + qubo_matrix.T) / 2 if is_matrix_positive_semidefinite(qubo_matrix): solution, optimal_value = solve_qp_problem_for_psd_matrix( qubo_matrix, symmetrize_matrix) else: if optimizer_specs is None: raise ValueError( "For qubo with semipositive definite matrix, an optimizer must be provided." ) optimizer = create_object(optimizer_specs) solution, optimal_value = solve_qp_problem_with_optimizer( qubo_matrix, optimizer, number_of_trials, symmetrize_matrix) save_list(solution.tolist(), "solution.json") save_value_estimate(ValueEstimate(optimal_value), "energy.json")
def get_evaluation_result(self, id): # make cost function result result = ValueEstimate(self.cost_func()) save_value_estimate(result, 'client_mock_evaluation_result.json') with open('client_mock_evaluation_result.json', 'r') as f: result_data = json.load(f) result_data["optimization-evaluation-id"] = "MOCKED-ID" return json.JSONEncoder().encode(result_data)
def test_value_estimate_with_no_precision_is_equivalent_to_its_raw_value(): value = 6.193 estimate = ValueEstimate(value) # Note that it is not that obvious that this comparison is symmetric, since we override # the __eq__ method in ValueEstimate. The same goes about __ne__ method in the next test. assert value == estimate assert estimate == value
def evaluate_operator_for_parameter_grid(ansatz, grid, backend, operator, previous_layer_params=[]): """Evaluate the expectation value of an operator for every set of circuit parameters in the parameter grid. Args: ansatz (dict): the ansatz grid (zquantum.core.circuit.ParameterGrid): The parameter grid containing the parameters for the last layer of the ansatz backend (zquantum.core.interfaces.backend.QuantumSimulator): the backend to run the circuits on operator (openfermion.ops.QubitOperator): the operator previous_layer_params (array): A list of the parameters for previous layers of the ansatz Returns: value_estimate (zquantum.core.utils.ValueEstimate): stores the value of the expectation and its precision optimal_parameters (numpy array): the ansatz parameters representing the ansatz parameters resulting in the best minimum evaluation. If multiple sets of parameters evaluate to the same value, the first set of parameters is chosen as the optimal. """ parameter_grid_evaluation = [] circuitset = [] params_set = [] for last_layer_params in grid.params_list: # Build the ansatz circuit params = np.concatenate( (np.asarray(previous_layer_params), np.asarray(last_layer_params))) # Build the ansatz circuit circuitset.append(ansatz.get_executable_circuit(params)) params_set.append(params) expectation_values_set = backend.get_expectation_values_for_circuitset( circuitset, operator) min_value_estimate = None for params, expectation_values in zip(params_set, expectation_values_set): expectation_values = expectation_values_to_real(expectation_values) value_estimate = ValueEstimate(sum(expectation_values.values)) parameter_grid_evaluation.append({ "value": value_estimate, "parameter1": params[-2], "parameter2": params[-1], }) if min_value_estimate is None: min_value_estimate = value_estimate optimal_parameters = params elif value_estimate.value < min_value_estimate.value: min_value_estimate = value_estimate optimal_parameters = params return parameter_grid_evaluation, optimal_parameters
def test_arithmetic_on_value_estimate_and_float_gives_the_same_result_as_arithmetic_on_two_floats(): value = 5.1 estimate = ValueEstimate(value, precision=None) other = 3.4 assert estimate + other == value + other assert estimate - other == value - other assert estimate * other == value * other assert estimate / other == value / other
def test_arithmetic_on_value_estimate_and_float(): value = 5.1 estimate = ValueEstimate(value, precision=None) other = 3.4 assert estimate + other == value + other assert estimate - other == value - other assert estimate * other == value * other assert estimate / other == value / other
def test_post_result(self): connection = http.client.HTTPConnection(self.ipaddress+":"+str(self.listening_port), timeout=2) # POST argument values to allow proxy to verify that id that comes in with # result POST are correct params = np.random.random((2,2)) save_circuit_template_params(params, 'proxy_test_current_argument_values_artifact.json') with open('proxy_test_current_argument_values_artifact.json', 'r') as f: arg_val_data = json.load(f) # set status to be OPTIMIZING in order to POST argument values connection.request('POST', '/status', body="OPTIMIZING") response = connection.getresponse() self.assertEqual(response.getcode(), 204) # POST argument values connection.request('POST', '/cost-function-argument-values', body=json.JSONEncoder().encode(arg_val_data)) response = connection.getresponse() self.assertEqual(response.getcode(), 200) # decode id from response id_from_argument_value_post = response.read().decode("utf-8") # set status to be EVALUATING connection.request('POST', '/status', body="EVALUATING") response = connection.getresponse() self.assertEqual(response.getcode(), 204) # make cost function result result = ValueEstimate(1.5,10.0) save_value_estimate(result, 'proxy_test_results_artifact.json') with open('proxy_test_results_artifact.json', 'r') as f: result_data = json.load(f) result_data["optimization-evaluation-id"] = id_from_argument_value_post # POST cost function result connection.request('POST', '/cost-function-results', body=json.JSONEncoder().encode(result_data)) response = connection.getresponse() self.assertEqual(response.getcode(), 204) # GET cost function result connection.request('GET', '/cost-function-results', body=id_from_argument_value_post) response = connection.getresponse() self.assertEqual(response.getcode(), 200) # remove id from response and verify it is correct response_string = response.read().decode("utf-8") response_json = json.loads(response_string) response_id = response_json.pop("optimization-evaluation-id") self.assertEqual(id_from_argument_value_post, response_id) # assert result is same as above with open('proxy_test_results_artifact_from_proxy.json', 'w') as f: f.write(json.dumps(response_json)) new_data_loaded_from_file = load_value_estimate('proxy_test_results_artifact_from_proxy.json') self.assertEqual(result.value, new_data_loaded_from_file.value) self.assertEqual(result.precision, new_data_loaded_from_file.precision)
def jw_get_ground_state_at_particle_number(particle_number, qubit_operator): qubit_operator = load_qubit_operator(qubit_operator) sparse_matrix = qubit_operator_sparse(qubit_operator) ground_energy, ground_state_amplitudes = _jw_get_ground_state_at_particle_number( sparse_matrix, particle_number ) ground_state = Wavefunction(ground_state_amplitudes) value_estimate = ValueEstimate(ground_energy) save_wavefunction(ground_state, "ground-state.json") save_value_estimate(value_estimate, "value-estimate.json")
def test_value_estimate_io(self): # Given value = -1.0 precision = 0.1 value_estimate_object = ValueEstimate(value, precision) # When save_value_estimate(value_estimate_object, "value_estimate.json") value_estimate_object_loaded = load_value_estimate( "value_estimate.json") # Then assert value_estimate_object.value == value_estimate_object_loaded.value assert value_estimate_object.precision == value_estimate_object_loaded.precision # Given value_estimate_object = ValueEstimate(value) # When save_value_estimate(value_estimate_object, "value_estimate.json") value_estimate_object_loaded = load_value_estimate( "value_estimate.json") # Then assert value_estimate_object.value == value_estimate_object_loaded.value assert value_estimate_object.precision == value_estimate_object_loaded.precision # Given value = np.float64(-1.0) precision = np.float64(0.1) value_estimate_object = ValueEstimate(value, precision) # When save_value_estimate(value_estimate_object, "value_estimate.json") value_estimate_object_loaded = load_value_estimate( "value_estimate.json") # Then assert value_estimate_object.value == value_estimate_object_loaded.value assert value_estimate_object.precision == value_estimate_object_loaded.precision remove_file_if_exists("value_estimate.json")
def test_evaluate(self): # Given client = MockedClient(self.ipaddress, self.port, "return_x_squared") params = np.array([4]) cost_function = ProxyCostFunction(client) target_value = ValueEstimate(16) # When value = cost_function(params) # Then self.assertEqual(value, target_value) os.remove("client_mock_evaluation_result.json") os.remove("current_optimization_params.json")
def solve_qubo(qubo, solver_specs, solver_params=None): """Solves qubo using any sampler implementing either dimod.Sampler or zquantum.qubo.BQMSolver""" if solver_params is None: solver_params = {} solver = create_object(solver_specs) qubo = load_qubo(qubo) sampleset = solver.sample(qubo, **solver_params) best_sample_dict = sampleset.first.sample solution_bitstring = tuple(best_sample_dict[i] for i in sorted(best_sample_dict)) lowest_energy = evaluate_bitstring_for_qubo(solution_bitstring, qubo) save_value_estimate(ValueEstimate(lowest_energy), "lowest-energy.json") Measurements([solution_bitstring]).save("solution.json") save_sampleset(sampleset, "sampleset.json")
def test_unsuccessful_post_result_wrong_status(self): connection = http.client.HTTPConnection(self.ipaddress+":"+str(self.listening_port), timeout=2) # POST argument values to allow proxy to verify that argument values that come in with # Value POST are correct params = np.random.random((2,2)) save_circuit_template_params(params, 'proxy_test_current_argument_values_artifact.json') with open('proxy_test_current_argument_values_artifact.json', 'r') as f: arg_val_data = json.load(f) # set status to be OPTIMIZING in order to POST argument values connection.request('POST', '/status', body="OPTIMIZING") response = connection.getresponse() self.assertEqual(response.getcode(), 204) # POST argument values connection.request('POST', '/cost-function-argument-values', body=json.JSONEncoder().encode(arg_val_data)) response = connection.getresponse() self.assertEqual(response.getcode(), 200) # decode id from response id_from_argument_value_post = response.read().decode("utf-8") # set status to be EVALUATING connection.request('POST', '/status', body="EVALUATING") response = connection.getresponse() self.assertEqual(response.getcode(), 204) # make cost function result result = ValueEstimate(1.5,10.0) save_value_estimate(result, 'proxy_test_results_artifact.json') with open('proxy_test_results_artifact.json', 'r') as f: result_data = json.load(f) result_data["optimization-evaluation-id"] = id_from_argument_value_post # set status to be OPTIMIZING - new results should not be able to # be posted while that is the status connection.request('POST', '/status', body="OPTIMIZING") response = connection.getresponse() self.assertEqual(response.getcode(), 204) # POST cost function result connection.request('POST', '/cost-function-results', body=json.JSONEncoder().encode(result_data)) response = connection.getresponse() self.assertEqual(response.getcode(), 409) response_lower = response.read().decode("utf-8").lower() self.assertTrue(response_lower.find('error') != -1) self.assertTrue(response_lower.find('status') != -1) self.assertTrue(response_lower.find('evaluating') != -1)
def cost_function(params): # build the ansatz circuit qcbm_circuit = build_qcbm_circuit_ion_trap(n_qubits, params, single_qubit_gate, static_entangler, topology=topology) measured_distr = backend.get_bitstring_distribution(qcbm_circuit) distribution_history.append(measured_distr) value_estimate = ValueEstimate( evaluate_distribution_distance( target_bitstring_distribution, measured_distr, distance_measure, epsilon=epsilon, )) return value_estimate.value
def jw_get_ground_state_at_particle_number( particle_number: int, qubit_operator: Union[str, SymbolicOperator]): """Get the ground state wavefunction of the operator for the input particle number. Outputs are serialized to JSON within the files: "ground-state.json" and "value-estimate.json" ARGS: particle_number (int): The given number of particles in the system qubit_operator (Union[str, SymbolicOperator]): The operator for which to find the ground state """ if isinstance(qubit_operator, str): qubit_operator = load_qubit_operator(qubit_operator) sparse_matrix = qubit_operator_sparse(qubit_operator) ground_energy, ground_state_amplitudes = _jw_get_ground_state_at_particle_number( sparse_matrix, particle_number) ground_state = Wavefunction(ground_state_amplitudes) value_estimate = ValueEstimate(ground_energy) save_wavefunction(ground_state, "ground-state.json") save_value_estimate(value_estimate, "value-estimate.json")
def evaluate_operator_for_parameter_grid(ansatz, grid, backend, operator, previous_layer_params=[]): """Evaluate the expectation value of an operator for every set of circuit parameters in the parameter grid. Args: ansatz (dict): the ansatz grid (zquantum.core.circuit.ParameterGrid): The parameter grid containing the parameters for the last layer of the ansatz backend (zquantum.core.interfaces.backend.QuantumSimulator): the backend to run the circuits on operator (openfermion.ops.QubitOperator): the operator previous_layer_params (array): A list of the parameters for previous layers of the ansatz Returns: value_estimate (zquantum.core.utils.ValueEstimate): stores the value of the expectation and its precision """ parameter_grid_evaluation = [] for last_layer_params in grid.params_list: # Build the ansatz circuit params = np.concatenate( (np.asarray(previous_layer_params), np.asarray(last_layer_params))) # Build the ansatz circuit circuit = build_ansatz_circuit(ansatz, params) expectation_values = backend.get_expectation_values(circuit, operator) value_estimate = ValueEstimate(sum(expectation_values.values)) parameter_grid_evaluation.append({ 'value': value_estimate, 'parameter1': last_layer_params[0], 'parameter2': last_layer_params[1] }) return parameter_grid_evaluation
def __call__(self, parameters: np.ndarray) -> ValueEstimate: """Evaluates the value of the cost function for given parameters. Args: parameters: parameters for which the evaluation should occur. Returns: value: cost function value for given parameters. """ if self.fixed_parameters is not None: parameters = combine_ansatz_params(self.fixed_parameters, parameters) circuit = self.ansatz.get_executable_circuit(parameters) expectation_values = self.estimator.get_estimated_expectation_values( self.backend, circuit, self.target_operator, n_samples=self.n_samples, epsilon=self.epsilon, delta=self.delta, ) return ValueEstimate(np.sum(expectation_values.values))
) from zquantum.core.utils import ValueEstimate, convert_array_to_dict # The result constructed below does not make sense. # It does not matter though, as we are only testing serialization and it contains variety # of data to be serialized. EXAMPLE_OPTIMIZATION_RESULT = optimization_result( opt_value=0.5, opt_params=np.array([0, 0.5, 2.5]), nit=3, fev=10, history=[ HistoryEntry( call_number=0, params=np.array([0.1, 0.2, 0.3j]), value=ValueEstimate(0.5, precision=6), ), HistoryEntry(call_number=1, params=np.array([1, 2, 3]), value=-10.0), HistoryEntryWithArtifacts( call_number=2, params=np.array([-1, -0.5, -0.6]), value=-20.0, artifacts={ "bitstring": "0111", "bitstring_distribution": BitstringDistribution({ "111": 0.25, "010": 0.75 }), },
assert value == estimate assert estimate == value def test_value_estimate_with_specified_precision_is_not_equal_to_its_raw_value(): value = 6.193 estimate = ValueEstimate(value, precision=4) assert value != estimate assert estimate != value @pytest.mark.parametrize( "estimate_1,estimate_2,expected_result", [ (ValueEstimate(14.1), ValueEstimate(14.1), True), (ValueEstimate(12.3, 3), ValueEstimate(12.3, 3), True), (ValueEstimate(14.1, 5), ValueEstimate(14.1, 4), False), (ValueEstimate(2.5, 3), ValueEstimate(2.5), False), (ValueEstimate(0.15, 3), ValueEstimate(1.1, 3), False), ], ) def test_two_value_estimates_are_equal_iff_their_values_and_precisions_are_equal( estimate_1, estimate_2, expected_result ): assert (estimate_1 == estimate_2) == expected_result @pytest.mark.parametrize( "estimate", [ValueEstimate(2.0), ValueEstimate(5.0, precision=1e-5)] )