Skip to content

Commit

Permalink
WIP Backend example (Qiskit#372)
Browse files Browse the repository at this point in the history
* Fix for the quantum program with new backends

* Fixing the tests

* Small changes

* Linting

* Update tests using coupling_map as list, add test

Update the test in order to specify the coupling_maps as lists, due
to recent changes.
Add a `test_compile_coupling_map_as_dict` that still uses the dict
format, for backwards compatibility during the deprecation.

* Update coupling_map as list related docstrings

Along with other fixes to docstrings and tests.

* Disable travis osx build temporarily (Qiskit#374)

Temporarily disable the osx build on Travis, as they are having a
backlog that might take some time to recover:
https://www.traviscistatus.com/incidents/qkqy13yk55q9

* adding a missing coupling in test_quantumprogram
  • Loading branch information
jaygambetta authored and diego-plan9 committed Mar 28, 2018
1 parent 01e82fb commit 93e40b6
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 63 deletions.
1 change: 1 addition & 0 deletions examples/python/hello_quantum.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
19 changes: 7 additions & 12 deletions qiskit/_openquantumcompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down Expand Up @@ -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)
Expand Down
63 changes: 35 additions & 28 deletions qiskit/_quantumprogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down Expand Up @@ -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)--,
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1455,27 +1460,25 @@ 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.
wait (int): Time interval to wait between requests for results
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)),
Expand Down Expand Up @@ -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
Expand Down
18 changes: 10 additions & 8 deletions test/python/test_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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)

Expand All @@ -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")
Expand Down Expand Up @@ -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"]
Expand Down
63 changes: 48 additions & 15 deletions test/python/test_quantumprogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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")
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)}
Expand All @@ -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)}
Expand Down Expand Up @@ -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": [
{
Expand Down Expand Up @@ -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."""
Expand Down

0 comments on commit 93e40b6

Please sign in to comment.