Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Backend example #372

Merged
merged 10 commits into from
Mar 28, 2018
20 changes: 10 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ jobs:
python: 3.6

# OSX, Python 3.latest (brew does not support versioning)
- stage: test
<<: *stage_osx
# - stage: test
# <<: *stage_osx

# "deploy" stage.
###########################################################################
Expand All @@ -168,11 +168,11 @@ jobs:
<<: *deploy_pypi

# OSX, Python 3.latest (brew does not support versions)
- stage: deploy doc and pypi
<<: *stage_osx
if: branch = stable and repo = QISKit/qiskit-sdk-py and type = push
install: mkdir out && cd out && cmake $CMAKE_FLAGS ..
script: cd ..
deploy:
<<: *deploy_pypi
distributions: "bdist_wheel"
# - stage: deploy doc and pypi
# <<: *stage_osx
# if: branch = stable and repo = QISKit/qiskit-sdk-py and type = push
# install: mkdir out && cd out && cmake $CMAKE_FLAGS ..
# script: cd ..
# deploy:
# <<: *deploy_pypi
# distributions: "bdist_wheel"
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