def _decompose_QAA(cmd): """ Decompose the Quantum Amplitude Apmplification algorithm as a gate. """ eng = cmd.engine # System-qubit is the first qubit/qureg. Ancilla qubit is the second qubit system_qubits = cmd.qubits[0] qaa_ancilla = cmd.qubits[1] # The Oracle and the Algorithm Oracle = cmd.gate.oracle A = cmd.gate.algorithm # Apply the oracle to invert the amplitude of the good states, S_Chi Oracle(eng, system_qubits, qaa_ancilla) # Apply the inversion of the Algorithm, # the inversion of the aplitude of |0> and the Algorithm with Compute(eng): with Dagger(eng): A(eng, system_qubits) All(X) | system_qubits with Control(eng, system_qubits[0:-1]): Z | system_qubits[-1] with CustomUncompute(eng): All(X) | system_qubits A(eng, system_qubits) Ph(math.pi) | system_qubits[0]
def add_constant_modN(eng, c, N, quint): """ Adds a classical constant c to a quantum integer (qureg) quint modulo N using Draper addition and the construction from https://arxiv.org/abs/quant-ph/0205095. """ assert (c < N and c >= 0) AddConstant(c) | quint with Compute(eng): SubConstant(N) | quint ancilla = eng.allocate_qubit() CNOT | (quint[-1], ancilla) with Control(eng, ancilla): AddConstant(N) | quint SubConstant(c) | quint with CustomUncompute(eng): X | quint[-1] CNOT | (quint[-1], ancilla) X | quint[-1] del ancilla AddConstant(c) | quint
def add_constant_modN(eng, constant, N, quint): # pylint: disable=invalid-name """ Add a classical constant c to a quantum integer (qureg) quint modulo N using Draper addition. This function uses Draper addition and the construction from https://arxiv.org/abs/quant-ph/0205095. """ if constant < 0 or constant > N: raise ValueError('Pre-condition failed: 0 <= constant < N') AddConstant(constant) | quint with Compute(eng): SubConstant(N) | quint ancilla = eng.allocate_qubit() CNOT | (quint[-1], ancilla) with Control(eng, ancilla): AddConstant(N) | quint SubConstant(constant) | quint with CustomUncompute(eng): X | quint[-1] CNOT | (quint[-1], ancilla) X | quint[-1] del ancilla AddConstant(constant) | quint
def _decompose_ucr(cmd, gate_class): """ Decomposition for an uniformly controlled single qubit rotation gate. Follows decomposition in arXiv:quant-ph/0407010 section II and arXiv:quant-ph/0410066v2 Fig. 9a. For Ry and Rz it uses 2**len(ucontrol_qubits) CNOT and also 2**len(ucontrol_qubits) single qubit rotations. Args: cmd: CommandObject to decompose. gate_class: Ry or Rz """ eng = cmd.engine with Control(eng, cmd.control_qubits): if not (len(cmd.qubits) == 2 and len(cmd.qubits[1]) == 1): raise TypeError("Wrong number of qubits ") ucontrol_qubits = cmd.qubits[0] target_qubit = cmd.qubits[1] if not len(cmd.gate.angles) == 2**len(ucontrol_qubits): raise ValueError("Wrong len(angles).") if len(ucontrol_qubits) == 0: gate_class(cmd.gate.angles[0]) | target_qubit return angles1 = [] angles2 = [] for lower_bits in range(2**(len(ucontrol_qubits) - 1)): leading_0 = cmd.gate.angles[lower_bits] leading_1 = cmd.gate.angles[lower_bits + 2**(len(ucontrol_qubits) - 1)] angles1.append((leading_0 + leading_1) / 2.0) angles2.append((leading_0 - leading_1) / 2.0) rightmost_cnot = {} for i in range(len(ucontrol_qubits) + 1): rightmost_cnot[i] = True _apply_ucr_n( angles=angles1, ucontrol_qubits=ucontrol_qubits[:-1], target_qubit=target_qubit, eng=eng, gate_class=gate_class, rightmost_cnot=rightmost_cnot, ) # Very custom usage of Compute/CustomUncompute in the following. with Compute(cmd.engine): CNOT | (ucontrol_qubits[-1], target_qubit) _apply_ucr_n( angles=angles2, ucontrol_qubits=ucontrol_qubits[:-1], target_qubit=target_qubit, eng=eng, gate_class=gate_class, rightmost_cnot=rightmost_cnot, ) with CustomUncompute(eng): CNOT | (ucontrol_qubits[-1], target_qubit)
def _apply_ucr_n(angles, ucontrol_qubits, target_qubit, eng, gate_class, rightmost_cnot): # pylint: disable=too-many-arguments if len(ucontrol_qubits) == 0: gate = gate_class(angles[0]) if gate != gate_class(0): gate | target_qubit else: if rightmost_cnot[len(ucontrol_qubits)]: angles1 = [] angles2 = [] for lower_bits in range(2**(len(ucontrol_qubits) - 1)): leading_0 = angles[lower_bits] leading_1 = angles[lower_bits + 2**(len(ucontrol_qubits) - 1)] angles1.append((leading_0 + leading_1) / 2.0) angles2.append((leading_0 - leading_1) / 2.0) else: angles1 = [] angles2 = [] for lower_bits in range(2**(len(ucontrol_qubits) - 1)): leading_0 = angles[lower_bits] leading_1 = angles[lower_bits + 2**(len(ucontrol_qubits) - 1)] angles1.append((leading_0 - leading_1) / 2.0) angles2.append((leading_0 + leading_1) / 2.0) _apply_ucr_n( angles=angles1, ucontrol_qubits=ucontrol_qubits[:-1], target_qubit=target_qubit, eng=eng, gate_class=gate_class, rightmost_cnot=rightmost_cnot, ) # Very custom usage of Compute/CustomUncompute in the following. if rightmost_cnot[len(ucontrol_qubits)]: with Compute(eng): CNOT | (ucontrol_qubits[-1], target_qubit) else: with CustomUncompute(eng): CNOT | (ucontrol_qubits[-1], target_qubit) _apply_ucr_n( angles=angles2, ucontrol_qubits=ucontrol_qubits[:-1], target_qubit=target_qubit, eng=eng, gate_class=gate_class, rightmost_cnot=rightmost_cnot, ) # Next iteration on this level do the other cnot placement rightmost_cnot[len( ucontrol_qubits)] = not rightmost_cnot[len(ucontrol_qubits)]