예제 #1
0
def test_from_braket_non_parameterized_two_qubit_gates():
    braket_circuit = BKCircuit()
    instructions = [
        Instruction(braket_gates.CNot(), target=[2, 3]),
        Instruction(braket_gates.Swap(), target=[3, 4]),
        Instruction(braket_gates.ISwap(), target=[2, 3]),
        Instruction(braket_gates.CZ(), target=(3, 4)),
        Instruction(braket_gates.CY(), target=(2, 3)),
    ]
    for instr in instructions:
        braket_circuit.add_instruction(instr)
    cirq_circuit = from_braket(braket_circuit)

    qreg = LineQubit.range(2, 5)
    expected_cirq_circuit = Circuit(
        ops.CNOT(*qreg[:2]),
        ops.SWAP(*qreg[1:]),
        ops.ISWAP(*qreg[:2]),
        ops.CZ(*qreg[1:]),
        ops.ControlledGate(ops.Y).on(*qreg[:2]),
    )
    assert np.allclose(
        protocols.unitary(cirq_circuit),
        protocols.unitary(expected_cirq_circuit),
    )
예제 #2
0
def _rx_ry_rz(cmd, mapping, qubits):
    """
    Translate a rotation gate into a Cirq roation (phase) gate.

    Global phase difference betwee proejctq rotation gate and cirq phase gate
    is dropped.

    Args:
        cmd (:class:`projectq.ops.Command`): a projectq command instance
        mapping (:class:`dict`): a dictionary of qubit mappings
        qubits (list of :class:cirq.QubitID`): cirq qubits

    Returns:
        :class:`cirq.Operation`
    """
    gates = {pqo.Rx: cop.XPowGate, pqo.Ry: cop.YPowGate, pqo.Rz: cop.ZPowGate}
    qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr]
    assert len(qb_pos) == 1
    cirqGate = gates[type(cmd.gate)](half_turns=cmd.gate.angle / cmath.pi)
    if get_control_count(cmd) > 0:
        ctrl_pos = [mapping[qb.id] for qb in cmd.control_qubits]
        return cop.ControlledGate(cirqGate)(
            *[qubits[c] for c in ctrl_pos + qb_pos])
    else:
        return cirqGate(*[qubits[idx] for idx in qb_pos])
def _expZGate(cmd, mapping, qubits):
    """
    Translate a ExpZ gate into a Cirq gate.

    Args:
        - cmd (:class:`projectq.ops.Command`) - a projectq command instance
        - mapping (:class:`dict`) - a dictionary of qubit mappings
        - qubits (list of :class:cirq.QubitID`) - cirq qubits

    Returns:
        - :class:`cirq.Operation`
    """
    qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr]
    assert len(qb_pos) == 1
    cirqGate = cxmon.ExpZGate(half_turns=cmd.gate.angle / cmath.pi)
    if get_control_count(cmd) > 0:
        ctrl_pos = [mapping[qb.id] for qb in cmd.control_qubits]
        return cop.ControlledGate(cirqGate)(
            *[qubits[c] for c in ctrl_pos + qb_pos])
    else:
        return cirqGate(*[qubits[idx] for idx in qb_pos])
예제 #4
0
def _h_s_gate(cmd, mapping, qubits):
    """
    Translate a Hadamard or S-gate into a Cirq gate.

    Args:
        cmd (:class:`projectq.ops.Command`): a projectq command instance
        mapping (:class:`dict`): a dictionary of qubit mappings
        qubits (list of :class:cirq.QubitID`): cirq qubits

    Returns:
        :class:`cirq.Operation`
    """
    gates = {pqo.HGate: cop.H, pqo.SGate: cop.S}
    qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr]
    assert len(qb_pos) == 1
    cirqGate = gates[type(cmd.gate)]
    if get_control_count(cmd) > 0:
        ctrl_pos = [mapping[qb.id] for qb in cmd.control_qubits]
        return cop.ControlledGate(cirqGate)(
            *[qubits[c] for c in ctrl_pos + qb_pos])
    else:
        return cirqGate(*[qubits[idx] for idx in qb_pos])
예제 #5
0
def _gates_with_known_matrix(cmd, mapping, qubits):
    """
    Translate a single qubit gate with known matrix into a Cirq gate.

    Args:
        cmd (:class:`projectq.ops.Command`): a projectq command instance
        mapping (:class:`dict`): a dictionary of qubit mappings
        qubits (list of :class:cirq.QubitID`): cirq qubits

    Returns:
        :class:`cirq.Operation`
    """
    gate = cmd.gate
    if len(get_control_count(cmd)) == 0 and hasattr(gate, 'matrix'):
            qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr]
            return cop.matrix_gates.SingleQubitMatrixGate(matrix=gate.matrix)(
                    *[qubits[q] for q in qb_pos])
    elif len(get_control_count(cmd)) > 0 and hasattr(gate, 'matrix'):
        qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr]
        ctrl_pos = [mapping[qb.id] for qb in cmd.control_qubits]
        cirqGate = cop.matrix_gates.SingleQubitMatrixGate(matrix=gate.matrix)
        return cop.ControlledGate(cirqGate)(*[qubits[q] for q in qb_pos+ctrl_pos])
예제 #6
0
class QasmParser:
    """Parser for QASM strings.

    Example:

        qasm = "OPENQASM 2.0; qreg q1[2]; CX q1[0], q1[1];"
        parsedQasm = QasmParser().parse(qasm)
    """
    def __init__(self):
        self.parser = yacc.yacc(module=self, debug=False, write_tables=False)
        self.circuit = Circuit()
        self.qregs: Dict[str, int] = {}
        self.cregs: Dict[str, int] = {}
        self.qelibinc = False
        self.lexer = QasmLexer()
        self.supported_format = False
        self.parsedQasm: Optional[Qasm] = None
        self.qubits: Dict[str, ops.Qid] = {}
        self.functions = {
            'sin': np.sin,
            'cos': np.cos,
            'tan': np.tan,
            'exp': np.exp,
            'ln': np.log,
            'sqrt': np.sqrt,
            'acos': np.arccos,
            'atan': np.arctan,
            'asin': np.arcsin,
        }

        self.binary_operators = {
            '+': operator.add,
            '-': operator.sub,
            '*': operator.mul,
            '/': operator.truediv,
            '^': operator.pow,
        }

    basic_gates: Dict[str, QasmGateStatement] = {
        'CX':
        QasmGateStatement(qasm_gate='CX',
                          cirq_gate=CX,
                          num_params=0,
                          num_args=2),
        'U':
        QasmGateStatement(
            qasm_gate='U',
            num_params=3,
            num_args=1,
            # QasmUGate expects half turns
            cirq_gate=(lambda params: QasmUGate(*[p / np.pi for p in params])),
        ),
    }

    qelib_gates = {
        'rx':
        QasmGateStatement(qasm_gate='rx',
                          cirq_gate=(lambda params: ops.rx(params[0])),
                          num_params=1,
                          num_args=1),
        'ry':
        QasmGateStatement(qasm_gate='ry',
                          cirq_gate=(lambda params: ops.ry(params[0])),
                          num_params=1,
                          num_args=1),
        'rz':
        QasmGateStatement(qasm_gate='rz',
                          cirq_gate=(lambda params: ops.rz(params[0])),
                          num_params=1,
                          num_args=1),
        'id':
        QasmGateStatement(qasm_gate='id',
                          cirq_gate=ops.IdentityGate(1),
                          num_params=0,
                          num_args=1),
        'u1':
        QasmGateStatement(
            qasm_gate='u1',
            cirq_gate=(lambda params: QasmUGate(0, 0, params[0] / np.pi)),
            num_params=1,
            num_args=1,
        ),
        'u2':
        QasmGateStatement(
            qasm_gate='u2',
            cirq_gate=(lambda params: QasmUGate(0.5, params[0] / np.pi, params[
                1] / np.pi)),
            num_params=2,
            num_args=1,
        ),
        'u3':
        QasmGateStatement(
            qasm_gate='u3',
            num_params=3,
            num_args=1,
            cirq_gate=(lambda params: QasmUGate(*[p / np.pi for p in params])),
        ),
        'x':
        QasmGateStatement(qasm_gate='x',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.X),
        'y':
        QasmGateStatement(qasm_gate='y',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.Y),
        'z':
        QasmGateStatement(qasm_gate='z',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.Z),
        'h':
        QasmGateStatement(qasm_gate='h',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.H),
        's':
        QasmGateStatement(qasm_gate='s',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.S),
        't':
        QasmGateStatement(qasm_gate='t',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.T),
        'cx':
        QasmGateStatement(qasm_gate='cx',
                          cirq_gate=CX,
                          num_params=0,
                          num_args=2),
        'cy':
        QasmGateStatement(qasm_gate='cy',
                          cirq_gate=ops.ControlledGate(ops.Y),
                          num_params=0,
                          num_args=2),
        'cz':
        QasmGateStatement(qasm_gate='cz',
                          cirq_gate=ops.CZ,
                          num_params=0,
                          num_args=2),
        'ch':
        QasmGateStatement(qasm_gate='ch',
                          cirq_gate=ops.ControlledGate(ops.H),
                          num_params=0,
                          num_args=2),
        'swap':
        QasmGateStatement(qasm_gate='swap',
                          cirq_gate=ops.SWAP,
                          num_params=0,
                          num_args=2),
        'cswap':
        QasmGateStatement(qasm_gate='cswap',
                          num_params=0,
                          num_args=3,
                          cirq_gate=ops.CSWAP),
        'ccx':
        QasmGateStatement(qasm_gate='ccx',
                          num_params=0,
                          num_args=3,
                          cirq_gate=ops.CCX),
        'sdg':
        QasmGateStatement(qasm_gate='sdg',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.S**-1),
        'tdg':
        QasmGateStatement(qasm_gate='tdg',
                          num_params=0,
                          num_args=1,
                          cirq_gate=ops.T**-1),
    }

    all_gates = {**basic_gates, **qelib_gates}

    tokens = QasmLexer.tokens
    start = 'start'

    precedence = (
        ('left', '+', '-'),
        ('left', '*', '/'),
        ('right', '^'),
    )

    def p_start(self, p):
        """start : qasm"""
        p[0] = p[1]

    def p_qasm_format_only(self, p):
        """qasm : format"""
        self.supported_format = True
        p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs,
                    self.cregs, self.circuit)

    def p_qasm_no_format_specified_error(self, p):
        """qasm : QELIBINC
        | circuit"""
        if self.supported_format is False:
            raise QasmException("Missing 'OPENQASM 2.0;' statement")

    def p_qasm_include(self, p):
        """qasm : qasm QELIBINC"""
        self.qelibinc = True
        p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs,
                    self.cregs, self.circuit)

    def p_qasm_circuit(self, p):
        """qasm : qasm circuit"""
        p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs,
                    self.cregs, p[2])

    def p_format(self, p):
        """format : FORMAT_SPEC"""
        if p[1] != "2.0":
            raise QasmException(
                "Unsupported OpenQASM version: {}, "
                "only 2.0 is supported currently by Cirq".format(p[1]))

    # circuit : new_reg circuit
    #         | gate_op circuit
    #         | measurement circuit
    #         | empty

    def p_circuit_reg(self, p):
        """circuit : new_reg circuit"""
        p[0] = self.circuit

    def p_circuit_gate_or_measurement(self, p):
        """circuit :  circuit gate_op
        |  circuit measurement"""
        self.circuit.append(p[2])
        p[0] = self.circuit

    def p_circuit_empty(self, p):
        """circuit : empty"""
        p[0] = self.circuit

    # qreg and creg

    def p_new_reg(self, p):
        """new_reg : QREG ID '[' NATURAL_NUMBER ']' ';'
        | CREG ID '[' NATURAL_NUMBER ']' ';'"""
        name, length = p[2], p[4]
        if name in self.qregs.keys() or name in self.cregs.keys():
            raise QasmException("{} is already defined at line {}".format(
                name, p.lineno(2)))
        if length == 0:
            raise QasmException(
                "Illegal, zero-length register '{}' at line {}".format(
                    name, p.lineno(4)))
        if p[1] == "qreg":
            self.qregs[name] = length
        else:
            self.cregs[name] = length
        p[0] = (name, length)

    # gate operations
    # gate_op : ID qargs
    #         | ID ( params ) qargs

    def p_gate_op_no_params(self, p):
        """gate_op :  ID qargs"""
        self._resolve_gate_operation(p[2], gate=p[1], p=p, params=[])

    def p_gate_op_with_params(self, p):
        """gate_op :  ID '(' params ')' qargs"""
        self._resolve_gate_operation(args=p[5], gate=p[1], p=p, params=p[3])

    def _resolve_gate_operation(self, args: List[List[ops.Qid]], gate: str,
                                p: Any, params: List[float]):
        gate_set = self.basic_gates if not self.qelibinc else self.all_gates
        if gate not in gate_set.keys():
            msg = 'Unknown gate "{}" at line {}{}'.format(
                gate,
                p.lineno(1),
                ", did you forget to include qelib1.inc?"
                if not self.qelibinc else "",
            )
            raise QasmException(msg)
        p[0] = gate_set[gate].on(args=args, params=params, lineno=p.lineno(1))

    # params : parameter ',' params
    #        | parameter

    def p_params_multiple(self, p):
        """params : expr ',' params"""
        p[3].insert(0, p[1])
        p[0] = p[3]

    def p_params_single(self, p):
        """params : expr """
        p[0] = [p[1]]

    # expr : term
    #            | func '(' expression ')' """
    #            | binary_op
    #            | unary_op

    def p_expr_term(self, p):
        """expr : term"""
        p[0] = p[1]

    def p_expr_parens(self, p):
        """expr : '(' expr ')'"""
        p[0] = p[2]

    def p_expr_function_call(self, p):
        """expr : ID '(' expr ')'"""
        func = p[1]
        if func not in self.functions.keys():
            raise QasmException(
                "Function not recognized: '{}' at line {}".format(
                    func, p.lineno(1)))
        p[0] = self.functions[func](p[3])

    def p_expr_unary(self, p):
        """expr : '-' expr
        | '+' expr"""
        if p[1] == '-':
            p[0] = -p[2]
        else:
            p[0] = p[2]

    def p_expr_binary(self, p):
        """expr : expr '*' expr
        | expr '/' expr
        | expr '+' expr
        | expr '-' expr
        | expr '^' expr
        """
        p[0] = self.binary_operators[p[2]](p[1], p[3])

    def p_term(self, p):
        """term : NUMBER
        | NATURAL_NUMBER
        | PI"""
        p[0] = p[1]

    # qargs : qarg ',' qargs
    #      | qarg ';'

    def p_args_multiple(self, p):
        """qargs : qarg ',' qargs"""
        p[3].insert(0, p[1])
        p[0] = p[3]

    def p_args_single(self, p):
        """qargs : qarg ';'"""
        p[0] = [p[1]]

    # qarg : ID
    #     | ID '[' NATURAL_NUMBER ']'

    def p_quantum_arg_register(self, p):
        """qarg : ID """
        reg = p[1]
        if reg not in self.qregs.keys():
            raise QasmException(
                'Undefined quantum register "{}" at line {}'.format(
                    reg, p.lineno(1)))
        qubits = []
        for idx in range(self.qregs[reg]):
            arg_name = self.make_name(idx, reg)
            if arg_name not in self.qubits.keys():
                self.qubits[arg_name] = NamedQubit(arg_name)
            qubits.append(self.qubits[arg_name])
        p[0] = qubits

    # carg : ID
    #     | ID '[' NATURAL_NUMBER ']'

    def p_classical_arg_register(self, p):
        """carg : ID """
        reg = p[1]
        if reg not in self.cregs.keys():
            raise QasmException(
                'Undefined classical register "{}" at line {}'.format(
                    reg, p.lineno(1)))

        p[0] = [self.make_name(idx, reg) for idx in range(self.cregs[reg])]

    def make_name(self, idx, reg):
        return str(reg) + "_" + str(idx)

    def p_quantum_arg_bit(self, p):
        """qarg : ID '[' NATURAL_NUMBER ']' """
        reg = p[1]
        idx = p[3]
        arg_name = self.make_name(idx, reg)
        if reg not in self.qregs.keys():
            raise QasmException(
                'Undefined quantum register "{}" at line {}'.format(
                    reg, p.lineno(1)))
        size = self.qregs[reg]
        if idx >= size:
            raise QasmException('Out of bounds qubit index {} '
                                'on register {} of size {} '
                                'at line {}'.format(idx, reg, size,
                                                    p.lineno(1)))
        if arg_name not in self.qubits.keys():
            self.qubits[arg_name] = NamedQubit(arg_name)
        p[0] = [self.qubits[arg_name]]

    def p_classical_arg_bit(self, p):
        """carg : ID '[' NATURAL_NUMBER ']' """
        reg = p[1]
        idx = p[3]
        arg_name = self.make_name(idx, reg)
        if reg not in self.cregs.keys():
            raise QasmException(
                'Undefined classical register "{}" at line {}'.format(
                    reg, p.lineno(1)))

        size = self.cregs[reg]
        if idx >= size:
            raise QasmException('Out of bounds bit index {} '
                                'on classical register {} of size {} '
                                'at line {}'.format(idx, reg, size,
                                                    p.lineno(1)))
        p[0] = [arg_name]

    # measurement operations
    # measurement : MEASURE qarg ARROW carg

    def p_measurement(self, p):
        """measurement : MEASURE qarg ARROW carg ';'"""
        qreg = p[2]
        creg = p[4]

        if len(qreg) != len(creg):
            raise QasmException(
                'mismatched register sizes {} -> {} for measurement '
                'at line {}'.format(len(qreg), len(creg), p.lineno(1)))

        p[0] = [
            ops.MeasurementGate(num_qubits=1, key=creg[i]).on(qreg[i])
            for i in range(len(qreg))
        ]

    def p_error(self, p):
        if p is None:
            raise QasmException('Unexpected end of file')

        raise QasmException("""Syntax error: '{}'
{}
at line {}, column {}""".format(p.value, self.debug_context(p), p.lineno,
                                self.find_column(p)))

    def find_column(self, p):
        line_start = self.qasm.rfind('\n', 0, p.lexpos) + 1
        return (p.lexpos - line_start) + 1

    def p_empty(self, p):
        """empty :"""

    def parse(self, qasm: str) -> Qasm:
        if self.parsedQasm is None:
            self.qasm = qasm
            self.lexer.input(self.qasm)
            self.parsedQasm = self.parser.parse(lexer=self.lexer)
        return self.parsedQasm

    def debug_context(self, p):
        debug_start = max(self.qasm.rfind('\n', 0, p.lexpos) + 1, p.lexpos - 5)
        debug_end = min(self.qasm.find('\n', p.lexpos, p.lexpos + 5),
                        p.lexpos + 5)

        return ("..." + self.qasm[debug_start:debug_end] + "\n" +
                (" " * (3 + p.lexpos - debug_start)) + "^")