Ejemplo n.º 1
0
    def exitGate(self, ctx: QuilParser.GateContext):
        gate_name = ctx.name().getText()
        params = list(map(_param, ctx.param()))
        qubits = list(map(_qubit, ctx.qubit()))
        # The Gate.controlled() method *prepends* the CONTROLLED modifier to the gate. But the
        # parser works from the outside-in. Therefore the controlled qubits would be in reverse
        # order. We reverse here to fix that.
        modifiers = [mod.getText() for mod in ctx.modifier()][::-1]
        control_qubits = qubits[0:len(list(filter(lambda str: str == "CONTROLLED", modifiers)))][::-1]
        target_qubits = qubits[len(control_qubits):]

        if gate_name in QUANTUM_GATES:
            if params:
                gate = QUANTUM_GATES[gate_name](*params, *target_qubits)
            else:
                gate = QUANTUM_GATES[gate_name](*target_qubits)
        else:
            gate = Gate(gate_name, params, target_qubits)

        for modifier in modifiers:
            if modifier == "CONTROLLED":
                gate.controlled(control_qubits.pop(0))
            elif modifier == "DAGGER":
                gate.dagger()
            else:
                raise ValueError(f"Unsupported gate modifier {modifier}.")

        self.result.append(gate)
Ejemplo n.º 2
0
    def exitGate(self, ctx: QuilParser.GateContext):
        gate_name = ctx.name().getText()
        modifiers = [mod.getText() for mod in ctx.modifier()]
        params = list(map(_param, ctx.param()))
        qubits = list(map(_qubit, ctx.qubit()))

        # The parsed string 'DAGGER CONTROLLED X 0 1' gives
        #   modifiers ['DAGGER', 'CONTROLLED']
        #   qubits    ['0', '1']
        #
        # We will build such gates by applying modifiers from right to left,
        # e.g. X 1 -> CONTROLLED X 0 1 -> DAGGER CONTROLLED X 0 1

        # Some gate modifiers increase the arity of the base gate.
        # The new qubit arguments prefix the old ones.
        modifier_qubits = []
        for m in modifiers:
            if m in ["CONTROLLED", "FORKED"]:
                modifier_qubits.append(qubits[len(modifier_qubits)])

        base_qubits = qubits[len(modifier_qubits):]

        # Each FORKED doubles the number of parameters,
        # e.g. FORKED RX(0.5, 1.5) 0 1 has two.
        forked_offset = len(params) >> modifiers.count("FORKED")
        base_params = params[:forked_offset]

        if gate_name in QUANTUM_GATES:
            if base_params:
                gate = QUANTUM_GATES[gate_name](*base_params, *base_qubits)
            else:
                gate = QUANTUM_GATES[gate_name](*base_qubits)
        else:
            gate = Gate(gate_name, base_params, base_qubits)

        # Track the last param used (for FORKED)
        for modifier in modifiers[::-1]:
            if modifier == "CONTROLLED":
                gate.controlled(modifier_qubits.pop())
            elif modifier == "DAGGER":
                gate.dagger()
            elif modifier == 'FORKED':
                gate.forked(modifier_qubits.pop(),
                            params[forked_offset:(2 * forked_offset)])
                forked_offset *= 2
            else:
                raise ValueError(f"Unsupported gate modifier {modifier}.")

        self.result.append(gate)