def circuit(angles): """Prepares the quantum state in the problem statement and returns qml.probs Args: - angles (list(float)): The relevant angles in the problem statement in this order: [alpha, beta, gamma] Returns: - (np.tensor): The probability of each computational basis state """ # QHACK # # Prepare -|001011> qml.PauliX(wires=2) qml.PauliX(wires=4) qml.PauliX(wires=5) qml.PauliZ(wires=2) # Exchange excitations qml.SingleExcitation(angles[0], wires=(1, 4)) # Rotate |001011> -> |011001> qml.DoubleExcitation(3 * np.pi + angles[1], wires=(0, 1, 4, 5)) # Rotate |001011> -> |111000> qml.QubitUnitary(triple_excitation_matrix(angles[2]), wires=(0, 1, 2, 3, 4, 5)) # Rotate |111000> -> |000111> # QHACK # return qml.probs(wires=range(NUM_WIRES))
def test_double_excitation_generator(self, phi): """Tests that the DoubleExcitation operation calculates the correct generator""" op = qml.DoubleExcitation(phi, wires=[0, 1, 2, 3]) g, a = op.generator res = expm(1j * a * g * phi) exp = DoubleExcitation(phi) assert np.allclose(res, exp)
def circuit_default(): qml.BasisState(hf_state, wires=range(qubits)) for i, excitation in enumerate(excitations): if len(excitation) == 4: qml.DoubleExcitation(1, wires=excitation) elif len(excitation) == 2: qml.SingleExcitation(1, wires=excitation) return qml.expval(qml.SparseHamiltonian(H_sparse, wires=wires))
def test_double_excitation_decomp(self, phi): """Tests that the DoubleExcitation operation calculates the correct decomposition""" op = qml.DoubleExcitation(phi, wires=[0, 1, 2, 3]) decomp = op.decomposition() mats = [m.matrix for m in decomp] decomposed_matrix = mats[0] @ mats[1] exp = DoubleExcitation(phi) assert np.allclose(decomposed_matrix, exp)
def op(op_name): ops_list = { "RX": qml.RX(0.123, wires=0), "RY": qml.RY(1.434, wires=0), "RZ": qml.RZ(2.774, wires=0), "S": qml.S(wires=0), "SX": qml.SX(wires=0), "T": qml.T(wires=0), "CNOT": qml.CNOT(wires=[0, 1]), "CZ": qml.CZ(wires=[0, 1]), "CY": qml.CY(wires=[0, 1]), "SWAP": qml.SWAP(wires=[0, 1]), "ISWAP": qml.ISWAP(wires=[0, 1]), "SISWAP": qml.SISWAP(wires=[0, 1]), "SQISW": qml.SQISW(wires=[0, 1]), "CSWAP": qml.CSWAP(wires=[0, 1, 2]), "PauliRot": qml.PauliRot(0.123, "Y", wires=0), "IsingXX": qml.IsingXX(0.123, wires=[0, 1]), "IsingXY": qml.IsingXY(0.123, wires=[0, 1]), "IsingYY": qml.IsingYY(0.123, wires=[0, 1]), "IsingZZ": qml.IsingZZ(0.123, wires=[0, 1]), "Identity": qml.Identity(wires=0), "Rot": qml.Rot(0.123, 0.456, 0.789, wires=0), "Toffoli": qml.Toffoli(wires=[0, 1, 2]), "PhaseShift": qml.PhaseShift(2.133, wires=0), "ControlledPhaseShift": qml.ControlledPhaseShift(1.777, wires=[0, 2]), "CPhase": qml.CPhase(1.777, wires=[0, 2]), "MultiRZ": qml.MultiRZ(0.112, wires=[1, 2, 3]), "CRX": qml.CRX(0.836, wires=[2, 3]), "CRY": qml.CRY(0.721, wires=[2, 3]), "CRZ": qml.CRZ(0.554, wires=[2, 3]), "Hadamard": qml.Hadamard(wires=0), "PauliX": qml.PauliX(wires=0), "PauliY": qml.PauliY(wires=0), "PauliZ": qml.PauliZ(wires=0), "CRot": qml.CRot(0.123, 0.456, 0.789, wires=[0, 1]), "DiagonalQubitUnitary": qml.DiagonalQubitUnitary(np.array([1.0, 1.0j]), wires=1), "ControlledQubitUnitary": qml.ControlledQubitUnitary( np.eye(2) * 1j, wires=[0], control_wires=[2] ), "MultiControlledX": qml.MultiControlledX(wires=(0, 1, 2), control_values="01"), "SingleExcitation": qml.SingleExcitation(0.123, wires=[0, 3]), "SingleExcitationPlus": qml.SingleExcitationPlus(0.123, wires=[0, 3]), "SingleExcitationMinus": qml.SingleExcitationMinus(0.123, wires=[0, 3]), "DoubleExcitation": qml.DoubleExcitation(0.123, wires=[0, 1, 2, 3]), "DoubleExcitationPlus": qml.DoubleExcitationPlus(0.123, wires=[0, 1, 2, 3]), "DoubleExcitationMinus": qml.DoubleExcitationMinus(0.123, wires=[0, 1, 2, 3]), "QFT": qml.QFT(wires=0), "QubitSum": qml.QubitSum(wires=[0, 1, 2]), "QubitCarry": qml.QubitCarry(wires=[0, 1, 2, 3]), "QubitUnitary": qml.QubitUnitary(np.eye(2) * 1j, wires=0), } return ops_list.get(op_name)
def test_double_excitation_decomp(self, phi): """Tests that the DoubleExcitation operation calculates the correct decomposition. The decomposition has already been expressed in terms of single-qubit rotations and CNOTs. For each term in the decomposition we need to construct the appropriate four-qubit tensor product matrix and then multiply them together. """ decomp = qml.DoubleExcitation(phi, wires=[0, 1, 2, 3]).decompose() from functools import reduce # To compute the matrix for CX on an arbitrary number of qubits, use the fact that # CU = |0><0| \otimes I + |1><1| \otimes U def cnot_four_qubits(wires): proj_0_term = [ StateZeroProjector if idx == wires[0] else np.eye(2) for idx in range(4) ] proj_1_term = [np.eye(2) for idx in range(4)] proj_1_term[wires[0]] = StateOneProjector proj_1_term[wires[1]] = X proj_0_kron = reduce(np.kron, proj_0_term) proj_1_kron = reduce(np.kron, proj_1_term) return proj_0_kron + proj_1_kron # Inserts a single-qubit matrix into a four-qubit matrix at the right place def single_mat_four_qubits(mat, wire): individual_mats = [ mat if idx == wire else np.eye(2) for idx in range(4) ] return reduce(np.kron, individual_mats) mats = [] for i in reversed(decomp): # Single-qubit gate if len(i.wires.tolist()) == 1: mat = single_mat_four_qubits(i.matrix, i.wires.tolist()[0]) mats.append(mat) # Two-qubit gate else: mat = cnot_four_qubits(i.wires.tolist()) mats.append(mat) decomposed_matrix = np.linalg.multi_dot(mats) exp = DoubleExcitation(phi) assert np.allclose(decomposed_matrix, exp)
def test_integration(self, C): """Test expected serialization for a random circuit""" with qml.tape.QuantumTape() as tape: qml.RX(0.4, wires=0) qml.RY(0.6, wires=1).inv().inv() qml.CNOT(wires=[0, 1]) qml.QubitUnitary(np.eye(4), wires=[0, 1]) qml.templates.QFT(wires=[0, 1, 2]).inv() qml.DoubleExcitation(0.555, wires=[3, 2, 1, 0]) qml.DoubleExcitationMinus(0.555, wires=[0, 1, 2, 3]) qml.DoubleExcitationPlus(0.555, wires=[0, 1, 2, 3]) s = _serialize_ops(tape, self.wires_dict) dtype = np.complex64 if C else np.complex128 s_expected = ( ( [ "RX", "RY", "CNOT", "QubitUnitary", "QFT", "DoubleExcitation", "DoubleExcitationMinus", "DoubleExcitationPlus", ], [[0.4], [0.6], [], [], [], [0.555], [0.555], [0.555]], [[0], [1], [0, 1], [0, 1], [0, 1, 2], [3, 2, 1, 0], [0, 1, 2, 3], [0, 1, 2, 3]], [False, False, False, False, False, False, False, False], [ [], [], [], qml.matrix(qml.QubitUnitary(np.eye(4, dtype=dtype), wires=[0, 1])), qml.matrix(qml.templates.QFT(wires=[0, 1, 2]).inv()), [], [], [], ], ), False, ) assert s[0][0] == s_expected[0][0] assert s[0][1] == s_expected[0][1] assert s[0][2] == s_expected[0][2] assert s[0][3] == s_expected[0][3] assert s[1] == s_expected[1] assert all(np.allclose(s1, s2) for s1, s2 in zip(s[0][4], s_expected[0][4]))
def expand(self): weights = self.parameters[0] with qml.tape.QuantumTape() as tape: BasisState(self.hf_state, wires=self.wires) for i, d_wires in enumerate(self.doubles): qml.DoubleExcitation(weights[len(self.singles) + i], wires=d_wires) for j, s_wires in enumerate(self.singles): qml.SingleExcitation(weights[j], wires=s_wires) return tape
def expand(self): with qml.tape.QuantumTape() as tape: qml.BasisEmbedding(self.init_state, wires=self.wires) weight = self.parameters[0] for layer in range(self.n_layers): for idx, wires in enumerate(self.qwires): if self.include_pi: qml.OrbitalRotation(np.pi, wires=wires) qml.DoubleExcitation(weight[layer][idx][0], wires=wires) qml.OrbitalRotation(weight[layer][idx][1], wires=wires) return tape
def circuit_ansatz(params, wires): """Circuit ansatz containing all the parametrized gates""" qml.QubitStateVector(unitary_group.rvs(2**4, random_state=0)[0], wires=wires) qml.RX(params[0], wires=wires[0]) qml.RY(params[1], wires=wires[1]) qml.RX(params[2], wires=wires[2]).inv() qml.RZ(params[0], wires=wires[3]) qml.CRX(params[3], wires=[wires[3], wires[0]]) qml.PhaseShift(params[4], wires=wires[2]) qml.CRY(params[5], wires=[wires[2], wires[1]]) qml.CRZ(params[5], wires=[wires[0], wires[3]]).inv() qml.PhaseShift(params[6], wires=wires[0]).inv() qml.Rot(params[6], params[7], params[8], wires=wires[0]) # # qml.Rot(params[8], params[8], params[9], wires=wires[1]).inv() qml.MultiRZ(params[11], wires=[wires[0], wires[1]]) # # qml.PauliRot(params[12], "XXYZ", wires=[wires[0], wires[1], wires[2], wires[3]]) qml.CPhase(params[12], wires=[wires[3], wires[2]]) qml.IsingXX(params[13], wires=[wires[1], wires[0]]) qml.IsingXY(params[14], wires=[wires[3], wires[2]]) qml.IsingYY(params[14], wires=[wires[3], wires[2]]) qml.IsingZZ(params[14], wires=[wires[2], wires[1]]) qml.U1(params[15], wires=wires[0]) qml.U2(params[16], params[17], wires=wires[0]) qml.U3(params[18], params[19], params[20], wires=wires[1]) # # qml.CRot(params[21], params[22], params[23], wires=[wires[1], wires[2]]).inv() # expected tofail qml.SingleExcitation(params[24], wires=[wires[2], wires[0]]) qml.DoubleExcitation(params[25], wires=[wires[2], wires[0], wires[1], wires[3]]) qml.SingleExcitationPlus(params[26], wires=[wires[0], wires[2]]) qml.SingleExcitationMinus(params[27], wires=[wires[0], wires[2]]) qml.DoubleExcitationPlus(params[27], wires=[wires[2], wires[0], wires[1], wires[3]]) qml.DoubleExcitationMinus(params[27], wires=[wires[2], wires[0], wires[1], wires[3]]) qml.RX(params[28], wires=wires[0]) qml.RX(params[29], wires=wires[1])
def test_double_excitation_matrix(self, phi): """Tests that the DoubleExcitation operation calculates the correct matrix""" op = qml.DoubleExcitation(phi, wires=[0, 1, 2, 3]) res = op.matrix exp = DoubleExcitation(phi) assert np.allclose(res, exp)
phi_t = torch.tensor(phi, dtype=torch.complex128, requires_grad=True) result = circuit(phi_t) result.backward() assert np.allclose(phi_t.grad, np.sin(phi)) label_data = [ (qml.SingleExcitation(1.2345, wires=(0, 1)), "G", "G\n(1.23)", "G\n(1)"), (qml.SingleExcitationMinus(1.2345, wires=(0, 1)), "G₋", "G₋\n(1.23)", "G₋\n(1)"), (qml.SingleExcitationPlus(1.2345, wires=(0, 1)), "G₊", "G₊\n(1.23)", "G₊\n(1)"), (qml.DoubleExcitation(2.3456, wires=(0, 1, 2, 3)), "G²", "G²\n(2.35)", "G²\n(2)"), (qml.DoubleExcitationPlus(2.3456, wires=(0, 1, 2, 3)), "G²₊", "G²₊\n(2.35)", "G²₊\n(2)"), (qml.DoubleExcitationMinus(2.345, wires=(0, 1, 2, 3)), "G²₋", "G²₋\n(2.35)", "G²₋\n(2)"), ( qml.OrbitalRotation(2.3456, wires=(0, 1, 2, 3)), "OrbitalRotation", "OrbitalRotation\n(2.35)", "OrbitalRotation\n(2)", ), ] @pytest.mark.parametrize("op, label1, label2, label3", label_data) def test_label_method(op, label1, label2, label3):
def circuit(*args): qml.PauliX(0) qml.PauliX(1) qml.DoubleExcitation(0.22350048111151138, wires=[0, 1, 2, 3]) h_qubit = generate_hamiltonian(mol)(*args) return qml.expval(h_qubit)
class TestSparse: """Tests for sparse hamiltonian observable""" @pytest.mark.parametrize("sparse_hamiltonian", SPARSE_HAMILTONIAN_TEST_DATA) def test_sparse_diagonalization(self, sparse_hamiltonian): """Test that the diagonalizing_gates property of the SparseHamiltonian class returns empty.""" num_wires = len(sparse_hamiltonian[0]) sparse_hamiltonian = coo_matrix(sparse_hamiltonian) diag_gates = qml.SparseHamiltonian( sparse_hamiltonian, range(num_wires) ).diagonalizing_gates() assert diag_gates == [] @pytest.mark.parametrize("sparse_hamiltonian", SPARSE_HAMILTONIAN_TEST_DATA) def test_sparse_typeerror(self, sparse_hamiltonian): """Test that the matrix property of the SparseHamiltonian class raises a TypeError on incorrect inputs.""" num_wires = len(sparse_hamiltonian[0]) sparse_hamiltonian = csr_matrix(sparse_hamiltonian) dev = qml.device("default.qubit", wires=num_wires) @qml.qnode(dev, diff_method="parameter-shift") def circuit(sparse_hamiltonian, num_wires): obs = qml.SparseHamiltonian(sparse_hamiltonian, range(num_wires)) return qml.expval(obs) with pytest.raises(TypeError, match="Observable must be a scipy sparse coo_matrix"): circuit(sparse_hamiltonian, num_wires) @pytest.mark.parametrize("sparse_hamiltonian", SPARSE_HAMILTONIAN_TEST_DATA) def test_sparse_matrix(self, sparse_hamiltonian, tol): """Test that the matrix property of the SparseHamiltonian class returns the correct matrix.""" num_wires = len(sparse_hamiltonian[0]) sparse_hamiltonian = coo_matrix(sparse_hamiltonian) returned_matrix = qml.SparseHamiltonian(sparse_hamiltonian, range(num_wires)).matrix assert np.allclose( returned_matrix.toarray(), sparse_hamiltonian.toarray(), atol=tol, rtol=0 ) def test_sparse_diffmethod_error(self): """Test that an error is raised when the observable is SparseHamiltonian and the differentiation method is not parameter-shift.""" dev = qml.device("default.qubit", wires=2, shots=None) @qml.qnode(dev, diff_method="backprop") def circuit(param): qml.RX(param, wires=0) return qml.expval(qml.SparseHamiltonian(coo_matrix(np.eye(4)), [0, 1])) with pytest.raises( qml.QuantumFunctionError, match="SparseHamiltonian observable must be" " used with the parameter-shift differentiation method", ): qml.grad(circuit)([0.5]) @pytest.mark.parametrize("qubits, hamiltonian, expected_output", [(4, H_hydrogen, -0.18092703)]) def test_sparse_gradient(self, qubits, hamiltonian, expected_output, tol): """Tests that gradients are computed correctly for a SparseHamiltonian observable.""" dev = qml.device("default.qubit", wires=qubits, shots=None) hamiltonian = coo_matrix(hamiltonian) @qml.qnode(dev, diff_method="parameter-shift") def circuit(param): qml.PauliX(0) qml.PauliX(1) qml.DoubleExcitation(param, wires=[0, 1, 2, 3]) return qml.expval(qml.SparseHamiltonian(hamiltonian, wires=range(qubits))) assert np.allclose(qml.grad(circuit)([0.0]), expected_output, atol=tol, rtol=0) @pytest.mark.parametrize( "qubits, operations, hamiltonian, expected_output", [ (1, [], np.array([[1.0, 0.0], [0.0, 1.0]]), 1.0), ( 2, [qml.PauliX(0), qml.PauliY(1)], np.array( [ [1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0], ] ), 1.0, ), ( 4, [ qml.PauliX(0), qml.PauliX(1), qml.DoubleExcitation(0.22350048065138242, wires=[0, 1, 2, 3]), ], H_hydrogen, -1.1373060481, ), ], ) def test_sparse_hamiltonian_expval(self, qubits, operations, hamiltonian, expected_output, tol): """Test that expectation values of sparse hamiltonians are properly calculated.""" hamiltonian = coo_matrix(hamiltonian) dev = qml.device("default.qubit", wires=qubits, shots=None) dev.apply(operations) expval = dev.expval(qml.SparseHamiltonian(hamiltonian, range(qubits)))[0] assert np.allclose(expval, expected_output, atol=tol, rtol=0) def test_sparse_expval_error(self): """Test that a DeviceError is raised when the observable is SparseHamiltonian and finite shots is requested.""" hamiltonian = coo_matrix(np.array([[1.0, 0.0], [0.0, 1.0]])) dev = qml.device("default.qubit", wires=1, shots=1) with pytest.raises(DeviceError, match="SparseHamiltonian must be used with shots=None"): dev.expval(qml.SparseHamiltonian(hamiltonian, [0]))[0]
def circuit(param): qml.PauliX(0) qml.PauliX(1) qml.DoubleExcitation(param, wires=[0, 1, 2, 3]) return qml.expval(qml.SparseHamiltonian(hamiltonian, wires=range(qubits)))
def circuit(params, wires): qml.PauliX(0) qml.PauliX(1) qml.DoubleExcitation(params[0], wires=[0, 1, 2, 3]) qml.SingleExcitation(params[1], wires=[0, 2]) qml.SingleExcitation(params[2], wires=[1, 3])
"ControlledQubitUnitary": qml.ControlledQubitUnitary(np.eye(2), control_wires=[1], wires=[0]), "MultiControlledX": qml.MultiControlledX(control_wires=[1, 2], wires=[0]), "RX": qml.RX(0, wires=[0]), "RY": qml.RY(0, wires=[0]), "RZ": qml.RZ(0, wires=[0]), "Rot": qml.Rot(0, 0, 0, wires=[0]), "S": qml.S(wires=[0]), "SWAP": qml.SWAP(wires=[0, 1]), "T": qml.T(wires=[0]), "SX": qml.SX(wires=[0]), "Toffoli": qml.Toffoli(wires=[0, 1, 2]), "QFT": qml.QFT(wires=[0, 1, 2]), "SingleExcitation": qml.SingleExcitation(0, wires=[0, 1]), "SingleExcitationPlus": qml.SingleExcitationPlus(0, wires=[0, 1]), "SingleExcitationMinus": qml.SingleExcitationMinus(0, wires=[0, 1]), "DoubleExcitation": qml.DoubleExcitation(0, wires=[0, 1, 2, 3]), "DoubleExcitationPlus": qml.DoubleExcitationPlus(0, wires=[0, 1, 2, 3]), "DoubleExcitationMinus": qml.DoubleExcitationMinus(0, wires=[0, 1, 2, 3]), "QubitCarry": qml.QubitCarry(wires=[0, 1, 2, 3]), "QubitSum:": qml.QubitSum(wires=[0, 1, 2]), } all_ops = ops.keys() # non-parametrized qubit gates I = np.identity(2) X = np.array([[0, 1], [1, 0]]) Y = np.array([[0, -1j], [1j, 0]]) Z = np.array([[1, 0], [0, -1]]) H = np.array([[1, 1], [1, -1]]) / sqrt(2) S = np.diag([1, 1j])
def circuit_decomposed(weights): qml.BasisState(np.array([1, 1, 0, 0]), wires=range(4)) qml.DoubleExcitation(weights[1], wires=[0, 1, 2, 3]) qml.SingleExcitation(weights[0], wires=[0, 1]) return qml.expval(qml.PauliZ(0))