def run_inv(a=11, b=1, param="simulation"): # build compilation engine list resource_counter = ResourceCounter() rule_set = DecompositionRuleSet(modules=[projectq.libs.math, projectq.setups.decompositions]) compilerengines = [AutoReplacer(rule_set), TagRemover(), LocalOptimizer(3), AutoReplacer(rule_set), TagRemover(), LocalOptimizer(3), resource_counter] # create a main compiler engine a1 = a b1 = b if a == 0: a1 = 1 if b == 0: b1 = 1 n = max(int(math.log(a1, 2)), int(math.log(b1, 2))) + 1 if param == "latex": drawing_engine = CircuitDrawer() eng2 = MainEngine(drawing_engine) xa = initialisation_n(eng2, a, n + 1) xb = initialisation_n(eng2, b, n + 1) # b --> phi(b) QFT | xb phi_adder(eng2, xa, xb) with Dagger(eng2): QFT | xb All(Measure) | xa All(Measure) | xb eng2.flush() print(drawing_engine.get_latex()) else: eng = MainEngine(Simulator(), compilerengines) xa = initialisation_n(eng, a, n + 1) xb = initialisation_n(eng, b, n + 1) # b --> phi(b) QFT | xb with Dagger(eng): phi_adder(eng, xa, xb) with Dagger(eng): QFT | xb All(Measure) | xa All(Measure) | xb eng.flush() n = n+1 measurements_a = [0] * n measurements_b = [0] * n for k in range(n): measurements_a[k] = int(xa[k]) measurements_b[k] = int(xb[k]) return [measurements_a, meas2int(measurements_b), measurements_b]
def ExecuteTeleport(eng, state_creation_function, verbose=False): b1, b2 = GetBellPair(eng) psi = eng.allocate_qubit() if verbose: print("Alice : state creation") state_creation_function(eng, psi) CNOT | (psi, b1) if verbose: print("Alice : entangled qubit") H | psi Measure | psi Measure | b1 messageToBob = [int(psi), int(b1)] if verbose: print("Alice : message {} : Bob.".format(messageToBob)) with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 if verbose: print("Bob is trying to uncompute the state.") with Dagger(eng): state_creation_function(eng, b2) del b2 eng.flush() if verbose: print("Bob successfully arrived at |0>")
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 adder(eng, xa, xb): # On passe de a a phi(a) : QTF """ n = xa.__len__() for i in range(n): N = n - i - 1 H | xa[N] for k in range(2, N + 2): with Control(eng, xa[N-k+1]): R((2*math.pi) / (1 << k)) | xa[N] """ QFT | xa eng.flush() inv_phi_adder(eng, xb, xa) eng.flush() """ # add b -> for i in range(n): N = n - i - 1 for k in range(1, N+2): with Control(eng, xb[N-k+1]): R((2*math.pi) / (1 << k)) | xa[N] """ with Dagger(eng): QFT | xa """
def lcu_oaa(eng, list_of_unitaries, coefts, ctrl, sys, ctrl_dim, sys_dim, rounds=1): phi = -1 * math.pi for i in range(0, rounds): cond_phase(eng, ctrl, sys, phi) with Dagger(eng): lcu_basic(eng, list_of_unitaries, coefts, ctrl, sys, ctrl_dim, sys_dim) size = pow(2, ctrl_dim) for l in range(1, size): # -R flips sign of everything except 00..0 temp = np.binary_repr(i) temp = temp.zfill(ctrl_dim) # pad with zeros for fixed length bin with Compute(eng): for j in range(0, ctrl_dim): if (int(temp[j]) == 0): X | ctrl[j] with Control(eng, ctrl): Ph(phi) | sys[0] # flip sign using any one sys qubit Uncompute(eng) lcu_basic(eng, list_of_unitaries, coefts, ctrl, sys, ctrl_dim, sys_dim) print("Amplitudes of ctrl+sys state after {} rounds of OAA:\n".format( int(i) + 1)) print_amplitudes(eng, ctrl + sys, ctrl_dim + sys_dim)
def run_decompose(a=11, param = "draw"): if param == "draw": drawing_engine = CircuitDrawer() eng = MainEngine(drawing_engine) else: eng = MainEngine() [La, n] = int2bit(a) xa = eng.allocate_qureg(n) # initialisation de a et b for i in range(n): if La[i]: X | xa[i] # On passe de a a phi(a) : QTF eng.flush() qft_decompose(eng, xa) eng.flush() with Dagger(eng): qft_decompose(eng, xa) if param != "draw": amp_xa = [] for i in range(1 << n): phase_reel = phase(eng.backend.get_amplitude(adapt_binary(bin(i), n), xa)) / (2 * math.pi) amp_xa.append(Fraction(phase_reel).limit_denominator(10)) print(amp_xa) All(Measure) | xa eng.flush() if param == "draw": print(drawing_engine.get_latex())
def _decompose_state_preparation(cmd): # pylint: disable=too-many-locals """Implement state preparation based on arXiv:quant-ph/0407010v1.""" eng = cmd.engine if len(cmd.qubits) != 1: raise ValueError( 'StatePreparation does not support multiple quantum registers!') num_qubits = len(cmd.qubits[0]) qureg = cmd.qubits[0] final_state = cmd.gate.final_state if len(final_state) != 2**num_qubits: raise ValueError("Length of final_state is invalid.") norm = 0.0 for amplitude in final_state: norm += abs(amplitude)**2 if norm < 1 - 1e-10 or norm > 1 + 1e-10: raise ValueError("final_state is not normalized.") with Control(eng, cmd.control_qubits): # As in the paper reference, we implement the inverse: with Dagger(eng): # Cancel all the relative phases phase_of_blocks = [] for amplitude in final_state: phase_of_blocks.append(cmath.phase(amplitude)) for qubit_idx, qubit in enumerate(qureg): angles = [] phase_of_next_blocks = [] for block in range(2**(len(qureg) - qubit_idx - 1)): phase0 = phase_of_blocks[2 * block] phase1 = phase_of_blocks[2 * block + 1] angles.append(phase0 - phase1) phase_of_next_blocks.append((phase0 + phase1) / 2.0) UniformlyControlledRz(angles) | ( qureg[(qubit_idx + 1):], # noqa: E203 qubit, ) phase_of_blocks = phase_of_next_blocks # Cancel global phase Ph(-phase_of_blocks[0]) | qureg[-1] # Remove amplitudes from states which contain a bit value 1: abs_of_blocks = [] for amplitude in final_state: abs_of_blocks.append(abs(amplitude)) for qubit_idx, qubit in enumerate(qureg): angles = [] abs_of_next_blocks = [] for block in range(2**(len(qureg) - qubit_idx - 1)): a0 = abs_of_blocks[2 * block] # pylint: disable=invalid-name a1 = abs_of_blocks[2 * block + 1] # pylint: disable=invalid-name if a0 == 0 and a1 == 0: angles.append(0) else: angles.append(-2.0 * math.acos(a0 / math.sqrt(a0**2 + a1**2))) abs_of_next_blocks.append(math.sqrt(a0**2 + a1**2)) UniformlyControlledRy(angles) | ( qureg[(qubit_idx + 1):], # noqa: E203 qubit, ) abs_of_blocks = abs_of_next_blocks
def run_teleport(eng, state_creation_function, verbose=False): """ Runs quantum teleportation on the provided main compiler engine. Creates a state from |0> using the state_creation_function, teleports this state to Bob who then tries to uncompute his qubit using the inverse of the state_creation_function. If successful, deleting the qubit won't raise an error in the underlying Simulator back-end (else it will). Args: eng (MainEngine): Main compiler engine to run the circuit on. state_creation_function (function): Function which accepts the main engine and a qubit in state |0>, which it then transforms to the state that Alice would like to send to Bob. verbose (bool): If True, info messages will be printed. """ # make a Bell-pair b1, b2 = create_bell_pair(eng) # Alice creates a nice state to send psi = eng.allocate_qubit() if verbose: print("Alice is creating her state from scratch, i.e., |0>.") state_creation_function(eng, psi) # entangle it with Alice's b1 CNOT | (psi, b1) if verbose: print("Alice entangled her qubit with her share of the Bell-pair.") # measure two values (once in Hadamard basis) and send the bits to Bob H | psi Measure | psi Measure | b1 msg_to_bob = [int(psi), int(b1)] if verbose: print("Alice is sending the message {} to Bob.".format(msg_to_bob)) # Bob may have to apply up to two operation depending on the message sent # by Alice: with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 # try to uncompute the psi state if verbose: print("Bob is trying to uncompute the state.") with Dagger(eng): state_creation_function(eng, b2) # check whether the uncompute was successful. The simulator only allows to # delete qubits which are in a computational basis state. del b2 eng.flush() if verbose: print("Bob successfully arrived at |0>")
def CMultModN(eng, circuit, c, x, qubits, ancilla, a, N): n = len(x) _CMultModN(eng, circuit, c, x, qubits, ancilla, a, N) for i in range(n): Swap(eng, circuit, x[i], qubits[i]) # All(Swap) | zip(x, qubits) with Dagger(eng): _CMultModN(eng, circuit, c, x, qubits, ancilla, modinv(a, N), N)
def CMultModN(eng, circuit, c, x, qubits, ancilla, a, N): n = len(x) _CMultModN(eng, circuit, c, x, qubits, ancilla, a, N) for i in range(n): circuit.apply_ld_two_qubit_gate(Swap, x[i], qubits[i]) # All(Swap) | zip(x, qubits) with Dagger(eng): _CMultModN(eng, circuit, c, x, qubits, ancilla, modinv(a, N), N)
def add_inverse(eng, qubits, value): """ The inverse adder gate, which effectively performs a subtraction of the classical value. :param eng: The engine used for computations. :param qubits: The qubits representing the quantum value (superposition of classical values). :param value: The classical value which should be subtracted. """ with Dagger(eng): add(eng, qubits, value)
def adder(eng, xa, xb): # On passe de a a phi(a) : QTF QFT | xa phi_adder(eng, xb, xa) # On passe de phi(a+b) à a+b QFT^-1 with Dagger(eng): QFT | xa
def _decompose_state_preparation(cmd): """ Implements state preparation based on arXiv:quant-ph/0407010v1. """ eng = cmd.engine assert len(cmd.qubits) == 1 num_qubits = len(cmd.qubits[0]) qureg = cmd.qubits[0] final_state = cmd.gate.final_state if len(final_state) != 2**num_qubits: raise ValueError("Length of final_state is invalid.") norm = 0. for amplitude in final_state: norm += abs(amplitude)**2 if norm < 1 - 1e-10 or norm > 1 + 1e-10: raise ValueError("final_state is not normalized.") with Control(eng, cmd.control_qubits): # As in the paper reference, we implement the inverse: with Dagger(eng): # Cancel all the relative phases phase_of_blocks = [] for amplitude in final_state: phase_of_blocks.append(cmath.phase(amplitude)) for target_qubit in range(len(qureg)): angles = [] phase_of_next_blocks = [] for block in range(2**(len(qureg) - target_qubit - 1)): phase0 = phase_of_blocks[2 * block] phase1 = phase_of_blocks[2 * block + 1] angles.append(phase0 - phase1) phase_of_next_blocks.append((phase0 + phase1) / 2.) UniformlyControlledRz(angles) | (qureg[(target_qubit + 1):], qureg[target_qubit]) phase_of_blocks = phase_of_next_blocks # Cancel global phase Ph(-phase_of_blocks[0]) | qureg[-1] # Remove amplitudes from states which contain a bit value 1: abs_of_blocks = [] for amplitude in final_state: abs_of_blocks.append(abs(amplitude)) for target_qubit in range(len(qureg)): angles = [] abs_of_next_blocks = [] for block in range(2**(len(qureg) - target_qubit - 1)): a0 = abs_of_blocks[2 * block] a1 = abs_of_blocks[2 * block + 1] if a0 == 0 and a1 == 0: angles.append(0) else: angles.append(-2. * math.acos(a0 / math.sqrt(a0**2 + a1**2))) abs_of_next_blocks.append(math.sqrt(a0**2 + a1**2)) UniformlyControlledRy(angles) | (qureg[(target_qubit + 1):], qureg[target_qubit]) abs_of_blocks = abs_of_next_blocks
def Cadd_inverse(eng, c, qubits, value): """ Similar to the inverse adder gate, which effectively performs a subtraction of the classical value. However, this gate is controlled by a qubit c. :param eng: The engine used for computations. :param c: The qubit control of the gate. :param qubits: The qubits representing the quantum value (superposition of classical values). :param value: The classical value which should be subtracted. """ with Dagger(eng): Cadd(eng, c, qubits, value)
def run_iqft_with_waveform_samples(self, number_of_qubits, sample_rate, correct_frequency, prep_function, prep_args): """ Tests my QFT implementation by comparing it to the classical DFT, ensuring it produces the same output as DFT when given the same input (after being normalized for quantum operations). Parameters: number_of_qubits (int): The size of the processing register to use, in qubits. This will be used to represent 2^N samples of the input signal. sample_rate (float): The sampling rate used by the prep opration. This is used to determine the actual frequency of the measured value once QFT is finished, which can vary based on the number of samples and the sample rate. correct_frequency (double): The correct answer that QFT should provide after running on the prepared input state. prep_function (function): The function that prepares the qubit register in the desired state for this test. prep_args (anything): Arguments to pass to the preparation function. """ engine = MainEngine() qubits = engine.allocate_qureg(number_of_qubits) # Set up the register so it's in the correct state for the test if prep_args is None: prep_function(qubits) else: prep_function(qubits, prep_args) # Run the inverse QFT, which corresponds to the normal DFT with Dagger(engine): qft.qft(qubits) # Measure the result from QFT bitstring = "" for qubit in qubits: Measure | qubit bitstring += str(int(qubit)) result = int(bitstring, 2) # QFT suffers from the same Nyquist-frequency mirroring as DFT, but we can't just # look at all of the output details and ignore the mirrored results. If we end up # measuring a mirrored result, this will flip it back to the proper result in the # 0 < X < N/2 space. number_of_states = 2 ** number_of_qubits if result > number_of_states / 2: result = number_of_states - result # Correct for the sample rate. total_time = number_of_states / sample_rate result = result / total_time # Verify we got the right result. if result != correct_frequency: raise ValueError(f"Expected frequency {correct_frequency} but measured {result}.")
def test_quantummultiplication_size_mismatch_inverse(eng, qubit_idx): qureg_a = eng.allocate_qureg(4 if qubit_idx != 0 else 3) qureg_b = eng.allocate_qureg(4 if qubit_idx != 1 else 3) qureg_c = eng.allocate_qureg(4 if qubit_idx != 2 else 3) with pytest.raises(ValueError): with Dagger(eng): MultiplyQuantum | (qureg_a, qureg_b, qureg_c) All(Measure) | qureg_a All(Measure) | qureg_b All(Measure) | qureg_c
def phase_flip_function(self, qubits): """ Flips the first of the provided qubits indirectly via entanglement. Parameters: qubits (Qureg): The qubit register being tested """ self.create_ghz_state(qubits) Z | qubits[1] with Dagger(qubits.engine): # This is how ProjectQ does adjoint code. self.create_ghz_state(qubits)
def test_quantum_conditional_add_carry_size_mismatch(eng, qubit_idx, inverse): qureg_a = eng.allocate_qureg(4 if qubit_idx != 0 else 3) qureg_b = eng.allocate_qureg(4 if qubit_idx != 1 else 3) qureg_c = eng.allocate_qureg(2 if qubit_idx != 2 else 3) control = eng.allocate_qureg(1 if qubit_idx != 3 else 2) with pytest.raises(ValueError): with Control(eng, control): if inverse: with Dagger(eng): AddQuantum | (qureg_a, qureg_b, qureg_c) else: AddQuantum | (qureg_a, qureg_b, qureg_c)
def run_test(self, description, iterations, prep_function): """ Runs a unit test of the teleportation protocol with the provided state preparation function. Parameters: description (str): A description of the test, for logging. iterations (int): The number of times to run the program. prep_function (function): The function that can prepare (and un-prepare) the desired state to be teleported. """ print(f"Running test: {description}") engine = MainEngine() original_qubit = engine.allocate_qubit() transfer_qubit = engine.allocate_qubit() reproduction_qubit = engine.allocate_qubit() # Try teleportation using all 4 of the Bell states for the entangled transfer qubit pair for entanglement_state in range(0, 4): for i in range(0, iterations): # Prepare the original qubit in the desired state, and the transfer qubits that will be used to teleport it prep_function(original_qubit) self.prepare_transfer_qubits(entanglement_state, transfer_qubit, reproduction_qubit) # Teleport the original qubit, turning the remote reproduction qubit's state into the original state (original_measurement, transfer_measurement) = self.measure_message_parameters(original_qubit, transfer_qubit) self.reproduce_original(entanglement_state, original_measurement, transfer_measurement, reproduction_qubit) # Run the adjoint preparation function on the reproduction qubit, and measure it. # If it is now in the original state, this should turn it back into |0> every time. with Dagger(engine): prep_function(reproduction_qubit) # Make sure the result qubit is 0 Measure | reproduction_qubit if int(reproduction_qubit) != 0: self.fail(f"Test {description} failed with entanglement state {entanglement_state}. " + f"Resulting state {result} had a 1 for the result, which means " + "the qubit wasn't teleported properly.") reset([original_qubit, transfer_qubit, reproduction_qubit]) engine.flush() print(f"Entanglement state {entanglement_state} passed."); print("Passed!") print()
def inv_cMultModN_non_Dagger(eng, a, xb, xx, xN, aux, xc, N): """ |b> --> |b+(ax) mod N> if xc=1; else |b> -> |b> :param eng: :param a: :param xc: control bit :param aux: auxiliary :param xx: multiplier :param xb: modified qubit :param xN: Mod :return: """ # b-->phi(b) QFT | xb n = len(xx) - 1 for i in range(n - 1, -1, -1): xa = initialisation_n(eng, ((2**i) * a) % N, n + 1) # both input of modularAdder must be <N # TODO define xa in a iterative way just by adding a new qubit 0 as LSB with Dagger(eng): modularAdder(eng, xa, xb, xN, xx[i], xc, aux) with Dagger(eng): QFT | xb
def run_shor(eng, N, a, verbose=False): """ Runs the quantum subroutine of Shor's algorithm for factoring. with 2n control qubits Args: eng (MainEngine): Main compiler engine to use. N (int): Number to factor. a (int): Relative prime to use as a base for a^x mod N. verbose (bool): If True, display intermediate measurement results. Returns: r (float): Potential period of a. """ n = int(math.ceil(math.log(N, 2))) x = eng.allocate_qureg(n) xN = initialisation_n(eng, N, n) xb = initialisation_n(eng, 0, n) aux = initialisation_n(eng, 0, 1) X | x[0] # set x to 1 measurements = [0] * (2 * n) # will hold the 2n measurement results ctrl_qubit = eng.allocate_qureg(2 * n) for k in range(2 * n): current_a = pow(a, 1 << k, N) # one iteration of 1-qubit QPE H | ctrl_qubit[k] gateUa(eng, current_a, mod_inv(current_a, N), x, xb, xN, aux, ctrl_qubit[k], N) with Dagger(eng): QFT | ctrl_qubit # and measure All(Measure) | ctrl_qubit eng.flush() for k in range(2 * n): measurements[k] = int(ctrl_qubit[k]) All(Measure) | x # turn the measured values into a number in [0,1) y = sum([(measurements[i] * 1. / (1 << (i + 1))) for i in range(2 * n)]) # continued fraction expansion to get denominator (the period?) r = Fraction(y).limit_denominator(N - 1).denominator # return the (potential) period return r
def test_quantumadder_size_mismatch(eng, qubit_idx, inverse, carry): qureg_a = eng.allocate_qureg(4 if qubit_idx != 0 else 3) qureg_b = eng.allocate_qureg(4 if qubit_idx != 1 else 3) qureg_c = eng.allocate_qureg(1 if qubit_idx != 2 else 2) if carry and inverse: pytest.skip('Inverse addition with carry not supported') elif not carry and qubit_idx == 2: pytest.skip('Invalid test parameter combination') with pytest.raises(ValueError): if inverse: with Dagger(eng): AddQuantum | (qureg_a, qureg_b, qureg_c if carry else []) else: AddQuantum | (qureg_a, qureg_b, qureg_c if carry else [])
def run_teleport(eng, state_creation_function): """ Runs quantum teleportation on the provided main compiler engine. Args: eng (MainEngine): Main compiler engine to run the circuit on. state_creation_function (function): Function which accepts the main engine and a qubit in state |0>, which it then transforms to the state that Alice would like to send to Bob. """ # make a Bell-pair b1, b2 = _create_bell_pair(eng) # Alice creates a nice state to send psi = eng.allocate_qubit() print("= Step 1. Alice creates the state to be sent from |0>") state_creation_function(eng, psi) # entangle it with Alice's b1 CNOT | (psi, b1) print("= Step 2. Alice entangles the state with her share of the Bell-pair") # measure two values (once in Hadamard basis) and send the bits to Bob H | psi Measure | psi Measure | b1 msg_to_bob = [int(psi), int(b1)] print("= Step 3. Alice sends the classical message {} to Bob".format(msg_to_bob)) # Bob may have to apply up to two operation depending on the message sent # by Alice: with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 # try to uncompute the psi state print("= Step 4. Bob tries to recover the state created by Alice") with Dagger(eng): state_creation_function(eng, b2) # check whether the uncompute was successful. The simulator only allows to # delete qubits which are in a computational basis state. del b2 eng.flush() print("\t Bob successfully arrived at |0>")
def CMultModN(eng, c, x, qubits, ancilla, a, N): """ This gate performs the operation (ax)mod(N), where x is stored in the qubits and a is a classical value. This gate also has a control. :param eng: The engine used for computations. :param c: A qubit control of the gate. :param qubits: The qubits representing the quantum value (superposition of classical values). :param ancilla: This is needed to check for overflows. :param a: The classical value 'a' which is used in (a + b)mod(N). :param N: The number to be factored into primes. """ n = len(x) _CMultModN(eng, c, x, qubits, ancilla, a, N) for i in range(n): Swap | (x[i], qubits[i]) # All(Swap) | zip(x, qubits) with Dagger(eng): _CMultModN(eng, c, x, qubits, ancilla, modinv(a, N), N)
def lcu_fpoaa(eng, list_of_unitaries, coefts, ctrl, sys, ctrl_dim, sys_dim, depth): phi = math.pi / 3.0 gate_seq = fpoaa_string(depth) t = len(gate_seq) # the rightmost operator is always W # which has already been applied above in the lcu step for i in range(1, t): if (gate_seq[t - 1 - i] == 'W'): lcu_basic(eng, list_of_unitaries, coefts, ctrl, sys, ctrl_dim, sys_dim) elif (gate_seq[t - 1 - i] == 'M'): with Dagger(eng): lcu_basic(eng, list_of_unitaries, coefts, ctrl, sys, ctrl_dim, sys_dim) elif (gate_seq[t - 1 - i] == 'R'): cond_phase(eng, ctrl, sys, phi) elif (gate_seq[t - 1 - i] == 'S'): cond_phase(eng, ctrl, sys, -1 * phi)
def run_teleport(eng, state_creation_function, verbose=False): # make a Bell-pair b1, b2 = create_bell_pair(eng) # Alice creates a nice state to send psi = eng.allocate_qubit() if verbose: print("Alice is creating her state from scratch, i.e., |0>.") state_creation_function(eng, psi) # entangle it with Alice's b1 CNOT | (psi, b1) if verbose: print("Alice entangled her qubit with her share of the Bell-pair.") # measure two values (once in Hadamard basis) and send the bits to Bob H | psi Measure | psi Measure | b1 msg_to_bob = [int(psi), int(b1)] if verbose: print("Alice is sending the message {} to Bob.".format(msg_to_bob)) # Bob may have to apply up to two operation depending on the message sent # by Alice: with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 # try to uncompute the psi state if verbose: print("Bob is trying to uncompute the state.") with Dagger(eng): state_creation_function(eng, b2) # check whether the uncompute was successful. The simulator only allows to # delete qubits which are in a computational basis state. del b2 eng.flush() if verbose: print("Bob successfully arrived at |0>")
def W(eng, individual_terms, initial_wavefunction, ancilla_qubits, system_qubits): """ Applies the W operator as defined in arXiv:1711.11025. Args: eng(MainEngine): compiler engine individual_terms(list<QubitOperator>): list of individual unitary QubitOperators. It applies individual_terms[0] if ancilla qubits are in state |0> where ancilla_qubits[0] is the least significant bit. initial_wavefunction: Initial wavefunction of the ancilla qubits ancilla_qubits(Qureg): ancilla quantum register in state |0> system_qubits(Qureg): system quantum register """ # Apply V: for ancilla_state in range(len(individual_terms)): with Compute(eng): for bit_pos in range(len(ancilla_qubits)): if not (ancilla_state >> bit_pos) & 1: X | ancilla_qubits[bit_pos] with Control(eng, ancilla_qubits): individual_terms[ancilla_state] | system_qubits Uncompute(eng) # Apply S: 1) Apply B^dagger with Compute(eng): with Dagger(eng): StatePreparation(initial_wavefunction) | ancilla_qubits # Apply S: 2) Apply I-2|0><0| with Compute(eng): All(X) | ancilla_qubits with Control(eng, ancilla_qubits[:-1]): Z | ancilla_qubits[-1] Uncompute(eng) # Apply S: 3) Apply B Uncompute(eng) # Could also be omitted and added when calculating the eigenvalues: Ph(math.pi) | system_qubits[0]
def test_simulator_kqubit_gate(sim): m1 = Rx(0.3).matrix m2 = Rx(0.8).matrix m3 = Ry(0.1).matrix m4 = Rz(0.9).matrix.dot(Ry(-0.1).matrix) m = numpy.kron(m4, numpy.kron(m3, numpy.kron(m2, m1))) class KQubitGate(BasicGate): @property def matrix(self): return m eng = HiQMainEngine(sim, [GreedyScheduler()]) qureg = eng.allocate_qureg(4) qubit = eng.allocate_qubit() Rx(-0.3) | qureg[0] Rx(-0.8) | qureg[1] Ry(-0.1) | qureg[2] Rz(-0.9) | qureg[3] Ry(0.1) | qureg[3] X | qubit with Control(eng, qubit): KQubitGate() | qureg X | qubit with Control(eng, qubit): with Dagger(eng): KQubitGate() | qureg assert sim.get_amplitude('0' * 5, qubit + qureg) == pytest.approx(1.) class LargerGate(BasicGate): @property def matrix(self): return numpy.eye(2**6) with pytest.raises(Exception): LargerGate() | (qureg + qubit) eng.flush()
def run_teleport(eng, state_creation_function, verbose=False): b1, b2 = create_bell_pair(eng) psi = eng.allocate_qubit() if verbose: print("Alice is creating her state from scratch, i.e., |0>.") state_creation_function(eng, psi) CNOT | (psi, b1) if verbose: print("Alice entangled her qubit with her share of the Bell-pair.") H | psi Measure | psi Measure | b1 msg_to_bob = [int(psi), int(b1)] if verbose: print("Alice is sending the message {} to Bob.".format(msg_to_bob)) with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 if verbose: print("Bob is trying to uncompute the state.") with Dagger(eng): state_creation_function(eng, b2) del b2 eng.flush() if verbose: print("Bob successfully arrived at |0>")
def CCadd_inverse(eng, circuit, c1, c2, qubits, value): with Dagger(eng): CCadd(eng, circuit, c1, c2, qubits, value)