Skip to content

Commit

Permalink
Merge remote-tracking branch 'qiskit/master' into move-loading-from-q…
Browse files Browse the repository at this point in the history
…asm-to-quantum-circuit-static-methods
  • Loading branch information
diego-plan9 committed Jun 11, 2018
2 parents b85e5de + 00d37c7 commit fbbec71
Show file tree
Hide file tree
Showing 18 changed files with 349 additions and 198 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ Fixed
- Fix hardcoded backend mapping tests (#521)
- Removed ``_modifiers call`` from ``reapply`` (#534)
- Fix circuit drawer issue with filename location on windows (#543)
- Change initial qubit layout only if the backend coupling map is not satisfied (#527)
- Fix incorrect unrolling of t to tdg in CircuitBackend (#557)
- Fix issue with simulator extension commands not reapplying correctly (#556)


`0.5.3`_ - 2018-05-29
Expand Down
75 changes: 63 additions & 12 deletions qiskit/_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import copy
import uuid
import warnings

import numpy as np
import scipy.sparse as sp
Expand All @@ -27,14 +28,15 @@
from .unroll import DagUnroller, DAGBackend, JsonBackend, Unroller, CircuitBackend
from .mapper import (Coupling, optimize_1q_gates, coupling_list2dict, swap_mapper,
cx_cancellation, direction_mapper)
from ._gate import Gate

logger = logging.getLogger(__name__)


def compile(circuits, backend,
config=None, basis_gates=None, coupling_map=None, initial_layout=None,
shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None,
skip_translation=False):
skip_transpiler=False, skip_translation=False):
"""Compile a list of circuits into a qobj.
FIXME THIS FUNCTION WILL BE REWRITTEN IN VERSION 0.6. It will be a thin wrapper
Expand All @@ -52,8 +54,9 @@ def compile(circuits, backend,
seed (int): random seed for simulators
qobj_id (int): identifier for the generated qobj
hpc (dict): HPC simulator parameters
skip_translation (bool): If True, bypass most of the compilation process and
skip_transpiler (bool): If True, bypass most of the compilation process and
creates a qobj with minimal check nor translation
skip_translation (bool): DEPRECATED. Use skip_transpiler instead.
Returns:
obj: the qobj to be run on the backends
Expand All @@ -62,6 +65,12 @@ def compile(circuits, backend,
QISKitError: if any of the circuit names cannot be found on the
Quantum Program.
"""
if skip_translation:
warnings.warn(
"skip_translation will be called skip_transpiler in future versions.",
DeprecationWarning)
skip_transpiler = True

if isinstance(circuits, QuantumCircuit):
circuits = [circuits]

Expand Down Expand Up @@ -114,22 +123,18 @@ def compile(circuits, backend,
else:
job["config"]["seed"] = seed

if skip_translation: # Just return the qobj, without any transformation or analysis
if skip_transpiler: # Just return the qobj, without any transformation or analysis
job["config"]["layout"] = None
job["compiled_circuit_qasm"] = circuit.qasm()
job["compiled_circuit"] = DagUnroller(
DAGCircuit.fromQuantumCircuit(circuit),
JsonBackend(job['config']['basis_gates'].split(','))).execute()
else:
# Pick good initial layout if None is given and not simulator
if initial_layout is None and not backend.configuration['simulator']:
best_sub = best_subset(backend, num_qubits)
initial_layout = {}
map_iter = 0
for key, value in circuit.get_qregs().items():
for i in range(value.size):
initial_layout[(key, i)] = ('q', best_sub[map_iter])
map_iter += 1
# if coupling_map is not already satisfied, pick a good initial layout
# otherwise leave as q[i]->q[i]
if not _matches_coupling_map(circuit.data, backend.configuration['coupling_map']):
initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs())

dag_circuit, final_layout = compile_circuit(
circuit,
Expand Down Expand Up @@ -265,7 +270,7 @@ def load_unroll_qasm_file(filename, basis_gates='u1,u2,u3,cx,id'):
return circuit_unrolled


def best_subset(backend, n_qubits):
def _best_subset(backend, n_qubits):
"""Computes the qubit mapping with the best
connectivity.
Expand Down Expand Up @@ -317,6 +322,52 @@ def best_subset(backend, n_qubits):
return best_map


def _matches_coupling_map(instructions, coupling_map):
""" Iterate over circuit instructions set to check if multi-qubit instruction coupling
graphs match the qubit coupling graph in the backend.
Parameters:
instructions (List): List of circuit instructions. Not all instructions
are Gates, hence not multi-qubit.
coupling_map (List): Backend coupling map, represented as an
adjacency list.
Returns:
True: If there's at least one instruction that uses multiple qubits and
these qubits coupling matches one of the backend couplings.
False: If there's no match between any of the instructions multiple qubits
coupling, and one of the couplings from the backend.
"""
for instruction in instructions:
if isinstance(instruction, Gate) and instruction.is_multi_qubit():
if instruction.get_qubit_coupling() not in coupling_map:
return False
return True


def _pick_best_layout(backend, num_qubits, qregs):
""" Pick a convenient layout depending on the best matching qubit connectivity
Parameters:
backend (BaseBackend) : The backend with the coupling_map for searching
num_qubits (int): Number of qubits
qregs (List): The list of quantum registers
Returns:
initial_layout: A special ordered layout
"""
best_sub = _best_subset(backend, num_qubits)
layout = {}
map_iter = 0
for key, value in qregs.items():
for i in range(value.size):
layout[(key, i)] = ('q', best_sub[map_iter])
map_iter += 1
return layout


class QISKitCompilerError(QISKitError):
"""Exceptions raised during compilation"""
pass
19 changes: 19 additions & 0 deletions qiskit/_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,19 @@ def __init__(self, name, param, args, circuit=None):
arg = list of pairs (Register, index)
circuit = QuantumCircuit or CompositeGate containing this gate
"""
self._is_multi_qubit = False
self._qubit_coupling = []
number_of_arguments = 0
for argument in args:
number_of_arguments += 1
if number_of_arguments > 1:
self._qubit_coupling.append(argument)
self._is_multi_qubit = True

if not isinstance(argument[0], QuantumRegister):
raise QISKitError("argument not (QuantumRegister, int) "
+ "tuple")

super().__init__(name, param, args, circuit)

def inverse(self):
Expand All @@ -38,3 +47,13 @@ def q_if(self, *qregs):
"""Add controls to this gate."""
# pylint: disable=unused-argument
raise QISKitError("control not implemented")

def is_multi_qubit(self):
"""Returns True if this Gate is uses multiple qubits as arguments"""
return self._is_multi_qubit

def get_qubit_coupling(self):
"""Gets the coupling graph of the qubits in case this is a multi-qubit gate"""
if not self.is_multi_qubit():
raise QISKitError("Can't get the qubit coupling of non multi-qubit gates!")
return self._qubit_coupling
2 changes: 1 addition & 1 deletion qiskit/_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def check_circuit(self):
raise QISKitError("Instruction's circuit not assigned")

def c_if(self, classical, val):
"""Add classical control on register clasical and value val."""
"""Add classical control on register classical and value val."""
self.check_circuit()
self.circuit._check_creg(classical)
if val < 0:
Expand Down
23 changes: 17 additions & 6 deletions qiskit/_quantumprogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -932,14 +932,19 @@ def get_backend_parameters(self, backend):
def compile(self, name_of_circuits=None, backend="local_qasm_simulator",
config=None, basis_gates=None, coupling_map=None,
initial_layout=None, shots=1024, max_credits=10, seed=None,
qobj_id=None, hpc=None, skip_translation=False):
qobj_id=None, hpc=None, skip_transpiler=False, skip_translation=False):
"""Compile the circuits into the execution list.
.. 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.
"""

# pylint: disable=missing-param-doc, missing-type-doc
if skip_translation:
warnings.warn(
"skip_translation will be called skip_transpiler in future versions.",
DeprecationWarning)
skip_transpiler = True
if isinstance(coupling_map, dict):
coupling_map = coupling_dict2list(coupling_map)
warnings.warn(
Expand All @@ -961,7 +966,7 @@ def compile(self, name_of_circuits=None, backend="local_qasm_simulator",
qobj = qiskit.wrapper.compile(list_of_circuits, my_backend,
config, basis_gates, coupling_map, initial_layout,
shots, max_credits, seed, qobj_id, hpc,
skip_translation)
skip_transpiler)
return qobj

def reconfig(self, qobj, backend=None, config=None, shots=None, max_credits=None, seed=None):
Expand Down Expand Up @@ -1126,7 +1131,7 @@ def _run_internal(self, qobj_list):
def execute(self, name_of_circuits=None, backend="local_qasm_simulator",
config=None, timeout=60, basis_gates=None,
coupling_map=None, initial_layout=None, shots=1024,
max_credits=3, seed=None, hpc=None, skip_translation=False):
max_credits=3, seed=None, hpc=None, skip_transpiler=False, skip_translation=False):
"""Execute, compile, and run an array of quantum circuits).
This builds the internal "to execute" list which is list of quantum
Expand Down Expand Up @@ -1174,7 +1179,7 @@ def execute(self, name_of_circuits=None, backend="local_qasm_simulator",
'omp_num_threads': Numeric
}
skip_translation (bool): If True, bypass most of the compilation process and
skip_transpiler (bool): If True, bypass most of the compilation process and
creates a qobj with minimal check nor translation
Returns:
Result: status done and populates the internal __quantum_program with the data.
Expand All @@ -1183,6 +1188,12 @@ def execute(self, name_of_circuits=None, backend="local_qasm_simulator",
The `coupling_map` parameter as a dictionary will be deprecated in
upcoming versions. Using the coupling_map as a list is recommended.
"""
# pylint: disable=missing-param-doc, missing-type-doc
if skip_translation:
warnings.warn(
"skip_translation will be called skip_transpiler in future versions.",
DeprecationWarning)
skip_transpiler = True
# 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
Expand All @@ -1191,7 +1202,7 @@ def execute(self, name_of_circuits=None, backend="local_qasm_simulator",
basis_gates=basis_gates,
coupling_map=coupling_map, initial_layout=initial_layout,
shots=shots, max_credits=max_credits, seed=seed,
hpc=hpc, skip_translation=skip_translation)
hpc=hpc, skip_transpiler=skip_transpiler)
result = self.run(qobj, timeout=timeout)
return result

Expand Down
Loading

0 comments on commit fbbec71

Please sign in to comment.