def test_evaluate_operator_for_parameter_grid(self): # Given ansatz = MockAnsatz(4, 2) grid = build_uniform_param_grid(1, 2, 0, np.pi, np.pi / 10) backend = create_object({ "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockQuantumSimulator", }) op = QubitOperator("0.5 [] + 0.5 [Z1]") previous_layer_parameters = [1, 1] # When ( parameter_grid_evaluation, optimal_parameters, ) = evaluate_operator_for_parameter_grid( ansatz, grid, backend, op, previous_layer_params=previous_layer_parameters) # Then (for brevity, only check first and last evaluations) self.assertIsInstance(parameter_grid_evaluation[0]["value"].value, float) self.assertEqual(parameter_grid_evaluation[0]["parameter1"], 0) self.assertEqual(parameter_grid_evaluation[0]["parameter2"], 0) self.assertIsInstance(parameter_grid_evaluation[99]["value"].value, float) self.assertEqual(parameter_grid_evaluation[99]["parameter1"], np.pi - np.pi / 10) self.assertEqual(parameter_grid_evaluation[99]["parameter2"], np.pi - np.pi / 10) self.assertEqual(len(optimal_parameters), 4) self.assertEqual(optimal_parameters[0], 1) self.assertEqual(optimal_parameters[1], 1)
def get_expectation_values_for_qubit_operator( backend_specs: Union[Dict, str], circuit: Union[str, Circuit], qubit_operator: Union[str, SymbolicOperator], ): """Measure the expection values of the terms in an input operator with respect to the state prepared by the input circuit on the backend described by the backend_specs. The results are serialized into a JSON under the file: "expectation-values.json" ARGS: backend_specs (Union[dict, str]): The backend on which to run the quantum circuit circuit (Union[str, Circuit]): The circuit that prepares the state to be measured qubit_operator (Union[str, SymbolicOperator]): The operator to measure """ if isinstance(circuit, str): circuit = load_circuit(circuit) if isinstance(qubit_operator, str): qubit_operator = load_qubit_operator(qubit_operator) if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) backend = create_object(backend_specs) expectation_values = backend.get_expectation_values( circuit, qubit_operator) save_expectation_values(expectation_values, "expectation-values.json")
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 setUp(self): number_of_layers = 1 number_of_qubits = 4 topology = "all" self.ansatz = QCBMAnsatz(number_of_layers, number_of_qubits, topology) self.target_bitstring_distribution = BitstringDistribution({ "0000": 1.0, "0001": 0.0, "0010": 0.0, "0011": 1.0, "0100": 0.0, "0101": 1.0, "0110": 0.0, "0111": 0.0, "1000": 0.0, "1001": 0.0, "1010": 1.0, "1011": 0.0, "1100": 1.0, "1101": 0.0, "1110": 0.0, "1111": 1.0, }) self.backend = create_object({ "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockQuantumSimulator", "n_samples": 1, }) self.gradient_types = ["finite_difference"]
def test_save_parameter_grid_evaluation(self): # Given ansatz = MockAnsatz(2, 2) grid = build_uniform_param_grid(1, 2, 0, np.pi, np.pi / 10) backend = create_object({ "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockQuantumSimulator", }) op = QubitOperator("0.5 [] + 0.5 [Z1]") ( parameter_grid_evaluation, optimal_parameters, ) = evaluate_operator_for_parameter_grid(ansatz, grid, backend, op) # When save_parameter_grid_evaluation(parameter_grid_evaluation, "parameter-grid-evaluation.json") save_circuit_template_params(optimal_parameters, "optimal-parameters.json") # Then # TODO files_to_remove = ("parameter-grid-evaluation.json", "optimal-parameters.json") failed_to_remove = [] for path in files_to_remove: try: os.remove(path) except OSError: failed_to_remove.append(path) if failed_to_remove: raise RuntimeError(f"Failed to remove files: {failed_to_remove}")
def get_expectation_values_for_qubit_operator( backend_specs: Specs, circuit: Union[str, Circuit, Dict], qubit_operator: Union[str, SymbolicOperator, Dict], ): """Measure the expectation values of the terms in an input operator with respect to the state prepared by the input circuit on the backend described by the `backend_specs`. The results are serialized into a JSON under the file: "expectation-values.json" Args: backend_specs: The backend on which to run the quantum circuit circuit: The circuit that prepares the state to be measured qubit_operator: The operator to measure """ if isinstance(circuit, str): circuit = load_circuit(circuit) elif isinstance(circuit, dict): circuit = circuit_from_dict(circuit) if isinstance(qubit_operator, str): qubit_operator = load_qubit_operator(qubit_operator) elif isinstance(qubit_operator, dict): qubit_operator = convert_dict_to_qubitop(qubit_operator) if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) backend = cast(QuantumBackend, create_object(backend_specs)) estimation_tasks = [ EstimationTask(qubit_operator, circuit, backend.n_samples) ] expectation_values = estimate_expectation_values_by_averaging( backend, estimation_tasks) save_expectation_values(expectation_values[0], "expectation-values.json")
def test_build_ansatz_circuit_with_parameter_values( self, params_filename_and_number_of_layers ): # Given params_filename, number_of_layers = params_filename_and_number_of_layers ansatz_specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockAnsatz", "number_of_layers": number_of_layers, "problem_size": 2, } parameters = load_circuit_template_params(params_filename) ansatz = create_object(copy.deepcopy(ansatz_specs)) expected_circuit = ansatz.get_executable_circuit(parameters) # When build_ansatz_circuit(ansatz_specs=ansatz_specs, params=params_filename) # Then try: circuit_filename = "circuit.json" circuit = load_circuit(circuit_filename) assert isinstance(circuit, Circuit) assert circuit == expected_circuit finally: remove_file_if_exists(circuit_filename)
def run_circuitset_and_measure( backend_specs: Specs, circuitset: str, n_samples: Optional[int] = None, noise_model: Optional[str] = None, device_connectivity: Optional[str] = None, ): if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) if noise_model is not None: backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity is not None: backend_specs["device_connectivity"] = load_circuit_connectivity( device_connectivity) circuit_set = load_circuit_set(circuitset) backend = create_object(backend_specs) measurements_set = backend.run_circuitset_and_measure(circuit_set, n_samples=n_samples) list_of_measurements = [ measurement.bitstrings for measurement in measurements_set ] save_list(list_of_measurements, "measurements-set.json")
def main(backend_specs): # Define registers and circuit q = QuantumRegister(2) c = ClassicalRegister(2) circuit = QuantumCircuit(q, c) # Quantum circuit starts here circuit.h(q[0]) circuit.cnot(q[0], q[1]) # Note we have to remove the Measurement to convert to Zapata's circuit format # End quantum circuit # After this point we use the power of Orquestra to use different backends! # Use Zapata's representation of quantum circuits zap_circuit = Circuit(circuit) # Build a backend from the specs we passed to the step if isinstance(backend_specs, str): backend_specs_dict = yaml.load(backend_specs, Loader=yaml.SafeLoader) else: backend_specs_dict = backend_specs backend = create_object(backend_specs_dict) # We can use this backend to get the bitstring distribution distribution = backend.get_bitstring_distribution(zap_circuit) # Finally, we can save the output! save_bitstring_distribution(distribution, "output-distribution.json")
def optimize_variational_qcbm_circuit( distance_measure_specs, distance_measure_parameters, n_layers, n_qubits, topology, backend_specs, optimizer_specs, initial_parameters, target_distribution, ): if isinstance(distance_measure_specs, str): distance_measure_specs = json.loads(distance_measure_specs) distance_measure = get_func_from_specs(distance_measure_specs) ansatz = QCBMAnsatz(n_layers, n_qubits, topology) if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) backend = create_object(backend_specs) if isinstance(optimizer_specs, str): optimizer_specs = json.loads(optimizer_specs) optimizer = create_object(optimizer_specs) initial_parameters = load_circuit_template_params(initial_parameters) target_distribution = load_bitstring_distribution(target_distribution) if isinstance(distance_measure_parameters, str): distance_measure_parameters = json.loads(distance_measure_parameters) cost_function = QCBMCostFunction( ansatz, backend, distance_measure, distance_measure_parameters, target_distribution, ) opt_results = optimizer.minimize(cost_function, initial_parameters) save_optimization_results(opt_results, "qcbm-optimization-results.json") save_circuit_template_params(opt_results.opt_params, "optimized-parameters.json")
def test_create_object_func_fails_with_multiple_assignments(self): # Given function_name = "sum_x_squared" data = np.array([1.0, 2.0]) specs = { "module_name": "zquantum.core.interfaces.optimizer_test", "function_name": function_name, "x": data, } # When with pytest.raises(ValueError): function = create_object(specs, x=data)
def build_ansatz_circuit(ansatz_specs: Dict, params: str = "None"): ansatz = create_object(json.loads(ansatz_specs)) if params != "None": # TODO Non issue in worklow v1 parameters = load_circuit_template_params(params) circuit = ansatz.get_executable_circuit(parameters) elif ansatz.supports_parametrized_circuits: circuit = ansatz.parametrized_circuit else: raise (Exception( "Ansatz is not parametrizable and no parameters has been provided." )) save_circuit(circuit, "circuit.json")
def test_create_object_func_fails_with_multiple_assignments(self): # Given function_name = "mock_cost_function" data = np.array([1.0, 2.0]) specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": function_name, "parameters": data, } # When with pytest.raises(ValueError): _ = create_object(specs, parameters=data)
def test_create_object(self): # Given function_name = "MockQuantumBackend" specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": function_name, } # When mock_backend = create_object(specs) # Then assert type(mock_backend).__name__ == function_name
def evaluate_ansatz_based_cost_function( ansatz_specs: str, backend_specs: str, cost_function_specs: str, ansatz_parameters: str, qubit_operator: str, noise_model="None", device_connectivity="None", ): ansatz_parameters = load_circuit_template_params(ansatz_parameters) # Load qubit op operator = load_qubit_operator(qubit_operator) ansatz_specs = json.loads(ansatz_specs) if ansatz_specs["function_name"] == "QAOAFarhiAnsatz": ansatz = create_object(ansatz_specs, cost_hamiltonian=operator) else: ansatz = create_object(ansatz_specs) backend_specs = json.loads(backend_specs) if noise_model != "None": backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity != "None": backend_specs["device_connectivity"] = load_circuit_connectivity( device_connectivity) backend = create_object(backend_specs) cost_function_specs = json.loads(cost_function_specs) estimator_specs = cost_function_specs.pop("estimator-specs", None) if estimator_specs is not None: cost_function_specs["estimator"] = create_object(estimator_specs) cost_function_specs["target_operator"] = operator cost_function_specs["ansatz"] = ansatz cost_function_specs["backend"] = backend cost_function = create_object(cost_function_specs) value_estimate = cost_function(ansatz_parameters) save_value_estimate(value_estimate, "value_estimate.json")
def test_create_object_func_with_kwargs(self): # Given function_name = "sum_x_squared" data = np.array([1.0, 2.0]) target_value = 5.0 specs = { "module_name": "zquantum.core.interfaces.optimizer_test", "function_name": function_name, } # When function = create_object(specs, x=data) # Then assert isinstance(function, partial) assert function() == target_value
def test_create_object_func_with_kwargs(self): # Given function_name = "mock_cost_function" data = np.array([1.0, 2.0]) target_value = 5.0 specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": function_name, } # When function = create_object(specs, parameters=data) # Then assert isinstance(function, partial) assert function() == target_value
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_create_object(self): # Given n_samples = 100 function_name = "MockQuantumSimulator" specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": function_name, "n_samples": n_samples, } # When mock_simulator = create_object(specs) # Then assert type(mock_simulator).__name__ == function_name assert mock_simulator.n_samples == n_samples
def vqe(backend_specs, coefficients, min_value=0, max_value=2 * np.pi): # Build a backend from the specs we passed to the step if isinstance(backend_specs, str): backend_specs_dict = yaml.load(backend_specs, Loader=yaml.SafeLoader) else: backend_specs_dict = backend_specs backend = create_object(backend_specs_dict) # Build the coeff we passed to the step if isinstance(coefficients, str): coefficients_dict = yaml.load(coefficients, Loader=yaml.SafeLoader) else: coefficients_dict = coefficients # Build the circuits theta = Parameter("θ") ansatz = build_ansatz(theta) circuits = build_circuits() # Search over our input parameters results, values = search( backend, ansatz, theta, circuits, coefficients_dict, min_value=min_value, max_value=max_value, ) # Find the index of the minimum energy # Finding the index helps us find the parameter too. minimum_idx = np.argmin(results) data = { "minimum": { "value": results[minimum_idx], "theta": values[minimum_idx], }, "results": results, "values": values.tolist(), } # Write out the results so they are in our workflow_results.json with open("results.json", "w") as f: json.dump(data, f)
def build_uniform_param_grid( ansatz_specs: Dict, number_of_params_per_layer: Union[str, int] = "None", number_of_layers: int = 1, min_value: float = 0, max_value: float = 2 * np.pi, step: float = np.pi / 5, ): if ansatz_specs != "None": # TODO None issue in workflow v1 ansatz = create_object(json.loads(ansatz_specs)) number_of_params = ansatz.number_of_params elif number_of_params_per_layer != "None": number_of_params = number_of_params_per_layer grid = _build_uniform_param_grid(number_of_params, number_of_layers, min_value, max_value, step) save_parameter_grid(grid, "parameter-grid.json")
def generate_random_ansatz_params( ansatz_specs: Dict, number_of_parameters: Union[str, int] = "None", min_value: float = -np.pi * 0.5, max_value: float = np.pi * 0.5, seed: Union[str, int] = "None", ): if ansatz_specs != "None": # TODO None issue in workflow v1 ansatz_specs_dict = json.loads(ansatz_specs) ansatz = create_object(ansatz_specs_dict) number_of_params = ansatz.number_of_params elif number_of_parameters != "None": number_of_params = number_of_parameters if seed != "None": np.random.seed(seed) params = np.random.uniform(min_value, max_value, number_of_params) save_circuit_template_params(params, "params.json")
def test_save_parameter_grid_evaluation(self): # Given ansatz = MockAnsatz(2, 2) grid = build_uniform_param_grid(1, 2, 0, np.pi, np.pi / 10) backend = create_object({ "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockQuantumSimulator", }) op = QubitOperator("0.5 [] + 0.5 [Z1]") ( parameter_grid_evaluation, optimal_parameters, ) = evaluate_operator_for_parameter_grid(ansatz, grid, backend, op) # When save_parameter_grid_evaluation(parameter_grid_evaluation, "parameter-grid-evaluation.json") save_circuit_template_params(optimal_parameters, "optimal-parameters.json")
def run_circuit_and_measure( backend_specs: Dict, circuit: str, noise_model: str = "None", device_connectivity: str = "None", ): backend_specs = json.loads(backend_specs) if noise_model != "None": backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity != "None": backend_specs["device_connectivity"] = load_circuit_connectivity( device_connectivity) backend = create_object(backend_specs) circuit = load_circuit(circuit) measurements = backend.run_circuit_and_measure(circuit) measurements.save("measurements.json")
def run_circuit_and_measure( backend_specs: Dict, circuit: str, noise_model: Optional[str] = None, device_connectivity: Optional[str] = None, ): if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) if noise_model is not None: backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity is not None: backend_specs["device_connectivity"] = load_circuit_connectivity( device_connectivity) backend = create_object(backend_specs) circuit = load_circuit(circuit) measurements = backend.run_circuit_and_measure(circuit) measurements.save("measurements.json")
def get_bitstring_distribution( backend_specs: Dict, circuit: str, noise_model: str = "None", device_connectivity: str = "None", ): backend_specs = json.loads(backend_specs) if noise_model != "None": backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity != "None": backend_specs["device_connectivity"] = load_circuit_connectivity( device_connectivity) backend = create_object(backend_specs) circuit = load_circuit(circuit) bitstring_distribution = backend.get_bitstring_distribution(circuit) save_bitstring_distribution(bitstring_distribution, "bitstring-distribution.json")
def test_build_uniform_param_grid_ansatz_specs_as_string( self, number_of_ansatz_layers, problem_size, number_of_layers, min_value, max_value, step, ): # Given expected_parameter_grid_filename = "parameter-grid.json" ansatz_specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockAnsatz", "number_of_layers": number_of_ansatz_layers, "problem_size": problem_size, } ansatz = create_object(copy.deepcopy(ansatz_specs)) expected_parameter_grid = _build_uniform_param_grid( ansatz.number_of_params, number_of_layers, min_value=min_value, max_value=max_value, step=step, ) # When build_uniform_param_grid( ansatz_specs=json.dumps(ansatz_specs), number_of_layers=number_of_layers, min_value=min_value, max_value=max_value, step=step, ) # Then try: parameter_grid = load_parameter_grid( expected_parameter_grid_filename) assert [tuple(param) for param in parameter_grid.param_ranges ] == expected_parameter_grid.param_ranges finally: remove_file_if_exists(expected_parameter_grid_filename)
def get_bitstring_distribution( backend_specs: Specs, circuit: str, noise_model: Optional[str] = None, device_connectivity: Optional[str] = None, ): if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) if noise_model is not None: backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity is not None: backend_specs["device_connectivity"] = layouts.load_circuit_connectivity( device_connectivity ) backend = create_object(backend_specs) circuit = circuits.load_circuit(circuit) bitstring_distribution = backend.get_bitstring_distribution(circuit) save_bitstring_distribution(bitstring_distribution, "bitstring-distribution.json")
def run_circuit_and_measure( backend_specs: Specs, circuit: Union[str, Dict], n_samples: Optional[int] = None, noise_model: Optional[str] = None, device_connectivity: Optional[str] = None, ): if isinstance(backend_specs, str): backend_specs = json.loads(backend_specs) if noise_model is not None: backend_specs["noise_model"] = load_noise_model(noise_model) if device_connectivity is not None: backend_specs["device_connectivity"] = layouts.load_circuit_connectivity( device_connectivity ) backend = create_object(backend_specs) if isinstance(circuit, str): circuit = circuits.load_circuit(circuit) else: circuit = circuits.circuit_from_dict(circuit) measurements = backend.run_circuit_and_measure(circuit, n_samples=n_samples) measurements.save("measurements.json")
def test_build_ansatz_circuit_ansatz_specs_as_string(self): # Given number_of_layers = 2 ansatz_specs = { "module_name": "zquantum.core.interfaces.mock_objects", "function_name": "MockAnsatz", "number_of_layers": number_of_layers, "problem_size": 2, } ansatz = create_object(copy.deepcopy(ansatz_specs)) expected_circuit = ansatz.parametrized_circuit # When build_ansatz_circuit(ansatz_specs=json.dumps(ansatz_specs)) # Then try: circuit_filename = "circuit.json" circuit = load_circuit(circuit_filename) assert isinstance(circuit, Circuit) assert circuit == expected_circuit finally: remove_file_if_exists(circuit_filename)