Skip to content

Commit

Permalink
Merge branch 'master' into add-catalina-job
Browse files Browse the repository at this point in the history
  • Loading branch information
mtreinish authored Feb 24, 2020
2 parents 8dfd67a + d47f827 commit 4aad45c
Show file tree
Hide file tree
Showing 127 changed files with 3,405 additions and 1,923 deletions.
398 changes: 232 additions & 166 deletions qiskit/assembler/assemble_schedules.py

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions qiskit/assembler/disassemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ def _experiments_to_circuits(qobj):
conditional = {}
for i in x.instructions:
name = i.name
if i.name == 'id':
name = 'iden'
qubits = []
params = getattr(i, 'params', [])
try:
Expand Down
8 changes: 8 additions & 0 deletions qiskit/circuit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,19 @@
ParameterVector
ParameterExpression
Random Circuits
===============
.. autosummary::
:toctree: ../stubs/
random.random_circuit
"""
from .quantumcircuit import QuantumCircuit
from .classicalregister import ClassicalRegister, Clbit
from .quantumregister import QuantumRegister, Qubit
from .gate import Gate
# pylint: disable=cyclic-import
from .controlledgate import ControlledGate
from .instruction import Instruction
from .instructionset import InstructionSet
Expand Down
76 changes: 48 additions & 28 deletions qiskit/circuit/add_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,57 +14,79 @@
"""
Add control to operation if supported.
"""
from qiskit import QiskitError
from typing import Union, Optional

from qiskit.circuit.exceptions import CircuitError
from qiskit.extensions import UnitaryGate
from . import ControlledGate, Gate, QuantumRegister, QuantumCircuit


def add_control(operation: Union[Gate, ControlledGate],
num_ctrl_qubits: int,
label: Union[str, None],
ctrl_state: Union[int, str, None]) -> ControlledGate:
"""For standard gates, if the controlled version already exists in the
library, it will be returned (e.g. XGate.control() = CnotGate().
For more generic gates, this method implements the controlled
version by first decomposing into the ['u1', 'u3', 'cx'] basis, then
controlling each gate in the decomposition.
def add_control(operation, num_ctrl_qubits, label):
"""Add num_ctrl_qubits controls to operation
Open controls are implemented by conjugating the control line with
X gates. Adds num_ctrl_qubits controls to operation.
Args:
operation (Gate or ControlledGate): operation to add control to.
num_ctrl_qubits (int): number of controls to add to gate (default=1)
label (str): optional gate label
operation: Operation for which control will be added.
num_ctrl_qubits: The number of controls to add to gate (default=1).
label: Optional gate label.
ctrl_state (int or str or None): The control state in decimal or as
a bitstring (e.g. '111'). If specified as a bitstring the length
must equal num_ctrl_qubits, MSB on left. If None, use
2**num_ctrl_qubits-1.
Returns:
ControlledGate: controlled version of gate. This default algorithm
uses num_ctrl_qubits-1 ancillae qubits so returns a gate of size
num_qubits + 2*num_ctrl_qubits - 1.
Controlled version of gate.
"""
import qiskit.extensions.standard as standard
if isinstance(operation, standard.RZGate) or operation.name == 'rz':
# num_ctrl_qubits > 1
# the condition matching 'name' above is to catch a test case,
# 'TestControlledGate.test_rotation_gates', where the rz gate
# gets converted to a circuit before becoming a generic Gate object.
cgate = standard.CrzGate(*operation.params)
cgate = standard.CRZGate(*operation.params)
return cgate.control(num_ctrl_qubits - 1)
if isinstance(operation, UnitaryGate):
# attempt decomposition
operation._define()
return control(operation, num_ctrl_qubits=num_ctrl_qubits, label=label)
return control(operation, num_ctrl_qubits=num_ctrl_qubits, label=label,
ctrl_state=ctrl_state)


def control(operation, num_ctrl_qubits=1, label=None):
def control(operation: Union[Gate, ControlledGate],
num_ctrl_qubits: Optional[int] = 1,
label: Optional[Union[None, str]] = None,
ctrl_state: Optional[Union[None, int, str]] = None) -> ControlledGate:
"""Return controlled version of gate using controlled rotations
Args:
operation (Gate or Controlledgate): gate to create ControlledGate from
num_ctrl_qubits (int): number of controls to add to gate (default=1)
label (str): optional gate label
operation: gate to create ControlledGate from
num_ctrl_qubits: number of controls to add to gate (default=1)
label: optional gate label
ctrl_state: The control state in decimal or as
a bitstring (e.g. '111'). If specified as a bitstring the length
must equal num_ctrl_qubits, MSB on left. If None, use
2**num_ctrl_qubits-1.
Returns:
ControlledGate: controlled version of gate. This default algorithm
uses num_ctrl_qubits-1 ancillae qubits so returns a gate of size
num_qubits + 2*num_ctrl_qubits - 1.
Controlled version of gate.
Raises:
QiskitError: gate contains non-gate in definitionl
CircuitError: gate contains non-gate in definition
"""
from math import pi
# pylint: disable=cyclic-import
import qiskit.circuit.controlledgate as controlledgate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.quantumcircuit import QuantumCircuit
# pylint: disable=unused-import
import qiskit.extensions.standard.multi_control_rotation_gates
import qiskit.extensions.standard.multi_control_toffoli_gate
Expand All @@ -73,7 +95,6 @@ def control(operation, num_ctrl_qubits=1, label=None):
q_control = QuantumRegister(num_ctrl_qubits, name='control')
q_target = QuantumRegister(operation.num_qubits, name='target')
q_ancillae = None # TODO: add

qc = QuantumCircuit(q_control, q_target)

if operation.name == 'x' or (
Expand All @@ -98,7 +119,7 @@ def control(operation, num_ctrl_qubits=1, label=None):
for rule in bgate.definition:
if rule[0].name == 'u3':
theta, phi, lamb = rule[0].params
if phi == -pi/2 and lamb == pi/2:
if phi == -pi / 2 and lamb == pi / 2:
qc.mcrx(theta, q_control, q_target[rule[1][0].index],
use_basis_gates=True)
elif phi == 0 and lamb == 0:
Expand All @@ -122,7 +143,7 @@ def control(operation, num_ctrl_qubits=1, label=None):
None,
mode='noancilla')
else:
raise QiskitError('gate contains non-controllable instructions')
raise CircuitError('gate contains non-controllable instructions')
instr = qc.to_instruction()
if isinstance(operation, controlledgate.ControlledGate):
new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits
Expand All @@ -146,20 +167,19 @@ def control(operation, num_ctrl_qubits=1, label=None):
operation.params,
label=label,
num_ctrl_qubits=new_num_ctrl_qubits,
definition=instr.definition)
definition=instr.definition,
ctrl_state=ctrl_state)
cgate.base_gate = base_gate
return cgate


def _gate_to_circuit(operation):
from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.circuit.quantumregister import QuantumRegister
qr = QuantumRegister(operation.num_qubits)
qc = QuantumCircuit(qr, name=operation.name)
if hasattr(operation, 'definition') and operation.definition:
for rule in operation.definition:
if rule[0].name in {'id', 'barrier', 'measure', 'snapshot'}:
raise QiskitError('Cannot make controlled gate with {} instruction'.format(
raise CircuitError('Cannot make controlled gate with {} instruction'.format(
rule[0].name))
qc.append(rule[0], qargs=[qr[bit.index] for bit in rule[1]], cargs=[])
else:
Expand Down
81 changes: 76 additions & 5 deletions qiskit/circuit/controlledgate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@
"""
Controlled unitary gate.
"""

from qiskit.circuit.exceptions import CircuitError
from .gate import Gate
from . import QuantumRegister


class ControlledGate(Gate):
"""Controlled unitary gate."""

def __init__(self, name, num_qubits, params, label=None, num_ctrl_qubits=1,
definition=None):
"""Create a new gate.
definition=None, ctrl_state=None):
"""Create a controlled gate.
Attributes:
num_ctrl_qubits (int): The number of control qubits.
ctrl_state (int): The control state in decimal notation.
Args:
name (str): The Qobj name of the gate.
Expand All @@ -34,8 +38,13 @@ def __init__(self, name, num_qubits, params, label=None, num_ctrl_qubits=1,
label (str or None): An optional label for the gate [Default: None]
num_ctrl_qubits (int): Number of control qubits.
definition (list): list of gate rules for implementing this gate.
ctrl_state (int or str or None): The control state in decimal or as
a bitstring (e.g. '111'). If specified as a bitstring the length
must equal num_ctrl_qubits, MSB on left. If None, use
2**num_ctrl_qubits-1.
Raises:
CircuitError: num_ctrl_qubits >= num_qubits
CircuitError: ctrl_state < 0 or ctrl_state > 2**num_ctrl_qubits.
"""
super().__init__(name, num_qubits, params, label=label)
if num_ctrl_qubits < num_qubits:
Expand All @@ -50,14 +59,76 @@ def __init__(self, name, num_qubits, params, label=None, num_ctrl_qubits=1,
self.base_gate = base_gate.base_gate
else:
self.base_gate = base_gate
self._ctrl_state = None
self.ctrl_state = ctrl_state

@property
def definition(self):
"""Return definition in terms of other basic gates. If the gate has
open controls, as determined from `self.ctrl_state`, the returned
definition is conjugated with X."""
if not self._definition:
self._define()
# pylint: disable=cyclic-import
from qiskit.extensions.standard import XGate, CnotGate
bit_ctrl_state = bin(self.ctrl_state)[2:].zfill(self.num_ctrl_qubits)
# hacky way to get register assuming single register
if self._definition:
qreg = self._definition[0][1][0].register
elif isinstance(self, CnotGate):
qreg = QuantumRegister(self.num_qubits, 'q')
self._definition = [(self, [qreg[0], qreg[1]], [])]
open_rules = []
for qind, val in enumerate(bit_ctrl_state[::-1]):
if val == '0':
open_rules.append([XGate(), [qreg[qind]], []])
return open_rules + self._definition + open_rules

@definition.setter
def definition(self, excited_def):
"""Set controlled gate definition with closed controls."""
super(Gate, self.__class__).definition.fset(self, excited_def)

@property
def ctrl_state(self):
"""Return the control state of the gate as a decimal integer."""
return self._ctrl_state

@ctrl_state.setter
def ctrl_state(self, ctrl_state):
"""Set the control state of this gate.
Args:
ctrl_state (int or str or None): The control state of the gate.
Raises:
CircuitError: ctrl_state is invalid.
"""
if isinstance(ctrl_state, str):
try:
assert len(ctrl_state) == self.num_ctrl_qubits
ctrl_state = int(ctrl_state, 2)
except ValueError:
raise CircuitError('invalid control bit string: ' + ctrl_state)
except AssertionError:
raise CircuitError('invalid control bit string: length != '
'num_ctrl_qubits')
if isinstance(ctrl_state, int):
if 0 <= ctrl_state < 2**self.num_ctrl_qubits:
self._ctrl_state = ctrl_state
else:
raise CircuitError('invalid control state specification')
elif ctrl_state is None:
self._ctrl_state = 2**self.num_ctrl_qubits - 1
else:
raise CircuitError('invalid control state specification')

def __eq__(self, other):
if not isinstance(other, ControlledGate):
return False
else:
return (other.num_ctrl_qubits == self.num_ctrl_qubits and
self.base_gate == other.base_gate and
super().__eq__(other))
self.base_gate == other.base_gate)

def inverse(self):
"""Invert this gate by calling inverse on the base gate."""
Expand Down
14 changes: 7 additions & 7 deletions qiskit/circuit/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,24 @@ def label(self, name):
else:
raise TypeError('label expects a string or None')

def control(self, num_ctrl_qubits=1, label=None):
def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return controlled version of gate
Args:
num_ctrl_qubits (int): number of controls to add to gate (default=1)
label (str): optional gate label
label (str or None): optional gate label
ctrl_state (int or str or None): The control state in decimal or as
a bitstring (e.g. '111'). If None, use 2**num_ctrl_qubits-1.
Returns:
ControlledGate: controlled version of gate. This default algorithm
uses num_ctrl_qubits-1 ancillae qubits so returns a gate of size
num_qubits + 2*num_ctrl_qubits - 1.
ControlledGate: controlled version of gate.
Raises:
QiskitError: unrecognized mode
QiskitError: unrecognized mode or invalid ctrl_state
"""
# pylint: disable=cyclic-import
from .add_control import add_control
return add_control(self, num_ctrl_qubits, label)
return add_control(self, num_ctrl_qubits, label, ctrl_state)

@staticmethod
def _broadcast_single_argument(qarg):
Expand Down
17 changes: 17 additions & 0 deletions qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Module for builtin library of circuits."""

from .boolean_logic import Permutation, XOR, InnerProduct
Loading

0 comments on commit 4aad45c

Please sign in to comment.