Пример #1
0
    def wrapper(self, *args):
        """Wrapper for control-target gate"""
        params = args[0:-2] if len(args) > 2 else tuple()
        ctl = args[-2]
        tgt = args[-1]
        if isinstance(ctl, QuantumRegister):
            ctl = [(ctl, i) for i in range(len(ctl))]
        if isinstance(tgt, QuantumRegister):
            tgt = [(tgt, i) for i in range(len(tgt))]
        if isinstance(ctl, list) != isinstance(tgt, list):
            # TODO: check for Qubit instance
            if isinstance(ctl, tuple):
                ctl = [ctl]
            elif isinstance(tgt, tuple):
                tgt = [tgt]
            else:
                raise ReNomQError('control or target are not qubits')

        if ctl and tgt and isinstance(ctl, list) and isinstance(tgt, list):
            instructions = InstructionSet()
            if len(ctl) == len(tgt):
                for ictl, itgt in zip(ctl, tgt):
                    instructions.add(func(self, *params, ictl, itgt))
            elif len(ctl) == 1:
                for itgt in tgt:
                    instructions.add(func(self, *params, ctl[0], itgt))
            elif len(tgt) == 1:
                for ictl in ctl:
                    instructions.add(func(self, *params, ictl, tgt[0]))
            else:
                raise ReNomQError('indeterminate control or target qubits')
            return instructions
        return func(self, *params, ctl, tgt)
Пример #2
0
    def _process_bit_id(self, node):
        """Process an Id or IndexedId node as a bit or register type.

        Return a list of tuples (Register,index).
        """
        # pylint: disable=inconsistent-return-statements
        reg = None
        if node.name in self.dag.qregs:
            reg = self.dag.qregs[node.name]
        elif node.name in self.dag.cregs:
            reg = self.dag.cregs[node.name]
        else:
            raise ReNomQError("expected qreg or creg name:",
                              "line=%s" % node.line, "file=%s" % node.file)

        if node.type == "indexed_id":
            # An indexed bit or qubit
            return [(reg, node.index)]
        elif node.type == "id":
            # A qubit or qreg or creg
            if not self.bit_stack[-1]:
                # Global scope
                return [(reg, j) for j in range(reg.size)]
            else:
                # local scope
                if node.name in self.bit_stack[-1]:
                    return [self.bit_stack[-1][node.name]]
                raise ReNomQError("expected local bit name:",
                                  "line=%s" % node.line, "file=%s" % node.file)
        return None
Пример #3
0
 def _check_qreg(self, register):
     """Raise exception if r is not in this circuit or not qreg."""
     if not isinstance(register, QuantumRegister):
         raise ReNomQError("expected quantum register")
     if not self.has_register(register):
         raise ReNomQError("register '%s' not in this circuit" %
                           register.name)
Пример #4
0
 def _check_creg(self, register):
     """Raise exception if r is not in this circuit or not creg."""
     if not isinstance(register, ClassicalRegister):
         raise ReNomQError("Expected ClassicalRegister, but %s given" %
                           type(register))
     if not self.has_register(register):
         raise ReNomQError("register '%s' not in this circuit" %
                           register.name)
Пример #5
0
 def add_register(self, *regs):
     """Add registers."""
     for register in regs:
         if register in self.qregs or register in self.cregs:
             raise ReNomQError("register name \"%s\" already exists" %
                               register.name)
         if isinstance(register, QuantumRegister):
             self.qregs.append(register)
         elif isinstance(register, ClassicalRegister):
             self.cregs.append(register)
         else:
             raise ReNomQError("expected a register")
Пример #6
0
 def _check_qubit(self, qubit):
     """Raise exception if qubit is not in this circuit or bad format."""
     if not isinstance(qubit, tuple):
         raise ReNomQError("%s is not a tuple."
                           "A qubit should be formated as a tuple." %
                           str(qubit))
     if not len(qubit) == 2:
         raise ReNomQError(
             "%s is not a tuple with two elements, but %i instead" %
             len(qubit))
     if not isinstance(qubit[1], int):
         raise ReNomQError(
             "The second element of a tuple defining a qubit should be an int:"
             "%s was found instead" % type(qubit[1]).__name__)
     self._check_qreg(qubit[0])
     qubit[0].check_range(qubit[1])
Пример #7
0
    def __init__(self, *regs, name=None):
        """Create a new circuit.

        A circuit is a list of instructions bound to some registers.

        Args:
            *regs (Registers): registers to include in the circuit.
            name (str or None): the name of the quantum circuit. If
                None, an automatically generated string will be assigned.

        Raises:
            ReNomQError: if the circuit name, if given, is not valid.
        """
        if name is None:
            name = self.cls_prefix() + str(self.cls_instances())
            # pylint: disable=not-callable
            # (known pylint bug: https://github.com/PyCQA/pylint/issues/1699)
            if sys.platform != "win32" and \
               isinstance(mp.current_process(), mp.context.ForkProcess):
                name += '-{}'.format(mp.current_process().pid)
        self._increment_instances()

        if not isinstance(name, str):
            raise ReNomQError("The circuit name should be a string "
                              "(or None to auto-generate a name).")

        self.name = name

        # Data contains a list of instructions in the order they were applied.
        self.data = []

        # This is a map of registers bound to this circuit, by name.
        self.qregs = []
        self.cregs = []
        self.add_register(*regs)
Пример #8
0
def cswap(self, ctl, tgt1, tgt2):
    """Apply Fredkin to circuit."""
    if isinstance(ctl, QuantumRegister):
        ctl = [(ctl, i) for i in range(len(ctl))]
    if isinstance(tgt1, QuantumRegister):
        tgt1 = [(tgt1, i) for i in range(len(tgt1))]
    if isinstance(tgt2, QuantumRegister):
        tgt2 = [(tgt2, i) for i in range(len(tgt2))]

    if ctl and tgt1 and tgt2:
        if isinstance(ctl, list) and \
           isinstance(tgt1, list) and \
           isinstance(tgt2, list):
            if len(ctl) == len(tgt1) and len(ctl) == len(tgt2):
                instructions = InstructionSet()
                for ictl, itgt1, itgt2 in zip(ctl, tgt1, tgt2):
                    instructions.add(self.cswap(ictl, itgt1, itgt2))
                return instructions
            else:
                raise ReNomQError('unequal register sizes')

    self._check_qubit(ctl)
    self._check_qubit(tgt1)
    self._check_qubit(tgt2)
    self._check_dups([ctl, tgt1, tgt2])
    return self._attach(FredkinGate(ctl, tgt1, tgt2, self))
Пример #9
0
    def wrapper(self, *args):
        """Wrapper for one qubit gate"""
        params = args[0:-2] if len(args) > 2 else tuple()
        qubit1 = args[-2]
        qubit2 = args[-1]
        if isinstance(qubit1, QuantumRegister):
            qubit1 = [(qubit1, j) for j in range(len(qubit1))]
        if isinstance(qubit2, QuantumRegister):
            qubit2 = [(qubit2, j) for j in range(len(qubit2))]

        if isinstance(qubit1, list) and isinstance(qubit2, list):
            if len(qubit1) != len(qubit2):
                raise ReNomQError('lengths of qubit arguments do not match: '
                                  '{0} != {1}'.format(len(qubit1),
                                                      len(qubit2)))

        if qubit1 and qubit2 and isinstance(qubit1, list) and isinstance(
                qubit2, list):
            instructions = InstructionSet()
            for iqubit1, iqubit2 in zip(qubit1, qubit2):
                self._check_qubit(iqubit1)
                self._check_qubit(iqubit2)
                instructions.add(func(self, *params, iqubit1, iqubit2))
            return instructions
        return func(self, *params, qubit1, qubit2)
Пример #10
0
 def _check_qubit(self, qubit):
     """Raise exception if q is not an argument or not qreg in circuit."""
     self.check_circuit()
     self.circuit._check_qubit(qubit)
     if (qubit[0].name, qubit[1]) not in map(lambda x: (x[0].name, x[1]),
                                             self.qargs):
         raise ReNomQError("qubit '%s[%d]' not argument of gate" %
                           (qubit[0].name, qubit[1]))
Пример #11
0
 def _modifiers(self, gate):
     """Apply any modifiers of this instruction to another one."""
     if self.control is not None:
         self.check_circuit()
         if not gate.circuit.has_register(self.control[0]):
             raise ReNomQError("control register %s not found" %
                               self.control[0].name)
         gate.c_if(self.control[0], self.control[1])
Пример #12
0
 def c_if(self, classical, val):
     """Add classical control on register classical and value val."""
     self.check_circuit()
     self.circuit._check_creg(classical)
     if val < 0:
         raise ReNomQError("control value should be non-negative")
     self.control = (classical, val)
     return self
Пример #13
0
    def _check_dups(self, qubits):
        """Raise exception.

        if list of qubits contains duplicates.
        """
        squbits = set(qubits)
        if len(squbits) != len(qubits):
            raise ReNomQError("duplicate qubit arguments")
Пример #14
0
 def _process_measure(self, node):
     """Process a measurement node."""
     id0 = self._process_bit_id(node.children[0])
     id1 = self._process_bit_id(node.children[1])
     if len(id0) != len(id1):
         raise ReNomQError("internal error: reg size mismatch",
                           "line=%s" % node.line, "file=%s" % node.file)
     for idx, idy in zip(id0, id1):
         self.dag.apply_operation_back(Measure(idx, idy), self.condition)
Пример #15
0
 def __init__(self, name, params, qargs, cargs, circuit=None):
     """Create a new instruction.
     Args:
         name (str): instruction name
         params (list[sympy.Basic|qasm.Node|int|float|complex|str]): list of parameters
         qargs (list[(QuantumRegister, index)]): list of quantum args
         cargs (list[(ClassicalRegister, index)]): list of classical args
         circuit (QuantumCircuit or Instruction): where the instruction is attached
     Raises:
         ReNomQError: when the register is not in the correct format.
     """
     if not all(
         (type(i[0]), type(i[1])) == (QuantumRegister, int) for i in qargs):
         raise ReNomQError("qarg not (QuantumRegister, int) tuple")
     if not all((type(i[0]), type(i[1])) == (ClassicalRegister, int)
                for i in cargs):
         raise ReNomQError("carg not (ClassicalRegister, int) tuple")
     self.name = name
     self.params = []  # a list of gate params stored as sympy objects
     for single_param in params:
         # example: u2(pi/2, sin(pi/4))
         if isinstance(single_param, sympy.Basic):
             self.params.append(single_param)
         # example: OpenQASM parsed instruction
         elif isinstance(single_param, _node.Node):
             self.params.append(single_param.sym())
         # example: u3(0.1, 0.2, 0.3)
         elif isinstance(single_param, (int, float)):
             self.params.append(sympy.Number(single_param))
         # example: Initialize([complex(0,1), complex(0,0)])
         elif isinstance(single_param, complex):
             self.params.append(single_param.real +
                                single_param.imag * sympy.I)
         # example: snapshot('label')
         elif isinstance(single_param, str):
             self.params.append(sympy.Symbol(single_param))
         else:
             raise ReNomQError("invalid param type {0} in instruction "
                               "{1}".format(type(single_param), name))
     self.qargs = qargs
     self.cargs = cargs
     self.control = None  # tuple (ClassicalRegister, int) for "if"
     self.circuit = circuit
Пример #16
0
    def __init__(self, size, name=None):
        """Create a new generic register.
        """

        if name is None:
            name = '%s%i' % (self.prefix, next(self.instances_counter))

        if not isinstance(name, str):
            raise ReNomQError("The circuit name should be a string "
                              "(or None for autogenerate a name).")

        test = re.compile('[a-z][a-zA-Z0-9_]*')
        if test.match(name) is None:
            raise ReNomQError("%s is an invalid OPENQASM register name." % name)

        self.name = name
        self.size = size
        if size <= 0:
            raise ReNomQError("register size must be positive")
Пример #17
0
    def _check_compatible_regs(self, rhs):
        """Raise exception if the circuits are defined on incompatible registers"""

        list1 = self.qregs + self.cregs
        list2 = rhs.qregs + rhs.cregs
        for element1 in list1:
            for element2 in list2:
                if element2.name == element1.name:
                    if element1 != element2:
                        raise ReNomQError("circuits are not compatible")
Пример #18
0
def measure(self, qubit, cbit):
    """Measure quantum bit into classical bit (tuples).

    Args:
        qubit (QuantumRegister|list|tuple): quantum register
        cbit (ClassicalRegister|list|tuple): classical register

    Returns:
        ReNomQ.Instruction: the attached measure instruction.

    Raises:
        ReNomQError: if qubit is not in this circuit or bad format;
            if cbit is not in this circuit or not creg.
    """
    if isinstance(qubit, QuantumRegister):
        qubit = [(qubit, i) for i in range(len(qubit))]
    if isinstance(cbit, ClassicalRegister):
        cbit = [(cbit, i) for i in range(len(cbit))]
    if isinstance(qubit, list) != isinstance(cbit, list):
        # TODO: check for Qubit instance
        if isinstance(qubit, tuple):
            qubit = [qubit]
        elif isinstance(cbit, tuple):
            cbit = [cbit]
        else:
            raise ReNomQError('control or target are not qubits')

    if qubit and cbit and isinstance(qubit, list) and isinstance(cbit, list):
        if len(qubit) != len(cbit):
            raise ReNomQError(
                'qubit and cbit should have the same length if lists')
        instructions = InstructionSet()
        for qb1, cb1 in zip(qubit, cbit):
            instructions.add(self.measure(qb1, cb1))
        return instructions

    self._check_qubit(qubit)
    self._check_creg(cbit[0])
    cbit[0].check_range(cbit[1])
    return self._attach(Measure(qubit, cbit, self))
Пример #19
0
def ccx(self, ctl1, ctl2, tgt):
    """Apply Toffoli to from ctl1 and ctl2 to tgt."""
    # expand registers to lists of qubits
    if isinstance(ctl1, QuantumRegister):
        ctl1 = [(ctl1, i) for i in range(len(ctl1))]
    if isinstance(ctl2, QuantumRegister):
        ctl2 = [(ctl2, i) for i in range(len(ctl2))]
    if isinstance(tgt, QuantumRegister):
        tgt = [(tgt, i) for i in range(len(tgt))]
    # expand single qubit target if controls are lists of qubits
    if isinstance(ctl1, list) and len(ctl1) == len(ctl2):
        if isinstance(tgt, tuple):
            tgt = [tgt]
        if len(tgt) == 1:
            tgt = tgt * len(ctl1)
        elif len(tgt) != len(ctl1):
            raise ReNomQError(
                'target register size should match controls or be one')

    if ctl1 and ctl2 and tgt:
        if isinstance(ctl1, list) and \
           isinstance(ctl2, list) and \
           isinstance(tgt, list):
            if len(ctl1) == len(tgt) and len(ctl2) == len(tgt):
                instructions = InstructionSet()
                for ictl1, ictl2, itgt in zip(ctl1, ctl2, tgt):
                    instructions.add(self.ccx(ictl1, ictl2, itgt))
                return instructions
            else:
                raise ReNomQError('unequal register sizes')
    else:
        raise ReNomQError('empty control or target argument')

    self._check_qubit(ctl1)
    self._check_qubit(ctl2)
    self._check_qubit(tgt)
    self._check_dups([ctl1, ctl2, tgt])
    return self._attach(ToffoliGate(ctl1, ctl2, tgt, self))
Пример #20
0
 def _process_cnot(self, node):
     """Process a CNOT gate node."""
     id0 = self._process_bit_id(node.children[0])
     id1 = self._process_bit_id(node.children[1])
     if not (len(id0) == len(id1) or len(id0) == 1 or len(id1) == 1):
         raise ReNomQError("internal error: qreg size mismatch",
                           "line=%s" % node.line, "file=%s" % node.file)
     maxidx = max([len(id0), len(id1)])
     for idx in range(maxidx):
         if len(id0) > 1 and len(id1) > 1:
             self.dag.apply_operation_back(CXBase(id0[idx], id1[idx]),
                                           self.condition)
         elif len(id0) > 1:
             self.dag.apply_operation_back(CXBase(id0[idx], id1[0]),
                                           self.condition)
         else:
             self.dag.apply_operation_back(CXBase(id0[0], id1[idx]),
                                           self.condition)
Пример #21
0
    def __getitem__(self, key):
        """
        Arg:
            key (int): index of the bit/qubit to be retrieved.

        Returns:
            tuple[Register, int]: a tuple in the form `(self, key)` if key is int.
                If key is a slice, return a `list((self,key))`.

        Raises:
            ReNomQError: if the `key` is not an integer.
            ReNomQIndexError: if the `key` is not in the range
                `(0, self.size)`.
        """
        if not isinstance(key, (int, slice)):
            raise ReNomQError("expected integer or slice index into register")
        self.check_range(key)
        if isinstance(key, slice):
            return [(self, ind) for ind in range(*key.indices(len(self)))]
        else:
            return self, key
Пример #22
0
 def _process_custom_unitary(self, node):
     """Process a custom unitary node."""
     name = node.name
     if node.arguments is not None:
         args = self._process_node(node.arguments)
     else:
         args = []
     bits = [
         self._process_bit_id(node_element)
         for node_element in node.bitlist.children
     ]
     if name in self.gates:
         gargs = self.gates[name]["args"]
         gbits = self.gates[name]["bits"]
         # Loop over register arguments, if any.
         maxidx = max(map(len, bits))
         for idx in range(maxidx):
             self.arg_stack.append(
                 {gargs[j]: args[j]
                  for j in range(len(gargs))})
             # Only index into register arguments.
             element = [
                 idx * x
                 for x in [len(bits[j]) > 1 for j in range(len(bits))]
             ]
             self.bit_stack.append(
                 {gbits[j]: bits[j][element[j]]
                  for j in range(len(gbits))})
             self._create_dag_op(
                 name, [self.arg_stack[-1][s].sym() for s in gargs],
                 [self.bit_stack[-1][s] for s in gbits])
             self.arg_stack.pop()
             self.bit_stack.pop()
     else:
         raise ReNomQError("internal error undefined gate:",
                           "line=%s" % node.line, "file=%s" % node.file)
Пример #23
0
 def check_circuit(self):
     """Raise exception if self.circuit is None."""
     if self.circuit is None:
         raise ReNomQError("Instruction's circuit not assigned")
Пример #24
0
 def q_if(self, *qregs):
     """Add controls to this gate."""
     # pylint: disable=unused-argument
     raise ReNomQError("control not implemented")
Пример #25
0
    def _process_node(self, node):
        """Carry out the action associated with a node."""
        if node.type == "program":
            self._process_children(node)

        elif node.type == "qreg":
            qreg = QuantumRegister(node.index, node.name)
            self.dag.add_qreg(qreg)

        elif node.type == "creg":
            creg = ClassicalRegister(node.index, node.name)
            self.dag.add_creg(creg)

        elif node.type == "id":
            raise ReNomQError("internal error: _process_node on id")

        elif node.type == "int":
            raise ReNomQError("internal error: _process_node on int")

        elif node.type == "real":
            raise ReNomQError("internal error: _process_node on real")

        elif node.type == "indexed_id":
            raise ReNomQError("internal error: _process_node on indexed_id")

        elif node.type == "id_list":
            # We process id_list nodes when they are leaves of barriers.
            return [
                self._process_bit_id(node_children)
                for node_children in node.children
            ]

        elif node.type == "primary_list":
            # We should only be called for a barrier.
            return [self._process_bit_id(m) for m in node.children]

        elif node.type == "gate":
            self._process_gate(node)

        elif node.type == "custom_unitary":
            self._process_custom_unitary(node)

        elif node.type == "universal_unitary":
            args = self._process_node(node.children[0])
            qid = self._process_bit_id(node.children[1])
            for element in qid:
                self.dag.apply_operation_back(UBase(*args, element),
                                              self.condition)

        elif node.type == "cnot":
            self._process_cnot(node)

        elif node.type == "expression_list":
            return node.children

        elif node.type == "binop":
            raise ReNomQError("internal error: _process_node on binop")

        elif node.type == "prefix":
            raise ReNomQError("internal error: _process_node on prefix")

        elif node.type == "measure":
            self._process_measure(node)

        elif node.type == "format":
            self.version = node.version()

        elif node.type == "barrier":
            ids = self._process_node(node.children[0])
            qubits = []
            for qubit in ids:
                for j, _ in enumerate(qubit):
                    qubits.append(qubit[j])
            self.dag.apply_operation_back(Barrier(qubits))

        elif node.type == "reset":
            id0 = self._process_bit_id(node.children[0])
            for i, _ in enumerate(id0):
                self.dag.apply_operation_back(Reset(id0[i]), self.condition)

        elif node.type == "if":
            self._process_if(node)

        elif node.type == "opaque":
            self._process_gate(node, opaque=True)

        elif node.type == "external":
            raise ReNomQError("internal error: _process_node on external")

        else:
            raise ReNomQError("internal error: undefined node type", node.type,
                              "line=%s" % node.line, "file=%s" % node.file)
        return None
Пример #26
0
 def add(self, gate):
     """Add instruction to set."""
     if not isinstance(gate, Instruction):
         raise ReNomQError("attempt to add non-Instruction" +
                           " to InstructionSet")
     self.instructions.append(gate)
Пример #27
0
 def inverse(self):
     """Invert this gate."""
     raise ReNomQError("inverse not implemented")
Пример #28
0
    def _create_dag_op(self, name, params, qargs):
        """
        Create a DAG node out of a parsed AST op node.

        Args:
            name (str): operation name to apply to the dag.
            params (list): op parameters
            qargs (list(QuantumRegister, int)): qubits to attach to

        Raises:
            ReNomQError: if encountering a non-basis opaque gate
        """
        if name == "u0":
            op_class = U0Gate
        elif name == "u1":
            op_class = U1Gate
        elif name == "u2":
            op_class = U2Gate
        elif name == "u3":
            op_class = U3Gate
        elif name == "x":
            op_class = XGate
        elif name == "y":
            op_class = YGate
        elif name == "z":
            op_class = ZGate
        elif name == "t":
            op_class = TGate
        elif name == "tdg":
            op_class = TdgGate
        elif name == "s":
            op_class = SGate
        elif name == "sdg":
            op_class = SdgGate
        elif name == "swap":
            op_class = SwapGate
        elif name == "rx":
            op_class = RXGate
        elif name == "ry":
            op_class = RYGate
        elif name == "rz":
            op_class = RZGate
        elif name == "rzz":
            op_class = RZZGate
        elif name == "id":
            op_class = IdGate
        elif name == "h":
            op_class = HGate
        elif name == "cx":
            op_class = CnotGate
        elif name == "cy":
            op_class = CyGate
        elif name == "cz":
            op_class = CzGate
        elif name == "ch":
            op_class = CHGate
        elif name == "crz":
            op_class = CrzGate
        elif name == "cu1":
            op_class = Cu1Gate
        elif name == "cu3":
            op_class = Cu3Gate
        elif name == "ccx":
            op_class = ToffoliGate
        elif name == "cswap":
            op_class = FredkinGate
        else:
            raise ReNomQError("unknown operation for ast node name %s" % name)

        op = op_class(*params, *qargs)

        self.dag.add_basis_element(name, len(qargs), 0, len(params))
        self.dag.apply_operation_back(op, condition=self.condition)