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)
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)