From a0592e658ab1f5090b1cc5bfa5b9ac5845fcf98c Mon Sep 17 00:00:00 2001 From: Christopher Wood Date: Fri, 24 Aug 2018 12:45:10 -0400 Subject: [PATCH] removed quantum program from tomography module (#818) * removed quantum program from tomography module, tutorials will need updating * removing QuantumProgram from dosctrings * linter * more linter --- qiskit/tools/qcvv/tomography.py | 179 ++++++++------------------------ test/python/test_tomography.py | 106 ++++++++++--------- 2 files changed, 102 insertions(+), 183 deletions(-) diff --git a/qiskit/tools/qcvv/tomography.py b/qiskit/tools/qcvv/tomography.py index a0aab45889ad..4a9a17fa109e 100644 --- a/qiskit/tools/qcvv/tomography.py +++ b/qiskit/tools/qcvv/tomography.py @@ -13,9 +13,9 @@ Description: This module contains functions for performing quantum state and quantum process tomography. This includes: - - Functions for generating a set of circuits in a QuantumProgram to + - Functions for generating a set of circuits to extract tomographically complete sets of measurement data. - - Functions for generating a tomography data set from the QuantumProgram + - Functions for generating a tomography data set from the results after the circuits have been executed on a backend. - Functions for reconstructing a quantum state, or quantum process (Choi-matrix) from tomography data sets. @@ -34,9 +34,7 @@ - `tomography_set`, `state_tomography_set`, and `process_tomography_set` all generates data structures for tomography experiments. - `create_tomography_circuits` generates the quantum circuits specified - in a `tomography_set` and adds them to a `QuantumProgram` for perform - state tomography of the output of a state preparation circuit, or - process tomography of a circuit. + in a `tomography_set` for performing state tomography of the output - `tomography_data` extracts the results after executing the tomography circuits and returns it in a data structure used by fitters for state reconstruction. @@ -51,6 +49,7 @@ import numpy as np +from qiskit import QuantumCircuit from qiskit import QISKitError from qiskit.tools.qi.qi import vectorize, devectorize, outer @@ -500,7 +499,7 @@ def tomography_circuit_names(tomo_set, name=''): ############################################################################### -def create_tomography_circuits(qp, name, qreg, creg, tomoset): +def create_tomography_circuits(circuit, qreg, creg, tomoset): """ Add tomography measurement circuits to a QuantumProgram. @@ -516,8 +515,8 @@ def create_tomography_circuits(qp, name, qreg, creg, tomoset): quantum program. Args: - qp (QuantumProgram): A quantum program to store the circuits. - name (string): The name of the base circuit to be appended. + circuit (QuantumCircuit): The circuit to be appended with tomography + state preparation and/or measurements. qreg (QuantumRegister): the quantum register containing qubits to be measured. creg (ClassicalRegister): the classical register containing bits to @@ -525,7 +524,10 @@ def create_tomography_circuits(qp, name, qreg, creg, tomoset): tomoset (tomography_set): the dict of tomography configurations. Returns: - list: A list of names of the added quantum state tomography circuits. + list: A list of quantum tomography circuits for the input circuit. + + Raises: + QISKitError: if circuit is not a valid QuantumCircuit Example: For a tomography set specififying state tomography of qubit-0 prepared @@ -547,33 +549,34 @@ def create_tomography_circuits(qp, name, qreg, creg, tomoset): ``` """ - dics = tomoset['circuits'] - labels = tomography_circuit_names(tomoset, name) - circuit = qp.get_circuit(name) + if not isinstance(circuit, QuantumCircuit): + raise QISKitError('Input circuit must be a QuantumCircuit object') + dics = tomoset['circuits'] + labels = tomography_circuit_names(tomoset, circuit.name) + tomography_circuits = [] for label, conf in zip(labels, dics): tmp = circuit # Add prep circuits if 'prep' in conf: - prep = qp.create_circuit('tmp_prep', [qreg], [creg]) + prep = QuantumCircuit(qreg, creg, name='tmp_prep') for qubit, op in conf['prep'].items(): tomoset['prep_basis'].prep_gate(prep, qreg[qubit], op) prep.barrier(qreg[qubit]) tmp = prep + tmp - del qp._QuantumProgram__quantum_program['tmp_prep'] # Add measurement circuits - meas = qp.create_circuit('tmp_meas', [qreg], [creg]) + meas = QuantumCircuit(qreg, creg, name='tmp_meas') for qubit, op in conf['meas'].items(): meas.barrier(qreg[qubit]) tomoset['meas_basis'].meas_gate(meas, qreg[qubit], op) meas.measure(qreg[qubit], creg[qubit]) tmp = tmp + meas - del qp._QuantumProgram__quantum_program['tmp_meas'] - # Add tomography circuit - qp.add_circuit(label, tmp) + # Add label to the circuit + tmp.name = label + tomography_circuits.append(tmp) - logger.info('>> created tomography circuits for "%s"', name) - return labels + logger.info('>> created tomography circuits for "%s"', circuit.name) + return tomography_circuits ############################################################################### @@ -901,113 +904,16 @@ def __wizard(rho, epsilon=None): return rho_wizard -############################################################################### -# DEPRECIATED r0.3 TOMOGRAPHY FUNCTIONS -# -# The following functions are here for backwards compatability with the -# r0.3 QISKit notebooks, but will be removed in the following release. -############################################################################### - - -def build_state_tomography_circuits(Q_program, - name, - qubits, - qreg, - creg, - meas_basis='Pauli', - silent=False): - """Depreciated function: Use `create_tomography_circuits` function instead. - """ - # pylint: disable=unused-argument - tomoset = tomography_set(qubits, meas_basis) - logger.warning( - 'WARNING: `build_state_tomography_circuits` is depreciated. ' - 'Use `tomography_set` and `create_tomography_circuits` instead') - - return create_tomography_circuits( - Q_program, name, qreg, creg, tomoset) - - -def build_process_tomography_circuits(Q_program, - name, - qubits, - qreg, - creg, - prep_basis='SIC', - meas_basis='Pauli'): - """Depreciated function: Use `create_tomography_circuits` function instead. - """ - - logger.warning( - 'WARNING: `build_process_tomography_circuits` is depreciated. ' - 'Use `tomography_set` and `create_tomography_circuits` instead') - - tomoset = tomography_set(qubits, meas_basis, prep_basis) - return create_tomography_circuits( - Q_program, name, qreg, creg, tomoset) - - -def state_tomography_circuit_names(name, qubits, meas_basis='Pauli'): - """Depreciated function: Use `tomography_circuit_names` function instead. - """ - - logger.warning( - 'WARNING: `state_tomography_circuit_names` is depreciated. ' - 'Use `tomography_set` and `tomography_circuit_names` instead') - tomoset = tomography_set(qubits, meas_basis=meas_basis) - return tomography_circuit_names(tomoset, name) - - -def process_tomography_circuit_names(name, - qubits, - prep_basis='SIC', - meas_basis='Pauli'): - """Depreciated function: Use `tomography_circuit_names` function instead. - """ - - logger.warning( - 'WARNING: `process_tomography_circuit_names` is depreciated. ' - 'Use `tomography_set` and `tomography_circuit_names` instead') - tomoset = tomography_set( - qubits, meas_basis=meas_basis, prep_basis=prep_basis) - return tomography_circuit_names(tomoset, name) - - -def state_tomography_data(Q_result, name, meas_qubits, meas_basis='Pauli'): - """Depreciated function: Use `tomography_data` function instead.""" - - logger.warning( - 'WARNING: `state_tomography_data` is depreciated. ' - 'Use `tomography_set` and `tomography_data` instead') - tomoset = tomography_set(meas_qubits, meas_basis=meas_basis) - return tomography_data(Q_result, name, tomoset) - - -def process_tomography_data(Q_result, - name, - meas_qubits, - prep_basis='SIC', - meas_basis='Pauli'): - """Depreciated function: Use `tomography_data` function instead.""" - - logger.warning( - 'WARNING: `process_tomography_data` is depreciated. ' - 'Use `tomography_set` and `tomography_data` instead') - tomoset = tomography_set( - meas_qubits, meas_basis=meas_basis, prep_basis=prep_basis) - return tomography_data(Q_result, name, tomoset) - - ############################################################### # Wigner function tomography ############################################################### -def build_wigner_circuits(q_program, name, phis, thetas, qubits, +def build_wigner_circuits(circuit, phis, thetas, qubits, qreg, creg): """Create the circuits to rotate to points in phase space Args: - q_program (QuantumProgram): A quantum program to store the circuits. - name (string): The name of the base circuit to be appended. + circuit (QuantumCircuit): The circuit to be appended with tomography + state preparation and/or measurements. phis (np.matrix[[complex]]): phis thetas (np.matrix[[complex]]): thetas qubits (list[int]): a list of the qubit indexes of qreg to be measured. @@ -1018,26 +924,31 @@ def build_wigner_circuits(q_program, name, phis, thetas, qubits, Returns: list: A list of names of the added wigner function circuits. + + Raises: + QISKitError: if circuit is not a valid QuantumCircuit. """ - orig = q_program.get_circuit(name) - labels = [] - points = len(phis[0]) + if not isinstance(circuit, QuantumCircuit): + raise QISKitError('Input circuit must be a QuantumCircuit object') + + tomography_circuits = [] + points = len(phis[0]) for point in range(points): label = '_wigner_phase_point' label += str(point) - circuit = q_program.create_circuit(label, [qreg], [creg]) - + tmp_circ = QuantumCircuit(qreg, creg, name=label) for qubit, _ in enumerate(qubits): - circuit.u3(thetas[qubit][point], 0, - phis[qubit][point], qreg[qubits[qubit]]) - circuit.measure(qreg[qubits[qubit]], creg[qubits[qubit]]) - - q_program.add_circuit(name + label, orig + circuit) - labels.append(name + label) - - logger.info('>> Created Wigner function circuits for "%s"', name) - return labels + tmp_circ.u3(thetas[qubit][point], 0, + phis[qubit][point], qreg[qubits[qubit]]) + tmp_circ.measure(qreg[qubits[qubit]], creg[qubits[qubit]]) + # Add to original circuit + tmp_circ = circuit + tmp_circ + tmp_circ.name = circuit.name + label + tomography_circuits.append(tmp_circ) + + logger.info('>> Created Wigner function circuits for "%s"', circuit.name) + return tomography_circuits def wigner_data(q_result, meas_qubits, labels, shots=None): diff --git a/test/python/test_tomography.py b/test/python/test_tomography.py index 24cf612ece5f..262220d4f303 100644 --- a/test/python/test_tomography.py +++ b/test/python/test_tomography.py @@ -13,7 +13,8 @@ import numpy as np -from qiskit import QuantumProgram +from qiskit import execute +from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister from qiskit.tools.qcvv import tomography as tomo from .common import QiskitTestCase @@ -41,27 +42,27 @@ def test_state_tomography_1qubit(self): # Tomography set tomo_set = tomo.state_tomography_set([0]) # Get test circuits - qprogram, qr, cr = _test_circuits_1qubit() + circuits, qr, cr = _test_circuits_1qubit() # Test simulation and fitting shots = 2000 threshold = 1e-2 - rho = _tomography_test_data(qprogram, 'Zp', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Zp'], qr, cr, tomo_set, shots) self.assertTrue(_tomography_test_fit(rho, [1, 0], threshold)) - rho = _tomography_test_data(qprogram, 'Zm', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Zm'], qr, cr, tomo_set, shots) self.assertTrue(_tomography_test_fit(rho, [0, 1], threshold)) - rho = _tomography_test_data(qprogram, 'Xp', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Xp'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(rho, [1 / np.sqrt(2), 1 / np.sqrt(2)], threshold)) - rho = _tomography_test_data(qprogram, 'Xm', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Xm'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(rho, [1 / np.sqrt(2), -1 / np.sqrt(2)], threshold)) - rho = _tomography_test_data(qprogram, 'Yp', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Yp'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(rho, [1 / np.sqrt(2), 1j / np.sqrt(2)], threshold)) - rho = _tomography_test_data(qprogram, 'Ym', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Ym'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(rho, [1 / np.sqrt(2), -1j / np.sqrt(2)], threshold)) @@ -70,30 +71,30 @@ def test_state_tomography_2qubit(self): # Tomography set tomo_set = tomo.state_tomography_set([0, 1]) # Get test circuits - qprogram, qr, cr = _test_circuits_2qubit() + circuits, qr, cr = _test_circuits_2qubit() shots = 2000 threshold = 1e-2 # Test simulation and fitting - rho = _tomography_test_data(qprogram, 'Bell', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['Bell'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(rho, [1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)], threshold)) - rho = _tomography_test_data(qprogram, 'X1Id0', qr, cr, tomo_set, shots) + rho = _tomography_test_data(circuits['X1Id0'], qr, cr, tomo_set, shots) self.assertTrue(_tomography_test_fit(rho, [0, 0, 1, 0], threshold)) def test_process_tomography_1qubit(self): # Tomography set tomo_set = tomo.process_tomography_set([0]) # Get test circuits - qprogram, qr, cr = _test_circuits_1qubit() + circuits, qr, cr = _test_circuits_1qubit() # Test simulation and fitting shots = 2000 threshold = 1e-2 - choi = _tomography_test_data(qprogram, 'Zp', qr, cr, tomo_set, shots) + choi = _tomography_test_data(circuits['Zp'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(choi, [1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)], threshold)) - choi = _tomography_test_data(qprogram, 'Xp', qr, cr, tomo_set, shots) + choi = _tomography_test_data(circuits['Xp'], qr, cr, tomo_set, shots) self.assertTrue( _tomography_test_fit(choi, [0.5, 0.5, 0.5, -0.5], threshold)) @@ -101,21 +102,20 @@ def test_process_tomography_2qubit(self): # Tomography set tomo_set = tomo.process_tomography_set([0, 1]) # Get test circuits - qprogram, qr, cr = _test_circuits_2qubit() + circuits, qr, cr = _test_circuits_2qubit() # Test simulation and fitting shots = 1000 threshold = 0.015 ref_x1_id0 = np.array( [0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0]) / 2 - choi = _tomography_test_data(qprogram, 'X1Id0', qr, cr, tomo_set, shots) + choi = _tomography_test_data(circuits['X1Id0'], qr, cr, tomo_set, shots) self.assertTrue(_tomography_test_fit(choi, ref_x1_id0, threshold)) -def _tomography_test_data(qprogram, name, qr, cr, tomoset, shots): - tomo.create_tomography_circuits(qprogram, name, qr, cr, tomoset) - result = qprogram.execute(tomo.tomography_circuit_names(tomoset, name), - shots=shots, seed=42, timeout=180) - data = tomo.tomography_data(result, name, tomoset) +def _tomography_test_data(circuit, qr, cr, tomoset, shots): + tomo_circs = tomo.create_tomography_circuits(circuit, qr, cr, tomoset) + result = execute(tomo_circs, 'local_qasm_simulator', shots=shots, seed=42).result() + data = tomo.tomography_data(result, circuit.name, tomoset) return tomo.fit_tomography_data(data) @@ -126,43 +126,51 @@ def _tomography_test_fit(fitted_rho, ref_state_vector, threshold=1e-2): def _test_circuits_1qubit(): - qprogram = QuantumProgram() - qr = qprogram.create_quantum_register('qr', 1) - cr = qprogram.create_classical_register('cr', 1) + circuits = {} + qr = QuantumRegister(1, name='qr') + cr = ClassicalRegister(1, name='cr') # Test Circuits Z eigenstate - circ = qprogram.create_circuit('Zp', [qr], [cr]) - circ = qprogram.create_circuit('Zm', [qr], [cr]) - circ.x(qr[0]) + tmp = QuantumCircuit(qr, cr, name='Zp') + circuits['Zp'] = tmp + tmp = QuantumCircuit(qr, cr, name='Zm') + tmp.x(qr[0]) + circuits['Zm'] = tmp # Test Circuits X eigenstate - circ = qprogram.create_circuit('Xp', [qr], [cr]) - circ.h(qr[0]) - circ = qprogram.create_circuit('Xm', [qr], [cr]) - circ.h(qr[0]) - circ.z(qr[0]) + tmp = QuantumCircuit(qr, cr, name='Xp') + tmp.h(qr[0]) + circuits['Xp'] = tmp + tmp = QuantumCircuit(qr, cr, name='Xm') + tmp.h(qr[0]) + tmp.z(qr[0]) + circuits['Xm'] = tmp # Test Circuits Y eigenstate - circ = qprogram.create_circuit('Yp', [qr], [cr]) - circ.h(qr[0]) - circ.s(qr[0]) - circ = qprogram.create_circuit('Ym', [qr], [cr]) - circ.h(qr[0]) - circ.s(qr[0]) - circ.z(qr[0]) - return qprogram, qr, cr + tmp = QuantumCircuit(qr, cr, name='Yp') + tmp.h(qr[0]) + tmp.s(qr[0]) + circuits['Yp'] = tmp + tmp = QuantumCircuit(qr, cr, name='Ym') + tmp.h(qr[0]) + tmp.s(qr[0]) + tmp.z(qr[0]) + circuits['Ym'] = tmp + return circuits, qr, cr def _test_circuits_2qubit(): - qprogram = QuantumProgram() - qr = qprogram.create_quantum_register('qr', 2) - cr = qprogram.create_classical_register('cr', 2) + circuits = {} + qr = QuantumRegister(2, name='qr') + cr = ClassicalRegister(2, name='cr') # Test Circuits Bell state - circ = qprogram.create_circuit('Bell', [qr], [cr]) - circ.h(qr[0]) - circ.cx(qr[0], qr[1]) - circ = qprogram.create_circuit('X1Id0', [qr], [cr]) - circ.x(qr[1]) - return qprogram, qr, cr + tmp = QuantumCircuit(qr, cr, name='Bell') + tmp.h(qr[0]) + tmp.cx(qr[0], qr[1]) + circuits['Bell'] = tmp + tmp = QuantumCircuit(qr, cr, name='X1Id0') + tmp.x(qr[1]) + circuits['X1Id0'] = tmp + return circuits, qr, cr if __name__ == '__main__':