def test_build_hartree_fock_circuit_bravyi_kitaev(self): number_of_qubits = 4 number_of_alpha_electrons = 1 number_of_beta_electrons = 1 transformation = "Bravyi-Kitaev" expected_circuit = Circuit([X(0)], n_qubits=number_of_qubits) actual_circuit = build_hartree_fock_circuit( number_of_qubits, number_of_alpha_electrons, number_of_beta_electrons, transformation, ) assert actual_circuit == expected_circuit
def test_build_hartree_fock_circuit_jordan_wigner(self): number_of_qubits = 4 number_of_alpha_electrons = 1 number_of_beta_electrons = 1 transformation = "Jordan-Wigner" expected_circuit = Circuit([X(0), X(1)], n_qubits=number_of_qubits) actual_circuit = build_hartree_fock_circuit( number_of_qubits, number_of_alpha_electrons, number_of_beta_electrons, transformation, ) assert actual_circuit == expected_circuit
def get_qulacs_state_from_circuit(self, circuit: Circuit): qulacs_state = qulacs.QuantumState(circuit.n_qubits) for executable, operations_group in itertools.groupby( circuit.operations, self.can_be_executed_natively): if executable: qulacs_circuit = convert_to_qulacs( Circuit(operations_group, circuit.n_qubits)) qulacs_circuit.update_quantum_state(qulacs_state) else: wavefunction = qulacs_state.get_vector() for operation in operations_group: wavefunction = operation.apply(wavefunction) qulacs_state.load(wavefunction) return qulacs_state
def test_ansatz_circuit_seven_layers(self, n_qubits, topology): # Given number_of_layers = 7 ansatz = QCBMAnsatz( number_of_layers=number_of_layers, number_of_qubits=n_qubits, topology=topology, ) params = [ np.random.rand(2 * n_qubits), np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)), np.random.rand(2 * n_qubits), np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)), np.random.rand(3 * n_qubits), np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)), np.random.rand(2 * n_qubits), ] expected_circuit = Circuit([ # First layer *[RX(params[0][i])(i) for i in range(n_qubits)], *[RZ(params[0][i + n_qubits])(i) for i in range(n_qubits)], # Second layer *get_entangling_layer(params[1], n_qubits, XX, topology).operations, # Third layer *[RX(params[2][i])(i) for i in range(n_qubits)], *[RZ(params[2][i + n_qubits])(i) for i in range(n_qubits)], # Fouth layer *get_entangling_layer(params[3], n_qubits, XX, topology).operations, # Fifth layer *[RX(params[4][i])(i) for i in range(n_qubits)], *[RZ(params[4][i + n_qubits])(i) for i in range(n_qubits)], *[RX(params[4][i + 2 * n_qubits])(i) for i in range(n_qubits)], # Sixth layer *get_entangling_layer(params[5], n_qubits, XX, topology).operations, # Seventh layer *[RZ(params[6][i])(i) for i in range(n_qubits)], *[RX(params[6][i + n_qubits])(i) for i in range(n_qubits)], ]) params = np.concatenate(params) # When circuit = ansatz.get_executable_circuit(params) # Then assert circuit == expected_circuit
def test_get_wavefunction_seed(self): # Given circuit = Circuit([H(0), CNOT(0, 1), CNOT(1, 2)]) backend1 = ForestSimulator("wavefunction-simulator", seed=5324) backend2 = ForestSimulator("wavefunction-simulator", seed=5324) # When wavefunction1 = backend1.get_wavefunction(circuit) wavefunction2 = backend2.get_wavefunction(circuit) # Then for (ampl1, ampl2) in zip(wavefunction1.amplitudes, wavefunction2.amplitudes): assert ampl1 == ampl2
def test_perform_context_selection(self): target_operators = [] target_operators.append(10.0 * QubitOperator("Z0")) target_operators.append(-3 * QubitOperator("Y0")) target_operators.append(1 * QubitOperator("X0")) target_operators.append(20 * QubitOperator("")) expected_operators = [] expected_operators.append(10.0 * QubitOperator("Z0")) expected_operators.append(-3 * QubitOperator("Z0")) expected_operators.append(1 * QubitOperator("Z0")) expected_operators.append(20 * QubitOperator("")) base_circuit = Circuit([X(0)]) x_term_circuit = Circuit([RY(-np.pi / 2)(0)]) y_term_circuit = Circuit([RX(np.pi / 2)(0)]) expected_circuits = [ base_circuit, base_circuit + y_term_circuit, base_circuit + x_term_circuit, base_circuit, ] estimation_tasks = [ EstimationTask(operator, base_circuit, None) for operator in target_operators ] tasks_with_context_selection = perform_context_selection( estimation_tasks) for task, expected_circuit, expected_operator in zip( tasks_with_context_selection, expected_circuits, expected_operators): assert task.operator.terms == expected_operator.terms assert task.circuit == expected_circuit
def circuits(self): circuits = [Circuit() for _ in range(5)] circuits[1] += RX(1.2)(0) circuits[1] += RY(1.5)(1) circuits[1] += RX(-0.0002)(0) circuits[1] += RY(0)(1) for circuit in circuits[2:]: circuit += RX(sympy.Symbol("theta_0"))(0) circuit += RY(sympy.Symbol("theta_1"))(1) circuit += RX(sympy.Symbol("theta_2"))(0) circuit += RY(sympy.Symbol("theta_3"))(1) return circuits
def create_X_target_unitary(number_of_params, k_body_depth=1): thetas = create_thetas(number_of_params) symbols_map = create_symbols_map(number_of_params) target_circuit = Circuit() # Add an x operator to every qubit for i in range(3): target_circuit += create_x_operator(i, thetas[i]) if k_body_depth == 2: target_circuit += create_2_qubit_x_operator(0, 1, thetas[3]) target_circuit += create_2_qubit_x_operator(0, 2, thetas[4]) target_circuit += create_2_qubit_x_operator(1, 2, thetas[5]) return target_circuit.bind(symbols_map).to_unitary()
def _zquantum_exponentiate_hamiltonian(hamiltonian, time, trotter_order): ops = [] for term in hamiltonian.get_operators(): mat = _zquantum_exponentiate_qubit_hamiltonian_term( term, time, trotter_order) ops.append( circuits.CustomGateDefinition( gate_name="custom_a", matrix=sympy.Matrix(mat), params_ordering=(), )()(0, 1)) circuit = Circuit(operations=ops * trotter_order) return circuit
def test_commutes_with_parameter_substitution(self): theta, gamma = sympy.symbols("theta, gamma") circuit = Circuit([ RX(theta / 2)(0), X(1), RY(gamma / 4).controlled(1)(1, 2), YY(0.1)(0, 4) ]) symbols_map = {theta: 0.1, gamma: 0.5} parameterized_unitary = circuit.to_unitary() unitary = circuit.bind(symbols_map).to_unitary() np.testing.assert_array_almost_equal( np.array(parameterized_unitary.subs(symbols_map), dtype=complex), unitary)
def create_XZ1_target_unitary(number_of_params, k_body_depth=1): thetas = create_thetas(number_of_params) symbols_map = create_symbols_map(number_of_params) target_circuit = Circuit() target_circuit += create_x_operator(0, thetas[0]) target_circuit += RZ(2 * thetas[1])(0) target_circuit += create_x_operator(1, thetas[2]) target_circuit += RZ(2 * thetas[3])(1) if k_body_depth == 2: target_circuit += create_2_qubit_x_operator(0, 1, thetas[4]) target_circuit += CNOT(0, 1) target_circuit += RZ(2 * thetas[5])(1) target_circuit += CNOT(0, 1) return target_circuit.bind(symbols_map).to_unitary()
def test_cvar_estimator_returns_correct_values(self, estimator, backend, operator): # Given estimation_tasks = [EstimationTask(operator, Circuit([H(0)]), 10000)] if estimator.alpha <= 0.5: target_value = -1 else: target_value = (-1 * 0.5 + 1 * (estimator.alpha - 0.5)) / estimator.alpha # When expectation_values = estimator( backend=backend, estimation_tasks=estimation_tasks, ) # Then assert expectation_values[0].values == pytest.approx(target_value, abs=2e-1)
def test_group_greedily_all_comeasureable(self): target_operator = 10.0 * QubitOperator("Y0") target_operator -= 3.0 * QubitOperator("Y0 Y1") target_operator += 1.0 * QubitOperator("Y1") target_operator += 20.0 * QubitOperator("Y0 Y1 Y2") circuit = Circuit([X(0), X(1), X(2)]) estimation_tasks = [EstimationTask(target_operator, circuit, None)] grouped_tasks = group_greedily(estimation_tasks) assert len(grouped_tasks) == 1 assert grouped_tasks[0].operator == target_operator for initial_task, modified_task in zip(estimation_tasks, grouped_tasks): assert modified_task.circuit == initial_task.circuit assert modified_task.number_of_shots == initial_task.number_of_shots
def test_allocate_shots_uniformly( self, frame_operators, n_samples, target_n_samples_list, ): allocate_shots = partial(allocate_shots_uniformly, number_of_shots=n_samples) circuit = Circuit() estimation_tasks = [ EstimationTask(operator, circuit, 1) for operator in frame_operators ] new_estimation_tasks = allocate_shots(estimation_tasks) for task, target_n_samples in zip(new_estimation_tasks, target_n_samples_list): assert task.number_of_shots == target_n_samples
def _build_circuit_layer(self, parameters: np.ndarray) -> Circuit: """Build circuit layer for the hardware efficient quantum compiling ansatz Args: parameters: The variational parameters (or symbolic parameters) Returns: Circuit containing a single layer of the Hardware Efficient Quantum Compiling Ansatz """ circuit_layer = Circuit() # Add RZ(theta) RX(pi/2) RZ(theta') RX(pi/2) RZ(theta'') circuit_layer = self._build_rotational_subcircuit( circuit_layer, parameters[:3 * self.number_of_qubits]) qubit_ids = list(range(self.number_of_qubits)) # Add CNOT(x, x+1) for x in even(qubits) for control, target in zip( qubit_ids[::2], qubit_ids[1::2]): # loop over qubits 0, 2, 4... circuit_layer += CNOT(control, target) # Add RZ(theta) RX(pi/2) RZ(theta') RX(pi/2) RZ(theta'') circuit_layer = self._build_rotational_subcircuit( circuit_layer, parameters[3 * self.number_of_qubits:6 * self.number_of_qubits], ) # Add CNOT layer working "inside -> out", skipping every other qubit for qubit_index in qubit_ids[:int(self.number_of_qubits / 2)][::-1][::2]: control = qubit_index target = self.number_of_qubits - qubit_index - 1 circuit_layer += CNOT(control, target) if qubit_index != 0 or self.number_of_qubits % 4 == 0: control = self.number_of_qubits - qubit_index target = qubit_index - 1 circuit_layer += CNOT(control, target) return circuit_layer
def create_target_unitary(thetas, number_of_layers): target_circuit = Circuit() target_circuit += RY(thetas[0])(0) target_circuit += RY(thetas[1])(1) betas = create_betas(number_of_layers) gammas = create_gammas(number_of_layers) symbols_map = create_symbols_map(number_of_layers) for layer_id in range(number_of_layers): beta = betas[layer_id] gamma = gammas[layer_id] target_circuit += RZ(2.0 * gamma)(0) target_circuit += RZ(2.0 * gamma)(1) target_circuit += RY(-thetas[0])(0) target_circuit += RY(-thetas[1])(1) target_circuit += RZ(-2.0 * beta)(0) target_circuit += RZ(-2.0 * beta)(1) target_circuit += RY(thetas[0])(0) target_circuit += RY(thetas[1])(1) return target_circuit.bind(symbols_map).to_unitary()
def test_ansatz_circuit_one_layer(self, n_qubits, topology): # Given number_of_layers = 1 ansatz = QCBMAnsatz( number_of_layers=number_of_layers, number_of_qubits=n_qubits, topology=topology, ) params = [np.random.rand(n_qubits)] expected_circuit = Circuit() for i in range(n_qubits): expected_circuit += RX(params[0][i])(i) params = np.concatenate(params) # When circuit = ansatz.get_executable_circuit(params) # Then assert circuit == expected_circuit
def test_gibbs_estimator_returns_correct_values(self, estimator, backend, operator): # Given estimation_tasks = [EstimationTask(operator, Circuit([H(0)]), 10000)] expval_0 = np.exp(1 * -estimator.alpha) # Expectation value of bitstring 0 expval_1 = np.exp(-1 * -estimator.alpha) # Expectation value of bitstring 1 # Target value is the -log of the mean of the expectation values of the 2 bitstrings target_value = -np.log((expval_1 + expval_0) / 2) # When expectation_values = estimator( backend=backend, estimation_tasks=estimation_tasks, ) # Then assert expectation_values[0].values == pytest.approx(target_value, abs=2e-2)
def _generate_circuit(self, parameters: Optional[np.ndarray] = None) -> Circuit: """Builds the ansatz circuit (based on: 2011.12245, Fig. 1) Args: params (numpy.array): input parameters of the circuit (1d array). Returns: Circuit """ if parameters is None: parameters = self.symbols assert len(parameters) == self.number_of_params circuit = Circuit() for layer_index in range(self.number_of_layers): circuit += self._build_circuit_layer( parameters[layer_index * self.number_of_params_per_layer:(layer_index + 1) * self.number_of_params_per_layer]) return circuit
def test_allocate_shots_proportionally( self, frame_operators, total_n_shots, prior_expectation_values, target_n_samples_list, ): allocate_shots = partial( allocate_shots_proportionally, total_n_shots=total_n_shots, prior_expectation_values=prior_expectation_values, ) circuit = Circuit() estimation_tasks = [ EstimationTask(operator, circuit, 1) for operator in frame_operators ] new_estimation_tasks = allocate_shots(estimation_tasks) for task, target_n_samples in zip(new_estimation_tasks, target_n_samples_list): assert task.number_of_shots == target_n_samples
def test_gives_the_same_unitary_as_original_gate_up_to_global_phase( self, gate_to_be_decomposed, target_qubits ): circuit = Circuit([gate_to_be_decomposed(*target_qubits)]) decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES) def numpy_caster(x): return np.array(x).astype(np.complex128) original_matrix = numpy_caster(circuit.operations[0].gate.wrapped_gate.matrix) decomposed_matrix = reduce( operator.matmul, [ op.gate.wrapped_gate.matrix for op in reversed(decomposed_circuit.operations) ], ) decomposed_matrix = numpy_caster(decomposed_matrix) assert _is_scaled_identity( original_matrix @ np.linalg.inv(decomposed_matrix), )
class TestEstimatorUtils: def test_get_context_selection_circuit_for_group(self): group = QubitOperator("X0 Y1") - 0.5 * QubitOperator((1, "Y")) circuit, ising_operator = get_context_selection_circuit_for_group( group) # Need to convert to QubitOperator in order to get matrix representation qubit_operator = change_operator_type(ising_operator, QubitOperator) target_unitary = qubit_operator_sparse(group) transformed_unitary = ( circuit.to_unitary().conj().T @ qubit_operator_sparse(qubit_operator) @ circuit.to_unitary()) assert np.allclose(target_unitary.todense(), transformed_unitary) def test_perform_context_selection(self): target_operators = [] target_operators.append(10.0 * QubitOperator("Z0")) target_operators.append(-3 * QubitOperator("Y0")) target_operators.append(1 * QubitOperator("X0")) target_operators.append(20 * QubitOperator("")) expected_operators = [] expected_operators.append(10.0 * QubitOperator("Z0")) expected_operators.append(-3 * QubitOperator("Z0")) expected_operators.append(1 * QubitOperator("Z0")) expected_operators.append(20 * QubitOperator("")) base_circuit = Circuit([X(0)]) x_term_circuit = Circuit([RY(-np.pi / 2)(0)]) y_term_circuit = Circuit([RX(np.pi / 2)(0)]) expected_circuits = [ base_circuit, base_circuit + y_term_circuit, base_circuit + x_term_circuit, base_circuit, ] estimation_tasks = [ EstimationTask(operator, base_circuit, None) for operator in target_operators ] tasks_with_context_selection = perform_context_selection( estimation_tasks) for task, expected_circuit, expected_operator in zip( tasks_with_context_selection, expected_circuits, expected_operators): assert task.operator.terms == expected_operator.terms assert task.circuit == expected_circuit @pytest.fixture() def frame_operators(self): operators = [ 2.0 * IsingOperator((1, "Z")) * IsingOperator((2, "Z")), 1.0 * IsingOperator((3, "Z")) * IsingOperator((0, "Z")), -1.0 * IsingOperator((2, "Z")), ] return operators @pytest.fixture() def circuits(self): circuits = [Circuit() for _ in range(5)] circuits[1] += RX(1.2)(0) circuits[1] += RY(1.5)(1) circuits[1] += RX(-0.0002)(0) circuits[1] += RY(0)(1) for circuit in circuits[2:]: circuit += RX(sympy.Symbol("theta_0"))(0) circuit += RY(sympy.Symbol("theta_1"))(1) circuit += RX(sympy.Symbol("theta_2"))(0) circuit += RY(sympy.Symbol("theta_3"))(1) return circuits @pytest.mark.parametrize( "n_samples, target_n_samples_list", [ (100, [100, 100, 100]), (17, [17, 17, 17]), ], ) def test_allocate_shots_uniformly( self, frame_operators, n_samples, target_n_samples_list, ): allocate_shots = partial(allocate_shots_uniformly, number_of_shots=n_samples) circuit = Circuit() estimation_tasks = [ EstimationTask(operator, circuit, 1) for operator in frame_operators ] new_estimation_tasks = allocate_shots(estimation_tasks) for task, target_n_samples in zip(new_estimation_tasks, target_n_samples_list): assert task.number_of_shots == target_n_samples @pytest.mark.parametrize( "total_n_shots, prior_expectation_values, target_n_samples_list", [ (400, None, [200, 100, 100]), (400, ExpectationValues(np.array([0, 0, 0])), [200, 100, 100]), (400, ExpectationValues(np.array([1, 0.3, 0.3])), [0, 200, 200]), ], ) def test_allocate_shots_proportionally( self, frame_operators, total_n_shots, prior_expectation_values, target_n_samples_list, ): allocate_shots = partial( allocate_shots_proportionally, total_n_shots=total_n_shots, prior_expectation_values=prior_expectation_values, ) circuit = Circuit() estimation_tasks = [ EstimationTask(operator, circuit, 1) for operator in frame_operators ] new_estimation_tasks = allocate_shots(estimation_tasks) for task, target_n_samples in zip(new_estimation_tasks, target_n_samples_list): assert task.number_of_shots == target_n_samples @pytest.mark.parametrize( "n_samples", [-1], ) def test_allocate_shots_uniformly_invalid_inputs( self, n_samples, ): estimation_tasks = [] with pytest.raises(ValueError): allocate_shots_uniformly(estimation_tasks, number_of_shots=n_samples) @pytest.mark.parametrize( "total_n_shots, prior_expectation_values", [ (-1, ExpectationValues(np.array([0, 0, 0]))), ], ) def test_allocate_shots_proportionally_invalid_inputs( self, total_n_shots, prior_expectation_values, ): estimation_tasks = [] with pytest.raises(ValueError): _ = allocate_shots_proportionally(estimation_tasks, total_n_shots, prior_expectation_values) def test_evaluate_estimation_circuits_no_symbols( self, circuits, ): evaluate_circuits = partial(evaluate_estimation_circuits, symbols_maps=[[] for _ in circuits]) operator = QubitOperator() estimation_tasks = [ EstimationTask(operator, circuit, 1) for circuit in circuits ] new_estimation_tasks = evaluate_circuits(estimation_tasks) for old_task, new_task in zip(estimation_tasks, new_estimation_tasks): assert old_task.circuit == new_task.circuit def test_evaluate_estimation_circuits_all_symbols( self, circuits, ): symbols_maps = [[ (sympy.Symbol("theta_0"), 0), (sympy.Symbol("theta_1"), 0), (sympy.Symbol("theta_2"), 0), (sympy.Symbol("theta_3"), 0), ] for _ in circuits] evaluate_circuits = partial( evaluate_estimation_circuits, symbols_maps=symbols_maps, ) operator = QubitOperator() estimation_tasks = [ EstimationTask(operator, circuit, 1) for circuit in circuits ] new_estimation_tasks = evaluate_circuits(estimation_tasks) for new_task in new_estimation_tasks: assert len(new_task.circuit.free_symbols) == 0 def test_group_greedily_all_different_groups(self): target_operator = 10.0 * QubitOperator("Z0") target_operator -= 3.0 * QubitOperator("Y0") target_operator += 1.0 * QubitOperator("X0") target_operator += 20.0 * QubitOperator("") expected_operators = [ 10.0 * QubitOperator("Z0"), -3.0 * QubitOperator("Y0"), 1.0 * QubitOperator("X0"), 20.0 * QubitOperator(""), ] circuit = Circuit([X(0)]) estimation_tasks = [EstimationTask(target_operator, circuit, None)] grouped_tasks = group_greedily(estimation_tasks) for task, operator in zip(grouped_tasks, expected_operators): assert task.operator == operator for initial_task, modified_task in zip(estimation_tasks, grouped_tasks): assert modified_task.circuit == initial_task.circuit assert modified_task.number_of_shots == initial_task.number_of_shots def test_group_greedily_all_comeasureable(self): target_operator = 10.0 * QubitOperator("Y0") target_operator -= 3.0 * QubitOperator("Y0 Y1") target_operator += 1.0 * QubitOperator("Y1") target_operator += 20.0 * QubitOperator("Y0 Y1 Y2") circuit = Circuit([X(0), X(1), X(2)]) estimation_tasks = [EstimationTask(target_operator, circuit, None)] grouped_tasks = group_greedily(estimation_tasks) assert len(grouped_tasks) == 1 assert grouped_tasks[0].operator == target_operator for initial_task, modified_task in zip(estimation_tasks, grouped_tasks): assert modified_task.circuit == initial_task.circuit assert modified_task.number_of_shots == initial_task.number_of_shots def test_group_individually(self): target_operator = 10.0 * QubitOperator("Z0") target_operator += 5.0 * QubitOperator("Z1") target_operator -= 3.0 * QubitOperator("Y0") target_operator += 1.0 * QubitOperator("X0") target_operator += 20.0 * QubitOperator("") expected_operator_terms_per_frame = [ (10.0 * QubitOperator("Z0")).terms, (5.0 * QubitOperator("Z1")).terms, (-3.0 * QubitOperator("Y0")).terms, (1.0 * QubitOperator("X0")).terms, (20.0 * QubitOperator("")).terms, ] circuit = Circuit([X(0)]) estimation_tasks = [EstimationTask(target_operator, circuit, None)] grouped_tasks = group_individually(estimation_tasks) assert len(grouped_tasks) == 5 for task in grouped_tasks: assert task.operator.terms in expected_operator_terms_per_frame @pytest.mark.parametrize( ",".join([ "estimation_tasks", "ref_estimation_tasks_to_measure", "ref_non_measured_estimation_tasks", "ref_indices_to_measure", "ref_non_measured_indices", ]), [ ( [ EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"), Circuit([X(0)]), 10), EstimationTask( IsingOperator("2[Z0] + 3 [Z1 Z2] + 4[]"), Circuit([RZ(np.pi / 2)(0)]), 1000, ), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 17, ), ], [ EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"), Circuit([X(0)]), 10), EstimationTask( IsingOperator("2[Z0] + 3 [Z1 Z2] + 4 []"), Circuit([RZ(np.pi / 2)(0)]), 1000, ), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 17, ), ], [], [0, 1, 2], [], ), ( [ EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"), Circuit([X(0)]), 10), EstimationTask( IsingOperator("4[] "), Circuit([RZ(np.pi / 2)(0)]), 1000, ), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 17, ), ], [ EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"), Circuit([X(0)]), 10), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 17, ), ], [ EstimationTask(IsingOperator("4[]"), Circuit([RZ(np.pi / 2)(0)]), 1000) ], [0, 2], [1], ), ( [ EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]), 0), EstimationTask( IsingOperator("2[Z0] + 3 [Z1 Z2] + 4[]"), Circuit([RZ(np.pi / 2)(0)]), 1000, ), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 17, ), ], [ EstimationTask( IsingOperator("2[Z0] + 3 [Z1 Z2] + 4 []"), Circuit([RZ(np.pi / 2)(0)]), 1000, ), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 17, ), ], [ EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]), 0), ], [1, 2], [0], ), ( [ EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]), 0), EstimationTask( IsingOperator("2[Z0] + 3 [Z1 Z2] + 4[]"), Circuit([RZ(np.pi / 2)(0)]), 1000, ), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 0, ), ], [ EstimationTask( IsingOperator("2[Z0] + 3 [Z1 Z2] + 4 []"), Circuit([RZ(np.pi / 2)(0)]), 1000, ), ], [ EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]), 0), EstimationTask( IsingOperator("4[Z3]"), Circuit([RY(np.pi / 2)(0)]), 0, ), ], [1], [0, 2], ), ], ) def test_split_estimation_tasks_to_measure( self, estimation_tasks, ref_estimation_tasks_to_measure, ref_non_measured_estimation_tasks, ref_indices_to_measure, ref_non_measured_indices, ): ( estimation_task_to_measure, non_measured_estimation_tasks, indices_to_measure, indices_for_non_measureds, ) = split_estimation_tasks_to_measure(estimation_tasks) assert estimation_task_to_measure == ref_estimation_tasks_to_measure assert non_measured_estimation_tasks == ref_non_measured_estimation_tasks assert indices_to_measure == ref_indices_to_measure assert ref_non_measured_indices == indices_for_non_measureds @pytest.mark.parametrize( "estimation_tasks,ref_expectation_values", [ ( [ EstimationTask( IsingOperator("4[] "), Circuit([RZ(np.pi / 2)(0)]), 1000, ), ], [ ExpectationValues( np.asarray([4.0]), correlations=[np.asarray([[0.0]])], estimator_covariances=[np.asarray([[0.0]])], ), ], ), ( [ EstimationTask(IsingOperator("- 2.5 [] - 0.5 []"), Circuit([X(0)]), 0), EstimationTask(IsingOperator("0.001[] "), Circuit([RZ(np.pi / 2)(0)]), 2), EstimationTask( IsingOperator("2.5 [Z1] + 1.0 [Z2 Z3]"), Circuit([RY(np.pi / 2)(0)]), 0, ), ], [ ExpectationValues( np.asarray([-3.0]), correlations=[np.asarray([[0.0]])], estimator_covariances=[np.asarray([[0.0]])], ), ExpectationValues( np.asarray([0.001]), correlations=[np.asarray([[0.0]])], estimator_covariances=[np.asarray([[0.0]])], ), ExpectationValues( np.asarray([0.0]), correlations=[np.asarray([[0.0]])], estimator_covariances=[np.asarray([[0.0]])], ), ], ), ], ) def test_evaluate_non_measured_estimation_tasks(self, estimation_tasks, ref_expectation_values): expectation_values = evaluate_non_measured_estimation_tasks( estimation_tasks) for ex_val, ref_ex_val in zip(expectation_values, ref_expectation_values): assert np.allclose(ex_val.values, ref_ex_val.values) assert np.allclose(ex_val.correlations, ref_ex_val.correlations) assert np.allclose(ex_val.estimator_covariances, ref_ex_val.estimator_covariances) @pytest.mark.parametrize( "estimation_tasks", [ ([ EstimationTask(IsingOperator("- 2.5 [] - 0.5 [Z1]"), Circuit([X(0)]), 1), ]), ([ EstimationTask( IsingOperator("0.001 [Z0]"), Circuit([RZ(np.pi / 2)(0)]), 0, ), EstimationTask(IsingOperator("2.0[] "), Circuit([RZ(np.pi / 2)(0)]), 2), EstimationTask( IsingOperator("1.5 [Z0 Z1]"), Circuit([RY(np.pi / 2)(0)]), 10, ), ]), ], ) def test_evaluate_non_measured_estimation_tasks_fails_with_non_zero_shots( self, estimation_tasks): with pytest.raises(RuntimeError): _ = evaluate_non_measured_estimation_tasks(estimation_tasks)
def concatenate_circuits(circuit_set: Union[str, List[Circuit]]): if isinstance(circuit_set, str): circuit_set = load_circuitset(circuit_set) result_circuit = sum(circuit_set, Circuit()) save_circuitset(result_circuit, "result-circuit.json")
def test_leaves_gates_not_matching_predicate_unaffected(self, operations): circuit = Circuit(operations) decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES) assert circuit.operations == decomposed_circuit.operations
class TestCreatingUnitaryFromCircuit: @pytest.fixture def cirq_unitaries(self): """ Note: We decided to go with file-based approach after extracting cirq from z-quantum-core and not being able to use `export_to_cirq` anymore. """ path_to_array = ("/".join(__file__.split("/")[:-1]) + "/hardcoded_cirq_unitaries.npy") return np.load(path_to_array, allow_pickle=True) @pytest.mark.parametrize( "circuit, unitary_index", [ # Identity gates in some test cases below are used so that comparable # Cirq circuits have the same number of qubits as Zquantum ones. (Circuit([RX(np.pi / 5)(0)]), 0), (Circuit([RY(np.pi / 2)(0), RX(np.pi / 5)(0)]), 1), ( Circuit( [I(1), I(2), I(3), I(4), RX(np.pi / 5)(0), XX(0.1)(5, 0)]), 2, ), ( Circuit([ XY(np.pi).controlled(1)(3, 1, 4), RZ(0.1 * np.pi).controlled(2)(0, 2, 1), ]), 3, ), ( Circuit( [H(1), YY(0.1).controlled(1)(0, 1, 2), X(2), Y(3), Z(4)]), 4, ), ], ) def test_without_free_params_gives_the_same_result_as_cirq( self, circuit, unitary_index, cirq_unitaries): zquantum_unitary = circuit.to_unitary() assert isinstance( zquantum_unitary, np.ndarray ), "Unitary constructed from non-parameterized circuit is not a numpy array." np.testing.assert_array_almost_equal(zquantum_unitary, cirq_unitaries[unitary_index]) def test_commutes_with_parameter_substitution(self): theta, gamma = sympy.symbols("theta, gamma") circuit = Circuit([ RX(theta / 2)(0), X(1), RY(gamma / 4).controlled(1)(1, 2), YY(0.1)(0, 4) ]) symbols_map = {theta: 0.1, gamma: 0.5} parameterized_unitary = circuit.to_unitary() unitary = circuit.bind(symbols_map).to_unitary() np.testing.assert_array_almost_equal( np.array(parameterized_unitary.subs(symbols_map), dtype=complex), unitary)
def circuit(self): return Circuit([X(0)])
def _generate_circuit(self, params: Optional[np.ndarray] = None) -> Circuit: """Builds a qcbm ansatz circuit, using the ansatz in https://advances.sciencemag.org/content/5/10/eaaw9918/tab-pdf (Fig.2 - top). Args: params (numpy.array): input parameters of the circuit (1d array). Returns: Circuit """ if params is None: params = np.asarray([ sympy.Symbol("theta_{}".format(i)) for i in range(self.number_of_params) ]) assert len(params) == self.number_of_params if self.number_of_layers == 1: # Only one layer, should be a single layer of rotations with RX return create_layer_of_gates(self.number_of_qubits, RX, params) circuit = Circuit() parameter_index = 0 for layer_index in range(self.number_of_layers): if layer_index == 0: # First layer is always 2 single qubit rotations on RX RZ circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index:parameter_index + self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RZ, params[parameter_index + self.number_of_qubits:parameter_index + 2 * self.number_of_qubits], ) parameter_index += 2 * self.number_of_qubits elif (self.number_of_layers % 2 == 1 and layer_index == self.number_of_layers - 1): # Last layer for odd number of layers is rotations on RX RZ circuit += create_layer_of_gates( self.number_of_qubits, RZ, params[parameter_index:parameter_index + self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index + self.number_of_qubits:parameter_index + 2 * self.number_of_qubits], ) parameter_index += 2 * self.number_of_qubits elif (self.number_of_layers % 2 == 0 and layer_index == self.number_of_layers - 2): # Even number of layers, second to last layer is 3 rotation layer with RX RZ RX circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index:parameter_index + self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RZ, params[parameter_index + self.number_of_qubits:parameter_index + 2 * self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index + 2 * self.number_of_qubits:parameter_index + 3 * self.number_of_qubits], ) parameter_index += 3 * self.number_of_qubits elif (self.number_of_layers % 2 == 1 and layer_index == self.number_of_layers - 3): # Odd number of layers, third to last layer is 3 rotation layer with RX RZ RX circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index:parameter_index + self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RZ, params[parameter_index + self.number_of_qubits:parameter_index + 2 * self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index + 2 * self.number_of_qubits:parameter_index + 3 * self.number_of_qubits], ) parameter_index += 3 * self.number_of_qubits elif layer_index % 2 == 1: # Currently on an entangling layer circuit += get_entangling_layer( params[parameter_index:parameter_index + self.n_params_per_ent_layer], self.number_of_qubits, XX, self.topology, ) parameter_index += self.n_params_per_ent_layer else: # A normal single qubit rotation layer of RX RZ circuit += create_layer_of_gates( self.number_of_qubits, RX, params[parameter_index:parameter_index + self.number_of_qubits], ) circuit += create_layer_of_gates( self.number_of_qubits, RZ, params[parameter_index + self.number_of_qubits:parameter_index + 2 * self.number_of_qubits], ) parameter_index += 2 * self.number_of_qubits return circuit
10, ), ]), ], ) def test_evaluate_non_measured_estimation_tasks_fails_with_non_zero_shots( self, estimation_tasks): with pytest.raises(RuntimeError): _ = evaluate_non_measured_estimation_tasks(estimation_tasks) TEST_CASES_EIGENSTATES = [ ( [ EstimationTask(IsingOperator("Z0"), circuit=Circuit([X(0)]), number_of_shots=10), EstimationTask( IsingOperator((), coefficient=2.0), circuit=Circuit([RY(np.pi / 4)(0)]), number_of_shots=30, ), ], [ExpectationValues(np.array([-1])), ExpectationValues(np.array([2]))], ), ] TEST_CASES_NONEIGENSTATES = [ ( [ EstimationTask(
assert contract(estimator) """ import numpy as np from openfermion import IsingOperator from zquantum.core.circuits import RX, RY, RZ, Circuit, H from zquantum.core.interfaces.estimation import ( EstimateExpectationValues, EstimationTask, ) from zquantum.core.symbolic_simulator import SymbolicSimulator _backend = SymbolicSimulator(seed=1997) _estimation_tasks = [ EstimationTask(IsingOperator("Z0"), Circuit([H(0)]), 10000), EstimationTask( IsingOperator("Z0") + IsingOperator("Z1") + IsingOperator("Z2"), Circuit([H(0), RX(np.pi / 3)(0), H(2)]), 10000, ), EstimationTask( IsingOperator("Z0") + IsingOperator("Z1", 4), Circuit([ RX(np.pi)(0), RY(0.12)(1), RZ(np.pi / 3)(1), RY(1.9213)(0), ]), 10000, ),
class SymbolicSimulatorWithNonSupportedOperations(SymbolicSimulator): def is_natively_supported(self, operation: Operation) -> bool: return super().is_natively_supported( operation) and operation.gate.name != "RX" class SymbolicSimulatorWithDefaultSetOfSupportedOperations(SymbolicSimulator): def is_natively_supported(self, operation: Operation) -> bool: return QuantumSimulator.is_natively_supported(self, operation) @pytest.mark.parametrize( "circuit", [ Circuit([RY(0.5)(0), RX(1)(1), CNOT(0, 2), RX(np.pi)(2)]), Circuit([RX(1)(1), CNOT(0, 2), RX(np.pi)(2), RY(0.5)(0)]), Circuit([RX(1)(1), CNOT(0, 2), RX(np.pi)(2), RY(0.5)(0), RX(0.5)(0)]), ], ) def test_quantum_simulator_switches_between_native_and_nonnative_modes_of_execution( circuit, ): simulator = SymbolicSimulatorWithNonSupportedOperations() reference_simulator = SymbolicSimulator() np.testing.assert_array_equal(