# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Utilities for logging."""

import logging
from logging.config import dictConfig

class SimpleInfoFormatter(logging.Formatter):
    """Custom Formatter that uses a simple format for INFO."""
    _style_info = logging._STYLES['%'][0]('%(message)s')

    def formatMessage(self, record):
        if record.levelno == logging.INFO:
            return self._style_info.format(record)
        return logging.Formatter.formatMessage(self, record)

QISKIT_LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'f': {
            '()': SimpleInfoFormatter,
            'format': '%(asctime)s:%(name)s:%(levelname)s: %(message)s'
        },
    },
    'handlers': {
        'h': {
            'class': 'logging.StreamHandler',
            'formatter': 'f'
        }
    },
    'loggers': {
        'qiskit': {
            'handlers': ['h'],
            'level': logging.INFO,
        },
    }
}

def set_qiskit_logger():
    """Update 'qiskit' logger configuration using a SDK default one.

    Update the configuration of the 'qiskit' logger using the default SDK
    configuration provided by `QISKIT_LOGGING_CONFIG`:

    * console logging using a custom format for levels != INFO.
    * console logging with simple format for level INFO.
    * set logger level to INFO.

    Warning:
        This function modifies the configuration of the standard logging system
        for the 'qiskit.*' loggers, and might interfere with custom logger
        configurations.
    """
    dictConfig(QISKIT_LOGGING_CONFIG)

def unset_qiskit_logger():
    """Remove the handlers for the 'qiskit' logger."""
    qiskit_logger = logging.getLogger('qiskit')
    for handler in qiskit_logger.handlers:
        qiskit_logger.removeHandler(handler)


# -*- coding: utf-8 -*-

# Copyright 2018, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""
Hinton visualization
"""
from string import Template
import sys
import time
import re
from qiskit.visualization.utils import _validate_input_state
if ('ipykernel' in sys.modules) and ('spyder' not in sys.modules):
    try:
        from IPython.core.display import display, HTML
    except ImportError:
        print("Error importing IPython.core.display")

def iplot_state_hinton(rho, figsize=None):
    """ Create a hinton representation.

        Graphical representation of the input array using a 2D city style
        graph (hinton).

        Args:
            rho (array): Density matrix
            figsize (tuple): Figure size in pixels.
    """

    # HTML
    html_template = Template("""

    """)

    # JavaScript
    javascript_template = Template("""

    """)
    rho = _validate_input_state(rho)
    if figsize is None:
        options = {}
    else:
        options = {'width': figsize[0], 'height': figsize[1]}

    # Process data and execute
    div_number = str(time.time())
    div_number = re.sub('[.]', '', div_number)

    # Process data and execute
    real = []
    imag = []
    for xvalue in rho:
        row_real = []
        col_imag = []

        for value_real in xvalue.real:
            row_real.append(float(value_real))
        real.append(row_real)

        for value_imag in xvalue.imag:
            col_imag.append(float(value_imag))
        imag.append(col_imag)

    html = html_template.substitute({
        'divNumber': div_number
    })

    javascript = javascript_template.substitute({
        'divNumber': div_number,
        'executions': [{'data': real}, {'data': imag}],
        'options': options
    })

    display(HTML(html + javascript))


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

# pylint: disable=invalid-name,anomalous-backslash-in-string

"""
A collection of useful quantum information functions for operators.
"""

import numpy as np

from qiskit.qiskiterror import QiskitError
from qiskit.quantum_info.operators import Operator
from qiskit.quantum_info.operators import SuperOp

def process_fidelity(channel1, channel2, require_cptp=True):
    """Return the process fidelity between two quantum channels.

    This is given by

        F_p(E1, E2) = Tr[S2^dagger.S1])/dim^2

    where S1 and S2 are the SuperOp matrices for channels E1 and E2,
    and dim is the dimension of the input output statespace.

    Args:
        channel1 (QuantumChannel or matrix): a quantum channel or unitary matrix.
        channel2 (QuantumChannel or matrix): a quantum channel or unitary matrix.
        require_cptp (bool): require input channels to be CPTP [Default: True].

    Returns:
        array_like: The state fidelity F(state1, state2).

    Raises:
        QiskitError: if inputs channels do not have the same dimensions,
        have different input and output dimensions, or are not CPTP with
        `require_cptp=True`.
    """
    # First we must determine if input is to be interpreted as a unitary matrix
    # or as a channel.
    # If input is a raw numpy array we will interpret it as a unitary matrix.
    is_cptp1 = None
    is_cptp2 = None
    if isinstance(channel1, (list, np.ndarray)):
        channel1 = Operator(channel1)
        if require_cptp:
            is_cptp1 = channel1.is_unitary()
    if isinstance(channel2, (list, np.ndarray)):
        channel2 = Operator(channel2)
        if require_cptp:
            is_cptp2 = channel2.is_unitary()

    # Next we convert inputs SuperOp objects
    # This works for objects that also have a `to_operator` or `to_channel` method
    s1 = SuperOp(channel1)
    s2 = SuperOp(channel2)

    # Check inputs are CPTP
    if require_cptp:
        # Only check SuperOp if we didn't already check unitary inputs
        if is_cptp1 is None:
            is_cptp1 = s1.is_cptp()
        if not is_cptp1:
            raise QiskitError('channel1 is not CPTP')
        if is_cptp2 is None:
            is_cptp2 = s2.is_cptp()
        if not is_cptp2:
            raise QiskitError('channel2 is not CPTP')

    # Check dimensions match
    input_dim1, output_dim1 = s1.dim
    input_dim2, output_dim2 = s2.dim
    if input_dim1 != output_dim1 or input_dim2 != output_dim2:
        raise QiskitError('Input channels must have same size input and output dimensions.')
    if input_dim1 != input_dim2:
        raise QiskitError('Input channels have different dimensions.')

    # Compute process fidelity
    fidelity = np.trace(s1.compose(s2.adjoint()).data) / (input_dim1 ** 2)
    return fidelity


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""
OPENQASM Lexer.

This is a wrapper around the PLY lexer to support the "include" statement
by creating a stack of lexers.
"""

import os

import ply.lex as lex
from sympy import Number

from . import node
from .exceptions import QasmError

CORE_LIBS_PATH = os.path.join(os.path.dirname(__file__), 'libs')
CORE_LIBS = os.listdir(CORE_LIBS_PATH)

class QasmLexer:
    """OPENQASM Lexer.

    This is a wrapper around the PLY lexer to support the "include" statement
    by creating a stack of lexers.
    """
    # pylint: disable=invalid-name,missing-docstring,unused-argument
    # pylint: disable=attribute-defined-outside-init,bad-docstring-quotes

    def __mklexer__(self, filename):
        """Create a PLY lexer."""
        self.lexer = lex.lex(module=self, debug=False)
        self.filename = filename
        self.lineno = 1

        if filename:
            with open(filename, 'r') as ifile:
                self.data = ifile.read()
            self.lexer.input(self.data)

    def __init__(self, filename):
        """Create the OPENQASM lexer."""
        self.__mklexer__(filename)
        self.stack = []

    def input(self, data):
        """Set the input text data."""
        self.data = data
        self.lexer.input(data)

    def token(self):
        """Return the next token."""
        ret = self.lexer.token()
        return ret

    def pop(self):
        """Pop a PLY lexer off the stack."""
        self.lexer = self.stack.pop()
        self.filename = self.lexer.qasm_file
        self.lineno = self.lexer.qasm_line

    def push(self, filename):
        """Push a PLY lexer on the stack to parse filename."""
        self.lexer.qasm_file = self.filename
        self.lexer.qasm_line = self.lineno
        self.stack.append(self.lexer)
        self.__mklexer__(filename)

    # ---- Beginning of the PLY lexer ----
    literals = r'=()[]{};<>,.+-/*^"'
    reserved = {
        'barrier': 'BARRIER',
        'creg': 'CREG',
        'gate': 'GATE',
        'if': 'IF',
        'measure': 'MEASURE',
        'opaque': 'OPAQUE',
        'qreg': 'QREG',
        'pi': 'PI',
        'reset': 'RESET',
    }
    tokens = [
        'NNINTEGER',
        'REAL',
        'CX',
        'U',
        'FORMAT',
        'ASSIGN',
        'MATCHES',
        'ID',
        'STRING',
    ] + list(reserved.values())

    def t_REAL(self, t):
        r'(([0-9]+|([0-9]+)?\.[0-9]+|[0-9]+\.)[eE][+-]?[0-9]+)|(([0-9]+)?\.[0-9]+|[0-9]+\.)'
        t.value = Number(t.value)
        # tad nasty, see mkfloat.py to see how this is derived from python spec
        return t

    def t_NNINTEGER(self, t):
        r'[1-9]+[0-9]*|0'
        t.value = int(t.value)
        return t

    def t_ASSIGN(self, t):
        '->'
        return t

    def t_MATCHES(self, t):
        '=='
        return t

    def t_STRING(self, t):
        r'\"([^\\\"]|\\.)*\"'
        return t

    def t_INCLUDE(self, t):
        'include'
        #
        # Now eat up the next two tokens which must be
        # 1 - the name of the include file, and
        # 2 - a terminating semicolon
        #
        # Then push the current lexer onto the stack, create a new one from
        # the include file, and push it onto the stack.
        #
        # When we hit eof (the t_eof) rule, we pop.
        next_token = self.lexer.token()
        lineno = next_token.lineno
        # print('NEXT', next, "next.value", next.value, type(next))
        if isinstance(next_token.value, str):
            incfile = next_token.value.strip('"')
        else:
            raise QasmError("Invalid include: must be a quoted string.")

        if incfile in CORE_LIBS:
            incfile = os.path.join(CORE_LIBS_PATH, incfile)

        next_token = self.lexer.token()
        if next_token is None or next_token.value != ';':
            raise QasmError('Invalid syntax, missing ";" at line', str(lineno))

        if not os.path.exists(incfile):
            raise QasmError(
                'Include file %s cannot be found, line %s, file %s' %
                (incfile, str(next_token.lineno), self.filename))
        self.push(incfile)
        return self.lexer.token()

    def t_FORMAT(self, t):
        r'OPENQASM\s+(\d+)\.(\d+)'
        return t

    def t_COMMENT(self, t):
        r'//.*'
        pass

    def t_CX(self, t):
        'CX'
        return t

    def t_U(self, t):
        'U'
        return t

    def t_ID(self, t):
        r'[a-z][a-zA-Z0-9_]*'

        t.type = self.reserved.get(t.value, 'ID')
        if t.type == 'ID':
            t.value = node.Id(t.value, self.lineno, self.filename)
        return t

    def t_newline(self, t):
        r'\n+'
        self.lineno += len(t.value)
        t.lexer.lineno = self.lineno

    def t_eof(self, t):
        if self.stack:
            self.pop()
            return self.lexer.token()
        return None

    t_ignore = ' \t\r'

    def t_error(self, t):
        print("Unable to match any token rule, got -->%s<--" % t.value[0])
        print("Check your OPENQASM source and any include statements.")
        # t.lexer.skip(1)


# -*- coding: utf-8 -*-

# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""
Specification of the device.
"""
import logging
from typing import List

from qiskit.pulse.exceptions import PulseError
from qiskit.validation.exceptions import ModelValidationError
from .pulse_channels import DriveChannel, ControlChannel, MeasureChannel
from .channels import AcquireChannel, MemorySlot, RegisterSlot
from .qubit import Qubit

logger = logging.getLogger(__name__)

class DeviceSpecification:
    """Implement a device specification, which is usually constructed from backend info."""

    def __init__(self,
                 qubits: List[Qubit],
                 registers: List[RegisterSlot],
                 mem_slots: List[MemorySlot]):
        """
        Create device specification with specified `qubits`.
        Args:
            qubits:
        """
        self._qubits = qubits
        self._reg_slots = registers
        self._mem_slots = mem_slots

    @classmethod
    def create_from(cls, backend):
        """
        Create device specification with values in backend configuration.
        Args:
            backend(Backend): backend configuration
        Returns:
            DeviceSpecification: created device specification
        Raises:
            PulseError: when an invalid backend is specified
        """
        backend_config = backend.configuration()

        # TODO : Remove usage of config.defaults when backend.defaults() is updated.
        try:
            backend_default = backend.defaults()
        except ModelValidationError:
            from collections import namedtuple
            BackendDefault = namedtuple('BackendDefault', ('qubit_freq_est', 'meas_freq_est'))

            backend_default = BackendDefault(
                qubit_freq_est=backend_config.defaults['qubit_freq_est'],
                meas_freq_est=backend_config.defaults['meas_freq_est']
            )

        # system size
        n_qubits = backend_config.n_qubits
        n_registers = backend_config.n_registers
        n_uchannels = backend_config.n_uchannels

        if n_uchannels > 0 and n_uchannels != n_qubits:
            raise PulseError("This version assumes no U-channels or #U-cannels==#qubits.")

        # frequency information
        qubit_lo_freqs = backend_default.qubit_freq_est
        qubit_lo_ranges = backend_config.qubit_lo_range
        meas_lo_freqs = backend_default.meas_freq_est
        meas_lo_ranges = backend_config.meas_lo_range

        # generate channels with assuming their numberings are aligned with qubits
        drives = [
            DriveChannel(i, qubit_lo_freqs[i], tuple(qubit_lo_ranges[i]))
            for i in range(n_qubits)
        ]
        measures = [
            MeasureChannel(i, meas_lo_freqs[i], tuple(meas_lo_ranges[i]))
            for i in range(n_qubits)
        ]
        acquires = [AcquireChannel(i) for i in range(n_qubits)]
        controls = [ControlChannel(i) for i in range(n_uchannels)]

        qubits = []
        for i in range(n_qubits):
            # TODO: get qubits <-> channels relationship from backend
            qubit = Qubit(i,
                          drive_channels=[drives[i]],
                          control_channels=None if n_uchannels == 0 else controls[i],
                          measure_channels=[measures[i]],
                          acquire_channels=[acquires[i]])
            qubits.append(qubit)

        registers = [RegisterSlot(i) for i in range(n_registers)]
        # TODO: get #mem_slots from backend
        mem_slots = [MemorySlot(i) for i in range(len(qubits))]

        return DeviceSpecification(qubits, registers, mem_slots)

    def __eq__(self, other):
        """Two device specs are the same if they have the same qubits.

        Args:
            other (DeviceSpecification): other DeviceSpecification

        Returns:
            bool: are self and other equal.
        """
        if type(self) is type(other) and \
                self._qubits == other._qubits:
            return True
        return False

    @property
    def q(self) -> List[Qubit]:
        """Return qubits in this device."""
        return self._qubits

    # pylint: disable=invalid-name
    @property
    def c(self) -> List[RegisterSlot]:
        """Return register slots in this device."""
        return self._reg_slots

    @property
    def mem(self) -> List[MemorySlot]:
        """Return memory slots in this device."""
        return self._mem_slots


# -*- coding: utf-8 -*-

# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

# pylint: disable=cell-var-from-loop

"""
Replace each block of consecutive gates by a single Unitary node.
The blocks are collected by a previous pass, such as Collect2qBlocks.
"""

from qiskit.circuit import QuantumRegister, QuantumCircuit
from qiskit.dagcircuit import DAGCircuit
from qiskit.quantum_info.operators import Operator
from qiskit.extensions import UnitaryGate
from qiskit.transpiler.passes.unroller import Unroller
from qiskit.transpiler.basepasses import TransformationPass

class ConsolidateBlocks(TransformationPass):
    """
    Pass to consolidate sequences of uninterrupted gates acting on
    the same qubits into a Unitary node, to be resynthesized later,
    to a potentially more optimal subcircuit.
    Important note: this pass assumes that the 'blocks_list' property that
    it reads is given such that blocks are in topological order.
    """
    def __init__(self):
        super().__init__()
        self.requires.append(Unroller(["u1", "u2", "u3", "cx", "id"]))

    def run(self, dag):
        """iterate over each block and replace it with an equivalent Unitary
        on the same wires.
        """
        new_dag = DAGCircuit()
        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        # compute ordered indices for the global circuit wires
        global_index_map = {}
        for wire in dag.wires:
            if not isinstance(wire[0], QuantumRegister):
                continue
            global_qregs = list(dag.qregs.values())
            global_index_map[wire] = global_qregs.index(wire[0]) + wire[1]

        blocks = self.property_set['block_list']
        nodes_seen = set()

        for node in dag.topological_op_nodes():
            # skip already-visited nodes or input/output nodes
            if node in nodes_seen or node.type == 'in' or node.type == 'out':
                continue
            # check if the node belongs to the next block
            if blocks and node in blocks[0]:
                block = blocks[0]
                # find the qubits involved in this block
                block_qargs = set()
                for nd in block:
                    block_qargs |= set(nd.qargs)
                # convert block to a sub-circuit, then simulate unitary and add
                block_width = len(block_qargs)
                q = QuantumRegister(block_width)
                subcirc = QuantumCircuit(q)
                block_index_map = self._block_qargs_to_indices(block_qargs,
                                                               global_index_map)
                for nd in block:
                    nodes_seen.add(nd)
                    subcirc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
                unitary = UnitaryGate(Operator(subcirc))  # simulates the circuit
                new_dag.apply_operation_back(
                    unitary, sorted(block_qargs, key=lambda x: block_index_map[x]))
                del blocks[0]
            else:
                # the node could belong to some future block, but in that case
                # we simply skip it. It is guaranteed that we will revisit that
                # future block, via its other nodes
                for block in blocks[1:]:
                    if node in block:
                        break
                # freestanding nodes can just be added
                else:
                    nodes_seen.add(node)
                    new_dag.apply_operation_back(node.op, node.qargs, node.cargs)

        return new_dag

    def _block_qargs_to_indices(self, block_qargs, global_index_map):
        """
        Map each qubit in block_qargs to its wire position among the block's wires.
        Args:
            block_qargs (list): list of qubits that a block acts on
            global_index_map (dict): mapping from each qubit in the
                circuit to its wire position within that circuit
        Returns:
            dict: mapping from qarg to position in block
        """
        block_indices = [global_index_map[q] for q in block_qargs]
        ordered_block_indices = sorted(block_indices)
        block_positions = {q: ordered_block_indices.index(global_index_map[q])
                           for q in block_qargs}
        return block_positions


# -*- coding: utf-8 -*-

# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Helper class used to convert a pulse instruction into PulseQobjInstruction."""

import functools

from qiskit.pulse import commands
from qiskit.pulse.exceptions import PulseError
from qiskit.qobj import QobjMeasurementOption

class ConversionMethodBinder:
    """Instruction conversion method registrar."""
    def __init__(self):
        """Acts as method registration decorator and tracker for instruction conversion methods."""
        self._bound_instructions = {}

    def __call__(self, type_instruction):
        """ Converter decorator method.

        Pulse instruction converter is defined for each instruction type,
        and this decorator binds converter function to valid instruction type.

        Args:
            type_instruction (Instruction): valid pulse instruction class to the converter.

        """
        # pylint: disable=missing-return-doc, missing-return-type-doc

        def _apply_converter(converter):
            """Return decorated converter function."""

            @functools.wraps(converter)
            def _call_valid_converter(self, shift, instruction):
                """Return a dictionary for to be used to construct a qobj
                if the given instruction matches the
                bound instruction type supplied to the function,
                otherwise return None."""
                if isinstance(instruction, type_instruction):
                    return converter(self, shift, instruction)
                else:
                    raise PulseError('Supplied instruction {0} '
                                     'is not of type {1}.'.format(instruction, type_instruction))

            # Track conversion methods for class.
            self._bound_instructions[type_instruction] = _call_valid_converter
            return _call_valid_converter

        return _apply_converter

    def get_bound_method(self, instruction):
        """Get conversion method for instruction."""
        try:
            return self._bound_instructions[type(instruction)]
        except KeyError:
            raise PulseError('Qobj conversion method for %s is not found.' % instruction)

class PulseQobjConverter:
    """
    This class exists for separating entity of pulse instructions and qobj instruction,
    and provides some alleviation of the complexity of the assembler.

    Converter is constructed with qobj model and some experimental configuration,
    and returns proper qobj instruction to each backend.

    Pulse instruction and its qobj are strongly depends on the design of backend,
    and third party providers can be easily add their custom pulse instruction by
    providing custom converter inherit from this.

    To create custom converter for custom instruction
    ```
    class CustomConverter(PulseQobjConverter):

        @bind_instruction(CustomInstruction)
        def convert_custom_command(self, shift, instruction):
            command_dict = {
                'name': 'custom_command',
                't0': shift+instruction.start_time,
                'param1': instruction.param1,
                'param2': instruction.param2
            }
            if self._run_config('option1', True):
                command_dict.update({
                    'param3': instruction.param3
                })
            return self.qobj_model(**command_dict)
    ```
    """
    # class level tracking of conversion methods
    bind_instruction = ConversionMethodBinder()

    def __init__(self, qobj_model, **run_config):
        """Create new converter.

        Args:
             qobj_model (QobjInstruction): marshmallow model to serialize to object.
             run_config (dict): experimental configuration.
        """
        self._qobj_model = qobj_model
        self._run_config = run_config

    def __call__(self, shift, instruction):

        method = self.bind_instruction.get_bound_method(instruction)
        return method(self, shift, instruction)

    @bind_instruction(commands.AcquireInstruction)
    def convert_acquire(self, shift, instruction):
        """Return converted `AcquireInstruction`.

        Args:
            shift(int): Offset time.
            instruction (AcquireInstruction): acquire instruction.
        Returns:
            dict: Dictionary of required parameters.
        """
        meas_level = self._run_config.get('meas_level', 2)

        command_dict = {
            'name': 'acquire',
            't0': shift+instruction.start_time,
            'duration': instruction.duration,
            'qubits': [q.index for q in instruction.acquires],
            'memory_slot': [m.index for m in instruction.mem_slots]
        }
        if meas_level == 2:
            # setup discriminators
            if instruction.command.discriminator:
                command_dict.update({
                    'discriminators': [
                        QobjMeasurementOption(
                            name=instruction.command.discriminator.name,
                            params=instruction.command.discriminator.params)
                    ]
                })
            # setup register_slots
            command_dict.update({
                'register_slot': [regs.index for regs in instruction.reg_slots]
            })
        if meas_level >= 1:
            # setup kernels
            if instruction.command.kernel:
                command_dict.update({
                    'kernels': [
                        QobjMeasurementOption(
                            name=instruction.command.kernel.name,
                            params=instruction.command.kernel.params)
                    ]
                })
        return self._qobj_model(**command_dict)

    @bind_instruction(commands.FrameChangeInstruction)
    def convert_frame_change(self, shift, instruction):
        """Return converted `FrameChangeInstruction`.

        Args:
            shift(int): Offset time.
            instruction (FrameChangeInstruction): frame change instruction.
        Returns:
            dict: Dictionary of required parameters.
        """
        command_dict = {
            'name': 'fc',
            't0': shift+instruction.start_time,
            'ch': instruction.channels[0].name,
            'phase': instruction.command.phase
        }
        return self._qobj_model(**command_dict)

    @bind_instruction(commands.PersistentValueInstruction)
    def convert_persistent_value(self, shift, instruction):
        """Return converted `PersistentValueInstruction`.

        Args:
            shift(int): Offset time.
            instruction (PersistentValueInstruction): persistent value instruction.
        Returns:
            dict: Dictionary of required parameters.
        """
        command_dict = {
            'name': 'pv',
            't0': shift+instruction.start_time,
            'ch': instruction.channels[0].name,
            'val': instruction.command.value
        }
        return self._qobj_model(**command_dict)

    @bind_instruction(commands.PulseInstruction)
    def convert_drive(self, shift, instruction):
        """Return converted `PulseInstruction`.

        Args:
            shift(int): Offset time.
            instruction (PulseInstruction): drive instruction.
        Returns:
            dict: Dictionary of required parameters.
        """
        command_dict = {
            'name': instruction.command.name,
            't0': shift+instruction.start_time,
            'ch': instruction.channels[0].name
        }
        return self._qobj_model(**command_dict)

    @bind_instruction(commands.Snapshot)
    def convert_snapshot(self, shift, instruction):
        """Return converted `Snapshot`.

        Args:
            shift(int): Offset time.
            instruction (Snapshot): snapshot instruction.
        Returns:
            dict: Dictionary of required parameters.
        """
        command_dict = {
            'name': 'snapshot',
            't0': shift+instruction.start_time,
            'label': instruction.name,
            'type': instruction.type
        }
        return self._qobj_model(**command_dict)


# -*- coding: utf-8 -*-

# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

# pylint: disable=missing-return-doc

"""Sampler decorator module for sampling of continuous pulses to discrete pulses to be
exposed to user.

Some atypical boilerplate has been added to solve the problem of decorators not preserving
their wrapped function signatures. Below we explain the problem that samplers solve and how
we implement this.

A sampler is a function that takes an continuous pulse function with signature:
    ```python
    def f(times: np.ndarray, *args, **kwargs) -> np.ndarray:
        ...
    ```
and returns a new function:
    def f(duration: int, *args, **kwargs) -> SamplePulse:
        ...

Samplers are used to build up pulse commands from continuous pulse functions.

In Python the creation of a dynamic function that wraps another function will cause
the underlying signature and documentation of the underlying function to be overwritten.
In order to circumvent this issue the Python standard library provides the decorator
`functools.wraps` which allows the programmer to expose the names and signature of the
wrapped function as those of the dynamic function.

Samplers are implemented by creating a function with signature
    @sampler
    def left(continuous_pulse: Callable, duration: int, *args, **kwargs)
        ...

This will create a sampler function for `left`. Since it is a dynamic function it would not
have the docstring of `left` available too `help`. This could be fixed by wrapping with
`functools.wraps` in the `sampler`, but this would then cause the signature to be that of the
sampler function which is called on the continuous pulse, below:
    `(continuous_pulse: Callable, duration: int, *args, **kwargs)``
This is not correct for the sampler as the output sampled functions accept only a function.
For the standard sampler we get around this by not using `functools.wraps` and
explicitly defining our samplers such as `left`, `right` and `midpoint` and
calling `sampler` internally on the function that implements the sampling schemes such as
`left_sample`, `right_sample` and `midpoint_sample` respectively. See `left` for an example of this.

In this way our standard samplers will expose the proper help signature, but a user can
still create their own sampler with
    @sampler
    def custom_sampler(time, *args, **kwargs):
        ...
However, in this case it will be missing documentation of the underlying sampling methods.
We believe that the definition of custom samplers will be rather infrequent.

However, users will frequently apply sampler instances too continuous pulses. Therefore, a different
approach was required for sampled continuous functions (the output of an continuous pulse function
decorated by a sampler instance).

A sampler instance is a decorator that may be used to wrap continuous pulse functions such as
linear below:
```python
    @left
    def linear(times: np.ndarray, m: float, b: float) -> np.ndarray:
        ```Linear test function
        Args:
            times: Input times.
            m: Slope.
            b: Intercept
        Returns:
            np.ndarray
        ```
        return m*times+b
```
Which after decoration may be called with a duration rather than an array of times
    ```python
    duration = 10
    pulse_command = linear(10, 0.1, 0.1)
    ```
If one calls help on `linear` they will find
    ```
    linear(duration:int, *args, **kwargs) -> numpy.ndarray
    Discretized continuous pulse function: `linear` using
    sampler: `_left`.

     The first argument (time) of the continuous pulse function has been replaced with
     a discretized `duration` of type (int).

     Args:
         duration (int)
         *args: Remaining arguments of continuous pulse function.
                See continuous pulse function documentation below.
         **kwargs: Remaining kwargs of continuous pulse function.
                   See continuous pulse function documentation below.

     Sampled continuous function:

        function linear in module test.python.pulse.test_samplers
        linear(x:numpy.ndarray, m:float, b:float) -> numpy.ndarray
            Linear test function
            Args:
                x: Input times.
                m: Slope.
                b: Intercept
            Returns:
                np.ndarray
    ```
This is partly because `functools.wraps` has been used on the underlying function.
This in itself is not sufficient as the signature of the sampled function has
`duration`, whereas the signature of the continuous function is `time`.

This is acheived by removing `__wrapped__` set by `functools.wraps` in order to preserve
the correct signature and also applying `_update_annotations` and `_update_docstring`
to the generated function which corrects the function annotations and adds an informative
docstring respectively.

The user therefore has access to the correct sampled function docstring in its entirety, while
still seeing the signature for the continuous pulse function and all of its arguments.
"""

import functools
from typing import Callable
import textwrap
import pydoc

import numpy as np

from qiskit.pulse.samplers import strategies
import qiskit.pulse.commands as commands

def _update_annotations(discretized_pulse: Callable) -> Callable:
    """Update annotations of discretized continuous pulse function with duration.

    Args:
        discretized_pulse: Discretized decorated continuous pulse.
    """
    undecorated_annotations = list(discretized_pulse.__annotations__.items())
    decorated_annotations = undecorated_annotations[1:]
    decorated_annotations.insert(0, ('duration', int))
    discretized_pulse.__annotations__ = dict(decorated_annotations)
    return discretized_pulse

def _update_docstring(discretized_pulse: Callable, sampler_inst: Callable) -> Callable:
    """Update annotations of discretized continuous pulse function.

    Args:
        discretized_pulse: Discretized decorated continuous pulse.
        sampler_inst: Applied sampler.
    """
    wrapped_docstring = pydoc.render_doc(discretized_pulse, '%s')
    header, body = wrapped_docstring.split('\n', 1)
    body = textwrap.indent(body, '                    ')
    wrapped_docstring = header+body
    updated_ds = """
                Discretized continuous pulse function: `{continuous_name}` using
                sampler: `{sampler_name}`.

                 The first argument (time) of the continuous pulse function has been replaced with
                 a discretized `duration` of type (int).

                 Args:
                     duration (int)
                     *args: Remaining arguments of continuous pulse function.
                            See continuous pulse function documentation below.
                     **kwargs: Remaining kwargs of continuous pulse function.
                               See continuous pulse function documentation below.

                 Sampled continuous function:

                    {continuous_doc}
                """.format(continuous_name=discretized_pulse.__name__,
                           sampler_name=sampler_inst.__name__,
                           continuous_doc=wrapped_docstring)

    discretized_pulse.__doc__ = updated_ds
    return discretized_pulse

def sampler(sample_function: Callable) -> Callable:
    """Sampler decorator base method.

    Samplers are used for converting an continuous function to a discretized pulse.

    They operate on a function with the signature:
        `def f(times: np.ndarray, *args, **kwargs) -> np.ndarray`
    Where `times` is a numpy array of floats with length n_times and the output array
    is a complex numpy array with length n_times. The output of the decorator is an
    instance of `FunctionalPulse` with signature:
        `def g(duration: int, *args, **kwargs) -> SamplePulse`

    Note if your continuous pulse function outputs a `complex` scalar rather than a
    `np.ndarray`, you should first vectorize it before applying a sampler.

    This class implements the sampler boilerplate for the sampler.

    Args:
        sample_function: A sampler function to be decorated.
    """

    def generate_sampler(continuous_pulse: Callable) -> Callable:
        """Return a decorated sampler function."""

        @functools.wraps(continuous_pulse)
        def call_sampler(duration: int, *args, **kwargs) -> commands.SamplePulse:
            """Replace the call to the continuous function with a call to the sampler applied
            to the anlytic pulse function."""
            sampled_pulse = sample_function(continuous_pulse, duration, *args, **kwargs)
            return np.asarray(sampled_pulse, dtype=np.complex_)

        # Update type annotations for wrapped continuous function to be discrete
        call_sampler = _update_annotations(call_sampler)
        # Update docstring with that of the sampler and include sampled function documentation.
        call_sampler = _update_docstring(call_sampler, sample_function)
        # Unset wrapped to return base sampler signature
        # but still get rest of benefits of wraps
        # such as __name__, __qualname__
        call_sampler.__dict__.pop('__wrapped__')
        # wrap with functional pulse
        return commands.functional_pulse(call_sampler)

    return generate_sampler

def left(continuous_pulse: Callable) -> Callable:
    r"""Left sampling strategy decorator.

    See `pulse.samplers.sampler` for more information.

    For `duration`, return:
        $$\{f(t) \in \mathbb{C} | t \in \mathbb{Z} \wedge  0<=t<\texttt{duration}\}$$

    Args:
        continuous_pulse: To sample.
    """

    return sampler(strategies.left_sample)(continuous_pulse)

def right(continuous_pulse: Callable) -> Callable:
    r"""Right sampling strategy decorator.

    See `pulse.samplers.sampler` for more information.

    For `duration`, return:
        $$\{f(t) \in \mathbb{C} | t \in \mathbb{Z} \wedge  0<t<=\texttt{duration}\}$$

    Args:
        continuous_pulse: To sample.
    """

    return sampler(strategies.right_sample)(continuous_pulse)

def midpoint(continuous_pulse: Callable) -> Callable:
    r"""Midpoint sampling strategy decorator.

    See `pulse.samplers.sampler` for more information.

    For `duration`, return:
        $$\{f(t+0.5) \in \mathbb{C} | t \in \mathbb{Z} \wedge  0<=t<\texttt{duration}\}$$

    Args:
        continuous_pulse: To sample.
    """
    return sampler(strategies.midpoint_sample)(continuous_pulse)


# -*- coding: utf-8 -*-

# Copyright 2018, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Utilities for providers."""

import logging

logger = logging.getLogger(__name__)

def filter_backends(backends, filters=None, **kwargs):
    """Return the backends matching the specified filtering.

    Filter the `backends` list by their `configuration` or `status`
    attributes, or from a boolean callable. The criteria for filtering can
    be specified via `**kwargs` or as a callable via `filters`, and the
    backends must fulfill all specified conditions.

    Args:
        backends (list[BaseBackend]): list of backends.
        filters (callable): filtering conditions as a callable.
        **kwargs (dict): dict of criteria.

    Returns:
        list[BaseBackend]: a list of backend instances matching the
            conditions.
    """
    def _match_all(obj, criteria):
        """Return True if all items in criteria matches items in obj."""
        return all(getattr(obj, key_, None) == value_ for
                   key_, value_ in criteria.items())

    # Inspect the backends to decide which filters belong to
    # backend.configuration and which ones to backend.status, as it does
    # not involve querying the API.
    configuration_filters = {}
    status_filters = {}
    for key, value in kwargs.items():
        if all(key in backend.configuration() for backend in backends):
            configuration_filters[key] = value
        else:
            status_filters[key] = value

    # 1. Apply backend.configuration filtering.
    if configuration_filters:
        backends = [b for b in backends if
                    _match_all(b.configuration(), configuration_filters)]

    # 2. Apply backend.status filtering (it involves one API call for
    # each backend).
    if status_filters:
        backends = [b for b in backends if
                    _match_all(b.status(), status_filters)]

    # 3. Apply acceptor filter.
    backends = list(filter(filters, backends))

    return backends

def resolve_backend_name(name, backends, deprecated, aliased):
    """Resolve backend name from a deprecated name or an alias.

    A group will be resolved in order of member priorities, depending on
    availability.

    Args:
        name (str): name of backend to resolve
        backends (list[BaseBackend]): list of available backends.
        deprecated (dict[str: str]): dict of deprecated names.
        aliased (dict[str: list[str]]): dict of aliased names.

    Returns:
        str: resolved name (name of an available backend)

    Raises:
        LookupError: if name cannot be resolved through regular available
            names, nor deprecated, nor alias names.
    """
    available = [backend.name() for backend in backends]

    resolved_name = deprecated.get(name, aliased.get(name, name))
    if isinstance(resolved_name, list):
        resolved_name = next((b for b in resolved_name if b in available), "")

    if resolved_name not in available:
        raise LookupError("backend '{}' not found.".format(name))

    if name in deprecated:
        logger.warning("WARNING: '%s' is deprecated. Use '%s'.", name, resolved_name)

    return resolved_name


# -*- coding: utf-8 -*-

# Copyright 2018, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Helper function for converting a dag to a circuit"""
import collections

from qiskit.circuit import QuantumCircuit
from qiskit.circuit import ClassicalRegister
from qiskit.circuit import QuantumRegister

def dag_to_circuit(dag):
    """Build a ``QuantumCircuit`` object from a ``DAGCircuit``.

    Args:
        dag (DAGCircuit): the input dag.

    Return:
        QuantumCircuit: the circuit representing the input dag.
    """
    qregs = collections.OrderedDict()
    for qreg in dag.qregs.values():
        qreg_tmp = QuantumRegister(qreg.size, name=qreg.name)
        qregs[qreg.name] = qreg_tmp
    cregs = collections.OrderedDict()
    for creg in dag.cregs.values():
        creg_tmp = ClassicalRegister(creg.size, name=creg.name)
        cregs[creg.name] = creg_tmp

    name = dag.name or None
    circuit = QuantumCircuit(*qregs.values(), *cregs.values(), name=name)

    for node in dag.topological_op_nodes():
        qubits = []
        for qubit in node.qargs:
            qubits.append(qregs[qubit[0].name][qubit[1]])

        clbits = []
        for clbit in node.cargs:
            clbits.append(cregs[clbit[0].name][clbit[1]])

        # Get arguments for classical control (if any)
        if node.condition is None:
            control = None
        else:
            control = (node.condition[0], node.condition[1])

        inst = node.op.copy()
        inst.control = control
        circuit.append(inst, qubits, clbits)
    return circuit


# -*- coding: utf-8 -*-

# Copyright 2018, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Helper functions for building dictionaries from matrices and lists."""

import numpy as np

def make_dict_observable(matrix_observable):
    """Convert an observable in matrix form to dictionary form.

    Takes in a diagonal observable as a matrix and converts it to a dictionary
    form. Can also handle a list sorted of the diagonal elements.

    Args:
        matrix_observable (list): The observable to be converted to dictionary
        form. Can be a matrix or just an ordered list of observed values

    Returns:
        Dict: A dictionary with all observable states as keys, and corresponding
        values being the observed value for that state
    """
    dict_observable = {}
    observable = np.array(matrix_observable)
    observable_size = len(observable)
    observable_bits = int(np.ceil(np.log2(observable_size)))
    binary_formater = '0{}b'.format(observable_bits)
    if observable.ndim == 2:
        observable = observable.diagonal()
    for state_no in range(observable_size):
        state_str = format(state_no, binary_formater)
        dict_observable[state_str] = observable[state_no]
    return dict_observable


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""OpenQASM parser."""

import os
import shutil
import tempfile

import ply.yacc as yacc
import sympy

from . import node
from .exceptions import QasmError
from .qasmlexer import QasmLexer

class QasmParser:
    """OPENQASM Parser."""

    # pylint: disable=unused-argument,missing-docstring,invalid-name

    def __init__(self, filename):
        """Create the parser."""
        if filename is None:
            filename = ""
        self.lexer = QasmLexer(filename)
        self.tokens = self.lexer.tokens
        self.parse_dir = tempfile.mkdtemp(prefix='qiskit')
        self.precedence = (
            ('left', '+', '-'),
            ('left', '*', '/'),
            ('left', 'negative', 'positive'),
            ('right', '^'))
        # For yacc, also, write_tables = Bool and optimize = Bool
        self.parser = yacc.yacc(module=self, debug=False,
                                outputdir=self.parse_dir)
        self.qasm = None
        self.parse_deb = False
        self.global_symtab = {}                          # global symtab
        self.current_symtab = self.global_symtab         # top of symbol stack
        self.symbols = []                                # symbol stack
        self.external_functions = ['sin', 'cos', 'tan', 'exp', 'ln', 'sqrt',
                                   'acos', 'atan', 'asin']

    def __enter__(self):
        return self

    def __exit__(self, *args):
        if os.path.exists(self.parse_dir):
            shutil.rmtree(self.parse_dir)

    def update_symtab(self, obj):
        """Update a node in the symbol table.

        Everything in the symtab must be a node with these attributes:
        name - the string name of the object
        type - the string type of the object
        line - the source line where the type was first found
        file - the source file where the type was first found
        """
        if obj.name in self.current_symtab:
            prev = self.current_symtab[obj.name]
            raise QasmError("Duplicate declaration for", obj.type + " '"
                            + obj.name + "' at line", str(obj.line)
                            + ', file', obj.file
                            + '.\nPrevious occurrence at line',
                            str(prev.line) + ', file', prev.file)
        self.current_symtab[obj.name] = obj

    def verify_declared_bit(self, obj):
        """Verify a qubit id against the gate prototype."""
        # We are verifying gate args against the formal parameters of a
        # gate prototype.
        if obj.name not in self.current_symtab:
            raise QasmError("Cannot find symbol '" + obj.name
                            + "' in argument list for gate, line",
                            str(obj.line), 'file', obj.file)

        # This insures the thing is from the bitlist and not from the
        # argument list.
        sym = self.current_symtab[obj.name]
        if not (sym.type == 'id' and sym.is_bit):
            raise QasmError("Bit", obj.name,
                            'is not declared as a bit in the gate.')

    def verify_bit_list(self, obj):
        """Verify each qubit in a list of ids."""
        # We expect the object to be a bitlist or an idlist, we don't care.
        # We will iterate it and ensure everything in it is declared as a bit,
        # and throw if not.
        for children in obj.children:
            self.verify_declared_bit(children)

    def verify_exp_list(self, obj):
        """Verify each expression in a list."""
        # A tad harder.  This is a list of expressions each of which could be
        # the head of a tree. We need to recursively walk each of these and
        # ensure that any Id elements resolve to the current stack.
        #
        # I believe we only have to look at the current symtab.
        if obj.children is not None:
            for children in obj.children:
                if isinstance(children, node.Id):
                    if children.name in self.external_functions:
                        continue

                    if children.name not in self.current_symtab:
                        raise QasmError("Argument '" + children.name
                                        + "' in expression cannot be "
                                        + "found, line", str(children.line),
                                        "file", children.file)
                else:
                    if hasattr(children, "children"):
                        self.verify_exp_list(children)

    def verify_as_gate(self, obj, bitlist, arglist=None):
        """Verify a user defined gate call."""
        if obj.name not in self.global_symtab:
            raise QasmError("Cannot find gate definition for '" + obj.name
                            + "', line", str(obj.line), 'file', obj.file)
        g_sym = self.global_symtab[obj.name]
        if not (g_sym.type == 'gate' or g_sym.type == 'opaque'):
            raise QasmError("'" + obj.name + "' is used as a gate "
                            + "or opaque call but the symbol is neither;"
                            + " it is a '" + g_sym.type + "' line",
                            str(obj.line), 'file', obj.file)

        if g_sym.n_bits() != bitlist.size():
            raise QasmError("Gate or opaque call to '" + obj.name
                            + "' uses", str(bitlist.size()),
                            "qubits but is declared for",
                            str(g_sym.n_bits()), "qubits", "line",
                            str(obj.line), 'file', obj.file)

        if arglist:
            if g_sym.n_args() != arglist.size():
                raise QasmError("Gate or opaque call to '" + obj.name
                                + "' uses", str(arglist.size()),
                                "qubits but is declared for",
                                str(g_sym.n_args()), "qubits", "line",
                                str(obj.line), 'file', obj.file)
        else:
            if g_sym.n_args() > 0:
                raise QasmError("Gate or opaque call to '" + obj.name
                                + "' has no arguments but is declared for",
                                str(g_sym.n_args()), "qubits", "line",
                                str(obj.line), 'file', obj.file)

    def verify_reg(self, obj, object_type):
        """Verify a register."""
        # How to verify:
        #    types must match
        #    indexes must be checked
        if obj.name not in self.global_symtab:
            raise QasmError('Cannot find definition for', object_type, "'"
                            + obj.name + "'", 'at line', str(obj.line),
                            'file', obj.file)

        g_sym = self.global_symtab[obj.name]

        if g_sym.type != object_type:
            raise QasmError("Type for '" + g_sym.name + "' should be '"
                            + object_type + "' but was found to be '"
                            + g_sym.type + "'", "line", str(obj.line),
                            "file", obj.file)

        if obj.type == 'indexed_id':
            bound = g_sym.index
            ndx = obj.index
            if ndx < 0 or ndx >= bound:
                raise QasmError("Register index for '" + g_sym.name
                                + "' out of bounds. Index is", str(ndx),
                                "bound is 0 <= index <", str(bound),
                                "at line", str(obj.line), "file", obj.file)

    def verify_reg_list(self, obj, object_type):
        """Verify a list of registers."""
        # We expect the object to be a bitlist or an idlist, we don't care.
        # We will iterate it and ensure everything in it is declared as a bit,
        # and throw if not.
        for children in obj.children:
            self.verify_reg(children, object_type)

    def id_tuple_list(self, id_node):
        """Return a list of (name, index) tuples for this id node."""
        if id_node.type != "id":
            raise QasmError("internal error, id_tuple_list")
        bit_list = []
        try:
            g_sym = self.current_symtab[id_node.name]
        except KeyError:
            g_sym = self.global_symtab[id_node.name]
        if g_sym.type == "qreg" or g_sym.type == "creg":
            # Return list of (name, idx) for reg ids
            for idx in range(g_sym.index):
                bit_list.append((id_node.name, idx))
        else:
            # Return (name, -1) for other ids
            bit_list.append((id_node.name, -1))
        return bit_list

    def verify_distinct(self, list_of_nodes):
        """Check that objects in list_of_nodes represent distinct (qu)bits.

        list_of_nodes is a list containing nodes of type id, indexed_id,
        primary_list, or id_list. We assume these are all the same type
        'qreg' or 'creg'.
        This method raises an exception if list_of_nodes refers to the
        same object more than once.
        """
        bit_list = []
        line_number = -1
        filename = ""
        for node_ in list_of_nodes:
            # id node: add all bits in register or (name, -1) for id
            if node_.type == "id":
                bit_list.extend(self.id_tuple_list(node_))
                line_number = node_.line
                filename = node_.file
            # indexed_id: add the bit
            elif node_.type == "indexed_id":
                bit_list.append((node_.name, node_.index))
                line_number = node_.line
                filename = node_.file
            # primary_list: for each id or indexed_id child, add
            elif node_.type == "primary_list":
                for child in node_.children:
                    if child.type == "id":
                        bit_list.extend(self.id_tuple_list(child))
                    else:
                        bit_list.append((child.name, child.index))
                    line_number = child.line
                    filename = child.file
            # id_list: for each id, add
            elif node_.type == "id_list":
                for child in node_.children:
                    bit_list.extend(self.id_tuple_list(child))
                    line_number = child.line
                    filename = child.file
            else:
                raise QasmError("internal error, verify_distinct")
        if len(bit_list) != len(set(bit_list)):
            raise QasmError("duplicate identifiers at line %d file %s"
                            % (line_number, filename))

    def pop_scope(self):
        """Return to the previous scope."""
        self.current_symtab = self.symbols.pop()

    def push_scope(self):
        """Enter a new scope."""
        self.symbols.append(self.current_symtab)
        self.current_symtab = {}

    # ---- Begin the PLY parser ----
    start = 'main'

    def p_main(self, program):
        """
            main : program
        """
        self.qasm = program[1]

    # ----------------------------------------
    #  program : statement
    #          | program statement
    # ----------------------------------------
    def p_program_0(self, program):
        """
           program : statement
        """
        program[0] = node.Program([program[1]])

    def p_program_1(self, program):
        """
           program : program statement
        """
        program[0] = program[1]
        program[0].add_child(program[2])

    # ----------------------------------------
    #  statement : decl
    #            | quantum_op ';'
    #            | format ';'
    # ----------------------------------------
    def p_statement(self, program):
        """
           statement : decl
                     | quantum_op ';'
                     | format ';'
                     | ignore
                     | quantum_op error
                     | format error
        """
        if len(program) > 2:
            if program[2] != ';':
                raise QasmError("Missing ';' at end of statement; "
                                + "received", str(program[2].value))
        program[0] = program[1]

    def p_format(self, program):
        """
           format : FORMAT
        """
        program[0] = node.Format(program[1])

    def p_format_0(self, program):
        """
           format : FORMAT error
        """
        version = "2.0;"
        raise QasmError("Invalid version string. Expected '" + version
                        + "'.  Is the semicolon missing?")

    # ----------------------------------------
    #  id : ID
    # ----------------------------------------
    def p_id(self, program):
        """
           id : ID
        """
        program[0] = program[1]

    def p_id_e(self, program):
        """
           id : error
        """
        raise QasmError("Expected an ID, received '"
                        + str(program[1].value) + "'")

    # ----------------------------------------
    #  indexed_id : ID [ int ]
    # ----------------------------------------
    def p_indexed_id(self, program):
        """
           indexed_id : id '[' NNINTEGER ']'
                      | id '[' NNINTEGER error
                      | id '[' error
        """
        if len(program) == 4:
            raise QasmError("Expecting an integer index; received",
                            str(program[3].value))
        if program[4] != ']':
            raise QasmError("Missing ']' in indexed ID; received",
                            str(program[4].value))
        program[0] = node.IndexedId([program[1], node.Int(program[3])])

    # ----------------------------------------
    #  primary : id
    #          | indexed_id
    # ----------------------------------------
    def p_primary(self, program):
        """
           primary : id
                   | indexed_id
        """
        program[0] = program[1]

    # ----------------------------------------
    #  id_list : id
    #          | id_list ',' id
    # ----------------------------------------
    def p_id_list_0(self, program):
        """
           id_list : id
        """
        program[0] = node.IdList([program[1]])

    def p_id_list_1(self, program):
        """
           id_list : id_list ',' id
        """
        program[0] = program[1]
        program[0].add_child(program[3])

    # ----------------------------------------
    #  gate_id_list : id
    #               | gate_id_list ',' id
    # ----------------------------------------
    def p_gate_id_list_0(self, program):
        """
           gate_id_list : id
        """
        program[0] = node.IdList([program[1]])
        self.update_symtab(program[1])

    def p_gate_id_list_1(self, program):
        """
           gate_id_list : gate_id_list ',' id
        """
        program[0] = program[1]
        program[0].add_child(program[3])
        self.update_symtab(program[3])

    # ----------------------------------------
    #  bit_list : bit
    #           | bit_list ',' bit
    # ----------------------------------------
    def p_bit_list_0(self, program):
        """
           bit_list : id
        """
        program[0] = node.IdList([program[1]])
        program[1].is_bit = True
        self.update_symtab(program[1])

    def p_bit_list_1(self, program):
        """
           bit_list : bit_list ',' id
        """
        program[0] = program[1]
        program[0].add_child(program[3])
        program[3].is_bit = True
        self.update_symtab(program[3])

    # ----------------------------------------
    #  primary_list : primary
    #               | primary_list ',' primary
    # ----------------------------------------
    def p_primary_list_0(self, program):
        """
           primary_list : primary
        """
        program[0] = node.PrimaryList([program[1]])

    def p_primary_list_1(self, program):
        """
           primary_list : primary_list ',' primary
        """
        program[0] = program[1]
        program[1].add_child(program[3])

    # ----------------------------------------
    #  decl : qreg_decl
    #       | creg_decl
    #       | gate_decl
    # ----------------------------------------
    def p_decl(self, program):
        """
           decl : qreg_decl ';'
                | creg_decl ';'
                | qreg_decl error
                | creg_decl error
                | gate_decl
        """
        if len(program) > 2:
            if program[2] != ';':
                raise QasmError("Missing ';' in qreg or creg declaration."
                                " Instead received '" + program[2].value + "'")
        program[0] = program[1]

    # ----------------------------------------
    #  qreg_decl : QREG indexed_id
    # ----------------------------------------
    def p_qreg_decl(self, program):
        """
           qreg_decl : QREG indexed_id
        """
        program[0] = node.Qreg([program[2]])
        if program[2].name in self.external_functions:
            raise QasmError("QREG names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        if program[2].index == 0:
            raise QasmError("QREG size must be positive")
        self.update_symtab(program[0])

    def p_qreg_decl_e(self, program):
        """
           qreg_decl : QREG error
        """
        raise QasmError("Expecting indexed id (ID[int]) in QREG"
                        + " declaration; received", program[2].value)

    # ----------------------------------------
    #  creg_decl : QREG indexed_id
    # ----------------------------------------
    def p_creg_decl(self, program):
        """
           creg_decl : CREG indexed_id
        """
        program[0] = node.Creg([program[2]])
        if program[2].name in self.external_functions:
            raise QasmError("CREG names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        if program[2].index == 0:
            raise QasmError("CREG size must be positive")
        self.update_symtab(program[0])

    def p_creg_decl_e(self, program):
        """
           creg_decl : CREG error
        """
        raise QasmError("Expecting indexed id (ID[int]) in CREG"
                        + " declaration; received", program[2].value)

    # Gate_body will throw if there are errors, so we don't need to cover
    # that here. Same with the id_lists - if they are not legal, we die
    # before we get here
    #
    # ----------------------------------------
    #  gate_decl : GATE id gate_scope                      bit_list gate_body
    #            | GATE id gate_scope '(' ')'              bit_list gate_body
    #            | GATE id gate_scope '(' gate_id_list ')' bit_list gate_body
    #
    # ----------------------------------------
    def p_gate_decl_0(self, program):
        """
           gate_decl : GATE id gate_scope bit_list gate_body
        """
        program[0] = node.Gate([program[2], program[4], program[5]])
        if program[2].name in self.external_functions:
            raise QasmError("GATE names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        self.pop_scope()
        self.update_symtab(program[0])

    def p_gate_decl_1(self, program):
        """
           gate_decl : GATE id gate_scope '(' ')' bit_list gate_body
        """
        program[0] = node.Gate([program[2], program[6], program[7]])
        if program[2].name in self.external_functions:
            raise QasmError("GATE names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        self.pop_scope()
        self.update_symtab(program[0])

    def p_gate_decl_2(self, program):
        """
        gate_decl : GATE id gate_scope '(' gate_id_list ')' bit_list gate_body
        """
        program[0] = node.Gate(
            [program[2], program[5], program[7], program[8]])
        if program[2].name in self.external_functions:
            raise QasmError("GATE names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        self.pop_scope()
        self.update_symtab(program[0])

    def p_gate_scope(self, program):
        """
           gate_scope :
        """
        self.push_scope()

    # ----------------------------------------
    #  gate_body : '{' gate_op_list '}'
    #            | '{' '}'
    #
    #            | '{' gate_op_list error
    #            | '{' error
    #
    # Error handling: gete_op will throw if there's a problem so we won't
    #                 get here with in the gate_op_list
    # ----------------------------------------
    def p_gate_body_0(self, program):
        """
           gate_body : '{' '}'
        """
        if program[2] != '}':
            raise QasmError("Missing '}' in gate definition; received'"
                            + str(program[2].value) + "'")
        program[0] = node.GateBody(None)

    def p_gate_body_1(self, program):
        """
           gate_body : '{' gate_op_list '}'
        """
        program[0] = node.GateBody(program[2])

    # ----------------------------------------
    #  gate_op_list : gate_op
    #               | gate_op_ist gate_op
    #
    # Error handling: gete_op will throw if there's a problem so we won't
    #                 get here with errors
    # ----------------------------------------
    def p_gate_op_list_0(self, program):
        """
            gate_op_list : gate_op
        """
        program[0] = [program[1]]

    def p_gate_op_list_1(self, program):
        """
            gate_op_list : gate_op_list gate_op
        """
        program[0] = program[1]
        program[0].append(program[2])

    # ----------------------------------------
    # These are for use outside of gate_bodies and allow
    # indexed ids everywhere.
    #
    # unitary_op : U '(' exp_list ')'  primary
    #            | CX                  primary ',' primary
    #            | id                  primary_list
    #            | id '(' ')'          primary_list
    #            | id '(' exp_list ')' primary_list
    #
    # Note that it might not be unitary - this is the mechanism that
    # is also used to invoke calls to 'opaque'
    # ----------------------------------------
    def p_unitary_op_0(self, program):
        """
          unitary_op : U '(' exp_list ')' primary
        """
        program[0] = node.UniversalUnitary([program[3], program[5]])
        self.verify_reg(program[5], 'qreg')
        self.verify_exp_list(program[3])

    def p_unitary_op_1(self, program):
        """
        unitary_op : CX primary ',' primary
        """
        program[0] = node.Cnot([program[2], program[4]])
        self.verify_reg(program[2], 'qreg')
        self.verify_reg(program[4], 'qreg')
        self.verify_distinct([program[2], program[4]])
        # TODO: check that if both primary are id, same size
        # TODO: this needs to be checked in other cases too

    def p_unitary_op_2(self, program):
        """
        unitary_op : id primary_list
        """
        program[0] = node.CustomUnitary([program[1], program[2]])
        self.verify_as_gate(program[1], program[2])
        self.verify_reg_list(program[2], 'qreg')
        self.verify_distinct([program[2]])

    def p_unitary_op_3(self, program):
        """
        unitary_op : id '(' ')' primary_list
        """
        program[0] = node.CustomUnitary([program[1], program[4]])
        self.verify_as_gate(program[1], program[4])
        self.verify_reg_list(program[4], 'qreg')
        self.verify_distinct([program[4]])

    def p_unitary_op_4(self, program):
        """
        unitary_op : id '(' exp_list ')' primary_list
        """
        program[0] = node.CustomUnitary([program[1], program[3], program[5]])
        self.verify_as_gate(program[1], program[5], arglist=program[3])
        self.verify_reg_list(program[5], 'qreg')
        self.verify_exp_list(program[3])
        self.verify_distinct([program[5]])

    # ----------------------------------------
    # This is a restricted set of "quantum_op" which also
    # prohibits indexed ids, for use in a gate_body
    #
    # gate_op : U '(' exp_list ')'  id         ';'
    #         | CX                  id ',' id  ';'
    #         | id                  id_list    ';'
    #         | id '(' ')'          id_list    ';'
    #         | id '(' exp_list ')' id_list    ';'
    #         | BARRIER id_list                ';'
    # ----------------------------------------
    def p_gate_op_0(self, program):
        """
        gate_op : U '(' exp_list ')' id ';'
        """
        program[0] = node.UniversalUnitary([program[3], program[5]])
        self.verify_declared_bit(program[5])
        self.verify_exp_list(program[3])

    def p_gate_op_0e1(self, p):
        """
        gate_op : U '(' exp_list ')' error
        """
        raise QasmError("Invalid U inside gate definition. "
                        + "Missing bit id or ';'")

    def p_gate_op_0e2(self, program):
        """
        gate_op : U '(' exp_list error
        """
        raise QasmError("Missing ')' in U invocation in gate definition.")

    def p_gate_op_1(self, program):
        """
        gate_op : CX id ',' id ';'
        """
        program[0] = node.Cnot([program[2], program[4]])
        self.verify_declared_bit(program[2])
        self.verify_declared_bit(program[4])
        self.verify_distinct([program[2], program[4]])

    def p_gate_op_1e1(self, program):
        """
        gate_op : CX error
        """
        raise QasmError("Invalid CX inside gate definition. "
                        + "Expected an ID or ',', received '"
                        + str(program[2].value) + "'")

    def p_gate_op_1e2(self, program):
        """
        gate_op : CX id ',' error
        """
        raise QasmError("Invalid CX inside gate definition. "
                        + "Expected an ID or ';', received '"
                        + str(program[4].value) + "'")

    def p_gate_op_2(self, program):
        """
        gate_op : id id_list ';'
        """
        program[0] = node.CustomUnitary([program[1], program[2]])
        # To verify:
        # 1. id is declared as a gate in global scope
        # 2. everything in the id_list is declared as a bit in local scope
        self.verify_as_gate(program[1], program[2])
        self.verify_bit_list(program[2])
        self.verify_distinct([program[2]])

    def p_gate_op_2e(self, program):
        """
        gate_op : id  id_list error
        """
        raise QasmError("Invalid gate invocation inside gate definition.")

    def p_gate_op_3(self, program):
        """
        gate_op : id '(' ')' id_list ';'
        """
        program[0] = node.CustomUnitary([program[1], program[4]])
        self.verify_as_gate(program[1], program[4])
        self.verify_bit_list(program[4])
        self.verify_distinct([program[4]])

    def p_gate_op_4(self, program):
        """
        gate_op : id '(' exp_list ')' id_list ';'
        """
        program[0] = node.CustomUnitary([program[1], program[3], program[5]])
        self.verify_as_gate(program[1], program[5], arglist=program[3])
        self.verify_bit_list(program[5])
        self.verify_exp_list(program[3])
        self.verify_distinct([program[5]])

    def p_gate_op_4e0(self, program):
        """
        gate_op : id '(' ')'  error
        """
        raise QasmError("Invalid bit list inside gate definition or"
                        + " missing ';'")

    def p_gate_op_4e1(self, program):
        """
        gate_op : id '('   error
        """
        raise QasmError("Unmatched () for gate invocation inside gate"
                        + " invocation.")

    def p_gate_op_5(self, program):
        """
        gate_op : BARRIER id_list ';'
        """
        program[0] = node.Barrier([program[2]])
        self.verify_bit_list(program[2])
        self.verify_distinct([program[2]])

    def p_gate_op_5e(self, program):
        """
        gate_op : BARRIER error
        """
        raise QasmError("Invalid barrier inside gate definition.")

    # ----------------------------------------
    # opaque : OPAQUE id gate_scope                      bit_list
    #        | OPAQUE id gate_scope '(' ')'              bit_list
    #        | OPAQUE id gate_scope '(' gate_id_list ')' bit_list
    #
    # These are like gate declarations only wihtout a body.
    # ----------------------------------------
    def p_opaque_0(self, program):
        """
           opaque : OPAQUE id gate_scope bit_list
        """
        # TODO: Review Opaque function
        program[0] = node.Opaque([program[2], program[4]])
        if program[2].name in self.external_functions:
            raise QasmError("OPAQUE names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        self.pop_scope()
        self.update_symtab(program[0])

    def p_opaque_1(self, program):
        """
           opaque : OPAQUE id gate_scope '(' ')' bit_list
        """
        program[0] = node.Opaque([program[2], program[6]])
        self.pop_scope()
        self.update_symtab(program[0])

    def p_opaque_2(self, program):
        """
           opaque : OPAQUE id gate_scope '(' gate_id_list ')' bit_list
        """
        program[0] = node.Opaque([program[2], program[5], program[7]])
        if program[2].name in self.external_functions:
            raise QasmError("OPAQUE names cannot be reserved words. "
                            + "Received '" + program[2].name + "'")
        self.pop_scope()
        self.update_symtab(program[0])

    def p_opaque_1e(self, program):
        """
           opaque : OPAQUE id gate_scope '(' error
        """
        raise QasmError("Poorly formed OPAQUE statement.")

    # ----------------------------------------
    # measure : MEASURE primary ASSIGN primary
    # ----------------------------------------
    def p_measure(self, program):
        """
           measure : MEASURE primary ASSIGN primary
        """
        program[0] = node.Measure([program[2], program[4]])
        self.verify_reg(program[2], 'qreg')
        self.verify_reg(program[4], 'creg')

    def p_measure_e(self, program):
        """
           measure : MEASURE primary error
        """
        raise QasmError("Illegal measure statement." +
                        str(program[3].value))

    # ----------------------------------------
    # barrier : BARRIER primary_list
    #
    # Errors are covered by handling erros in primary_list
    # ----------------------------------------
    def p_barrier(self, program):
        """
        barrier : BARRIER primary_list
        """
        program[0] = node.Barrier([program[2]])
        self.verify_reg_list(program[2], 'qreg')
        self.verify_distinct([program[2]])

    # ----------------------------------------
    # reset : RESET primary
    # ----------------------------------------
    def p_reset(self, program):
        """
        reset : RESET primary
        """
        program[0] = node.Reset([program[2]])
        self.verify_reg(program[2], 'qreg')

    # ----------------------------------------
    # IF '(' ID MATCHES NNINTEGER ')' quantum_op
    # ----------------------------------------
    def p_if(self, program):
        """
        if : IF '(' id MATCHES NNINTEGER ')' quantum_op
        if : IF '(' id error
        if : IF '(' id MATCHES error
        if : IF '(' id MATCHES NNINTEGER error
        if : IF error
        """
        if len(program) == 3:
            raise QasmError("Ill-formed IF statement. Perhaps a"
                            + " missing '('?")
        if len(program) == 5:
            raise QasmError("Ill-formed IF statement.  Expected '==', "
                            + "received '" + str(program[4].value))
        if len(program) == 6:
            raise QasmError("Ill-formed IF statement.  Expected a number, "
                            + "received '" + str(program[5].value))
        if len(program) == 7:
            raise QasmError("Ill-formed IF statement, unmatched '('")

        if program[7].type == 'if':
            raise QasmError("Nested IF statements not allowed")
        if program[7].type == 'barrier':
            raise QasmError("barrier not permitted in IF statement")

        program[0] = node.If([program[3], node.Int(program[5]), program[7]])

    # ----------------------------------------
    # These are all the things you can have outside of a gate declaration
    #        quantum_op : unitary_op
    #                   | opaque
    #                   | measure
    #                   | reset
    #                   | barrier
    #                   | if
    #
    # ----------------------------------------
    def p_quantum_op(self, program):
        """
            quantum_op : unitary_op
                       | opaque
                       | measure
                       | barrier
                       | reset
                       | if
        """
        program[0] = program[1]

    # ----------------------------------------
    # unary : NNINTEGER
    #       | REAL
    #       | PI
    #       | ID
    #       | '(' expression ')'
    #       | id '(' expression ')'
    #
    # We will trust 'expression' to throw before we have to handle it here
    # ----------------------------------------
    def p_unary_0(self, program):
        """
           unary : NNINTEGER
        """
        program[0] = node.Int(program[1])

    def p_unary_1(self, program):
        """
           unary : REAL
        """
        program[0] = node.Real(sympy.Number(program[1]))

    def p_unary_2(self, program):
        """
           unary : PI
        """
        program[0] = node.Real(sympy.pi)

    def p_unary_3(self, program):
        """
           unary : id
        """
        program[0] = program[1]

    def p_unary_4(self, program):
        """
           unary : '(' expression ')'
        """
        program[0] = program[2]

    def p_unary_6(self, program):
        """
           unary : id '(' expression ')'
        """
        # note this is a semantic check, not syntactic
        if program[1].name not in self.external_functions:
            raise QasmError("Illegal external function call: ",
                            str(program[1].name))
        program[0] = node.External([program[1], program[3]])

    # ----------------------------------------
    # Prefix
    # ----------------------------------------

    def p_expression_1(self, program):
        """
            expression : '-' expression %prec negative
                        | '+' expression %prec positive
        """
        program[0] = node.Prefix([node.UnaryOperator(program[1]), program[2]])

    def p_expression_0(self, program):
        """
        expression : expression '*' expression
                    | expression '/' expression
                    | expression '+' expression
                    | expression '-' expression
                    | expression '^' expression
        """
        program[0] = node.BinaryOp([node.BinaryOperator(program[2]),
                                    program[1], program[3]])

    def p_expression_2(self, program):
        """
            expression : unary
        """
        program[0] = program[1]

    # ----------------------------------------
    # exp_list : exp
    #          | exp_list ',' exp
    # ----------------------------------------
    def p_exp_list_0(self, program):
        """
           exp_list : expression
        """
        program[0] = node.ExpressionList([program[1]])

    def p_exp_list_1(self, program):
        """
           exp_list : exp_list ',' expression
        """
        program[0] = program[1]
        program[0].add_child(program[3])

    def p_ignore(self, program):
        """
           ignore : STRING
        """
        # this should never hit but it keeps the insuppressible warnings at bay
        pass

    def p_error(self, program):
        # EOF is a special case because the stupid error token isn't placed
        # on the stack
        if not program:
            raise QasmError("Error at end of file. "
                            + "Perhaps there is a missing ';'")

        col = self.find_column(self.lexer.data, program)
        print("Error near line", str(self.lexer.lineno), 'Column', col)

    def find_column(self, input_, token):
        """Compute the column.

        Input is the input text string.
        token is a token instance.
        """
        if token is None:
            return 0
        last_cr = input_.rfind('\n', 0, token.lexpos)
        if last_cr < 0:
            last_cr = 0
        column = (token.lexpos - last_cr) + 1
        return column

    def get_tokens(self):
        """Returns a generator of the tokens."""
        try:
            while True:
                token = self.lexer.token()

                if not token:
                    break

                yield token
        except QasmError as e:
            print('Exception tokenizing qasm file:', e.msg)

    def parse_debug(self, val):
        """Set the parse_deb field."""
        if val is True:
            self.parse_deb = True
        elif val is False:
            self.parse_deb = False
        else:
            raise QasmError("Illegal debug value '" + str(val)
                            + "' must be True or False.")

    def parse(self, data):
        """Parse some data."""
        self.parser.parse(data, lexer=self.lexer, debug=self.parse_deb)
        if self.qasm is None:
            raise QasmError("Uncaught exception in parser; "
                            + "see previous messages for details.")
        return self.qasm

    def print_tree(self):
        """Print parsed OPENQASM."""
        if self.qasm is not None:
            self.qasm.to_string(0)
        else:
            print("No parsed qasm to print")

    def run(self, data):
        """Parser runner.

        To use this module stand-alone.
        """
        ast = self.parser.parse(data, debug=True)
        self.parser.parse(data, debug=True)
        ast.to_string(0)


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""
OPENQASM circuit object.
"""
from .exceptions import QasmError
from .qasmparser import QasmParser

class Qasm:
    """OPENQASM circuit object."""

    def __init__(self, filename=None, data=None):
        """Create an OPENQASM circuit object."""
        if filename is None and data is None:
            raise QasmError("Missing input file and/or data")
        if filename is not None and data is not None:
            raise QasmError("File and data must not both be specified"
                            "initializing qasm")
        self._filename = filename
        self._data = data

    def get_filename(self):
        """Return the filename."""
        return self._filename

    def get_tokens(self):
        """Returns a generator of the tokens."""
        if self._filename:
            with open(self._filename) as ifile:
                self._data = ifile.read()

        with QasmParser(self._filename) as qasm_p:
            return qasm_p.get_tokens()

    def parse(self):
        """Parse the data."""
        if self._filename:
            with open(self._filename) as ifile:
                self._data = ifile.read()

        with QasmParser(self._filename) as qasm_p:
            qasm_p.parse_debug(False)
            return qasm_p.parse(self._data)


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""
controlled-rz gate.
"""
from qiskit.circuit import CompositeGate
from qiskit.circuit import Gate
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.circuit.decorators import _op_expand, _to_bits
from qiskit.extensions.standard.u1 import U1Gate
from qiskit.extensions.standard.cx import CnotGate

class CrzGate(Gate):
    """controlled-rz gate."""

    def __init__(self, theta):
        """Create new crz gate."""
        super().__init__("crz", 2, [theta])

    def _define(self):
        """
        gate crz(lambda) a,b
        { u1(lambda/2) b; cx a,b;
          u1(-lambda/2) b; cx a,b;
        }
        """
        definition = []
        q = QuantumRegister(2, "q")
        rule = [
            (U1Gate(self.params[0] / 2), [q[1]], []),
            (CnotGate(), [q[0], q[1]], []),
            (U1Gate(-self.params[0] / 2), [q[1]], []),
            (CnotGate(), [q[0], q[1]], [])
        ]
        for inst in rule:
            definition.append(inst)
        self.definition = definition

    def inverse(self):
        """Invert this gate."""
        return CrzGate(-self.params[0])

@_to_bits(2)
@_op_expand(2)
def crz(self, theta, ctl, tgt):
    """Apply crz from ctl to tgt with angle theta."""
    return self.append(CrzGate(theta), [ctl, tgt], [])

QuantumCircuit.crz = crz
CompositeGate.crz = crz


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

# pylint: disable=invalid-name,anomalous-backslash-in-string

"""
A collection of useful quantum information functions for states.

"""
import logging
import numpy as np
from qiskit.exceptions import QiskitError

logger = logging.getLogger(__name__)

def basis_state(str_state, num):
    """
    Return a basis state ndarray.

    Args:
        str_state (string): a string representing the state.
        num (int): the number of qubits
    Returns:
        ndarray:  state(2**num) a quantum state with basis basis state.
     Raises:
        QiskitError: if the dimensions is wrong
    """
    n = int(str_state, 2)
    if num >= len(str_state):
        state = np.zeros(1 << num, dtype=complex)
        state[n] = 1
        return state
    else:
        raise QiskitError('size of bitstring is greater than num.')

def projector(state, flatten=False):
    """
    maps a pure state to a state matrix

    Args:
        state (ndarray): the number of qubits
        flatten (bool): determine if state matrix of column work
    Returns:
        ndarray:  state_mat(2**num, 2**num) if flatten is false
        ndarray:  state_mat(4**num) if flatten is true stacked on by the column
    """
    density_matrix = np.outer(state.conjugate(), state)
    if flatten:
        return density_matrix.flatten(order='F')
    return density_matrix

def purity(state):
    """Calculate the purity of a quantum state.

    Args:
        state (ndarray): a quantum state
    Returns:
        float: purity.
    """
    rho = np.array(state)
    if rho.ndim == 1:
        return 1.0
    return np.real(np.trace(rho.dot(rho)))


# -*- coding: utf-8 -*-

# Copyright 2017, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

# pylint: disable=invalid-name

"""Node for an OPENQASM gate definition."""

from .node import Node

class Gate(Node):
    """Node for an OPENQASM gate definition.

    children[0] is an id node.
    If len(children) is 3, children[1] is an idlist node,
    and children[2] is a gatebody node.
    Otherwise, children[1] is an expressionlist node,
    children[2] is an idlist node, and children[3] is a gatebody node.
    """

    def __init__(self, children):
        """Create the gate node."""
        super().__init__('gate', children, None)
        self.id = children[0]
        # The next three fields are required by the symbtab
        self.name = self.id.name
        self.line = self.id.line
        self.file = self.id.file

        if len(children) == 3:
            self.arguments = None
            self.bitlist = children[1]
            self.body = children[2]
        else:
            self.arguments = children[1]
            self.bitlist = children[2]
            self.body = children[3]

    def n_args(self):
        """Return the number of parameter expressions."""
        if self.arguments:
            return self.arguments.size()
        return 0

    def n_bits(self):
        """Return the number of qubit arguments."""
        return self.bitlist.size()

    def qasm(self, prec=15):
        """Return the corresponding OPENQASM string."""
        string = "gate " + self.name
        if self.arguments is not None:
            string += "(" + self.arguments.qasm(prec) + ")"
        string += " " + self.bitlist.qasm(prec) + "\n"
        string += "{\n" + self.body.qasm(prec) + "}"
        return string