def adjoint_qft_reverse_register(circuit, register): """ The adjoint version of qft_reverse_register. """ reverse_register = register[::-1] qft.iqft(circuit, reverse_register)
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. """ qubits = cirq.NamedQubit.range(number_of_qubits, prefix="qubit") circuit = cirq.Circuit() # Set up the register so it's in the correct state for the test if prep_args is None: prep_function(circuit, qubits) else: prep_function(circuit, qubits, prep_args) # Run the inverse QFT, which corresponds to the normal DFT qft.iqft(circuit, qubits) # Measure the result from QFT circuit.append(cirq.measure(*qubits, key="result")) # Run the circuit simulator = cirq.Simulator() result = simulator.run(circuit, repetitions=1) result_states = result.histogram(key="result") for(state, count) in result_states.items(): result = state break # 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 add(circ, a, b, n): # Take the QFT. qft(circ, b, n) # Compute controlled-phases. # Iterate through the targets. for i in range(n, 0, -1): # Iterate through the controls. for j in range(i, 0, -1): circ.cu1(2 * pi / 2**(i - j + 1), a[j - 1], b[i - 1]) # Take the inverse QFT. iqft(circ, b, n)
def add(circ, a, b, n): # move n forward by one to account for overflow n += 1 # Take the QFT. qft(circ, b, n) # Compute controlled-phases. # Iterate through the targets. for i in range(n,0,-1): # Iterate through the controls. for j in range(i,0,-1): # If the qubit a[j-1] exists run ccu, if not assume the qubit is 0 and never existed if len(a) - 1 >= j - 1: circ.cu1(2*pi/2**(i-j+1), a[j-1], b[i-1]) # Take the inverse QFT. iqft(circ, b, n)
def retrieve(self, num_bobs: int) -> Program: # Assert: Has received all components for the target entanglement set assert None not in self.received_shares, \ "Bob #" + str(self.id) + ": retrieve() attempted without receiving all shares" self.protocol += iqft(self.received_shares, num_bobs) self.protocol += disentangle(self.received_shares[0], self.received_shares[1:]) self.protocol += qft(self.received_shares[0], 1) wf_sim = WavefunctionSimulator() for i, share in enumerate(self.received_shares): self.protocol += MEASURE(share, self.memory[i])
def deal_shares(self, num_bobs: int) -> QubitShareMatrix: self.generate_qubit_matrix(num_bobs) if random() < self.prob_real: self.secret_revealed = True for bob in range(num_bobs): qubit_list = [q[0] for q in self.q_mat[bob]] self.protocol += init_p(qubit_list[1:]) if self.secret_revealed: self.protocol += self.secret_ansatz(qubit_list[0]) else: self.protocol += self.tester_ansatz(qubit_list[0]) self.protocol += iqft(qubit_list[0], 1) self.protocol += entangle(qubit_list[0], qubit_list[1:]) self.protocol += qft(qubit_list, num_bobs) return self.roll_matrix(self.q_mat)
def test_period_6(self): """ Tests QFT by running a single iteration of the period-finding subroutine from Shor's algorithm. This test will use 21 as the number to factor, 11 as the original guess, and ensure that QFT reports that the modular exponential equation has a period of 6. """ # So this test basically just runs a hardcoded iteration of the quantum portion # of Shor's algorithm. I don't want to explain the entire thing here; you can # look at shor.py for my implementation, which has plenty of documentation # attached to it. For this test, I'm trying to factor 21. That means the # "output" register needs to be 5 qubits (because 2^4 = 16 and 2^5 = 32, so it # needs 5 qubits to be represented in binary). For the input register, I'm going # with 9 qubits: 21^2 = 441, 2^8 = 256, and 2^9 = 512, so 21^2 needs 9 qubits to # be represented in binary. That will give 512 discrete states. For a guess of # 11, the period will be 6: # ------------------------- # State (i) | 11^i mod 21 # ------------------------- # 0 | 1 # 1 | 11 # 2 | 16 # 3 | 8 # 4 | 4 # 5 | 2 # 6 | 1 <== Pattern repeats here, after 6 entries # 7 | 11 # 8 | 16 # ... # # QFT should return some value X which, when divided by 512, should be really # close to 0/6, 1/6, 2/6, 3/6, 4/6, or 5/6. The amplitude peaks (the expected # values) are 0, 85, 171, 256, 341, and 427. input_length = 9 output_length = 5 number_to_factor = 21 guess = 11 input = QuantumRegister(input_length) output = QuantumRegister(output_length) measurement = ClassicalRegister(input_length) circuit = QuantumCircuit(input, output, measurement) circuit.h(input) # Input = |+...+> circuit.x(output[output_length - 1]) # Output = |0...01> # Do the arithmetic so the input register is entangled with the output register; after # this, if the state X is measured on the input register, the output register will always # be measured as 11^X mod 21. for i in range(0, input_length): power_of_two = input_length - 1 - i power_of_guess = 2**power_of_two constant = pow(guess, power_of_guess, number_to_factor) shor_math.controlled_modular_multiply(circuit, input[i], constant, number_to_factor, output) # Run inverse QFT (the analog of the normal DFT) to find the period qft.iqft(circuit, input) circuit.measure(input, measurement) # Run the circuit simulator = Aer.get_backend("qasm_simulator") simulation = execute(circuit, simulator, shots=1) result = simulation.result() counts = result.get_counts(circuit) measurement = 0 for (state, count) in counts.items(): state = state[::-1] measurement = int(state, 2) break # Measure the resulting period and make sure it's close to a multiple of 1/6, # with a tolerance of 0.01. scaled_measurement = measurement / 512 * 6 nearest_multiple = round(scaled_measurement) delta = abs(scaled_measurement - nearest_multiple) print( f"Measured {measurement}/512 => {scaled_measurement}, delta = {delta}" ) if delta >= 0.01: self.fail(f"QFT failed, delta of {delta} is too high.") print("Passed!")
def shor_quantum_subroutine(guess, number_to_factor): """ Runs the quantum subroutine of Shor's algorithm. This will find a value called X', where X' is the nearest integer for any value of N * i / P where N = 2^(2b), b = the number of bits needed to represent NumberToFactor as a binary integer, i is any integer 0 <= i < P, and P is the period of the modular exponentiation function: Y = Guess^X mod NumberToFactor. Wow. A better name for this function might be "Get_Approximate_Multiple_Of_Reciprocal_Of_Modular_Exponentiation_Period", but that would just be pushing it. Parameters: guess (int): The random number that was guessed as a factor of number_to_factor. This will be used as the base of the power term in the modular exponentiation function. number_to_factor (int): The number being factored by the algorithm. This will be used as the modulus in the modular exponentiation function. Returns: A tuple of ints where the first term is the nearest integer value for X', and the second term is N. """ # Number of bits needed to represent number_to_factor output_size = math.ceil(math.log(number_to_factor + 1, 2)) input_size = output_size * 2 # Construct the circuit and registers input = QuantumRegister(input_size) output = QuantumRegister(output_size) measurement = ClassicalRegister(input_size) circuit = QuantumCircuit(input, output, measurement) circuit.h(input) # Input = |+...+>, so all possible states at once # Run the quantum modular exponentiation function, # |output> = guess ^ |input> mod number_to_factor. # This will entangle input and output so that for each state of input, # output will correspond to the solution to the equation. modular_exponentiation(circuit, input, output, guess, number_to_factor) # Since guess and number_to_factor are coprime, the modular exponentiation function # with them is going to be periodic. By encoding all possible input and output # values into these two entangled registers, we can use QFT to measure the period... # sort of. I'll explain below. qft.iqft(circuit, input) # Ok, so really what we'll end up measuring is an approximation of a fraction that # has the period P on the denominator, and N * i on the numerator (where N = the number # of states in the input register, so 2^Length(input) and i is an integer where # 0 <= i < P). # # That's not going to make a lot of sense, so let me give you an example. Say the # number we want to factor is 21 and our guess is 11. 21 takes 5 bits to represent in # binary, so length(output) = 5 and length(input) = 10. Input has 2^10 = 1024 possible # states in it, so N = 1024. QFT will modify the input so all of the output values # will basically have zero probability except for P values, where P is the period # (in this case, 6). These values will be N * 0 / P, N * 1 / P ... N * (P-1) / P. # For the example, with 11^X mod 21, QFT will modify the states so these 6 have very # high probabilities: # 1024 * 0 / 6 = 0 # 1024 * 1 / 6 = 170.666... # 1024 * 2 / 6 = 341.333... # 1024 * 3 / 6 = 512 # 1024 * 4 / 6 = 682.666... # 1024 * 5 / 6 = 853.333... # # The reason for this is way too hard to explain in code comments - you're going to # have to read some papers to understand why it does this. All you need to know is this # is what's going to happen. Anyway, since we're dealing with binary integers here, we # can't get these exact values. So when we measure X, it's going to be the closest integer # approximation of one of these 6 values. Thus the 6 possibilities we can measure for # this example are 0, 171, 341, 512, 683, and 853. I'll explain what to do with this value # in the next step. # Measure the result from QFT circuit.measure(input, measurement) # Run the circuit simulator = Aer.get_backend("qasm_simulator") simulation = execute(circuit, simulator, shots=1) result = simulation.result() counts = result.get_counts(circuit) for (state, count) in counts.items(): state = state[::-1] result = int(state, 2) break return (result, 2**(input_size))