diff --git a/examples/python/hello_quantum.py b/examples/python/hello_quantum.py index 658c58e4ec2c..5c1ca40e4e0b 100644 --- a/examples/python/hello_quantum.py +++ b/examples/python/hello_quantum.py @@ -20,6 +20,7 @@ print("""WARNING: There's no connection with IBMQuantumExperience servers. Have you initialized a Qconfig.py file with your personal token? For now, there's only access to local simulator backends...""") + remote_backends = {} local_backends = qiskit.backends.discover_local_backends() try: diff --git a/qiskit/_openquantumcompiler.py b/qiskit/_openquantumcompiler.py index 2ecc58061ed0..a10f9a5a85ab 100644 --- a/qiskit/_openquantumcompiler.py +++ b/qiskit/_openquantumcompiler.py @@ -39,19 +39,14 @@ def compile(quantum_circuit, basis_gates='u1,u2,u3,cx,id', coupling_map=None, quantum_circuit (QuantumCircuit): circuit to compile basis_gates (str): a comma seperated string and are the base gates, which by default are: u1,u2,u3,cx,id - coupling_map (dict): A directed graph of coupling:: + coupling_map (list): A graph of coupling:: - { - control(int): - [ - target1(int), - target2(int), - , ... - ], - ... - } + [ + [control0(int), target0(int)], + [control1(int), target1(int)], + ] - eg. {0: [2], 1: [2], 3: [2]} + eg. [[0, 2], [1, 2], [1, 3], [3, 4]} initial_layout (dict): A mapping of qubit to qubit:: @@ -89,7 +84,7 @@ def compile(quantum_circuit, basis_gates='u1,u2,u3,cx,id', coupling_map=None, logger.info("pre-mapping properties: %s", compiled_dag_circuit.property_summary()) # Insert swap gates - coupling = mapper.Coupling(coupling_map) + coupling = mapper.Coupling(mapper.coupling_list2dict(coupling_map)) logger.info("initial layout: %s", initial_layout) compiled_dag_circuit, final_layout = mapper.swap_mapper( compiled_dag_circuit, coupling, initial_layout, trials=20, seed=13) diff --git a/qiskit/_quantumprogram.py b/qiskit/_quantumprogram.py index df51ce0db698..2ed8a14531f2 100644 --- a/qiskit/_quantumprogram.py +++ b/qiskit/_quantumprogram.py @@ -1005,26 +1005,21 @@ def compile(self, name_of_circuits=None, backend="local_qasm_simulator", circuits to run on different backends. Args: - name_of_circuits (list[hashable] or None): circuit names to be compiled. If None, all - the circuits will be compiled. + name_of_circuits (list[hashable] or hashable or None): circuit + names to be compiled. If None, all the circuits will be compiled. backend (str): a string representing the backend to compile to. config (dict): a dictionary of configurations parameters for the compiler. basis_gates (str): a comma separated string and are the base gates, which by default are provided by the backend. - coupling_map (dict): A directed graph of coupling:: + coupling_map (list): A graph of coupling:: - { - control(int): - [ - target1(int), - target2(int), - , ... - ], - ... - } + [ + [control0(int), target0(int)], + [control1(int), target1(int)], + ] - eg. {0: [2], 1: [2], 3: [2]} + eg. [[0, 2], [1, 2], [3, 2]] initial_layout (dict): A mapping of qubit to qubit:: @@ -1076,7 +1071,7 @@ def compile(self, name_of_circuits=None, backend="local_qasm_simulator", "compiled_circuit_qasm": --compiled quantum circuit (QASM format)--, "config": --dictionary of additional config settings (dict)--, { - "coupling_map": --adjacency list (dict)--, + "coupling_map": --adjacency list (list)--, "basis_gates": --comma separated gate names (string)--, "layout": --layout computed by mapper (dict)--, "seed": (simulator only)--initial seed for the simulator (int)--, @@ -1090,10 +1085,20 @@ def compile(self, name_of_circuits=None, backend="local_qasm_simulator", ValueError: if no names of the circuits have been specified. QISKitError: if any of the circuit names cannot be found on the Quantum Program. + + .. deprecated:: 0.5 + The `coupling_map` parameter as a dictionary will be deprecated in + upcoming versions. Using the coupling_map as a list is recommended. """ # TODO: Jay: currently basis_gates, coupling_map, initial_layout, # shots, max_credits and seed are extra inputs but I would like # them to go into the config. + if isinstance(coupling_map, dict): + coupling_map = qiskit.mapper.coupling_dict2list(coupling_map) + warnings.warn( + "coupling_map as a dictionary will be deprecated in upcoming versions (>0.5.0). " + "Using the coupling_map as a list recommended.", DeprecationWarning) + qobj = {} if not qobj_id: qobj_id = "".join([random.choice(string.ascii_letters + string.digits) @@ -1176,7 +1181,7 @@ def compile(self, name_of_circuits=None, backend="local_qasm_simulator", if config is None: config = {} # default to empty config dict job["config"] = copy.deepcopy(config) - job["config"]["coupling_map"] = mapper.coupling_dict2list(coupling_map) + job["config"]["coupling_map"] = coupling_map # TODO: Jay: make config options optional for different backends # Map the layout to a format that can be json encoded list_layout = None @@ -1455,8 +1460,9 @@ def execute(self, name_of_circuits=None, backend="local_qasm_simulator", circuits to run on different backends. Args: - name_of_circuits (list[hashable] or None): circuit names to be - executed. If None, all the circuits will be executed. + name_of_circuits (list[hashable] or hashable or None): circuit + names to be executed. If None, all the circuits will be + executed. backend (str): a string representing the backend to compile to. config (dict): a dictionary of configurations parameters for the compiler. @@ -1464,18 +1470,15 @@ def execute(self, name_of_circuits=None, backend="local_qasm_simulator", timeout (int): Total time to wait until the execution stops basis_gates (str): a comma separated string and are the base gates, which by default are: u1,u2,u3,cx,id. - coupling_map (dict): A directed graph of coupling:: + coupling_map (list): A graph of coupling:: + + [ + [control0(int), target0(int)], + [control1(int), target1(int)], + ] + + eg. [[0, 2], [1, 2], [3, 2]] - { - control(int): - [ - target1(int), - target2(int), - , ... - ], - ... - } - eg. {0: [2], 1: [2], 3: [2]} initial_layout (dict): A mapping of qubit to qubit { ("q", start(int)): ("q", final(int)), @@ -1506,6 +1509,10 @@ def execute(self, name_of_circuits=None, backend="local_qasm_simulator", Returns: Result: status done and populates the internal __quantum_program with the data + + .. deprecated:: 0.5 + The `coupling_map` parameter as a dictionary will be deprecated in + upcoming versions. Using the coupling_map as a list is recommended. """ # TODO: Jay: currently basis_gates, coupling_map, initial_layout, shots, # max_credits, and seed are extra inputs but I would like them to go diff --git a/test/python/test_mapper.py b/test/python/test_mapper.py index 6f18090fe843..e4847d3d0baa 100644 --- a/test/python/test_mapper.py +++ b/test/python/test_mapper.py @@ -36,7 +36,7 @@ def test_mapper_overoptimization(self): the issue #81: https://github.com/QISKit/qiskit-sdk-py/issues/81 """ self.qp.load_qasm_file(self._get_resource_path('qasm/overoptimization.qasm'), name='test') - coupling_map = {0: [2], 1: [2], 2: [3], 3: []} + coupling_map = [[0, 2], [1, 2], [2, 3]] result1 = self.qp.execute(["test"], backend="local_qasm_simulator", coupling_map=coupling_map) count1 = result1.get_counts("test") @@ -51,7 +51,7 @@ def test_math_domain_error(self): See: https://github.com/QISKit/qiskit-sdk-py/issues/111 """ self.qp.load_qasm_file(self._get_resource_path('qasm/math_domain_error.qasm'), name='test') - coupling_map = {0: [2], 1: [2], 2: [3], 3: []} + coupling_map = [[0, 2], [1, 2], [2, 3]] result1 = self.qp.execute(["test"], backend="local_qasm_simulator", coupling_map=coupling_map, seed=self.seed) @@ -73,17 +73,17 @@ def test_optimize_1q_gates_issue159(self): qc.measure(qr[0], cr[0]) qc.measure(qr[1], cr[1]) backend = 'local_qasm_simulator' - cmap = {1: [0], 2: [0, 1, 4], 3: [2, 4]} + coupling_map = [[1, 0], [2, 0], [2, 1], [2, 4], [3, 2], [3, 4]] initial_layout = {('qr', 0): ('q', 1), ('qr', 1): ('q', 0)} qobj = self.qp.compile(["Bell"], backend=backend, - initial_layout=initial_layout, coupling_map=cmap) + initial_layout=initial_layout, coupling_map=coupling_map) self.assertEqual(self.qp.get_compiled_qasm(qobj, "Bell"), EXPECTED_QASM_1Q_GATES_3_5) def test_random_parameter_circuit(self): """Run a circuit with randomly generated parameters.""" self.qp.load_qasm_file(self._get_resource_path('qasm/random_n5_d5.qasm'), name='rand') - coupling_map = {0: [1], 1: [2], 2: [3], 3: [4]} + coupling_map = [[0, 1], [1, 2], [2, 3], [3, 4]] result1 = self.qp.execute(["rand"], backend="local_qasm_simulator", coupling_map=coupling_map, seed=self.seed) res = result1.get_counts("rand") @@ -180,9 +180,11 @@ def test_already_mapped(self): for j in range(16): qc.measure(qr[j], cr[j]) backend = 'local_qasm_simulator' - cmap = {1: [0, 2], 2: [3], 3: [4, 14], 5: [4], 6: [5, 7, 11], 7: [10], 8: [7], - 9: [8, 10], 11: [10], 12: [5, 11, 13], 13: [4, 14], 15: [0, 2, 14]} - qobj = self.qp.compile(["native_cx"], backend=backend, coupling_map=cmap) + coupling_map = [[1, 0], [1, 2], [2, 3], [3, 4], [3, 14], [5, 4], + [6, 5], [6, 7], [6, 11], [7, 10], [8, 7], [9, 8], + [9, 10], [11, 10], [12, 5], [12, 11], [12, 13], + [13, 4], [13, 14], [15, 0], [15, 2], [15, 14]] + qobj = self.qp.compile(["native_cx"], backend=backend, coupling_map=coupling_map) cx_qubits = [x["qubits"] for x in qobj["circuits"][0]["compiled_circuit"]["operations"] if x["name"] == "cx"] diff --git a/test/python/test_quantumprogram.py b/test/python/test_quantumprogram.py index 2d1ed368cc44..c68623822dcf 100644 --- a/test/python/test_quantumprogram.py +++ b/test/python/test_quantumprogram.py @@ -825,7 +825,7 @@ def test_compile_coupling_map(self): qc.measure(q[2], c[2]) backend = 'local_qasm_simulator' # the backend to run on shots = 1024 # the number of shots in the experiment. - coupling_map = {0: [1], 1: [2]} + coupling_map = [[0, 1], [1, 2]] initial_layout = {("q", 0): ("q", 0), ("q", 1): ("q", 1), ("q", 2): ("q", 2)} circuits = ["circuitName"] @@ -838,6 +838,38 @@ def test_compile_coupling_map(self): self.assertEqual(result.get_counts("circuitName"), {'000': 518, '111': 506}) + def test_compile_coupling_map_as_dict(self): + """Test compile_coupling_map in dict format (to be deprecated). + + TODO: This test is very specific, and should be removed when the only + format allowed for the coupling map is a `list`. + """ + q_program = QuantumProgram() + q = q_program.create_quantum_register("q", 3) + c = q_program.create_classical_register("c", 3) + qc = q_program.create_circuit("circuitName", [q], [c]) + qc.h(q[0]) + qc.cx(q[0], q[1]) + qc.cx(q[0], q[2]) + qc.measure(q[0], c[0]) + qc.measure(q[1], c[1]) + qc.measure(q[2], c[2]) + backend = 'local_qasm_simulator' # the backend to run on + shots = 1024 # the number of shots in the experiment. + coupling_map = {0: [1], 1: [2]} # as dict + initial_layout = {("q", 0): ("q", 0), ("q", 1): ("q", 1), + ("q", 2): ("q", 2)} + circuits = ["circuitName"] + with self.assertWarns(DeprecationWarning): + qobj = q_program.compile(circuits, backend=backend, shots=shots, + coupling_map=coupling_map, + initial_layout=initial_layout, seed=88) + result = q_program.run(qobj) + to_check = q_program.get_qasm("circuitName") + self.assertEqual(len(to_check), 160) + self.assertEqual(result.get_counts("circuitName"), + {'000': 518, '111': 506}) + def test_change_circuit_qobj_after_compile(self): q_program = QuantumProgram(specs=self.QPS_SPECS) qr = q_program.get_quantum_register("q_name") @@ -901,8 +933,11 @@ def test_gate_after_measure(self, QE_TOKEN, QE_URL): api = IBMQuantumExperience(QE_TOKEN, {'url': QE_URL}) qiskit.backends.discover_remote_backends(api) backend = 'ibmqx5' - coupling_map = {1: [0, 2], 2: [3], 3: [4, 14], 5: [4], 6: [5, 7, 11], 7: [10], 8: [7], - 9: [8, 10], 11: [10], 12: [5, 11, 13], 13: [4, 14], 15: [0, 2, 14]} + coupling_map = [[1, 0], [1, 2], [2, 3], [3, 4], [3, 14], [5, 4], + [6, 5], [6, 7], [6, 11], [7, 10], [8, 7], [9, 8], + [9, 10], [11, 10], [12, 5], [12, 11], [12, 13], + [13, 4], [13, 14], [15, 0], [15, 2], [15, 14]] + initial_layout = {('qr', 0): ('q', 1), ('qr', 1): ('q', 0), ('qr', 2): ('q', 2), ('qr', 3): ('q', 3), ('qr', 4): ('q', 4), ('qr', 5): ('q', 14), @@ -1266,7 +1301,7 @@ def test_run_program_map(self): backend = 'local_qasm_simulator' # the backend to run on shots = 100 # the number of shots in the experiment. max_credits = 3 - coupling_map = {0: [1], 1: [2], 2: [3], 3: [4]} + coupling_map = [[0, 1], [1, 2], [2, 3], [3, 4]] initial_layout = {("q", 0): ("q", 0), ("q", 1): ("q", 1), ("q", 2): ("q", 2), ("q", 3): ("q", 3), ("q", 4): ("q", 4)} @@ -1288,7 +1323,7 @@ def test_execute_program_map(self): backend = 'local_qasm_simulator' # the backend to run on shots = 100 # the number of shots in the experiment. max_credits = 3 - coupling_map = {0: [1], 1: [2], 2: [3], 3: [4]} + coupling_map = [[0, 1], [1, 2], [2, 3], [3, 4]] initial_layout = {("q", 0): ("q", 0), ("q", 1): ("q", 1), ("q", 2): ("q", 2), ("q", 3): ("q", 3), ("q", 4): ("q", 4)} @@ -1552,11 +1587,10 @@ def test_example_multiple_compile(self): Pass if the results are correct. """ - coupling_map = {0: [1, 2], - 1: [2], - 2: [], - 3: [2, 4], - 4: [2]} + coupling_map = [[0, 1], [0, 2], + [1, 2], + [3, 2], [3, 4], + [4, 2]] QPS_SPECS = { "circuits": [ { @@ -1620,11 +1654,10 @@ def test_example_swap_bits(self): Uses the mapper. Pass if results are correct. """ - backend = "ibmqx_qasm_simulator" - coupling_map = {0: [1, 8], 1: [2, 9], 2: [3, 10], 3: [4, 11], - 4: [5, 12], 5: [6, 13], 6: [7, 14], 7: [15], 8: [9], - 9: [10], 10: [11], 11: [12], 12: [13], 13: [14], - 14: [15]} + coupling_map = [[0, 1], [0, 8], [1, 2], [1, 9], [2, 3], [2, 10], + [3, 4], [3, 11], [4, 5], [4, 12], [5, 6], [5, 13], + [6, 7], [6, 14], [7, 15], [8, 9], [9, 10], [10, 11], + [11, 12], [12, 13], [13, 14], [14, 15]] def swap(qc, q0, q1): """Swap gate."""